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/lsan.h"
     21 #include "src/machine-type.h"
     22 #include "src/macro-assembler.h"
     23 #include "src/objects-inl.h"
     24 #include "src/utils.h"
     25 #include "src/zone/zone.h"
     26 
     27 namespace v8 {
     28 namespace internal {
     29 
     30 constexpr MachineType MachineTypeOf<Smi>::value;
     31 constexpr MachineType MachineTypeOf<Object>::value;
     32 
     33 namespace compiler {
     34 
     35 static_assert(std::is_convertible<TNode<Number>, TNode<Object>>::value,
     36               "test subtyping");
     37 static_assert(std::is_convertible<TNode<UnionT<Smi, HeapNumber>>,
     38                                   TNode<UnionT<Smi, HeapObject>>>::value,
     39               "test subtyping");
     40 static_assert(
     41     !std::is_convertible<TNode<UnionT<Smi, HeapObject>>, TNode<Number>>::value,
     42     "test subtyping");
     43 
     44 CodeAssemblerState::CodeAssemblerState(
     45     Isolate* isolate, Zone* zone, const CallInterfaceDescriptor& descriptor,
     46     Code::Kind kind, const char* name, PoisoningMitigationLevel poisoning_level,
     47     uint32_t stub_key, int32_t builtin_index)
     48     // TODO(rmcilroy): Should we use Linkage::GetBytecodeDispatchDescriptor for
     49     // bytecode handlers?
     50     : CodeAssemblerState(
     51           isolate, zone,
     52           Linkage::GetStubCallDescriptor(
     53               zone, descriptor, descriptor.GetStackParameterCount(),
     54               CallDescriptor::kNoFlags, Operator::kNoProperties),
     55           kind, name, poisoning_level, stub_key, builtin_index) {}
     56 
     57 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
     58                                        int parameter_count, Code::Kind kind,
     59                                        const char* name,
     60                                        PoisoningMitigationLevel poisoning_level,
     61                                        int32_t builtin_index)
     62     : CodeAssemblerState(
     63           isolate, zone,
     64           Linkage::GetJSCallDescriptor(zone, false, parameter_count,
     65                                        kind == Code::BUILTIN
     66                                            ? CallDescriptor::kPushArgumentCount
     67                                            : CallDescriptor::kNoFlags),
     68           kind, name, poisoning_level, 0, builtin_index) {}
     69 
     70 CodeAssemblerState::CodeAssemblerState(Isolate* isolate, Zone* zone,
     71                                        CallDescriptor* call_descriptor,
     72                                        Code::Kind kind, const char* name,
     73                                        PoisoningMitigationLevel poisoning_level,
     74                                        uint32_t stub_key, int32_t builtin_index)
     75     : raw_assembler_(new RawMachineAssembler(
     76           isolate, new (zone) Graph(zone), call_descriptor,
     77           MachineType::PointerRepresentation(),
     78           InstructionSelector::SupportedMachineOperatorFlags(),
     79           InstructionSelector::AlignmentRequirements(), poisoning_level)),
     80       kind_(kind),
     81       name_(name),
     82       stub_key_(stub_key),
     83       builtin_index_(builtin_index),
     84       code_generated_(false),
     85       variables_(zone) {}
     86 
     87 CodeAssemblerState::~CodeAssemblerState() {}
     88 
     89 int CodeAssemblerState::parameter_count() const {
     90   return static_cast<int>(raw_assembler_->call_descriptor()->ParameterCount());
     91 }
     92 
     93 CodeAssembler::~CodeAssembler() {}
     94 
     95 #if DEBUG
     96 void CodeAssemblerState::PrintCurrentBlock(std::ostream& os) {
     97   raw_assembler_->PrintCurrentBlock(os);
     98 }
     99 
    100 bool CodeAssemblerState::InsideBlock() { return raw_assembler_->InsideBlock(); }
    101 #endif
    102 
    103 void CodeAssemblerState::SetInitialDebugInformation(const char* msg,
    104                                                     const char* file,
    105                                                     int line) {
    106 #if DEBUG
    107   AssemblerDebugInfo debug_info = {msg, file, line};
    108   raw_assembler_->SetInitialDebugInformation(debug_info);
    109 #endif  // DEBUG
    110 }
    111 
    112 class BreakOnNodeDecorator final : public GraphDecorator {
    113  public:
    114   explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
    115 
    116   void Decorate(Node* node) final {
    117     if (node->id() == node_id_) {
    118       base::OS::DebugBreak();
    119     }
    120   }
    121 
    122  private:
    123   NodeId node_id_;
    124 };
    125 
    126 void CodeAssembler::BreakOnNode(int node_id) {
    127   Graph* graph = raw_assembler()->graph();
    128   Zone* zone = graph->zone();
    129   GraphDecorator* decorator =
    130       new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id));
    131   graph->AddDecorator(decorator);
    132 }
    133 
    134 void CodeAssembler::RegisterCallGenerationCallbacks(
    135     const CodeAssemblerCallback& call_prologue,
    136     const CodeAssemblerCallback& call_epilogue) {
    137   // The callback can be registered only once.
    138   DCHECK(!state_->call_prologue_);
    139   DCHECK(!state_->call_epilogue_);
    140   state_->call_prologue_ = call_prologue;
    141   state_->call_epilogue_ = call_epilogue;
    142 }
    143 
    144 void CodeAssembler::UnregisterCallGenerationCallbacks() {
    145   state_->call_prologue_ = nullptr;
    146   state_->call_epilogue_ = nullptr;
    147 }
    148 
    149 void CodeAssembler::CallPrologue() {
    150   if (state_->call_prologue_) {
    151     state_->call_prologue_();
    152   }
    153 }
    154 
    155 void CodeAssembler::CallEpilogue() {
    156   if (state_->call_epilogue_) {
    157     state_->call_epilogue_();
    158   }
    159 }
    160 
    161 bool CodeAssembler::Word32ShiftIsSafe() const {
    162   return raw_assembler()->machine()->Word32ShiftIsSafe();
    163 }
    164 
    165 PoisoningMitigationLevel CodeAssembler::poisoning_level() const {
    166   return raw_assembler()->poisoning_level();
    167 }
    168 
    169 // static
    170 Handle<Code> CodeAssembler::GenerateCode(CodeAssemblerState* state,
    171                                          const AssemblerOptions& options) {
    172   DCHECK(!state->code_generated_);
    173 
    174   RawMachineAssembler* rasm = state->raw_assembler_.get();
    175   Schedule* schedule = rasm->Export();
    176 
    177   JumpOptimizationInfo jump_opt;
    178   bool should_optimize_jumps =
    179       rasm->isolate()->serializer_enabled() && FLAG_turbo_rewrite_far_jumps;
    180 
    181   Handle<Code> code =
    182       Pipeline::GenerateCodeForCodeStub(
    183           rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
    184           state->kind_, state->name_, state->stub_key_, state->builtin_index_,
    185           should_optimize_jumps ? &jump_opt : nullptr, rasm->poisoning_level(),
    186           options)
    187           .ToHandleChecked();
    188 
    189   if (jump_opt.is_optimizable()) {
    190     jump_opt.set_optimizing();
    191 
    192     // Regenerate machine code
    193     code =
    194         Pipeline::GenerateCodeForCodeStub(
    195             rasm->isolate(), rasm->call_descriptor(), rasm->graph(), schedule,
    196             state->kind_, state->name_, state->stub_key_, state->builtin_index_,
    197             &jump_opt, rasm->poisoning_level(), options)
    198             .ToHandleChecked();
    199   }
    200 
    201   state->code_generated_ = true;
    202   return code;
    203 }
    204 
    205 bool CodeAssembler::Is64() const { return raw_assembler()->machine()->Is64(); }
    206 
    207 bool CodeAssembler::IsFloat64RoundUpSupported() const {
    208   return raw_assembler()->machine()->Float64RoundUp().IsSupported();
    209 }
    210 
    211 bool CodeAssembler::IsFloat64RoundDownSupported() const {
    212   return raw_assembler()->machine()->Float64RoundDown().IsSupported();
    213 }
    214 
    215 bool CodeAssembler::IsFloat64RoundTiesEvenSupported() const {
    216   return raw_assembler()->machine()->Float64RoundTiesEven().IsSupported();
    217 }
    218 
    219 bool CodeAssembler::IsFloat64RoundTruncateSupported() const {
    220   return raw_assembler()->machine()->Float64RoundTruncate().IsSupported();
    221 }
    222 
    223 bool CodeAssembler::IsInt32AbsWithOverflowSupported() const {
    224   return raw_assembler()->machine()->Int32AbsWithOverflow().IsSupported();
    225 }
    226 
    227 bool CodeAssembler::IsInt64AbsWithOverflowSupported() const {
    228   return raw_assembler()->machine()->Int64AbsWithOverflow().IsSupported();
    229 }
    230 
    231 bool CodeAssembler::IsIntPtrAbsWithOverflowSupported() const {
    232   return Is64() ? IsInt64AbsWithOverflowSupported()
    233                 : IsInt32AbsWithOverflowSupported();
    234 }
    235 
    236 #ifdef DEBUG
    237 void CodeAssembler::GenerateCheckMaybeObjectIsObject(Node* node,
    238                                                      const char* location) {
    239   Label ok(this);
    240   GotoIf(WordNotEqual(WordAnd(BitcastMaybeObjectToWord(node),
    241                               IntPtrConstant(kHeapObjectTagMask)),
    242                       IntPtrConstant(kWeakHeapObjectTag)),
    243          &ok);
    244   Node* message_node = StringConstant(location);
    245   DebugAbort(message_node);
    246   Unreachable();
    247   Bind(&ok);
    248 }
    249 #endif
    250 
    251 TNode<Int32T> CodeAssembler::Int32Constant(int32_t value) {
    252   return UncheckedCast<Int32T>(raw_assembler()->Int32Constant(value));
    253 }
    254 
    255 TNode<Int64T> CodeAssembler::Int64Constant(int64_t value) {
    256   return UncheckedCast<Int64T>(raw_assembler()->Int64Constant(value));
    257 }
    258 
    259 TNode<IntPtrT> CodeAssembler::IntPtrConstant(intptr_t value) {
    260   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrConstant(value));
    261 }
    262 
    263 TNode<Number> CodeAssembler::NumberConstant(double value) {
    264   int smi_value;
    265   if (DoubleToSmiInteger(value, &smi_value)) {
    266     return UncheckedCast<Number>(SmiConstant(smi_value));
    267   } else {
    268     // We allocate the heap number constant eagerly at this point instead of
    269     // deferring allocation to code generation
    270     // (see AllocateAndInstallRequestedHeapObjects) since that makes it easier
    271     // to generate constant lookups for embedded builtins.
    272     return UncheckedCast<Number>(
    273         HeapConstant(isolate()->factory()->NewHeapNumber(value, TENURED)));
    274   }
    275 }
    276 
    277 TNode<Smi> CodeAssembler::SmiConstant(Smi* value) {
    278   return UncheckedCast<Smi>(
    279       BitcastWordToTaggedSigned(IntPtrConstant(bit_cast<intptr_t>(value))));
    280 }
    281 
    282 TNode<Smi> CodeAssembler::SmiConstant(int value) {
    283   return SmiConstant(Smi::FromInt(value));
    284 }
    285 
    286 TNode<HeapObject> CodeAssembler::UntypedHeapConstant(
    287     Handle<HeapObject> object) {
    288   return UncheckedCast<HeapObject>(raw_assembler()->HeapConstant(object));
    289 }
    290 
    291 TNode<String> CodeAssembler::StringConstant(const char* str) {
    292   Handle<String> internalized_string =
    293       factory()->InternalizeOneByteString(OneByteVector(str));
    294   return UncheckedCast<String>(HeapConstant(internalized_string));
    295 }
    296 
    297 TNode<Oddball> CodeAssembler::BooleanConstant(bool value) {
    298   return UncheckedCast<Oddball>(raw_assembler()->BooleanConstant(value));
    299 }
    300 
    301 TNode<ExternalReference> CodeAssembler::ExternalConstant(
    302     ExternalReference address) {
    303   return UncheckedCast<ExternalReference>(
    304       raw_assembler()->ExternalConstant(address));
    305 }
    306 
    307 TNode<Float64T> CodeAssembler::Float64Constant(double value) {
    308   return UncheckedCast<Float64T>(raw_assembler()->Float64Constant(value));
    309 }
    310 
    311 TNode<HeapNumber> CodeAssembler::NaNConstant() {
    312   return UncheckedCast<HeapNumber>(LoadRoot(Heap::kNanValueRootIndex));
    313 }
    314 
    315 bool CodeAssembler::ToInt32Constant(Node* node, int32_t& out_value) {
    316   {
    317     Int64Matcher m(node);
    318     if (m.HasValue() && m.IsInRange(std::numeric_limits<int32_t>::min(),
    319                                     std::numeric_limits<int32_t>::max())) {
    320       out_value = static_cast<int32_t>(m.Value());
    321       return true;
    322     }
    323   }
    324 
    325   {
    326     Int32Matcher m(node);
    327     if (m.HasValue()) {
    328       out_value = m.Value();
    329       return true;
    330     }
    331   }
    332 
    333   return false;
    334 }
    335 
    336 bool CodeAssembler::ToInt64Constant(Node* node, int64_t& out_value) {
    337   Int64Matcher m(node);
    338   if (m.HasValue()) out_value = m.Value();
    339   return m.HasValue();
    340 }
    341 
    342 bool CodeAssembler::ToSmiConstant(Node* node, Smi*& out_value) {
    343   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned) {
    344     node = node->InputAt(0);
    345   }
    346   IntPtrMatcher m(node);
    347   if (m.HasValue()) {
    348     intptr_t value = m.Value();
    349     // Make sure that the value is actually a smi
    350     CHECK_EQ(0, value & ((static_cast<intptr_t>(1) << kSmiShiftSize) - 1));
    351     out_value = Smi::cast(bit_cast<Object*>(value));
    352     return true;
    353   }
    354   return false;
    355 }
    356 
    357 bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
    358   if (node->opcode() == IrOpcode::kBitcastWordToTaggedSigned ||
    359       node->opcode() == IrOpcode::kBitcastWordToTagged) {
    360     node = node->InputAt(0);
    361   }
    362   IntPtrMatcher m(node);
    363   if (m.HasValue()) out_value = m.Value();
    364   return m.HasValue();
    365 }
    366 
    367 bool CodeAssembler::IsUndefinedConstant(TNode<Object> node) {
    368   compiler::HeapObjectMatcher m(node);
    369   return m.Is(isolate()->factory()->undefined_value());
    370 }
    371 
    372 bool CodeAssembler::IsNullConstant(TNode<Object> node) {
    373   compiler::HeapObjectMatcher m(node);
    374   return m.Is(isolate()->factory()->null_value());
    375 }
    376 
    377 Node* CodeAssembler::Parameter(int index) {
    378   if (index == kTargetParameterIndex) return raw_assembler()->TargetParameter();
    379   return raw_assembler()->Parameter(index);
    380 }
    381 
    382 bool CodeAssembler::IsJSFunctionCall() const {
    383   auto call_descriptor = raw_assembler()->call_descriptor();
    384   return call_descriptor->IsJSFunctionCall();
    385 }
    386 
    387 TNode<Context> CodeAssembler::GetJSContextParameter() {
    388   auto call_descriptor = raw_assembler()->call_descriptor();
    389   DCHECK(call_descriptor->IsJSFunctionCall());
    390   return CAST(Parameter(Linkage::GetJSCallContextParamIndex(
    391       static_cast<int>(call_descriptor->JSParameterCount()))));
    392 }
    393 
    394 void CodeAssembler::Return(SloppyTNode<Object> value) {
    395   return raw_assembler()->Return(value);
    396 }
    397 
    398 void CodeAssembler::Return(SloppyTNode<Object> value1,
    399                            SloppyTNode<Object> value2) {
    400   return raw_assembler()->Return(value1, value2);
    401 }
    402 
    403 void CodeAssembler::Return(SloppyTNode<Object> value1,
    404                            SloppyTNode<Object> value2,
    405                            SloppyTNode<Object> value3) {
    406   return raw_assembler()->Return(value1, value2, value3);
    407 }
    408 
    409 void CodeAssembler::PopAndReturn(Node* pop, Node* value) {
    410   return raw_assembler()->PopAndReturn(pop, value);
    411 }
    412 
    413 void CodeAssembler::ReturnIf(Node* condition, Node* value) {
    414   Label if_return(this), if_continue(this);
    415   Branch(condition, &if_return, &if_continue);
    416   Bind(&if_return);
    417   Return(value);
    418   Bind(&if_continue);
    419 }
    420 
    421 void CodeAssembler::ReturnRaw(Node* value) {
    422   return raw_assembler()->Return(value);
    423 }
    424 
    425 void CodeAssembler::DebugAbort(Node* message) {
    426   raw_assembler()->DebugAbort(message);
    427 }
    428 
    429 void CodeAssembler::DebugBreak() { raw_assembler()->DebugBreak(); }
    430 
    431 void CodeAssembler::Unreachable() {
    432   DebugBreak();
    433   raw_assembler()->Unreachable();
    434 }
    435 
    436 void CodeAssembler::Comment(const char* format, ...) {
    437   if (!FLAG_code_comments) return;
    438   char buffer[4 * KB];
    439   StringBuilder builder(buffer, arraysize(buffer));
    440   va_list arguments;
    441   va_start(arguments, format);
    442   builder.AddFormattedList(format, arguments);
    443   va_end(arguments);
    444 
    445   // Copy the string before recording it in the assembler to avoid
    446   // issues when the stack allocated buffer goes out of scope.
    447   const int prefix_len = 2;
    448   int length = builder.position() + 1;
    449   char* copy = reinterpret_cast<char*>(malloc(length + prefix_len));
    450   LSAN_IGNORE_OBJECT(copy);
    451   MemCopy(copy + prefix_len, builder.Finalize(), length);
    452   copy[0] = ';';
    453   copy[1] = ' ';
    454   raw_assembler()->Comment(copy);
    455 }
    456 
    457 void CodeAssembler::Bind(Label* label) { return label->Bind(); }
    458 
    459 #if DEBUG
    460 void CodeAssembler::Bind(Label* label, AssemblerDebugInfo debug_info) {
    461   return label->Bind(debug_info);
    462 }
    463 #endif  // DEBUG
    464 
    465 Node* CodeAssembler::LoadFramePointer() {
    466   return raw_assembler()->LoadFramePointer();
    467 }
    468 
    469 Node* CodeAssembler::LoadParentFramePointer() {
    470   return raw_assembler()->LoadParentFramePointer();
    471 }
    472 
    473 Node* CodeAssembler::LoadStackPointer() {
    474   return raw_assembler()->LoadStackPointer();
    475 }
    476 
    477 TNode<Object> CodeAssembler::TaggedPoisonOnSpeculation(
    478     SloppyTNode<Object> value) {
    479   return UncheckedCast<Object>(
    480       raw_assembler()->TaggedPoisonOnSpeculation(value));
    481 }
    482 
    483 TNode<WordT> CodeAssembler::WordPoisonOnSpeculation(SloppyTNode<WordT> value) {
    484   return UncheckedCast<WordT>(raw_assembler()->WordPoisonOnSpeculation(value));
    485 }
    486 
    487 #define DEFINE_CODE_ASSEMBLER_BINARY_OP(name, ResType, Arg1Type, Arg2Type) \
    488   TNode<ResType> CodeAssembler::name(SloppyTNode<Arg1Type> a,              \
    489                                      SloppyTNode<Arg2Type> b) {            \
    490     return UncheckedCast<ResType>(raw_assembler()->name(a, b));            \
    491   }
    492 CODE_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_ASSEMBLER_BINARY_OP)
    493 #undef DEFINE_CODE_ASSEMBLER_BINARY_OP
    494 
    495 TNode<WordT> CodeAssembler::IntPtrAdd(SloppyTNode<WordT> left,
    496                                       SloppyTNode<WordT> right) {
    497   intptr_t left_constant;
    498   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    499   intptr_t right_constant;
    500   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    501   if (is_left_constant) {
    502     if (is_right_constant) {
    503       return IntPtrConstant(left_constant + right_constant);
    504     }
    505     if (left_constant == 0) {
    506       return right;
    507     }
    508   } else if (is_right_constant) {
    509     if (right_constant == 0) {
    510       return left;
    511     }
    512   }
    513   return UncheckedCast<WordT>(raw_assembler()->IntPtrAdd(left, right));
    514 }
    515 
    516 TNode<WordT> CodeAssembler::IntPtrSub(SloppyTNode<WordT> left,
    517                                       SloppyTNode<WordT> right) {
    518   intptr_t left_constant;
    519   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    520   intptr_t right_constant;
    521   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    522   if (is_left_constant) {
    523     if (is_right_constant) {
    524       return IntPtrConstant(left_constant - right_constant);
    525     }
    526   } else if (is_right_constant) {
    527     if (right_constant == 0) {
    528       return left;
    529     }
    530   }
    531   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrSub(left, right));
    532 }
    533 
    534 TNode<WordT> CodeAssembler::IntPtrMul(SloppyTNode<WordT> left,
    535                                       SloppyTNode<WordT> right) {
    536   intptr_t left_constant;
    537   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    538   intptr_t right_constant;
    539   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    540   if (is_left_constant) {
    541     if (is_right_constant) {
    542       return IntPtrConstant(left_constant * right_constant);
    543     }
    544     if (base::bits::IsPowerOfTwo(left_constant)) {
    545       return WordShl(right, WhichPowerOf2(left_constant));
    546     }
    547   } else if (is_right_constant) {
    548     if (base::bits::IsPowerOfTwo(right_constant)) {
    549       return WordShl(left, WhichPowerOf2(right_constant));
    550     }
    551   }
    552   return UncheckedCast<IntPtrT>(raw_assembler()->IntPtrMul(left, right));
    553 }
    554 
    555 TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> value, int shift) {
    556   return (shift != 0) ? WordShl(value, IntPtrConstant(shift)) : value;
    557 }
    558 
    559 TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> value, int shift) {
    560   return (shift != 0) ? WordShr(value, IntPtrConstant(shift)) : value;
    561 }
    562 
    563 TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> value, int shift) {
    564   return (shift != 0) ? WordSar(value, IntPtrConstant(shift)) : value;
    565 }
    566 
    567 TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> value, int shift) {
    568   return (shift != 0) ? Word32Shr(value, Int32Constant(shift)) : value;
    569 }
    570 
    571 TNode<WordT> CodeAssembler::WordOr(SloppyTNode<WordT> left,
    572                                    SloppyTNode<WordT> right) {
    573   intptr_t left_constant;
    574   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    575   intptr_t right_constant;
    576   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    577   if (is_left_constant) {
    578     if (is_right_constant) {
    579       return IntPtrConstant(left_constant | right_constant);
    580     }
    581     if (left_constant == 0) {
    582       return right;
    583     }
    584   } else if (is_right_constant) {
    585     if (right_constant == 0) {
    586       return left;
    587     }
    588   }
    589   return UncheckedCast<WordT>(raw_assembler()->WordOr(left, right));
    590 }
    591 
    592 TNode<WordT> CodeAssembler::WordAnd(SloppyTNode<WordT> left,
    593                                     SloppyTNode<WordT> right) {
    594   intptr_t left_constant;
    595   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    596   intptr_t right_constant;
    597   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    598   if (is_left_constant) {
    599     if (is_right_constant) {
    600       return IntPtrConstant(left_constant & right_constant);
    601     }
    602   }
    603   return UncheckedCast<WordT>(raw_assembler()->WordAnd(left, right));
    604 }
    605 
    606 TNode<WordT> CodeAssembler::WordXor(SloppyTNode<WordT> left,
    607                                     SloppyTNode<WordT> right) {
    608   intptr_t left_constant;
    609   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    610   intptr_t right_constant;
    611   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    612   if (is_left_constant) {
    613     if (is_right_constant) {
    614       return IntPtrConstant(left_constant ^ right_constant);
    615     }
    616   }
    617   return UncheckedCast<WordT>(raw_assembler()->WordXor(left, right));
    618 }
    619 
    620 TNode<WordT> CodeAssembler::WordShl(SloppyTNode<WordT> left,
    621                                     SloppyTNode<IntegralT> right) {
    622   intptr_t left_constant;
    623   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    624   intptr_t right_constant;
    625   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    626   if (is_left_constant) {
    627     if (is_right_constant) {
    628       return IntPtrConstant(left_constant << right_constant);
    629     }
    630   } else if (is_right_constant) {
    631     if (right_constant == 0) {
    632       return left;
    633     }
    634   }
    635   return UncheckedCast<WordT>(raw_assembler()->WordShl(left, right));
    636 }
    637 
    638 TNode<WordT> CodeAssembler::WordShr(SloppyTNode<WordT> left,
    639                                     SloppyTNode<IntegralT> right) {
    640   intptr_t left_constant;
    641   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    642   intptr_t right_constant;
    643   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    644   if (is_left_constant) {
    645     if (is_right_constant) {
    646       return IntPtrConstant(static_cast<uintptr_t>(left_constant) >>
    647                             right_constant);
    648     }
    649   } else if (is_right_constant) {
    650     if (right_constant == 0) {
    651       return left;
    652     }
    653   }
    654   return UncheckedCast<WordT>(raw_assembler()->WordShr(left, right));
    655 }
    656 
    657 TNode<WordT> CodeAssembler::WordSar(SloppyTNode<WordT> left,
    658                                     SloppyTNode<IntegralT> right) {
    659   intptr_t left_constant;
    660   bool is_left_constant = ToIntPtrConstant(left, left_constant);
    661   intptr_t right_constant;
    662   bool is_right_constant = ToIntPtrConstant(right, right_constant);
    663   if (is_left_constant) {
    664     if (is_right_constant) {
    665       return IntPtrConstant(left_constant >> right_constant);
    666     }
    667   } else if (is_right_constant) {
    668     if (right_constant == 0) {
    669       return left;
    670     }
    671   }
    672   return UncheckedCast<WordT>(raw_assembler()->WordSar(left, right));
    673 }
    674 
    675 TNode<Word32T> CodeAssembler::Word32Or(SloppyTNode<Word32T> left,
    676                                        SloppyTNode<Word32T> right) {
    677   int32_t left_constant;
    678   bool is_left_constant = ToInt32Constant(left, left_constant);
    679   int32_t right_constant;
    680   bool is_right_constant = ToInt32Constant(right, right_constant);
    681   if (is_left_constant) {
    682     if (is_right_constant) {
    683       return Int32Constant(left_constant | right_constant);
    684     }
    685     if (left_constant == 0) {
    686       return right;
    687     }
    688   } else if (is_right_constant) {
    689     if (right_constant == 0) {
    690       return left;
    691     }
    692   }
    693   return UncheckedCast<Word32T>(raw_assembler()->Word32Or(left, right));
    694 }
    695 
    696 TNode<Word32T> CodeAssembler::Word32And(SloppyTNode<Word32T> left,
    697                                         SloppyTNode<Word32T> right) {
    698   int32_t left_constant;
    699   bool is_left_constant = ToInt32Constant(left, left_constant);
    700   int32_t right_constant;
    701   bool is_right_constant = ToInt32Constant(right, right_constant);
    702   if (is_left_constant) {
    703     if (is_right_constant) {
    704       return Int32Constant(left_constant & right_constant);
    705     }
    706   }
    707   return UncheckedCast<Word32T>(raw_assembler()->Word32And(left, right));
    708 }
    709 
    710 TNode<Word32T> CodeAssembler::Word32Xor(SloppyTNode<Word32T> left,
    711                                         SloppyTNode<Word32T> right) {
    712   int32_t left_constant;
    713   bool is_left_constant = ToInt32Constant(left, left_constant);
    714   int32_t right_constant;
    715   bool is_right_constant = ToInt32Constant(right, right_constant);
    716   if (is_left_constant) {
    717     if (is_right_constant) {
    718       return Int32Constant(left_constant ^ right_constant);
    719     }
    720   }
    721   return UncheckedCast<Word32T>(raw_assembler()->Word32Xor(left, right));
    722 }
    723 
    724 TNode<Word32T> CodeAssembler::Word32Shl(SloppyTNode<Word32T> left,
    725                                         SloppyTNode<Word32T> right) {
    726   int32_t left_constant;
    727   bool is_left_constant = ToInt32Constant(left, left_constant);
    728   int32_t right_constant;
    729   bool is_right_constant = ToInt32Constant(right, right_constant);
    730   if (is_left_constant) {
    731     if (is_right_constant) {
    732       return Int32Constant(left_constant << right_constant);
    733     }
    734   } else if (is_right_constant) {
    735     if (right_constant == 0) {
    736       return left;
    737     }
    738   }
    739   return UncheckedCast<Word32T>(raw_assembler()->Word32Shl(left, right));
    740 }
    741 
    742 TNode<Word32T> CodeAssembler::Word32Shr(SloppyTNode<Word32T> left,
    743                                         SloppyTNode<Word32T> right) {
    744   int32_t left_constant;
    745   bool is_left_constant = ToInt32Constant(left, left_constant);
    746   int32_t right_constant;
    747   bool is_right_constant = ToInt32Constant(right, right_constant);
    748   if (is_left_constant) {
    749     if (is_right_constant) {
    750       return Int32Constant(static_cast<uint32_t>(left_constant) >>
    751                            right_constant);
    752     }
    753   } else if (is_right_constant) {
    754     if (right_constant == 0) {
    755       return left;
    756     }
    757   }
    758   return UncheckedCast<Word32T>(raw_assembler()->Word32Shr(left, right));
    759 }
    760 
    761 TNode<Word32T> CodeAssembler::Word32Sar(SloppyTNode<Word32T> left,
    762                                         SloppyTNode<Word32T> right) {
    763   int32_t left_constant;
    764   bool is_left_constant = ToInt32Constant(left, left_constant);
    765   int32_t right_constant;
    766   bool is_right_constant = ToInt32Constant(right, right_constant);
    767   if (is_left_constant) {
    768     if (is_right_constant) {
    769       return Int32Constant(left_constant >> right_constant);
    770     }
    771   } else if (is_right_constant) {
    772     if (right_constant == 0) {
    773       return left;
    774     }
    775   }
    776   return UncheckedCast<Word32T>(raw_assembler()->Word32Sar(left, right));
    777 }
    778 
    779 TNode<Word64T> CodeAssembler::Word64Or(SloppyTNode<Word64T> left,
    780                                        SloppyTNode<Word64T> right) {
    781   int64_t left_constant;
    782   bool is_left_constant = ToInt64Constant(left, left_constant);
    783   int64_t right_constant;
    784   bool is_right_constant = ToInt64Constant(right, right_constant);
    785   if (is_left_constant) {
    786     if (is_right_constant) {
    787       return Int64Constant(left_constant | right_constant);
    788     }
    789     if (left_constant == 0) {
    790       return right;
    791     }
    792   } else if (is_right_constant) {
    793     if (right_constant == 0) {
    794       return left;
    795     }
    796   }
    797   return UncheckedCast<Word64T>(raw_assembler()->Word64Or(left, right));
    798 }
    799 
    800 TNode<Word64T> CodeAssembler::Word64And(SloppyTNode<Word64T> left,
    801                                         SloppyTNode<Word64T> right) {
    802   int64_t left_constant;
    803   bool is_left_constant = ToInt64Constant(left, left_constant);
    804   int64_t right_constant;
    805   bool is_right_constant = ToInt64Constant(right, right_constant);
    806   if (is_left_constant) {
    807     if (is_right_constant) {
    808       return Int64Constant(left_constant & right_constant);
    809     }
    810   }
    811   return UncheckedCast<Word64T>(raw_assembler()->Word64And(left, right));
    812 }
    813 
    814 TNode<Word64T> CodeAssembler::Word64Xor(SloppyTNode<Word64T> left,
    815                                         SloppyTNode<Word64T> right) {
    816   int64_t left_constant;
    817   bool is_left_constant = ToInt64Constant(left, left_constant);
    818   int64_t right_constant;
    819   bool is_right_constant = ToInt64Constant(right, right_constant);
    820   if (is_left_constant) {
    821     if (is_right_constant) {
    822       return Int64Constant(left_constant ^ right_constant);
    823     }
    824   }
    825   return UncheckedCast<Word64T>(raw_assembler()->Word64Xor(left, right));
    826 }
    827 
    828 TNode<Word64T> CodeAssembler::Word64Shl(SloppyTNode<Word64T> left,
    829                                         SloppyTNode<Word64T> right) {
    830   int64_t left_constant;
    831   bool is_left_constant = ToInt64Constant(left, left_constant);
    832   int64_t right_constant;
    833   bool is_right_constant = ToInt64Constant(right, right_constant);
    834   if (is_left_constant) {
    835     if (is_right_constant) {
    836       return Int64Constant(left_constant << right_constant);
    837     }
    838   } else if (is_right_constant) {
    839     if (right_constant == 0) {
    840       return left;
    841     }
    842   }
    843   return UncheckedCast<Word64T>(raw_assembler()->Word64Shl(left, right));
    844 }
    845 
    846 TNode<Word64T> CodeAssembler::Word64Shr(SloppyTNode<Word64T> left,
    847                                         SloppyTNode<Word64T> right) {
    848   int64_t left_constant;
    849   bool is_left_constant = ToInt64Constant(left, left_constant);
    850   int64_t right_constant;
    851   bool is_right_constant = ToInt64Constant(right, right_constant);
    852   if (is_left_constant) {
    853     if (is_right_constant) {
    854       return Int64Constant(static_cast<uint64_t>(left_constant) >>
    855                            right_constant);
    856     }
    857   } else if (is_right_constant) {
    858     if (right_constant == 0) {
    859       return left;
    860     }
    861   }
    862   return UncheckedCast<Word64T>(raw_assembler()->Word64Shr(left, right));
    863 }
    864 
    865 TNode<Word64T> CodeAssembler::Word64Sar(SloppyTNode<Word64T> left,
    866                                         SloppyTNode<Word64T> right) {
    867   int64_t left_constant;
    868   bool is_left_constant = ToInt64Constant(left, left_constant);
    869   int64_t right_constant;
    870   bool is_right_constant = ToInt64Constant(right, right_constant);
    871   if (is_left_constant) {
    872     if (is_right_constant) {
    873       return Int64Constant(left_constant >> right_constant);
    874     }
    875   } else if (is_right_constant) {
    876     if (right_constant == 0) {
    877       return left;
    878     }
    879   }
    880   return UncheckedCast<Word64T>(raw_assembler()->Word64Sar(left, right));
    881 }
    882 
    883 #define CODE_ASSEMBLER_COMPARE(Name, ArgT, VarT, ToConstant, op)     \
    884   TNode<BoolT> CodeAssembler::Name(SloppyTNode<ArgT> left,           \
    885                                    SloppyTNode<ArgT> right) {        \
    886     VarT lhs, rhs;                                                   \
    887     if (ToConstant(left, lhs) && ToConstant(right, rhs)) {           \
    888       return BoolConstant(lhs op rhs);                               \
    889     }                                                                \
    890     return UncheckedCast<BoolT>(raw_assembler()->Name(left, right)); \
    891   }
    892 
    893 CODE_ASSEMBLER_COMPARE(IntPtrEqual, WordT, intptr_t, ToIntPtrConstant, ==)
    894 CODE_ASSEMBLER_COMPARE(WordEqual, WordT, intptr_t, ToIntPtrConstant, ==)
    895 CODE_ASSEMBLER_COMPARE(WordNotEqual, WordT, intptr_t, ToIntPtrConstant, !=)
    896 CODE_ASSEMBLER_COMPARE(Word32Equal, Word32T, int32_t, ToInt32Constant, ==)
    897 CODE_ASSEMBLER_COMPARE(Word32NotEqual, Word32T, int32_t, ToInt32Constant, !=)
    898 CODE_ASSEMBLER_COMPARE(Word64Equal, Word64T, int64_t, ToInt64Constant, ==)
    899 CODE_ASSEMBLER_COMPARE(Word64NotEqual, Word64T, int64_t, ToInt64Constant, !=)
    900 #undef CODE_ASSEMBLER_COMPARE
    901 
    902 TNode<UintPtrT> CodeAssembler::ChangeUint32ToWord(SloppyTNode<Word32T> value) {
    903   if (raw_assembler()->machine()->Is64()) {
    904     return UncheckedCast<UintPtrT>(
    905         raw_assembler()->ChangeUint32ToUint64(value));
    906   }
    907   return ReinterpretCast<UintPtrT>(value);
    908 }
    909 
    910 TNode<IntPtrT> CodeAssembler::ChangeInt32ToIntPtr(SloppyTNode<Word32T> value) {
    911   if (raw_assembler()->machine()->Is64()) {
    912     return ReinterpretCast<IntPtrT>(raw_assembler()->ChangeInt32ToInt64(value));
    913   }
    914   return ReinterpretCast<IntPtrT>(value);
    915 }
    916 
    917 TNode<UintPtrT> CodeAssembler::ChangeFloat64ToUintPtr(
    918     SloppyTNode<Float64T> value) {
    919   if (raw_assembler()->machine()->Is64()) {
    920     return ReinterpretCast<UintPtrT>(
    921         raw_assembler()->ChangeFloat64ToUint64(value));
    922   }
    923   return ReinterpretCast<UintPtrT>(
    924       raw_assembler()->ChangeFloat64ToUint32(value));
    925 }
    926 
    927 Node* CodeAssembler::RoundIntPtrToFloat64(Node* value) {
    928   if (raw_assembler()->machine()->Is64()) {
    929     return raw_assembler()->RoundInt64ToFloat64(value);
    930   }
    931   return raw_assembler()->ChangeInt32ToFloat64(value);
    932 }
    933 
    934 #define DEFINE_CODE_ASSEMBLER_UNARY_OP(name, ResType, ArgType) \
    935   TNode<ResType> CodeAssembler::name(SloppyTNode<ArgType> a) { \
    936     return UncheckedCast<ResType>(raw_assembler()->name(a));   \
    937   }
    938 CODE_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_ASSEMBLER_UNARY_OP)
    939 #undef DEFINE_CODE_ASSEMBLER_UNARY_OP
    940 
    941 Node* CodeAssembler::Load(MachineType rep, Node* base,
    942                           LoadSensitivity needs_poisoning) {
    943   return raw_assembler()->Load(rep, base, needs_poisoning);
    944 }
    945 
    946 Node* CodeAssembler::Load(MachineType rep, Node* base, Node* offset,
    947                           LoadSensitivity needs_poisoning) {
    948   return raw_assembler()->Load(rep, base, offset, needs_poisoning);
    949 }
    950 
    951 Node* CodeAssembler::AtomicLoad(MachineType rep, Node* base, Node* offset) {
    952   return raw_assembler()->AtomicLoad(rep, base, offset);
    953 }
    954 
    955 TNode<Object> CodeAssembler::LoadRoot(Heap::RootListIndex root_index) {
    956   if (isolate()->heap()->RootCanBeTreatedAsConstant(root_index)) {
    957     Handle<Object> root = isolate()->heap()->root_handle(root_index);
    958     if (root->IsSmi()) {
    959       return SmiConstant(Smi::cast(*root));
    960     } else {
    961       return HeapConstant(Handle<HeapObject>::cast(root));
    962     }
    963   }
    964 
    965   // TODO(jgruber): In theory we could generate better code for this by
    966   // letting the macro assembler decide how to load from the roots list. In most
    967   // cases, it would boil down to loading from a fixed kRootRegister offset.
    968   Node* roots_array_start =
    969       ExternalConstant(ExternalReference::roots_array_start(isolate()));
    970   return UncheckedCast<Object>(Load(MachineType::AnyTagged(), roots_array_start,
    971                                     IntPtrConstant(root_index * kPointerSize)));
    972 }
    973 
    974 Node* CodeAssembler::Store(Node* base, Node* value) {
    975   return raw_assembler()->Store(MachineRepresentation::kTagged, base, value,
    976                                 kFullWriteBarrier);
    977 }
    978 
    979 Node* CodeAssembler::Store(Node* base, Node* offset, Node* value) {
    980   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
    981                                 value, kFullWriteBarrier);
    982 }
    983 
    984 Node* CodeAssembler::StoreWithMapWriteBarrier(Node* base, Node* offset,
    985                                               Node* value) {
    986   return raw_assembler()->Store(MachineRepresentation::kTagged, base, offset,
    987                                 value, kMapWriteBarrier);
    988 }
    989 
    990 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
    991                                          Node* value) {
    992   return raw_assembler()->Store(rep, base, value, kNoWriteBarrier);
    993 }
    994 
    995 Node* CodeAssembler::StoreNoWriteBarrier(MachineRepresentation rep, Node* base,
    996                                          Node* offset, Node* value) {
    997   return raw_assembler()->Store(rep, base, offset, value, kNoWriteBarrier);
    998 }
    999 
   1000 Node* CodeAssembler::AtomicStore(MachineRepresentation rep, Node* base,
   1001                                  Node* offset, Node* value) {
   1002   return raw_assembler()->AtomicStore(rep, base, offset, value);
   1003 }
   1004 
   1005 #define ATOMIC_FUNCTION(name)                                        \
   1006   Node* CodeAssembler::Atomic##name(MachineType type, Node* base,    \
   1007                                     Node* offset, Node* value) {     \
   1008     return raw_assembler()->Atomic##name(type, base, offset, value); \
   1009   }
   1010 ATOMIC_FUNCTION(Exchange);
   1011 ATOMIC_FUNCTION(Add);
   1012 ATOMIC_FUNCTION(Sub);
   1013 ATOMIC_FUNCTION(And);
   1014 ATOMIC_FUNCTION(Or);
   1015 ATOMIC_FUNCTION(Xor);
   1016 #undef ATOMIC_FUNCTION
   1017 
   1018 Node* CodeAssembler::AtomicCompareExchange(MachineType type, Node* base,
   1019                                            Node* offset, Node* old_value,
   1020                                            Node* new_value) {
   1021   return raw_assembler()->AtomicCompareExchange(type, base, offset, old_value,
   1022                                                 new_value);
   1023 }
   1024 
   1025 Node* CodeAssembler::StoreRoot(Heap::RootListIndex root_index, Node* value) {
   1026   DCHECK(Heap::RootCanBeWrittenAfterInitialization(root_index));
   1027   Node* roots_array_start =
   1028       ExternalConstant(ExternalReference::roots_array_start(isolate()));
   1029   return StoreNoWriteBarrier(MachineRepresentation::kTagged, roots_array_start,
   1030                              IntPtrConstant(root_index * kPointerSize), value);
   1031 }
   1032 
   1033 Node* CodeAssembler::Retain(Node* value) {
   1034   return raw_assembler()->Retain(value);
   1035 }
   1036 
   1037 Node* CodeAssembler::Projection(int index, Node* value) {
   1038   return raw_assembler()->Projection(index, value);
   1039 }
   1040 
   1041 void CodeAssembler::GotoIfException(Node* node, Label* if_exception,
   1042                                     Variable* exception_var) {
   1043   if (if_exception == nullptr) {
   1044     // If no handler is supplied, don't add continuations
   1045     return;
   1046   }
   1047 
   1048   DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
   1049 
   1050   Label success(this), exception(this, Label::kDeferred);
   1051   success.MergeVariables();
   1052   exception.MergeVariables();
   1053 
   1054   raw_assembler()->Continuations(node, success.label_, exception.label_);
   1055 
   1056   Bind(&exception);
   1057   const Operator* op = raw_assembler()->common()->IfException();
   1058   Node* exception_value = raw_assembler()->AddNode(op, node, node);
   1059   if (exception_var != nullptr) {
   1060     exception_var->Bind(exception_value);
   1061   }
   1062   Goto(if_exception);
   1063 
   1064   Bind(&success);
   1065 }
   1066 
   1067 namespace {
   1068 template <size_t kMaxSize>
   1069 class NodeArray {
   1070  public:
   1071   void Add(Node* node) {
   1072     DCHECK_GT(kMaxSize, size());
   1073     *ptr_++ = node;
   1074   }
   1075 
   1076   Node* const* data() const { return arr_; }
   1077   int size() const { return static_cast<int>(ptr_ - arr_); }
   1078 
   1079  private:
   1080   Node* arr_[kMaxSize];
   1081   Node** ptr_ = arr_;
   1082 };
   1083 }  // namespace
   1084 
   1085 TNode<Object> CodeAssembler::CallRuntimeImpl(
   1086     Runtime::FunctionId function, TNode<Object> context,
   1087     std::initializer_list<TNode<Object>> args) {
   1088   int result_size = Runtime::FunctionForId(function)->result_size;
   1089   TNode<Code> centry =
   1090       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
   1091   return CallRuntimeWithCEntryImpl(function, centry, context, args);
   1092 }
   1093 
   1094 TNode<Object> CodeAssembler::CallRuntimeWithCEntryImpl(
   1095     Runtime::FunctionId function, TNode<Code> centry, TNode<Object> context,
   1096     std::initializer_list<TNode<Object>> args) {
   1097   constexpr size_t kMaxNumArgs = 6;
   1098   DCHECK_GE(kMaxNumArgs, args.size());
   1099   int argc = static_cast<int>(args.size());
   1100   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
   1101       zone(), function, argc, Operator::kNoProperties,
   1102       CallDescriptor::kNoFlags);
   1103 
   1104   Node* ref = ExternalConstant(ExternalReference::Create(function));
   1105   Node* arity = Int32Constant(argc);
   1106 
   1107   NodeArray<kMaxNumArgs + 4> inputs;
   1108   inputs.Add(centry);
   1109   for (auto arg : args) inputs.Add(arg);
   1110   inputs.Add(ref);
   1111   inputs.Add(arity);
   1112   inputs.Add(context);
   1113 
   1114   CallPrologue();
   1115   Node* return_value =
   1116       raw_assembler()->CallN(call_descriptor, inputs.size(), inputs.data());
   1117   CallEpilogue();
   1118   return UncheckedCast<Object>(return_value);
   1119 }
   1120 
   1121 void CodeAssembler::TailCallRuntimeImpl(
   1122     Runtime::FunctionId function, TNode<Int32T> arity, TNode<Object> context,
   1123     std::initializer_list<TNode<Object>> args) {
   1124   int result_size = Runtime::FunctionForId(function)->result_size;
   1125   TNode<Code> centry =
   1126       HeapConstant(CodeFactory::RuntimeCEntry(isolate(), result_size));
   1127   return TailCallRuntimeWithCEntryImpl(function, arity, centry, context, args);
   1128 }
   1129 
   1130 void CodeAssembler::TailCallRuntimeWithCEntryImpl(
   1131     Runtime::FunctionId function, TNode<Int32T> arity, TNode<Code> centry,
   1132     TNode<Object> context, std::initializer_list<TNode<Object>> args) {
   1133   constexpr size_t kMaxNumArgs = 6;
   1134   DCHECK_GE(kMaxNumArgs, args.size());
   1135   int argc = static_cast<int>(args.size());
   1136   auto call_descriptor = Linkage::GetRuntimeCallDescriptor(
   1137       zone(), function, argc, Operator::kNoProperties,
   1138       CallDescriptor::kNoFlags);
   1139 
   1140   Node* ref = ExternalConstant(ExternalReference::Create(function));
   1141 
   1142   NodeArray<kMaxNumArgs + 4> inputs;
   1143   inputs.Add(centry);
   1144   for (auto arg : args) inputs.Add(arg);
   1145   inputs.Add(ref);
   1146   inputs.Add(arity);
   1147   inputs.Add(context);
   1148 
   1149   raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
   1150 }
   1151 
   1152 Node* CodeAssembler::CallStubN(const CallInterfaceDescriptor& descriptor,
   1153                                size_t result_size, int input_count,
   1154                                Node* const* inputs) {
   1155   // implicit nodes are target and optionally context.
   1156   int implicit_nodes = descriptor.HasContextParameter() ? 2 : 1;
   1157   DCHECK_LE(implicit_nodes, input_count);
   1158   int argc = input_count - implicit_nodes;
   1159   DCHECK_LE(descriptor.GetParameterCount(), argc);
   1160   // Extra arguments not mentioned in the descriptor are passed on the stack.
   1161   int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
   1162   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
   1163   DCHECK_EQ(result_size, descriptor.GetReturnCount());
   1164 
   1165   auto call_descriptor = Linkage::GetStubCallDescriptor(
   1166       zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
   1167       Operator::kNoProperties);
   1168 
   1169   CallPrologue();
   1170   Node* return_value =
   1171       raw_assembler()->CallN(call_descriptor, input_count, inputs);
   1172   CallEpilogue();
   1173   return return_value;
   1174 }
   1175 
   1176 void CodeAssembler::TailCallStubImpl(const CallInterfaceDescriptor& descriptor,
   1177                                      TNode<Code> target, TNode<Object> context,
   1178                                      std::initializer_list<Node*> args) {
   1179   constexpr size_t kMaxNumArgs = 11;
   1180   DCHECK_GE(kMaxNumArgs, args.size());
   1181   DCHECK_EQ(descriptor.GetParameterCount(), args.size());
   1182   auto call_descriptor = Linkage::GetStubCallDescriptor(
   1183       zone(), descriptor, descriptor.GetStackParameterCount(),
   1184       CallDescriptor::kNoFlags, Operator::kNoProperties);
   1185 
   1186   NodeArray<kMaxNumArgs + 2> inputs;
   1187   inputs.Add(target);
   1188   for (auto arg : args) inputs.Add(arg);
   1189   if (descriptor.HasContextParameter()) {
   1190     inputs.Add(context);
   1191   }
   1192 
   1193   raw_assembler()->TailCallN(call_descriptor, inputs.size(), inputs.data());
   1194 }
   1195 
   1196 Node* CodeAssembler::CallStubRImpl(const CallInterfaceDescriptor& descriptor,
   1197                                    size_t result_size, SloppyTNode<Code> target,
   1198                                    SloppyTNode<Object> context,
   1199                                    std::initializer_list<Node*> args) {
   1200   constexpr size_t kMaxNumArgs = 10;
   1201   DCHECK_GE(kMaxNumArgs, args.size());
   1202 
   1203   NodeArray<kMaxNumArgs + 2> inputs;
   1204   inputs.Add(target);
   1205   for (auto arg : args) inputs.Add(arg);
   1206   if (descriptor.HasContextParameter()) {
   1207     inputs.Add(context);
   1208   }
   1209 
   1210   return CallStubN(descriptor, result_size, inputs.size(), inputs.data());
   1211 }
   1212 
   1213 Node* CodeAssembler::TailCallStubThenBytecodeDispatchImpl(
   1214     const CallInterfaceDescriptor& descriptor, Node* target, Node* context,
   1215     std::initializer_list<Node*> args) {
   1216   constexpr size_t kMaxNumArgs = 6;
   1217   DCHECK_GE(kMaxNumArgs, args.size());
   1218 
   1219   DCHECK_LE(descriptor.GetParameterCount(), args.size());
   1220   int argc = static_cast<int>(args.size());
   1221   // Extra arguments not mentioned in the descriptor are passed on the stack.
   1222   int stack_parameter_count = argc - descriptor.GetRegisterParameterCount();
   1223   DCHECK_LE(descriptor.GetStackParameterCount(), stack_parameter_count);
   1224   auto call_descriptor = Linkage::GetStubCallDescriptor(
   1225       zone(), descriptor, stack_parameter_count, CallDescriptor::kNoFlags,
   1226       Operator::kNoProperties);
   1227 
   1228   NodeArray<kMaxNumArgs + 2> inputs;
   1229   inputs.Add(target);
   1230   for (auto arg : args) inputs.Add(arg);
   1231   inputs.Add(context);
   1232 
   1233   return raw_assembler()->TailCallN(call_descriptor, inputs.size(),
   1234                                     inputs.data());
   1235 }
   1236 
   1237 template <class... TArgs>
   1238 Node* CodeAssembler::TailCallBytecodeDispatch(
   1239     const CallInterfaceDescriptor& descriptor, Node* target, TArgs... args) {
   1240   DCHECK_EQ(descriptor.GetParameterCount(), sizeof...(args));
   1241   auto call_descriptor = Linkage::GetBytecodeDispatchCallDescriptor(
   1242       zone(), descriptor, descriptor.GetStackParameterCount());
   1243 
   1244   Node* nodes[] = {target, args...};
   1245   CHECK_EQ(descriptor.GetParameterCount() + 1, arraysize(nodes));
   1246   return raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes);
   1247 }
   1248 
   1249 // Instantiate TailCallBytecodeDispatch() for argument counts used by
   1250 // CSA-generated code
   1251 template V8_EXPORT_PRIVATE Node* CodeAssembler::TailCallBytecodeDispatch(
   1252     const CallInterfaceDescriptor& descriptor, Node* target, Node*, Node*,
   1253     Node*, Node*);
   1254 
   1255 TNode<Object> CodeAssembler::TailCallJSCode(TNode<Code> code,
   1256                                             TNode<Context> context,
   1257                                             TNode<JSFunction> function,
   1258                                             TNode<Object> new_target,
   1259                                             TNode<Int32T> arg_count) {
   1260   JSTrampolineDescriptor descriptor;
   1261   auto call_descriptor = Linkage::GetStubCallDescriptor(
   1262       zone(), descriptor, descriptor.GetStackParameterCount(),
   1263       CallDescriptor::kFixedTargetRegister, Operator::kNoProperties);
   1264 
   1265   Node* nodes[] = {code, function, new_target, arg_count, context};
   1266   CHECK_EQ(descriptor.GetParameterCount() + 2, arraysize(nodes));
   1267   return UncheckedCast<Object>(
   1268       raw_assembler()->TailCallN(call_descriptor, arraysize(nodes), nodes));
   1269 }
   1270 
   1271 Node* CodeAssembler::CallCFunctionN(Signature<MachineType>* signature,
   1272                                     int input_count, Node* const* inputs) {
   1273   auto call_descriptor = Linkage::GetSimplifiedCDescriptor(zone(), signature);
   1274   return raw_assembler()->CallN(call_descriptor, input_count, inputs);
   1275 }
   1276 
   1277 Node* CodeAssembler::CallCFunction1(MachineType return_type,
   1278                                     MachineType arg0_type, Node* function,
   1279                                     Node* arg0) {
   1280   return raw_assembler()->CallCFunction1(return_type, arg0_type, function,
   1281                                          arg0);
   1282 }
   1283 
   1284 Node* CodeAssembler::CallCFunction1WithCallerSavedRegisters(
   1285     MachineType return_type, MachineType arg0_type, Node* function, Node* arg0,
   1286     SaveFPRegsMode mode) {
   1287   DCHECK(return_type.LessThanOrEqualPointerSize());
   1288   return raw_assembler()->CallCFunction1WithCallerSavedRegisters(
   1289       return_type, arg0_type, function, arg0, mode);
   1290 }
   1291 
   1292 Node* CodeAssembler::CallCFunction2(MachineType return_type,
   1293                                     MachineType arg0_type,
   1294                                     MachineType arg1_type, Node* function,
   1295                                     Node* arg0, Node* arg1) {
   1296   return raw_assembler()->CallCFunction2(return_type, arg0_type, arg1_type,
   1297                                          function, arg0, arg1);
   1298 }
   1299 
   1300 Node* CodeAssembler::CallCFunction3(MachineType return_type,
   1301                                     MachineType arg0_type,
   1302                                     MachineType arg1_type,
   1303                                     MachineType arg2_type, Node* function,
   1304                                     Node* arg0, Node* arg1, Node* arg2) {
   1305   return raw_assembler()->CallCFunction3(return_type, arg0_type, arg1_type,
   1306                                          arg2_type, function, arg0, arg1, arg2);
   1307 }
   1308 
   1309 Node* CodeAssembler::CallCFunction3WithCallerSavedRegisters(
   1310     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
   1311     MachineType arg2_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
   1312     SaveFPRegsMode mode) {
   1313   DCHECK(return_type.LessThanOrEqualPointerSize());
   1314   return raw_assembler()->CallCFunction3WithCallerSavedRegisters(
   1315       return_type, arg0_type, arg1_type, arg2_type, function, arg0, arg1, arg2,
   1316       mode);
   1317 }
   1318 
   1319 Node* CodeAssembler::CallCFunction4(
   1320     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
   1321     MachineType arg2_type, MachineType arg3_type, Node* function, Node* arg0,
   1322     Node* arg1, Node* arg2, Node* arg3) {
   1323   return raw_assembler()->CallCFunction4(return_type, arg0_type, arg1_type,
   1324                                          arg2_type, arg3_type, function, arg0,
   1325                                          arg1, arg2, arg3);
   1326 }
   1327 
   1328 Node* CodeAssembler::CallCFunction5(
   1329     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
   1330     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
   1331     Node* function, Node* arg0, Node* arg1, Node* arg2, Node* arg3,
   1332     Node* arg4) {
   1333   return raw_assembler()->CallCFunction5(
   1334       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
   1335       function, arg0, arg1, arg2, arg3, arg4);
   1336 }
   1337 
   1338 Node* CodeAssembler::CallCFunction6(
   1339     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
   1340     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
   1341     MachineType arg5_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
   1342     Node* arg3, Node* arg4, Node* arg5) {
   1343   return raw_assembler()->CallCFunction6(
   1344       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
   1345       arg5_type, function, arg0, arg1, arg2, arg3, arg4, arg5);
   1346 }
   1347 
   1348 Node* CodeAssembler::CallCFunction9(
   1349     MachineType return_type, MachineType arg0_type, MachineType arg1_type,
   1350     MachineType arg2_type, MachineType arg3_type, MachineType arg4_type,
   1351     MachineType arg5_type, MachineType arg6_type, MachineType arg7_type,
   1352     MachineType arg8_type, Node* function, Node* arg0, Node* arg1, Node* arg2,
   1353     Node* arg3, Node* arg4, Node* arg5, Node* arg6, Node* arg7, Node* arg8) {
   1354   return raw_assembler()->CallCFunction9(
   1355       return_type, arg0_type, arg1_type, arg2_type, arg3_type, arg4_type,
   1356       arg5_type, arg6_type, arg7_type, arg8_type, function, arg0, arg1, arg2,
   1357       arg3, arg4, arg5, arg6, arg7, arg8);
   1358 }
   1359 
   1360 void CodeAssembler::Goto(Label* label) {
   1361   label->MergeVariables();
   1362   raw_assembler()->Goto(label->label_);
   1363 }
   1364 
   1365 void CodeAssembler::GotoIf(SloppyTNode<IntegralT> condition,
   1366                            Label* true_label) {
   1367   Label false_label(this);
   1368   Branch(condition, true_label, &false_label);
   1369   Bind(&false_label);
   1370 }
   1371 
   1372 void CodeAssembler::GotoIfNot(SloppyTNode<IntegralT> condition,
   1373                               Label* false_label) {
   1374   Label true_label(this);
   1375   Branch(condition, &true_label, false_label);
   1376   Bind(&true_label);
   1377 }
   1378 
   1379 void CodeAssembler::Branch(SloppyTNode<IntegralT> condition, Label* true_label,
   1380                            Label* false_label) {
   1381   int32_t constant;
   1382   if (ToInt32Constant(condition, constant)) {
   1383     if ((true_label->is_used() || true_label->is_bound()) &&
   1384         (false_label->is_used() || false_label->is_bound())) {
   1385       return Goto(constant ? true_label : false_label);
   1386     }
   1387   }
   1388   true_label->MergeVariables();
   1389   false_label->MergeVariables();
   1390   return raw_assembler()->Branch(condition, true_label->label_,
   1391                                  false_label->label_);
   1392 }
   1393 
   1394 void CodeAssembler::Branch(TNode<BoolT> condition,
   1395                            std::function<void()> true_body,
   1396                            std::function<void()> false_body) {
   1397   int32_t constant;
   1398   if (ToInt32Constant(condition, constant)) {
   1399     return constant ? true_body() : false_body();
   1400   }
   1401 
   1402   Label vtrue(this), vfalse(this);
   1403   Branch(condition, &vtrue, &vfalse);
   1404 
   1405   Bind(&vtrue);
   1406   true_body();
   1407 
   1408   Bind(&vfalse);
   1409   false_body();
   1410 }
   1411 
   1412 void CodeAssembler::Branch(TNode<BoolT> condition, Label* true_label,
   1413                            std::function<void()> false_body) {
   1414   int32_t constant;
   1415   if (ToInt32Constant(condition, constant)) {
   1416     return constant ? Goto(true_label) : false_body();
   1417   }
   1418 
   1419   Label vfalse(this);
   1420   Branch(condition, true_label, &vfalse);
   1421   Bind(&vfalse);
   1422   false_body();
   1423 }
   1424 
   1425 void CodeAssembler::Branch(TNode<BoolT> condition,
   1426                            std::function<void()> true_body,
   1427                            Label* false_label) {
   1428   int32_t constant;
   1429   if (ToInt32Constant(condition, constant)) {
   1430     return constant ? true_body() : Goto(false_label);
   1431   }
   1432 
   1433   Label vtrue(this);
   1434   Branch(condition, &vtrue, false_label);
   1435   Bind(&vtrue);
   1436   true_body();
   1437 }
   1438 
   1439 void CodeAssembler::Switch(Node* index, Label* default_label,
   1440                            const int32_t* case_values, Label** case_labels,
   1441                            size_t case_count) {
   1442   RawMachineLabel** labels =
   1443       new (zone()->New(sizeof(RawMachineLabel*) * case_count))
   1444           RawMachineLabel*[case_count];
   1445   for (size_t i = 0; i < case_count; ++i) {
   1446     labels[i] = case_labels[i]->label_;
   1447     case_labels[i]->MergeVariables();
   1448   }
   1449   default_label->MergeVariables();
   1450   return raw_assembler()->Switch(index, default_label->label_, case_values,
   1451                                  labels, case_count);
   1452 }
   1453 
   1454 bool CodeAssembler::UnalignedLoadSupported(MachineRepresentation rep) const {
   1455   return raw_assembler()->machine()->UnalignedLoadSupported(rep);
   1456 }
   1457 bool CodeAssembler::UnalignedStoreSupported(MachineRepresentation rep) const {
   1458   return raw_assembler()->machine()->UnalignedStoreSupported(rep);
   1459 }
   1460 
   1461 // RawMachineAssembler delegate helpers:
   1462 Isolate* CodeAssembler::isolate() const { return raw_assembler()->isolate(); }
   1463 
   1464 Factory* CodeAssembler::factory() const { return isolate()->factory(); }
   1465 
   1466 Zone* CodeAssembler::zone() const { return raw_assembler()->zone(); }
   1467 
   1468 RawMachineAssembler* CodeAssembler::raw_assembler() const {
   1469   return state_->raw_assembler_.get();
   1470 }
   1471 
   1472 // The core implementation of Variable is stored through an indirection so
   1473 // that it can outlive the often block-scoped Variable declarations. This is
   1474 // needed to ensure that variable binding and merging through phis can
   1475 // properly be verified.
   1476 class CodeAssemblerVariable::Impl : public ZoneObject {
   1477  public:
   1478   explicit Impl(MachineRepresentation rep)
   1479       :
   1480 #if DEBUG
   1481         debug_info_(AssemblerDebugInfo(nullptr, nullptr, -1)),
   1482 #endif
   1483         value_(nullptr),
   1484         rep_(rep) {
   1485   }
   1486 
   1487 #if DEBUG
   1488   AssemblerDebugInfo debug_info() const { return debug_info_; }
   1489   void set_debug_info(AssemblerDebugInfo debug_info) {
   1490     debug_info_ = debug_info;
   1491   }
   1492 
   1493   AssemblerDebugInfo debug_info_;
   1494 #endif  // DEBUG
   1495   Node* value_;
   1496   MachineRepresentation rep_;
   1497 };
   1498 
   1499 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
   1500                                              MachineRepresentation rep)
   1501     : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
   1502   state_->variables_.insert(impl_);
   1503 }
   1504 
   1505 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
   1506                                              MachineRepresentation rep,
   1507                                              Node* initial_value)
   1508     : CodeAssemblerVariable(assembler, rep) {
   1509   Bind(initial_value);
   1510 }
   1511 
   1512 #if DEBUG
   1513 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
   1514                                              AssemblerDebugInfo debug_info,
   1515                                              MachineRepresentation rep)
   1516     : impl_(new (assembler->zone()) Impl(rep)), state_(assembler->state()) {
   1517   impl_->set_debug_info(debug_info);
   1518   state_->variables_.insert(impl_);
   1519 }
   1520 
   1521 CodeAssemblerVariable::CodeAssemblerVariable(CodeAssembler* assembler,
   1522                                              AssemblerDebugInfo debug_info,
   1523                                              MachineRepresentation rep,
   1524                                              Node* initial_value)
   1525     : CodeAssemblerVariable(assembler, debug_info, rep) {
   1526   impl_->set_debug_info(debug_info);
   1527   Bind(initial_value);
   1528 }
   1529 #endif  // DEBUG
   1530 
   1531 CodeAssemblerVariable::~CodeAssemblerVariable() {
   1532   state_->variables_.erase(impl_);
   1533 }
   1534 
   1535 void CodeAssemblerVariable::Bind(Node* value) { impl_->value_ = value; }
   1536 
   1537 Node* CodeAssemblerVariable::value() const {
   1538 #if DEBUG
   1539   if (!IsBound()) {
   1540     std::stringstream str;
   1541     str << "#Use of unbound variable:"
   1542         << "#\n    Variable:      " << *this << "#\n    Current Block: ";
   1543     state_->PrintCurrentBlock(str);
   1544     FATAL("%s", str.str().c_str());
   1545   }
   1546   if (!state_->InsideBlock()) {
   1547     std::stringstream str;
   1548     str << "#Accessing variable value outside a block:"
   1549         << "#\n    Variable:      " << *this;
   1550     FATAL("%s", str.str().c_str());
   1551   }
   1552 #endif  // DEBUG
   1553   return impl_->value_;
   1554 }
   1555 
   1556 MachineRepresentation CodeAssemblerVariable::rep() const { return impl_->rep_; }
   1557 
   1558 bool CodeAssemblerVariable::IsBound() const { return impl_->value_ != nullptr; }
   1559 
   1560 std::ostream& operator<<(std::ostream& os,
   1561                          const CodeAssemblerVariable::Impl& impl) {
   1562 #if DEBUG
   1563   AssemblerDebugInfo info = impl.debug_info();
   1564   if (info.name) os << "V" << info;
   1565 #endif  // DEBUG
   1566   return os;
   1567 }
   1568 
   1569 std::ostream& operator<<(std::ostream& os,
   1570                          const CodeAssemblerVariable& variable) {
   1571   os << *variable.impl_;
   1572   return os;
   1573 }
   1574 
   1575 CodeAssemblerLabel::CodeAssemblerLabel(CodeAssembler* assembler,
   1576                                        size_t vars_count,
   1577                                        CodeAssemblerVariable* const* vars,
   1578                                        CodeAssemblerLabel::Type type)
   1579     : bound_(false),
   1580       merge_count_(0),
   1581       state_(assembler->state()),
   1582       label_(nullptr) {
   1583   void* buffer = assembler->zone()->New(sizeof(RawMachineLabel));
   1584   label_ = new (buffer)
   1585       RawMachineLabel(type == kDeferred ? RawMachineLabel::kDeferred
   1586                                         : RawMachineLabel::kNonDeferred);
   1587   for (size_t i = 0; i < vars_count; ++i) {
   1588     variable_phis_[vars[i]->impl_] = nullptr;
   1589   }
   1590 }
   1591 
   1592 CodeAssemblerLabel::~CodeAssemblerLabel() { label_->~RawMachineLabel(); }
   1593 
   1594 void CodeAssemblerLabel::MergeVariables() {
   1595   ++merge_count_;
   1596   for (CodeAssemblerVariable::Impl* var : state_->variables_) {
   1597     size_t count = 0;
   1598     Node* node = var->value_;
   1599     if (node != nullptr) {
   1600       auto i = variable_merges_.find(var);
   1601       if (i != variable_merges_.end()) {
   1602         i->second.push_back(node);
   1603         count = i->second.size();
   1604       } else {
   1605         count = 1;
   1606         variable_merges_[var] = std::vector<Node*>(1, node);
   1607       }
   1608     }
   1609     // If the following asserts, then you've jumped to a label without a bound
   1610     // variable along that path that expects to merge its value into a phi.
   1611     DCHECK(variable_phis_.find(var) == variable_phis_.end() ||
   1612            count == merge_count_);
   1613     USE(count);
   1614 
   1615     // If the label is already bound, we already know the set of variables to
   1616     // merge and phi nodes have already been created.
   1617     if (bound_) {
   1618       auto phi = variable_phis_.find(var);
   1619       if (phi != variable_phis_.end()) {
   1620         DCHECK_NOT_NULL(phi->second);
   1621         state_->raw_assembler_->AppendPhiInput(phi->second, node);
   1622       } else {
   1623         auto i = variable_merges_.find(var);
   1624         if (i != variable_merges_.end()) {
   1625           // If the following assert fires, then you've declared a variable that
   1626           // has the same bound value along all paths up until the point you
   1627           // bound this label, but then later merged a path with a new value for
   1628           // the variable after the label bind (it's not possible to add phis to
   1629           // the bound label after the fact, just make sure to list the variable
   1630           // in the label's constructor's list of merged variables).
   1631 #if DEBUG
   1632           if (find_if(i->second.begin(), i->second.end(),
   1633                       [node](Node* e) -> bool { return node != e; }) !=
   1634               i->second.end()) {
   1635             std::stringstream str;
   1636             str << "Unmerged variable found when jumping to block. \n"
   1637                 << "#    Variable:      " << *var;
   1638             if (bound_) {
   1639               str << "\n#    Target block:  " << *label_->block();
   1640             }
   1641             str << "\n#    Current Block: ";
   1642             state_->PrintCurrentBlock(str);
   1643             FATAL("%s", str.str().c_str());
   1644           }
   1645 #endif  // DEBUG
   1646         }
   1647       }
   1648     }
   1649   }
   1650 }
   1651 
   1652 #if DEBUG
   1653 void CodeAssemblerLabel::Bind(AssemblerDebugInfo debug_info) {
   1654   if (bound_) {
   1655     std::stringstream str;
   1656     str << "Cannot bind the same label twice:"
   1657         << "\n#    current:  " << debug_info
   1658         << "\n#    previous: " << *label_->block();
   1659     FATAL("%s", str.str().c_str());
   1660   }
   1661   state_->raw_assembler_->Bind(label_, debug_info);
   1662   UpdateVariablesAfterBind();
   1663 }
   1664 #endif  // DEBUG
   1665 
   1666 void CodeAssemblerLabel::Bind() {
   1667   DCHECK(!bound_);
   1668   state_->raw_assembler_->Bind(label_);
   1669   UpdateVariablesAfterBind();
   1670 }
   1671 
   1672 void CodeAssemblerLabel::UpdateVariablesAfterBind() {
   1673   // Make sure that all variables that have changed along any path up to this
   1674   // point are marked as merge variables.
   1675   for (auto var : state_->variables_) {
   1676     Node* shared_value = nullptr;
   1677     auto i = variable_merges_.find(var);
   1678     if (i != variable_merges_.end()) {
   1679       for (auto value : i->second) {
   1680         DCHECK_NOT_NULL(value);
   1681         if (value != shared_value) {
   1682           if (shared_value == nullptr) {
   1683             shared_value = value;
   1684           } else {
   1685             variable_phis_[var] = nullptr;
   1686           }
   1687         }
   1688       }
   1689     }
   1690   }
   1691 
   1692   for (auto var : variable_phis_) {
   1693     CodeAssemblerVariable::Impl* var_impl = var.first;
   1694     auto i = variable_merges_.find(var_impl);
   1695 #if DEBUG
   1696     bool not_found = i == variable_merges_.end();
   1697     if (not_found || i->second.size() != merge_count_) {
   1698       std::stringstream str;
   1699       str << "A variable that has been marked as beeing merged at the label"
   1700           << "\n# doesn't have a bound value along all of the paths that "
   1701           << "\n# have been merged into the label up to this point."
   1702           << "\n#"
   1703           << "\n# This can happen in the following cases:"
   1704           << "\n# - By explicitly marking it so in the label constructor"
   1705           << "\n# - By having seen different bound values at branches"
   1706           << "\n#"
   1707           << "\n# Merge count:     expected=" << merge_count_
   1708           << " vs. found=" << (not_found ? 0 : i->second.size())
   1709           << "\n# Variable:      " << *var_impl
   1710           << "\n# Current Block: " << *label_->block();
   1711       FATAL("%s", str.str().c_str());
   1712     }
   1713 #endif  // DEBUG
   1714     Node* phi = state_->raw_assembler_->Phi(
   1715         var.first->rep_, static_cast<int>(merge_count_), &(i->second[0]));
   1716     variable_phis_[var_impl] = phi;
   1717   }
   1718 
   1719   // Bind all variables to a merge phi, the common value along all paths or
   1720   // null.
   1721   for (auto var : state_->variables_) {
   1722     auto i = variable_phis_.find(var);
   1723     if (i != variable_phis_.end()) {
   1724       var->value_ = i->second;
   1725     } else {
   1726       auto j = variable_merges_.find(var);
   1727       if (j != variable_merges_.end() && j->second.size() == merge_count_) {
   1728         var->value_ = j->second.back();
   1729       } else {
   1730         var->value_ = nullptr;
   1731       }
   1732     }
   1733   }
   1734 
   1735   bound_ = true;
   1736 }
   1737 
   1738 }  // namespace compiler
   1739 
   1740 Smi* CheckObjectType(Object* value, Smi* type, String* location) {
   1741 #ifdef DEBUG
   1742   const char* expected;
   1743   switch (static_cast<ObjectType>(type->value())) {
   1744 #define TYPE_CASE(Name)                            \
   1745   case ObjectType::k##Name:                        \
   1746     if (value->Is##Name()) return Smi::FromInt(0); \
   1747     expected = #Name;                              \
   1748     break;
   1749 #define TYPE_STRUCT_CASE(NAME, Name, name)         \
   1750   case ObjectType::k##Name:                        \
   1751     if (value->Is##Name()) return Smi::FromInt(0); \
   1752     expected = #Name;                              \
   1753     break;
   1754 
   1755     TYPE_CASE(Object)
   1756     OBJECT_TYPE_LIST(TYPE_CASE)
   1757     HEAP_OBJECT_TYPE_LIST(TYPE_CASE)
   1758     STRUCT_LIST(TYPE_STRUCT_CASE)
   1759 #undef TYPE_CASE
   1760 #undef TYPE_STRUCT_CASE
   1761   }
   1762   std::stringstream value_description;
   1763   value->Print(value_description);
   1764   V8_Fatal(__FILE__, __LINE__,
   1765            "Type cast failed in %s\n"
   1766            "  Expected %s but found %s",
   1767            location->ToAsciiArray(), expected, value_description.str().c_str());
   1768 #else
   1769   UNREACHABLE();
   1770 #endif
   1771 }
   1772 
   1773 }  // namespace internal
   1774 }  // namespace v8
   1775