Home | History | Annotate | Download | only in compiler
      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 
     35 namespace v8 {
     36 namespace internal {
     37 namespace compiler {
     38 
     39 CodeAssemblerState::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 
     50 CodeAssemblerState::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 
     61 CodeAssemblerState::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 
     74 CodeAssemblerState::~CodeAssemblerState() {}
     75 
     76 int CodeAssemblerState::parameter_count() const {
     77   return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
     78 }
     79 
     80 CodeAssembler::~CodeAssembler() {}
     81 
     82 class 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 
     96 void 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 
    104 void 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 
    114 void CodeAssembler::UnregisterCallGenerationCallbacks() {
    115   state_->call_prologue_ = nullptr;
    116   state_->call_epilogue_ = nullptr;
    117 }
    118 
    119 void CodeAssembler::CallPrologue() {
    120   if (state_->call_prologue_) {
    121     state_->call_prologue_();
    122   }
    123 }
    124 
    125 void CodeAssembler::CallEpilogue() {
    126   if (state_->call_epilogue_) {
    127     state_->call_epilogue_();
    128   }
    129 }
    130 
    131 // static
    132 Handle<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 
    145 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
    146 
    147 bool CodeAssembler::IsFloat64RoundUpSupported() const {
    148   return raw_assembler()->machine()->Float64RoundUp().IsSupported();
    149 }
    150 
    151 bool CodeAssembler::IsFloat64RoundDownSupported() const {
    152   return raw_assembler()->machine()->Float64RoundDown().IsSupported();
    153 }
    154 
    155 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
    156   return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
    157 }
    158 
    159 bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
    160   return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
    161 }
    162 
    163 Node* CodeAssembler::Int32Constant(int32_t value) {
    164   return raw_assembler()->Int32Constant(value);
    165 }
    166 
    167 Node* CodeAssembler::Int64Constant(int64_t value) {
    168   return raw_assembler()->Int64Constant(value);
    169 }
    170 
    171 Node* CodeAssembler::IntPtrConstant(intptr_t value) {
    172   return raw_assembler()->IntPtrConstant(value);
    173 }
    174 
    175 Node* CodeAssembler::NumberConstant(double value) {
    176   return raw_assembler()->NumberConstant(value);
    177 }
    178 
    179 Node* CodeAssembler::SmiConstant(Smi* value) {
    180   return BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value)));
    181 }
    182 
    183 Node* CodeAssembler::SmiConstant(int value) {
    184   return SmiConstant(Smi::FromInt(value));
    185 }
    186 
    187 Node* CodeAssembler::HeapConstant(Handle<HeapObject> object) {
    188   return raw_assembler()->HeapConstant(object);
    189 }
    190 
    191 Node* CodeAssembler::CStringConstant(const char* str) {
    192   return HeapConstant(factory()->NewStringFromAsciiChecked(str, TENURED));
    193 }
    194 
    195 Node* CodeAssembler::BooleanConstant(bool value) {
    196   return raw_assembler()->BooleanConstant(value);
    197 }
    198 
    199 Node* CodeAssembler::ExternalConstant(ExternalReference address) {
    200   return raw_assembler()->ExternalConstant(address);
    201 }
    202 
    203 Node* CodeAssembler::Float64Constant(double value) {
    204   return raw_assembler()->Float64Constant(value);
    205 }
    206 
    207 Node* CodeAssembler::NaNConstant() {
    208   return LoadRoot(Heap::kNanValueRootIndex);
    209 }
    210 
    211 bool 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 
    223 bool 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 
    229 bool 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 
    243 bool 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 
    253 Node* CodeAssembler::Parameter(int value) {
    254   return raw_assembler()->Parameter(value);
    255 }
    256 
    257 Node* 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 
    264 void CodeAssembler::Return(Node* value) {
    265   return raw_assembler()->Return(value);
    266 }
    267 
    268 void CodeAssembler::Return(Node* value1, Node* value2) {
    269   return raw_assembler()->Return(value1, value2);
    270 }
    271 
    272 void CodeAssembler::Return(Node* value1, Node* value2, Node* value3) {
    273   return raw_assembler()->Return(value1, value2, value3);
    274 }
    275 
    276 void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
    277   return raw_assembler()->PopAndReturn(pop, value);
    278 }
    279 
    280 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
    281 
    282 void CodeAssembler::Unreachable() {
    283   DebugBreak();
    284   raw_assembler()->Unreachable();
    285 }
    286 
    287 void 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 
    307 void CodeAssembler::Bind(Label* label) { return label->Bind(); }
    308 
    309 Node* CodeAssembler::LoadFramePointer() {
    310   return raw_assembler()->LoadFramePointer();
    311 }
    312 
    313 Node* CodeAssembler::LoadParentFramePointer() {
    314   return raw_assembler()->LoadParentFramePointer();
    315 }
    316 
    317 Node* 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   }
    325 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
    326 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP
    327 
    328 Node* 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 
    348 Node* 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 
    365 Node* CodeAssembler::WordShl(Node* value, int shift) {
    366   return (shift != 0) ? raw_assembler()->WordShl(value, IntPtrConstant(shift))
    367                       : value;
    368 }
    369 
    370 Node* CodeAssembler::WordShr(Node* value, int shift) {
    371   return (shift != 0) ? raw_assembler()->WordShr(value, IntPtrConstant(shift))
    372                       : value;
    373 }
    374 
    375 Node* CodeAssembler::Word32Shr(Node* value, int shift) {
    376   return (shift != 0) ? raw_assembler()->Word32Shr(value, Int32Constant(shift))
    377                       : value;
    378 }
    379 
    380 Node* CodeAssembler::ChangeUint32ToWord(Node* value) {
    381   if (raw_assembler()->machine()->Is64()) {
    382     value = raw_assembler()->ChangeUint32ToUint64(value);
    383   }
    384   return value;
    385 }
    386 
    387 Node* CodeAssembler::ChangeInt32ToIntPtr(Node* value) {
    388   if (raw_assembler()->machine()->Is64()) {
    389     value = raw_assembler()->ChangeInt32ToInt64(value);
    390   }
    391   return value;
    392 }
    393 
    394 Node* 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); }
    403 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
    404 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP
    405 
    406 Node* CodeAssembler::Load(MachineType rep, Node* base) {
    407   return raw_assembler()->Load(rep, base);
    408 }
    409 
    410 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset) {
    411   return raw_assembler()->Load(rep, base, offset);
    412 }
    413 
    414 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) {
    415   return raw_assembler()->AtomicLoad(rep, base, offset);
    416 }
    417 
    418 Node* 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 
    434 Node* CodeAssembler::Store(Node* base, Node* value) {
    435   return raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
    436                                 kFullWriteBarrier);
    437 }
    438 
    439 Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) {
    440   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
    441                                 value, kFullWriteBarrier);
    442 }
    443 
    444 Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset,
    445                                               Node* value) {
    446   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
    447                                 value, kMapWriteBarrier);
    448 }
    449 
    450 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
    451                                          Node* value) {
    452   return raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
    453 }
    454 
    455 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
    456                                          Node* offset, Node* value) {
    457   return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
    458 }
    459 
    460 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
    461                                  Node* offset, Node* value) {
    462   return raw_assembler()->AtomicStore(rep, base, offset, value);
    463 }
    464 
    465 Node* 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 
    473 Node* CodeAssembler::Retain(Node* value) {
    474   return raw_assembler()->Retain(value);
    475 }
    476 
    477 Node* CodeAssembler::Projection(int index, Node* value) {
    478   return raw_assembler()->Projection(index, value);
    479 }
    480 
    481 void 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 
    501 template <class... TArgs>
    502 Node* 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__);
    527 REPEAT_1_TO_7(INSTANTIATE, Node*)
    528 #undef INSTANTIATE
    529 
    530 template <class... TArgs>
    531 Node* 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__);
    553 REPEAT_1_TO_7(INSTANTIATE, Node*)
    554 #undef INSTANTIATE
    555 
    556 template <class... TArgs>
    557 Node* 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__);
    568 REPEAT_1_TO_7(INSTANTIATE, Node*)
    569 #undef INSTANTIATE
    570 
    571 Node* 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 
    592 template <class... TArgs>
    593 Node* 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__);
    611 REPEAT_1_TO_7(INSTANTIATE, Node*)
    612 #undef INSTANTIATE
    613 
    614 template <class... TArgs>
    615 Node* 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.
    626 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
    627     const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
    628     Node*, Node*);
    629 
    630 Node* 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 
    636 Node* 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 
    644 Node* 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 
    653 void CodeAssembler::Goto(Label* label) {
    654   label->MergeVariables();
    655   raw_assembler()->Goto(label->label_);
    656 }
    657 
    658 void 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 
    664 void 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 
    670 void 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 
    678 void 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:
    694 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
    695 
    696 Factory* CodeAssembler::factory() const { return isolate()->factory(); }
    697 
    698 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
    699 
    700 RawMachineAssembler* 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.
    708 class CodeAssemblerVariable::Impl : public ZoneObject {
    709  public:
    710   explicit Impl(MachineRepresentation rep) : value_(nullptr), rep_(rep) {}
    711   Node* value_;
    712   MachineRepresentation rep_;
    713 };
    714 
    715 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
    716                                              MachineRepresentation rep)
    717     : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
    718   state_->variables_.insert(impl_);
    719 }
    720 
    721 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
    722                                              MachineRepresentation rep,
    723                                              Node* initial_value)
    724     : CodeAssemblerVariable(assembler, rep) {
    725   Bind(initial_value);
    726 }
    727 
    728 CodeAssemblerVariable::~CodeAssemblerVariable() {
    729   state_->variables_.erase(impl_);
    730 }
    731 
    732 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
    733 
    734 Node* CodeAssemblerVariable::value() const {
    735   DCHECK_NOT_NULL(impl_->value_);
    736   return impl_->value_;
    737 }
    738 
    739 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
    740 
    741 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
    742 
    743 CodeAssemblerLabel::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 
    760 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
    761 
    762 void 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 
    808 void 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