1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/code-assembler.h"
6
7#include <ostream>
8
9#include "src/code-factory.h"
10#include "src/compiler/graph.h"
11#include "src/compiler/instruction-selector.h"
12#include "src/compiler/linkage.h"
13#include "src/compiler/node-matchers.h"
14#include "src/compiler/pipeline.h"
15#include "src/compiler/raw-machine-assembler.h"
16#include "src/compiler/schedule.h"
17#include "src/frames.h"
18#include "src/interface-descriptors.h"
19#include "src/interpreter/bytecodes.h"
20#include "src/machine-type.h"
21#include "src/macro-assembler.h"
22#include "src/objects-inl.h"
23#include "src/utils.h"
24#include "src/zone/zone.h"
25
26#define REPEAT_1_TO_2(V, T) V(T) V(T, T)
27#define REPEAT_1_TO_3(V, T) REPEAT_1_TO_2(V, T) V(T, T, T)
28#define REPEAT_1_TO_4(V, T) REPEAT_1_TO_3(V, T) V(T, T, T, T)
29#define REPEAT_1_TO_5(V, T) REPEAT_1_TO_4(V, T) V(T, T, T, T, T)
30#define REPEAT_1_TO_6(V, T) REPEAT_1_TO_5(V, T) V(T, T, T, T, T, T)
31#define REPEAT_1_TO_7(V, T) REPEAT_1_TO_6(V, T) V(T, T, T, T, T, T, T)
32#define REPEAT_1_TO_8(V, T) REPEAT_1_TO_7(V, T) V(T, T, T, T, T, T, T, T)
33#define REPEAT_1_TO_9(V, T) REPEAT_1_TO_8(V, T) V(T, T, T, T, T, T, T, T, T)
34
35namespace v8 {
36namespace internal {
37namespace compiler {
38
39CodeAssemblerState::CodeAssemblerState(
40    Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
41    Code::Flags flags, const char* name, size_t result_size)
42    : CodeAssemblerState(
43          isolate, zone,
44          Linkage::GetStubCallDescriptor(
45              isolate, zone, descriptor, descriptor.GetStackParameterCount(),
46              CallDescriptor::kNoFlags, Operator::kNoProperties,
47              MachineType::AnyTagged(), result_size),
48          flags, name) {}
49
50CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
51                                       int parameter_count, Code::Flags flags,
52                                       const char* name)
53    : CodeAssemblerState(isolate, zone,
54                         Linkage::GetJSCallDescriptor(
55                             zone, false, parameter_count,
56                             Code::ExtractKindFromFlags(flags) == Code::BUILTIN
57                                 ? CallDescriptor::kPushArgumentCount
58                                 : CallDescriptor::kNoFlags),
59                         flags, name) {}
60
61CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
62                                       CallDescriptor* call_descriptor,
63                                       Code::Flags flags, const char* name)
64    : raw_assembler_(new RawMachineAssembler(
65          isolate, new (zone) Graph(zone), call_descriptor,
66          MachineType::PointerRepresentation(),
67          InstructionSelector::SupportedMachineOperatorFlags(),
68          InstructionSelector::AlignmentRequirements())),
69      flags_(flags),
70      name_(name),
71      code_generated_(false),
72      variables_(zone) {}
73
74CodeAssemblerState::~CodeAssemblerState() {}
75
76int CodeAssemblerState::parameter_count() const {
77  return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
78}
79
80CodeAssembler::~CodeAssembler() {}
81
82class BreakOnNodeDecorator final : public GraphDecorator {
83 public:
84  explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
85
86  void Decorate(Node* node) final {
87    if (node->id() == node_id_) {
88      base::OS::DebugBreak();
89    }
90  }
91
92 private:
93  NodeId node_id_;
94};
95
96void CodeAssembler::BreakOnNode(int node_id) {
97  Graph* graph = raw_assembler()->graph();
98  Zone* zone = graph->zone();
99  GraphDecorator* decorator =
100      new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id));
101  graph->AddDecorator(decorator);
102}
103
104void CodeAssembler::RegisterCallGenerationCallbacks(
105    const CodeAssemblerCallback& call_prologue,
106    const CodeAssemblerCallback& call_epilogue) {
107  // The callback can be registered only once.
108  DCHECK(!state_->call_prologue_);
109  DCHECK(!state_->call_epilogue_);
110  state_->call_prologue_ = call_prologue;
111  state_->call_epilogue_ = call_epilogue;
112}
113
114void CodeAssembler::UnregisterCallGenerationCallbacks() {
115  state_->call_prologue_ = nullptr;
116  state_->call_epilogue_ = nullptr;
117}
118
119void CodeAssembler::CallPrologue() {
120  if (state_->call_prologue_) {
121    state_->call_prologue_();
122  }
123}
124
125void CodeAssembler::CallEpilogue() {
126  if (state_->call_epilogue_) {
127    state_->call_epilogue_();
128  }
129}
130
131// static
132Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state) {
133  DCHECK(!state->code_generated_);
134
135  RawMachineAssembler* rasm = state->raw_assembler_.get();
136  Schedule* schedule = rasm->Export();
137  Handle<Code> code = Pipeline::GenerateCodeForCodeStub(
138      rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
139      state->flags_, state->name_);
140
141  state->code_generated_ = true;
142  return code;
143}
144
145bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
146
147bool CodeAssembler::IsFloat64RoundUpSupported() const {
148  return raw_assembler()->machine()->Float64RoundUp().IsSupported();
149}
150
151bool CodeAssembler::IsFloat64RoundDownSupported() const {
152  return raw_assembler()->machine()->Float64RoundDown().IsSupported();
153}
154
155bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
156  return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
157}
158
159bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
160  return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
161}
162
163Node* CodeAssembler::Int32Constant(int32_t value) {
164  return raw_assembler()->Int32Constant(value);
165}
166
167Node* CodeAssembler::Int64Constant(int64_t value) {
168  return raw_assembler()->Int64Constant(value);
169}
170
171Node* CodeAssembler::IntPtrConstant(intptr_t value) {
172  return raw_assembler()->IntPtrConstant(value);
173}
174
175Node* CodeAssembler::NumberConstant(double value) {
176  return raw_assembler()->NumberConstant(value);
177}
178
179Node* CodeAssembler::SmiConstant(Smi* value) {
180  return BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value)));
181}
182
183Node* CodeAssembler::SmiConstant(int value) {
184  return SmiConstant(Smi::FromInt(value));
185}
186
187Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) {
188  return raw_assembler()->HeapConstant(object);
189}
190
191Node* CodeAssembler::CStringConstant(const char* str) {
192  return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED));
193}
194
195Node* CodeAssembler::BooleanConstant(bool value) {
196  return raw_assembler()->BooleanConstant(value);
197}
198
199Node* CodeAssembler::ExternalConstant(ExternalReference address) {
200  return raw_assembler()->ExternalConstant(address);
201}
202
203Node* CodeAssembler::Float64Constant(double value) {
204  return raw_assembler()->Float64Constant(value);
205}
206
207Node* CodeAssembler::NaNConstant() {
208  return LoadRoot(Heap::kNanValueRootIndex);
209}
210
211bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
212  Int64Matcher m(node);
213  if (m.HasValue() &&
214      m.IsInRange(std::numeric_limits<int32_t>::min(),
215                  std::numeric_limits<int32_t>::max())) {
216    out_value = static_cast<int32_t>(m.Value());
217    return true;
218  }
219
220  return false;
221}
222
223bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
224  Int64Matcher m(node);
225  if (m.HasValue()) out_value = m.Value();
226  return m.HasValue();
227}
228
229bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) {
230  if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
231    node = node->InputAt(0);
232  } else {
233    return false;
234  }
235  IntPtrMatcher m(node);
236  if (m.HasValue()) {
237    out_value = Smi::cast(bit_cast<Object*>(m.Value()));
238    return true;
239  }
240  return false;
241}
242
243bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
244  if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
245      node->opcode() == IrOpcode::kBitcastWordToTagged) {
246    node = node->InputAt(0);
247  }
248  IntPtrMatcher m(node);
249  if (m.HasValue()) out_value = m.Value();
250  return m.HasValue();
251}
252
253Node* CodeAssembler::Parameter(int value) {
254  return raw_assembler()->Parameter(value);
255}
256
257Node* CodeAssembler::GetJSContextParameter() {
258  CallDescriptor* desc = raw_assembler()->call_descriptor();
259  DCHECK(desc->IsJSFunctionCall());
260  return Parameter(Linkage::GetJSCallContextParamIndex(
261      static_cast<int>(desc->JSParameterCount())));
262}
263
264void CodeAssembler::Return(Node* value) {
265  return raw_assembler()->Return(value);
266}
267
268void CodeAssembler::Return(Node* value1, Node* value2) {
269  return raw_assembler()->Return(value1, value2);
270}
271
272void CodeAssembler::Return(Node* value1, Node* value2, Node* value3) {
273  return raw_assembler()->Return(value1, value2, value3);
274}
275
276void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
277  return raw_assembler()->PopAndReturn(pop, value);
278}
279
280void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
281
282void CodeAssembler::Unreachable() {
283  DebugBreak();
284  raw_assembler()->Unreachable();
285}
286
287void CodeAssembler::Comment(const char* format, ...) {
288  if (!FLAG_code_comments) return;
289  char buffer[4 * KB];
290  StringBuilder builder(buffer, arraysize(buffer));
291  va_list arguments;
292  va_start(arguments, format);
293  builder.AddFormattedList(format, arguments);
294  va_end(arguments);
295
296  // Copy the string before recording it in the assembler to avoid
297  // issues when the stack allocated buffer goes out of scope.
298  const int prefix_len = 2;
299  int length = builder.position() + 1;
300  char* copy = reinterpret_cast<char*>(malloc(length + prefix_len));
301  MemCopy(copy + prefix_len, builder.Finalize(), length);
302  copy[0] = ';';
303  copy[1] = ' ';
304  raw_assembler()->Comment(copy);
305}
306
307void CodeAssembler::Bind(Label* label) { return label->Bind(); }
308
309Node* CodeAssembler::LoadFramePointer() {
310  return raw_assembler()->LoadFramePointer();
311}
312
313Node* CodeAssembler::LoadParentFramePointer() {
314  return raw_assembler()->LoadParentFramePointer();
315}
316
317Node* CodeAssembler::LoadStackPointer() {
318  return raw_assembler()->LoadStackPointer();
319}
320
321#define DEFINE_CODE_ASSEMBLER_BINARY_OP(name)   \
322  Node* CodeAssembler::name(Node* a, Node* b) { \
323    return raw_assembler()->name(a, b);         \
324  }
325CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
326#undef DEFINE_CODE_ASSEMBLER_BINARY_OP
327
328Node* CodeAssembler::IntPtrAdd(Node* left, Node* right) {
329  intptr_t left_constant;
330  bool is_left_constant = ToIntPtrConstant(left, left_constant);
331  intptr_t right_constant;
332  bool is_right_constant = ToIntPtrConstant(right, right_constant);
333  if (is_left_constant) {
334    if (is_right_constant) {
335      return IntPtrConstant(left_constant + right_constant);
336    }
337    if (left_constant == 0) {
338      return right;
339    }
340  } else if (is_right_constant) {
341    if (right_constant == 0) {
342      return left;
343    }
344  }
345  return raw_assembler()->IntPtrAdd(left, right);
346}
347
348Node* CodeAssembler::IntPtrSub(Node* left, Node* right) {
349  intptr_t left_constant;
350  bool is_left_constant = ToIntPtrConstant(left, left_constant);
351  intptr_t right_constant;
352  bool is_right_constant = ToIntPtrConstant(right, right_constant);
353  if (is_left_constant) {
354    if (is_right_constant) {
355      return IntPtrConstant(left_constant - right_constant);
356    }
357  } else if (is_right_constant) {
358    if (right_constant == 0) {
359      return left;
360    }
361  }
362  return raw_assembler()->IntPtrSub(left, right);
363}
364
365Node* CodeAssembler::WordShl(Node* value, int shift) {
366  return (shift != 0) ? raw_assembler()->WordShl(value, IntPtrConstant(shift))
367                      : value;
368}
369
370Node* CodeAssembler::WordShr(Node* value, int shift) {
371  return (shift != 0) ? raw_assembler()->WordShr(value, IntPtrConstant(shift))
372                      : value;
373}
374
375Node* CodeAssembler::Word32Shr(Node* value, int shift) {
376  return (shift != 0) ? raw_assembler()->Word32Shr(value, Int32Constant(shift))
377                      : value;
378}
379
380Node* CodeAssembler::ChangeUint32ToWord(Node* value) {
381  if (raw_assembler()->machine()->Is64()) {
382    value = raw_assembler()->ChangeUint32ToUint64(value);
383  }
384  return value;
385}
386
387Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
388  if (raw_assembler()->machine()->Is64()) {
389    value = raw_assembler()->ChangeInt32ToInt64(value);
390  }
391  return value;
392}
393
394Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) {
395  if (raw_assembler()->machine()->Is64()) {
396    return raw_assembler()->RoundInt64ToFloat64(value);
397  }
398  return raw_assembler()->ChangeInt32ToFloat64(value);
399}
400
401#define DEFINE_CODE_ASSEMBLER_UNARY_OP(name) \
402  Node* CodeAssembler::name(Node* a) { return raw_assembler()->name(a); }
403CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
404#undef DEFINE_CODE_ASSEMBLER_UNARY_OP
405
406Node* CodeAssembler::Load(MachineType rep, Node* base) {
407  return raw_assembler()->Load(rep, base);
408}
409
410Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset) {
411  return raw_assembler()->Load(rep, base, offset);
412}
413
414Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) {
415  return raw_assembler()->AtomicLoad(rep, base, offset);
416}
417
418Node* CodeAssembler::LoadRoot(Heap::RootListIndex root_index) {
419  if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
420    Handle<Object> root = isolate()->heap()->root_handle(root_index);
421    if (root->IsSmi()) {
422      return SmiConstant(Smi::cast(*root));
423    } else {
424      return HeapConstant(Handle<HeapObject>::cast(root));
425    }
426  }
427
428  Node* roots_array_start =
429      ExternalConstant(ExternalReference::roots_array_start(isolate()));
430  return Load(MachineType::AnyTagged(), roots_array_start,
431              IntPtrConstant(root_index * kPointerSize));
432}
433
434Node* CodeAssembler::Store(Node* base, Node* value) {
435  return raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
436                                kFullWriteBarrier);
437}
438
439Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) {
440  return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
441                                value, kFullWriteBarrier);
442}
443
444Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset,
445                                              Node* value) {
446  return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
447                                value, kMapWriteBarrier);
448}
449
450Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
451                                         Node* value) {
452  return raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
453}
454
455Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
456                                         Node* offset, Node* value) {
457  return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
458}
459
460Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
461                                 Node* offset, Node* value) {
462  return raw_assembler()->AtomicStore(rep, base, offset, value);
463}
464
465Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) {
466  DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index));
467  Node* roots_array_start =
468      ExternalConstant(ExternalReference::roots_array_start(isolate()));
469  return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start,
470                             IntPtrConstant(root_index * kPointerSize), value);
471}
472
473Node* CodeAssembler::Retain(Node* value) {
474  return raw_assembler()->Retain(value);
475}
476
477Node* CodeAssembler::Projection(int index, Node* value) {
478  return raw_assembler()->Projection(index, value);
479}
480
481void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
482                                    Variable* exception_var) {
483  Label success(this), exception(this, Label::kDeferred);
484  success.MergeVariables();
485  exception.MergeVariables();
486  DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
487
488  raw_assembler()->Continuations(node, success.label_, exception.label_);
489
490  Bind(&exception);
491  const Operator* op = raw_assembler()->common()->IfException();
492  Node* exception_value = raw_assembler()->AddNode(op, node, node);
493  if (exception_var != nullptr) {
494    exception_var->Bind(exception_value);
495  }
496  Goto(if_exception);
497
498  Bind(&success);
499}
500
501template <class... TArgs>
502Node* CodeAssembler::CallRuntime(Runtime::FunctionId function, Node* context,
503                                 TArgs... args) {
504  int argc = static_cast<int>(sizeof...(args));
505  CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
506      zone(), function, argc, Operator::kNoProperties,
507      CallDescriptor::kNoFlags);
508  int return_count = static_cast<int>(desc->ReturnCount());
509
510  Node* centry =
511      HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
512  Node* ref = ExternalConstant(ExternalReference(function, isolate()));
513  Node* arity = Int32Constant(argc);
514
515  Node* nodes[] = {centry, args..., ref, arity, context};
516
517  CallPrologue();
518  Node* return_value = raw_assembler()->CallN(desc, arraysize(nodes), nodes);
519  CallEpilogue();
520  return return_value;
521}
522
523// Instantiate CallRuntime() with up to 6 arguments.
524#define INSTANTIATE(...)                                       \
525  template V8_EXPORT_PRIVATE Node* CodeAssembler::CallRuntime( \
526      Runtime::FunctionId, __VA_ARGS__);
527REPEAT_1_TO_7(INSTANTIATE, Node*)
528#undef INSTANTIATE
529
530template <class... TArgs>
531Node* CodeAssembler::TailCallRuntime(Runtime::FunctionId function,
532                                     Node* context, TArgs... args) {
533  int argc = static_cast<int>(sizeof...(args));
534  CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
535      zone(), function, argc, Operator::kNoProperties,
536      CallDescriptor::kSupportsTailCalls);
537  int return_count = static_cast<int>(desc->ReturnCount());
538
539  Node* centry =
540      HeapConstant(CodeFactory::RuntimeCEntry(isolate(), return_count));
541  Node* ref = ExternalConstant(ExternalReference(function, isolate()));
542  Node* arity = Int32Constant(argc);
543
544  Node* nodes[] = {centry, args..., ref, arity, context};
545
546  return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
547}
548
549// Instantiate TailCallRuntime() with up to 6 arguments.
550#define INSTANTIATE(...)                                           \
551  template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallRuntime( \
552      Runtime::FunctionId, __VA_ARGS__);
553REPEAT_1_TO_7(INSTANTIATE, Node*)
554#undef INSTANTIATE
555
556template <class... TArgs>
557Node* CodeAssembler::CallStubR(const CallInterfaceDescriptor& descriptor,
558                               size_t result_size, Node* target, Node* context,
559                               TArgs... args) {
560  Node* nodes[] = {target, args..., context};
561  return CallStubN(descriptor, result_size, arraysize(nodes), nodes);
562}
563
564// Instantiate CallStubR() with up to 6 arguments.
565#define INSTANTIATE(...)                                     \
566  template V8_EXPORT_PRIVATE Node* CodeAssembler::CallStubR( \
567      const CallInterfaceDescriptor& descriptor, size_t, Node*, __VA_ARGS__);
568REPEAT_1_TO_7(INSTANTIATE, Node*)
569#undef INSTANTIATE
570
571Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
572                               size_t result_size, int input_count,
573                               Node* const* inputs) {
574  // 2 is for target and context.
575  DCHECK_LE(2, input_count);
576  int argc = input_count - 2;
577  DCHECK_LE(descriptor.GetParameterCount(), argc);
578  // Extra arguments not mentioned in the descriptor are passed on the stack.
579  int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
580  DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
581  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
582      isolate(), zone(), descriptor, stack_parameter_count,
583      CallDescriptor::kNoFlags, Operator::kNoProperties,
584      MachineType::AnyTagged(), result_size);
585
586  CallPrologue();
587  Node* return_value = raw_assembler()->CallN(desc, input_count, inputs);
588  CallEpilogue();
589  return return_value;
590}
591
592template <class... TArgs>
593Node* CodeAssembler::TailCallStub(const CallInterfaceDescriptor& descriptor,
594                                  Node* target, Node* context, TArgs... args) {
595  DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
596  size_t result_size = 1;
597  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
598      isolate(), zone(), descriptor, descriptor.GetStackParameterCount(),
599      CallDescriptor::kSupportsTailCalls, Operator::kNoProperties,
600      MachineType::AnyTagged(), result_size);
601
602  Node* nodes[] = {target, args..., context};
603
604  return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
605}
606
607// Instantiate TailCallStub() with up to 6 arguments.
608#define INSTANTIATE(...)                                        \
609  template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallStub( \
610      const CallInterfaceDescriptor& descriptor, Node*, __VA_ARGS__);
611REPEAT_1_TO_7(INSTANTIATE, Node*)
612#undef INSTANTIATE
613
614template <class... TArgs>
615Node* CodeAssembler::TailCallBytecodeDispatch(
616    const CallInterfaceDescriptor& descriptor, Node* target, TArgs... args) {
617  DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
618  CallDescriptor* desc = Linkage::GetBytecodeDispatchCallDescriptor(
619      isolate(), zone(), descriptor, descriptor.GetStackParameterCount());
620
621  Node* nodes[] = {target, args...};
622  return raw_assembler()->TailCallN(desc, arraysize(nodes), nodes);
623}
624
625// Instantiate TailCallBytecodeDispatch() with 4 arguments.
626template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
627    const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
628    Node*, Node*);
629
630Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
631                                    int input_count, Node* const* inputs) {
632  CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(zone(), signature);
633  return raw_assembler()->CallN(desc, input_count, inputs);
634}
635
636Node* CodeAssembler::CallCFunction2(MachineType return_type,
637                                    MachineType arg0_type,
638                                    MachineType arg1_type, Node* function,
639                                    Node* arg0, Node* arg1) {
640  return raw_assembler()->CallCFunction2(return_type, arg0_type, arg1_type,
641                                         function, arg0, arg1);
642}
643
644Node* CodeAssembler::CallCFunction3(MachineType return_type,
645                                    MachineType arg0_type,
646                                    MachineType arg1_type,
647                                    MachineType arg2_type, Node* function,
648                                    Node* arg0, Node* arg1, Node* arg2) {
649  return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type,
650                                         arg2_type, function, arg0, arg1, arg2);
651}
652
653void CodeAssembler::Goto(Label* label) {
654  label->MergeVariables();
655  raw_assembler()->Goto(label->label_);
656}
657
658void CodeAssembler::GotoIf(Node* condition, Label* true_label) {
659  Label false_label(this);
660  Branch(condition, true_label, &false_label);
661  Bind(&false_label);
662}
663
664void CodeAssembler::GotoIfNot(Node* condition, Label* false_label) {
665  Label true_label(this);
666  Branch(condition, &true_label, false_label);
667  Bind(&true_label);
668}
669
670void CodeAssembler::Branch(Node* condition, Label* true_label,
671                           Label* false_label) {
672  true_label->MergeVariables();
673  false_label->MergeVariables();
674  return raw_assembler()->Branch(condition, true_label->label_,
675                                 false_label->label_);
676}
677
678void CodeAssembler::Switch(Node* index, Label* default_label,
679                           const int32_t* case_values, Label** case_labels,
680                           size_t case_count) {
681  RawMachineLabel** labels =
682      new (zone()->New(sizeof(RawMachineLabel*) * case_count))
683          RawMachineLabel*[case_count];
684  for (size_t i = 0; i < case_count; ++i) {
685    labels[i] = case_labels[i]->label_;
686    case_labels[i]->MergeVariables();
687    default_label->MergeVariables();
688  }
689  return raw_assembler()->Switch(index, default_label->label_, case_values,
690                                 labels, case_count);
691}
692
693// RawMachineAssembler delegate helpers:
694Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
695
696Factory* CodeAssembler::factory() const { return isolate()->factory(); }
697
698Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
699
700RawMachineAssembler* CodeAssembler::raw_assembler() const {
701  return state_->raw_assembler_.get();
702}
703
704// The core implementation of Variable is stored through an indirection so
705// that it can outlive the often block-scoped Variable declarations. This is
706// needed to ensure that variable binding and merging through phis can
707// properly be verified.
708class CodeAssemblerVariable::Impl : public ZoneObject {
709 public:
710  explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {}
711  Node* value_;
712  MachineRepresentation rep_;
713};
714
715CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
716                                             MachineRepresentation rep)
717    : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
718  state_->variables_.insert(impl_);
719}
720
721CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
722                                             MachineRepresentation rep,
723                                             Node* initial_value)
724    : CodeAssemblerVariable(assembler, rep) {
725  Bind(initial_value);
726}
727
728CodeAssemblerVariable::~CodeAssemblerVariable() {
729  state_->variables_.erase(impl_);
730}
731
732void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
733
734Node* CodeAssemblerVariable::value() const {
735  DCHECK_NOT_NULL(impl_->value_);
736  return impl_->value_;
737}
738
739MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
740
741bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
742
743CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
744                                       size_t vars_count,
745                                       CodeAssemblerVariable** vars,
746                                       CodeAssemblerLabel::Type type)
747    : bound_(false),
748      merge_count_(0),
749      state_(assembler->state()),
750      label_(nullptr) {
751  void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
752  label_ = new (buffer)
753      RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
754                                        : RawMachineLabel::kNonDeferred);
755  for (size_t i = 0; i < vars_count; ++i) {
756    variable_phis_[vars[i]->impl_] = nullptr;
757  }
758}
759
760CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
761
762void CodeAssemblerLabel::MergeVariables() {
763  ++merge_count_;
764  for (auto var : state_->variables_) {
765    size_t count = 0;
766    Node* node = var->value_;
767    if (node != nullptr) {
768      auto i = variable_merges_.find(var);
769      if (i != variable_merges_.end()) {
770        i->second.push_back(node);
771        count = i->second.size();
772      } else {
773        count = 1;
774        variable_merges_[var] = std::vector<Node*>(1, node);
775      }
776    }
777    // If the following asserts, then you've jumped to a label without a bound
778    // variable along that path that expects to merge its value into a phi.
779    DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
780           count == merge_count_);
781    USE(count);
782
783    // If the label is already bound, we already know the set of variables to
784    // merge and phi nodes have already been created.
785    if (bound_) {
786      auto phi = variable_phis_.find(var);
787      if (phi != variable_phis_.end()) {
788        DCHECK_NOT_NULL(phi->second);
789        state_->raw_assembler_->AppendPhiInput(phi->second, node);
790      } else {
791        auto i = variable_merges_.find(var);
792        if (i != variable_merges_.end()) {
793          // If the following assert fires, then you've declared a variable that
794          // has the same bound value along all paths up until the point you
795          // bound this label, but then later merged a path with a new value for
796          // the variable after the label bind (it's not possible to add phis to
797          // the bound label after the fact, just make sure to list the variable
798          // in the label's constructor's list of merged variables).
799          DCHECK(find_if(i->second.begin(), i->second.end(),
800                         [node](Node* e) -> bool { return node != e; }) ==
801                 i->second.end());
802        }
803      }
804    }
805  }
806}
807
808void CodeAssemblerLabel::Bind() {
809  DCHECK(!bound_);
810  state_->raw_assembler_->Bind(label_);
811
812  // Make sure that all variables that have changed along any path up to this
813  // point are marked as merge variables.
814  for (auto var : state_->variables_) {
815    Node* shared_value = nullptr;
816    auto i = variable_merges_.find(var);
817    if (i != variable_merges_.end()) {
818      for (auto value : i->second) {
819        DCHECK(value != nullptr);
820        if (value != shared_value) {
821          if (shared_value == nullptr) {
822            shared_value = value;
823          } else {
824            variable_phis_[var] = nullptr;
825          }
826        }
827      }
828    }
829  }
830
831  for (auto var : variable_phis_) {
832    CodeAssemblerVariable::Impl* var_impl = var.first;
833    auto i = variable_merges_.find(var_impl);
834    // If the following asserts fire, then a variable that has been marked as
835    // being merged at the label--either by explicitly marking it so in the
836    // label constructor or by having seen different bound values at branches
837    // into the label--doesn't have a bound value along all of the paths that
838    // have been merged into the label up to this point.
839    DCHECK(i != variable_merges_.end());
840    DCHECK_EQ(i->second.size(), merge_count_);
841    Node* phi = state_->raw_assembler_->Phi(
842        var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
843    variable_phis_[var_impl] = phi;
844  }
845
846  // Bind all variables to a merge phi, the common value along all paths or
847  // null.
848  for (auto var : state_->variables_) {
849    auto i = variable_phis_.find(var);
850    if (i != variable_phis_.end()) {
851      var->value_ = i->second;
852    } else {
853      auto j = variable_merges_.find(var);
854      if (j != variable_merges_.end() && j->second.size() == merge_count_) {
855        var->value_ = j->second.back();
856      } else {
857        var->value_ = nullptr;
858      }
859    }
860  }
861
862  bound_ = true;
863}
864
865}  // namespace compiler
866}  // namespace internal
867}  // namespace v8
868