Home | History | Annotate | Download | only in src
      1 // Copyright 2012 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/code-stubs.h"
      6 
      7 #include <sstream>
      8 
      9 #include "src/bootstrapper.h"
     10 #include "src/code-factory.h"
     11 #include "src/code-stub-assembler.h"
     12 #include "src/factory.h"
     13 #include "src/gdb-jit.h"
     14 #include "src/ic/handler-compiler.h"
     15 #include "src/ic/ic.h"
     16 #include "src/macro-assembler.h"
     17 #include "src/parsing/parser.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 
     23 RUNTIME_FUNCTION(UnexpectedStubMiss) {
     24   FATAL("Unexpected deopt of a stub");
     25   return Smi::FromInt(0);
     26 }
     27 
     28 
     29 CodeStubDescriptor::CodeStubDescriptor(CodeStub* stub)
     30     : call_descriptor_(stub->GetCallInterfaceDescriptor()),
     31       stack_parameter_count_(no_reg),
     32       hint_stack_parameter_count_(-1),
     33       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
     34       deoptimization_handler_(NULL),
     35       miss_handler_(),
     36       has_miss_handler_(false) {
     37   stub->InitializeDescriptor(this);
     38 }
     39 
     40 
     41 CodeStubDescriptor::CodeStubDescriptor(Isolate* isolate, uint32_t stub_key)
     42     : stack_parameter_count_(no_reg),
     43       hint_stack_parameter_count_(-1),
     44       function_mode_(NOT_JS_FUNCTION_STUB_MODE),
     45       deoptimization_handler_(NULL),
     46       miss_handler_(),
     47       has_miss_handler_(false) {
     48   CodeStub::InitializeDescriptor(isolate, stub_key, this);
     49 }
     50 
     51 
     52 void CodeStubDescriptor::Initialize(Address deoptimization_handler,
     53                                     int hint_stack_parameter_count,
     54                                     StubFunctionMode function_mode) {
     55   deoptimization_handler_ = deoptimization_handler;
     56   hint_stack_parameter_count_ = hint_stack_parameter_count;
     57   function_mode_ = function_mode;
     58 }
     59 
     60 
     61 void CodeStubDescriptor::Initialize(Register stack_parameter_count,
     62                                     Address deoptimization_handler,
     63                                     int hint_stack_parameter_count,
     64                                     StubFunctionMode function_mode) {
     65   Initialize(deoptimization_handler, hint_stack_parameter_count, function_mode);
     66   stack_parameter_count_ = stack_parameter_count;
     67 }
     68 
     69 
     70 bool CodeStub::FindCodeInCache(Code** code_out) {
     71   UnseededNumberDictionary* stubs = isolate()->heap()->code_stubs();
     72   int index = stubs->FindEntry(GetKey());
     73   if (index != UnseededNumberDictionary::kNotFound) {
     74     *code_out = Code::cast(stubs->ValueAt(index));
     75     return true;
     76   }
     77   return false;
     78 }
     79 
     80 
     81 void CodeStub::RecordCodeGeneration(Handle<Code> code) {
     82   std::ostringstream os;
     83   os << *this;
     84   PROFILE(isolate(),
     85           CodeCreateEvent(CodeEventListener::STUB_TAG,
     86                           AbstractCode::cast(*code), os.str().c_str()));
     87   Counters* counters = isolate()->counters();
     88   counters->total_stubs_code_size()->Increment(code->instruction_size());
     89 #ifdef DEBUG
     90   code->VerifyEmbeddedObjects();
     91 #endif
     92 }
     93 
     94 
     95 Code::Kind CodeStub::GetCodeKind() const {
     96   return Code::STUB;
     97 }
     98 
     99 
    100 Code::Flags CodeStub::GetCodeFlags() const {
    101   return Code::ComputeFlags(GetCodeKind(), GetExtraICState());
    102 }
    103 
    104 
    105 Handle<Code> CodeStub::GetCodeCopy(const Code::FindAndReplacePattern& pattern) {
    106   Handle<Code> ic = GetCode();
    107   ic = isolate()->factory()->CopyCode(ic);
    108   ic->FindAndReplace(pattern);
    109   RecordCodeGeneration(ic);
    110   return ic;
    111 }
    112 
    113 
    114 Handle<Code> PlatformCodeStub::GenerateCode() {
    115   Factory* factory = isolate()->factory();
    116 
    117   // Generate the new code.
    118   MacroAssembler masm(isolate(), NULL, 256, CodeObjectRequired::kYes);
    119 
    120   {
    121     // Update the static counter each time a new code stub is generated.
    122     isolate()->counters()->code_stubs()->Increment();
    123 
    124     // Generate the code for the stub.
    125     masm.set_generating_stub(true);
    126     // TODO(yangguo): remove this once we can serialize IC stubs.
    127     masm.enable_serializer();
    128     NoCurrentFrameScope scope(&masm);
    129     Generate(&masm);
    130   }
    131 
    132   // Create the code object.
    133   CodeDesc desc;
    134   masm.GetCode(&desc);
    135   // Copy the generated code into a heap object.
    136   Code::Flags flags = Code::ComputeFlags(GetCodeKind(), GetExtraICState());
    137   Handle<Code> new_object = factory->NewCode(
    138       desc, flags, masm.CodeObject(), NeedsImmovableCode());
    139   return new_object;
    140 }
    141 
    142 
    143 Handle<Code> CodeStub::GetCode() {
    144   Heap* heap = isolate()->heap();
    145   Code* code;
    146   if (UseSpecialCache() ? FindCodeInSpecialCache(&code)
    147                         : FindCodeInCache(&code)) {
    148     DCHECK(GetCodeKind() == code->kind());
    149     return Handle<Code>(code);
    150   }
    151 
    152   {
    153     HandleScope scope(isolate());
    154 
    155     Handle<Code> new_object = GenerateCode();
    156     new_object->set_stub_key(GetKey());
    157     FinishCode(new_object);
    158     RecordCodeGeneration(new_object);
    159 
    160 #ifdef ENABLE_DISASSEMBLER
    161     if (FLAG_print_code_stubs) {
    162       CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
    163       OFStream os(trace_scope.file());
    164       std::ostringstream name;
    165       name << *this;
    166       new_object->Disassemble(name.str().c_str(), os);
    167       os << "\n";
    168     }
    169 #endif
    170 
    171     if (UseSpecialCache()) {
    172       AddToSpecialCache(new_object);
    173     } else {
    174       // Update the dictionary and the root in Heap.
    175       Handle<UnseededNumberDictionary> dict =
    176           UnseededNumberDictionary::AtNumberPut(
    177               Handle<UnseededNumberDictionary>(heap->code_stubs()),
    178               GetKey(),
    179               new_object);
    180       heap->SetRootCodeStubs(*dict);
    181     }
    182     code = *new_object;
    183   }
    184 
    185   Activate(code);
    186   DCHECK(!NeedsImmovableCode() ||
    187          heap->lo_space()->Contains(code) ||
    188          heap->code_space()->FirstPage()->Contains(code->address()));
    189   return Handle<Code>(code, isolate());
    190 }
    191 
    192 
    193 const char* CodeStub::MajorName(CodeStub::Major major_key) {
    194   switch (major_key) {
    195 #define DEF_CASE(name) case name: return #name "Stub";
    196     CODE_STUB_LIST(DEF_CASE)
    197 #undef DEF_CASE
    198     case NoCache:
    199       return "<NoCache>Stub";
    200     case NUMBER_OF_IDS:
    201       UNREACHABLE();
    202       return NULL;
    203   }
    204   return NULL;
    205 }
    206 
    207 
    208 void CodeStub::PrintBaseName(std::ostream& os) const {  // NOLINT
    209   os << MajorName(MajorKey());
    210 }
    211 
    212 
    213 void CodeStub::PrintName(std::ostream& os) const {  // NOLINT
    214   PrintBaseName(os);
    215   PrintState(os);
    216 }
    217 
    218 
    219 void CodeStub::Dispatch(Isolate* isolate, uint32_t key, void** value_out,
    220                         DispatchedCall call) {
    221   switch (MajorKeyFromKey(key)) {
    222 #define DEF_CASE(NAME)             \
    223   case NAME: {                     \
    224     NAME##Stub stub(key, isolate); \
    225     CodeStub* pstub = &stub;       \
    226     call(pstub, value_out);        \
    227     break;                         \
    228   }
    229     CODE_STUB_LIST(DEF_CASE)
    230 #undef DEF_CASE
    231     case NUMBER_OF_IDS:
    232     case NoCache:
    233       UNREACHABLE();
    234       break;
    235   }
    236 }
    237 
    238 
    239 static void InitializeDescriptorDispatchedCall(CodeStub* stub,
    240                                                void** value_out) {
    241   CodeStubDescriptor* descriptor_out =
    242       reinterpret_cast<CodeStubDescriptor*>(value_out);
    243   stub->InitializeDescriptor(descriptor_out);
    244   descriptor_out->set_call_descriptor(stub->GetCallInterfaceDescriptor());
    245 }
    246 
    247 
    248 void CodeStub::InitializeDescriptor(Isolate* isolate, uint32_t key,
    249                                     CodeStubDescriptor* desc) {
    250   void** value_out = reinterpret_cast<void**>(desc);
    251   Dispatch(isolate, key, value_out, &InitializeDescriptorDispatchedCall);
    252 }
    253 
    254 
    255 void CodeStub::GetCodeDispatchCall(CodeStub* stub, void** value_out) {
    256   Handle<Code>* code_out = reinterpret_cast<Handle<Code>*>(value_out);
    257   // Code stubs with special cache cannot be recreated from stub key.
    258   *code_out = stub->UseSpecialCache() ? Handle<Code>() : stub->GetCode();
    259 }
    260 
    261 
    262 MaybeHandle<Code> CodeStub::GetCode(Isolate* isolate, uint32_t key) {
    263   HandleScope scope(isolate);
    264   Handle<Code> code;
    265   void** value_out = reinterpret_cast<void**>(&code);
    266   Dispatch(isolate, key, value_out, &GetCodeDispatchCall);
    267   return scope.CloseAndEscape(code);
    268 }
    269 
    270 
    271 // static
    272 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate) {
    273   // Generate the uninitialized versions of the stub.
    274   for (int op = Token::BIT_OR; op <= Token::MOD; ++op) {
    275     BinaryOpICStub stub(isolate, static_cast<Token::Value>(op));
    276     stub.GetCode();
    277   }
    278 
    279   // Generate special versions of the stub.
    280   BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
    281 }
    282 
    283 
    284 void BinaryOpICStub::PrintState(std::ostream& os) const {  // NOLINT
    285   os << state();
    286 }
    287 
    288 
    289 // static
    290 void BinaryOpICStub::GenerateAheadOfTime(Isolate* isolate,
    291                                          const BinaryOpICState& state) {
    292   BinaryOpICStub stub(isolate, state);
    293   stub.GetCode();
    294 }
    295 
    296 
    297 // static
    298 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
    299   // Generate special versions of the stub.
    300   BinaryOpICState::GenerateAheadOfTime(isolate, &GenerateAheadOfTime);
    301 }
    302 
    303 
    304 void BinaryOpICWithAllocationSiteStub::PrintState(
    305     std::ostream& os) const {  // NOLINT
    306   os << state();
    307 }
    308 
    309 
    310 // static
    311 void BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(
    312     Isolate* isolate, const BinaryOpICState& state) {
    313   if (state.CouldCreateAllocationMementos()) {
    314     BinaryOpICWithAllocationSiteStub stub(isolate, state);
    315     stub.GetCode();
    316   }
    317 }
    318 
    319 
    320 std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
    321   switch (flags) {
    322     case STRING_ADD_CHECK_NONE:
    323       return os << "CheckNone";
    324     case STRING_ADD_CHECK_LEFT:
    325       return os << "CheckLeft";
    326     case STRING_ADD_CHECK_RIGHT:
    327       return os << "CheckRight";
    328     case STRING_ADD_CHECK_BOTH:
    329       return os << "CheckBoth";
    330     case STRING_ADD_CONVERT_LEFT:
    331       return os << "ConvertLeft";
    332     case STRING_ADD_CONVERT_RIGHT:
    333       return os << "ConvertRight";
    334     case STRING_ADD_CONVERT:
    335       break;
    336   }
    337   UNREACHABLE();
    338   return os;
    339 }
    340 
    341 
    342 void StringAddStub::PrintBaseName(std::ostream& os) const {  // NOLINT
    343   os << "StringAddStub_" << flags() << "_" << pretenure_flag();
    344 }
    345 
    346 
    347 InlineCacheState CompareICStub::GetICState() const {
    348   CompareICState::State state = Max(left(), right());
    349   switch (state) {
    350     case CompareICState::UNINITIALIZED:
    351       return ::v8::internal::UNINITIALIZED;
    352     case CompareICState::BOOLEAN:
    353     case CompareICState::SMI:
    354     case CompareICState::NUMBER:
    355     case CompareICState::INTERNALIZED_STRING:
    356     case CompareICState::STRING:
    357     case CompareICState::UNIQUE_NAME:
    358     case CompareICState::RECEIVER:
    359     case CompareICState::KNOWN_RECEIVER:
    360       return MONOMORPHIC;
    361     case CompareICState::GENERIC:
    362       return ::v8::internal::GENERIC;
    363   }
    364   UNREACHABLE();
    365   return ::v8::internal::UNINITIALIZED;
    366 }
    367 
    368 
    369 Condition CompareICStub::GetCondition() const {
    370   return CompareIC::ComputeCondition(op());
    371 }
    372 
    373 
    374 void CompareICStub::Generate(MacroAssembler* masm) {
    375   switch (state()) {
    376     case CompareICState::UNINITIALIZED:
    377       GenerateMiss(masm);
    378       break;
    379     case CompareICState::BOOLEAN:
    380       GenerateBooleans(masm);
    381       break;
    382     case CompareICState::SMI:
    383       GenerateSmis(masm);
    384       break;
    385     case CompareICState::NUMBER:
    386       GenerateNumbers(masm);
    387       break;
    388     case CompareICState::STRING:
    389       GenerateStrings(masm);
    390       break;
    391     case CompareICState::INTERNALIZED_STRING:
    392       GenerateInternalizedStrings(masm);
    393       break;
    394     case CompareICState::UNIQUE_NAME:
    395       GenerateUniqueNames(masm);
    396       break;
    397     case CompareICState::RECEIVER:
    398       GenerateReceivers(masm);
    399       break;
    400     case CompareICState::KNOWN_RECEIVER:
    401       DCHECK(*known_map_ != NULL);
    402       GenerateKnownReceivers(masm);
    403       break;
    404     case CompareICState::GENERIC:
    405       GenerateGeneric(masm);
    406       break;
    407   }
    408 }
    409 
    410 Handle<Code> TurboFanCodeStub::GenerateCode() {
    411   const char* name = CodeStub::MajorName(MajorKey());
    412   Zone zone(isolate()->allocator());
    413   CallInterfaceDescriptor descriptor(GetCallInterfaceDescriptor());
    414   CodeStubAssembler assembler(isolate(), &zone, descriptor, GetCodeFlags(),
    415                               name);
    416   GenerateAssembly(&assembler);
    417   return assembler.GenerateCode();
    418 }
    419 
    420 void LoadICTrampolineTFStub::GenerateAssembly(
    421     CodeStubAssembler* assembler) const {
    422   typedef compiler::Node Node;
    423 
    424   Node* receiver = assembler->Parameter(0);
    425   Node* name = assembler->Parameter(1);
    426   Node* slot = assembler->Parameter(2);
    427   Node* context = assembler->Parameter(3);
    428   Node* vector = assembler->LoadTypeFeedbackVectorForStub();
    429 
    430   CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
    431   assembler->LoadIC(&p);
    432 }
    433 
    434 void LoadICTFStub::GenerateAssembly(CodeStubAssembler* assembler) const {
    435   typedef compiler::Node Node;
    436 
    437   Node* receiver = assembler->Parameter(0);
    438   Node* name = assembler->Parameter(1);
    439   Node* slot = assembler->Parameter(2);
    440   Node* vector = assembler->Parameter(3);
    441   Node* context = assembler->Parameter(4);
    442 
    443   CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
    444   assembler->LoadIC(&p);
    445 }
    446 
    447 void LoadGlobalICTrampolineStub::GenerateAssembly(
    448     CodeStubAssembler* assembler) const {
    449   typedef compiler::Node Node;
    450 
    451   Node* slot = assembler->Parameter(0);
    452   Node* context = assembler->Parameter(1);
    453   Node* vector = assembler->LoadTypeFeedbackVectorForStub();
    454 
    455   CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
    456                                         vector);
    457   assembler->LoadGlobalIC(&p);
    458 }
    459 
    460 void LoadGlobalICStub::GenerateAssembly(CodeStubAssembler* assembler) const {
    461   typedef compiler::Node Node;
    462 
    463   Node* slot = assembler->Parameter(0);
    464   Node* vector = assembler->Parameter(1);
    465   Node* context = assembler->Parameter(2);
    466 
    467   CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
    468                                         vector);
    469   assembler->LoadGlobalIC(&p);
    470 }
    471 
    472 void AllocateHeapNumberStub::GenerateAssembly(
    473     CodeStubAssembler* assembler) const {
    474   typedef compiler::Node Node;
    475 
    476   Node* result = assembler->AllocateHeapNumber();
    477   assembler->Return(result);
    478 }
    479 
    480 #define SIMD128_GEN_ASM(TYPE, Type, type, lane_count, lane_type)            \
    481   void Allocate##Type##Stub::GenerateAssembly(CodeStubAssembler* assembler) \
    482       const {                                                               \
    483     compiler::Node* result =                                                \
    484         assembler->Allocate(Simd128Value::kSize, CodeStubAssembler::kNone); \
    485     compiler::Node* map_offset =                                            \
    486         assembler->IntPtrConstant(HeapObject::kMapOffset - kHeapObjectTag); \
    487     compiler::Node* map = assembler->IntPtrAdd(result, map_offset);         \
    488     assembler->StoreNoWriteBarrier(                                         \
    489         MachineRepresentation::kTagged, map,                                \
    490         assembler->HeapConstant(isolate()->factory()->type##_map()));       \
    491     assembler->Return(result);                                              \
    492   }
    493 SIMD128_TYPES(SIMD128_GEN_ASM)
    494 #undef SIMD128_GEN_ASM
    495 
    496 void StringLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
    497   compiler::Node* value = assembler->Parameter(0);
    498   compiler::Node* string =
    499       assembler->LoadObjectField(value, JSValue::kValueOffset);
    500   compiler::Node* result =
    501       assembler->LoadObjectField(string, String::kLengthOffset);
    502   assembler->Return(result);
    503 }
    504 
    505 // static
    506 compiler::Node* AddStub::Generate(CodeStubAssembler* assembler,
    507                                   compiler::Node* left, compiler::Node* right,
    508                                   compiler::Node* context) {
    509   typedef CodeStubAssembler::Label Label;
    510   typedef compiler::Node Node;
    511   typedef CodeStubAssembler::Variable Variable;
    512 
    513   // Shared entry for floating point addition.
    514   Label do_fadd(assembler);
    515   Variable var_fadd_lhs(assembler, MachineRepresentation::kFloat64),
    516       var_fadd_rhs(assembler, MachineRepresentation::kFloat64);
    517 
    518   // We might need to loop several times due to ToPrimitive, ToString and/or
    519   // ToNumber conversions.
    520   Variable var_lhs(assembler, MachineRepresentation::kTagged),
    521       var_rhs(assembler, MachineRepresentation::kTagged),
    522       var_result(assembler, MachineRepresentation::kTagged);
    523   Variable* loop_vars[2] = {&var_lhs, &var_rhs};
    524   Label loop(assembler, 2, loop_vars), end(assembler),
    525       string_add_convert_left(assembler, Label::kDeferred),
    526       string_add_convert_right(assembler, Label::kDeferred);
    527   var_lhs.Bind(left);
    528   var_rhs.Bind(right);
    529   assembler->Goto(&loop);
    530   assembler->Bind(&loop);
    531   {
    532     // Load the current {lhs} and {rhs} values.
    533     Node* lhs = var_lhs.value();
    534     Node* rhs = var_rhs.value();
    535 
    536     // Check if the {lhs} is a Smi or a HeapObject.
    537     Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
    538     assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
    539 
    540     assembler->Bind(&if_lhsissmi);
    541     {
    542       // Check if the {rhs} is also a Smi.
    543       Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
    544       assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
    545                         &if_rhsisnotsmi);
    546 
    547       assembler->Bind(&if_rhsissmi);
    548       {
    549         // Try fast Smi addition first.
    550         Node* pair = assembler->SmiAddWithOverflow(lhs, rhs);
    551         Node* overflow = assembler->Projection(1, pair);
    552 
    553         // Check if the Smi additon overflowed.
    554         Label if_overflow(assembler), if_notoverflow(assembler);
    555         assembler->Branch(overflow, &if_overflow, &if_notoverflow);
    556 
    557         assembler->Bind(&if_overflow);
    558         {
    559           var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
    560           var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
    561           assembler->Goto(&do_fadd);
    562         }
    563 
    564         assembler->Bind(&if_notoverflow);
    565         var_result.Bind(assembler->Projection(0, pair));
    566         assembler->Goto(&end);
    567       }
    568 
    569       assembler->Bind(&if_rhsisnotsmi);
    570       {
    571         // Load the map of {rhs}.
    572         Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset);
    573 
    574         // Check if the {rhs} is a HeapNumber.
    575         Label if_rhsisnumber(assembler),
    576             if_rhsisnotnumber(assembler, Label::kDeferred);
    577         Node* number_map = assembler->HeapNumberMapConstant();
    578         assembler->Branch(assembler->WordEqual(rhs_map, number_map),
    579                           &if_rhsisnumber, &if_rhsisnotnumber);
    580 
    581         assembler->Bind(&if_rhsisnumber);
    582         {
    583           var_fadd_lhs.Bind(assembler->SmiToFloat64(lhs));
    584           var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
    585           assembler->Goto(&do_fadd);
    586         }
    587 
    588         assembler->Bind(&if_rhsisnotnumber);
    589         {
    590           // Load the instance type of {rhs}.
    591           Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
    592 
    593           // Check if the {rhs} is a String.
    594           Label if_rhsisstring(assembler, Label::kDeferred),
    595               if_rhsisnotstring(assembler, Label::kDeferred);
    596           assembler->Branch(assembler->Int32LessThan(
    597                                 rhs_instance_type,
    598                                 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
    599                             &if_rhsisstring, &if_rhsisnotstring);
    600 
    601           assembler->Bind(&if_rhsisstring);
    602           {
    603             var_lhs.Bind(lhs);
    604             var_rhs.Bind(rhs);
    605             assembler->Goto(&string_add_convert_left);
    606           }
    607 
    608           assembler->Bind(&if_rhsisnotstring);
    609           {
    610             // Check if {rhs} is a JSReceiver.
    611             Label if_rhsisreceiver(assembler, Label::kDeferred),
    612                 if_rhsisnotreceiver(assembler, Label::kDeferred);
    613             assembler->Branch(
    614                 assembler->Int32LessThanOrEqual(
    615                     assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
    616                     rhs_instance_type),
    617                 &if_rhsisreceiver, &if_rhsisnotreceiver);
    618 
    619             assembler->Bind(&if_rhsisreceiver);
    620             {
    621               // Convert {rhs} to a primitive first passing no hint.
    622               // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
    623               var_rhs.Bind(
    624                   assembler->CallRuntime(Runtime::kToPrimitive, context, rhs));
    625               assembler->Goto(&loop);
    626             }
    627 
    628             assembler->Bind(&if_rhsisnotreceiver);
    629             {
    630               // Convert {rhs} to a Number first.
    631               Callable callable =
    632                   CodeFactory::NonNumberToNumber(assembler->isolate());
    633               var_rhs.Bind(assembler->CallStub(callable, context, rhs));
    634               assembler->Goto(&loop);
    635             }
    636           }
    637         }
    638       }
    639     }
    640 
    641     assembler->Bind(&if_lhsisnotsmi);
    642     {
    643       // Load the map and instance type of {lhs}.
    644       Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
    645 
    646       // Check if {lhs} is a String.
    647       Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
    648       assembler->Branch(assembler->Int32LessThan(
    649                             lhs_instance_type,
    650                             assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
    651                         &if_lhsisstring, &if_lhsisnotstring);
    652 
    653       assembler->Bind(&if_lhsisstring);
    654       {
    655         var_lhs.Bind(lhs);
    656         var_rhs.Bind(rhs);
    657         assembler->Goto(&string_add_convert_right);
    658       }
    659 
    660       assembler->Bind(&if_lhsisnotstring);
    661       {
    662         // Check if {rhs} is a Smi.
    663         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
    664         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
    665                           &if_rhsisnotsmi);
    666 
    667         assembler->Bind(&if_rhsissmi);
    668         {
    669           // Check if {lhs} is a Number.
    670           Label if_lhsisnumber(assembler),
    671               if_lhsisnotnumber(assembler, Label::kDeferred);
    672           assembler->Branch(assembler->Word32Equal(
    673                                 lhs_instance_type,
    674                                 assembler->Int32Constant(HEAP_NUMBER_TYPE)),
    675                             &if_lhsisnumber, &if_lhsisnotnumber);
    676 
    677           assembler->Bind(&if_lhsisnumber);
    678           {
    679             // The {lhs} is a HeapNumber, the {rhs} is a Smi, just add them.
    680             var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
    681             var_fadd_rhs.Bind(assembler->SmiToFloat64(rhs));
    682             assembler->Goto(&do_fadd);
    683           }
    684 
    685           assembler->Bind(&if_lhsisnotnumber);
    686           {
    687             // The {lhs} is neither a Number nor a String, and the {rhs} is a
    688             // Smi.
    689             Label if_lhsisreceiver(assembler, Label::kDeferred),
    690                 if_lhsisnotreceiver(assembler, Label::kDeferred);
    691             assembler->Branch(
    692                 assembler->Int32LessThanOrEqual(
    693                     assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
    694                     lhs_instance_type),
    695                 &if_lhsisreceiver, &if_lhsisnotreceiver);
    696 
    697             assembler->Bind(&if_lhsisreceiver);
    698             {
    699               // Convert {lhs} to a primitive first passing no hint.
    700               // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
    701               var_lhs.Bind(
    702                   assembler->CallRuntime(Runtime::kToPrimitive, context, lhs));
    703               assembler->Goto(&loop);
    704             }
    705 
    706             assembler->Bind(&if_lhsisnotreceiver);
    707             {
    708               // Convert {lhs} to a Number first.
    709               Callable callable =
    710                   CodeFactory::NonNumberToNumber(assembler->isolate());
    711               var_lhs.Bind(assembler->CallStub(callable, context, lhs));
    712               assembler->Goto(&loop);
    713             }
    714           }
    715         }
    716 
    717         assembler->Bind(&if_rhsisnotsmi);
    718         {
    719           // Load the instance type of {rhs}.
    720           Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
    721 
    722           // Check if {rhs} is a String.
    723           Label if_rhsisstring(assembler), if_rhsisnotstring(assembler);
    724           assembler->Branch(assembler->Int32LessThan(
    725                                 rhs_instance_type,
    726                                 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
    727                             &if_rhsisstring, &if_rhsisnotstring);
    728 
    729           assembler->Bind(&if_rhsisstring);
    730           {
    731             var_lhs.Bind(lhs);
    732             var_rhs.Bind(rhs);
    733             assembler->Goto(&string_add_convert_left);
    734           }
    735 
    736           assembler->Bind(&if_rhsisnotstring);
    737           {
    738             // Check if {lhs} is a HeapNumber.
    739             Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
    740             assembler->Branch(assembler->Word32Equal(
    741                                   lhs_instance_type,
    742                                   assembler->Int32Constant(HEAP_NUMBER_TYPE)),
    743                               &if_lhsisnumber, &if_lhsisnotnumber);
    744 
    745             assembler->Bind(&if_lhsisnumber);
    746             {
    747               // Check if {rhs} is also a HeapNumber.
    748               Label if_rhsisnumber(assembler),
    749                   if_rhsisnotnumber(assembler, Label::kDeferred);
    750               assembler->Branch(assembler->Word32Equal(
    751                                     rhs_instance_type,
    752                                     assembler->Int32Constant(HEAP_NUMBER_TYPE)),
    753                                 &if_rhsisnumber, &if_rhsisnotnumber);
    754 
    755               assembler->Bind(&if_rhsisnumber);
    756               {
    757                 // Perform a floating point addition.
    758                 var_fadd_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
    759                 var_fadd_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
    760                 assembler->Goto(&do_fadd);
    761               }
    762 
    763               assembler->Bind(&if_rhsisnotnumber);
    764               {
    765                 // Check if {rhs} is a JSReceiver.
    766                 Label if_rhsisreceiver(assembler, Label::kDeferred),
    767                     if_rhsisnotreceiver(assembler, Label::kDeferred);
    768                 assembler->Branch(
    769                     assembler->Int32LessThanOrEqual(
    770                         assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
    771                         rhs_instance_type),
    772                     &if_rhsisreceiver, &if_rhsisnotreceiver);
    773 
    774                 assembler->Bind(&if_rhsisreceiver);
    775                 {
    776                   // Convert {rhs} to a primitive first passing no hint.
    777                   // TODO(bmeurer): Hook up ToPrimitiveStub here too.
    778                   var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
    779                                                       context, rhs));
    780                   assembler->Goto(&loop);
    781                 }
    782 
    783                 assembler->Bind(&if_rhsisnotreceiver);
    784                 {
    785                   // Convert {rhs} to a Number first.
    786                   Callable callable =
    787                       CodeFactory::NonNumberToNumber(assembler->isolate());
    788                   var_rhs.Bind(assembler->CallStub(callable, context, rhs));
    789                   assembler->Goto(&loop);
    790                 }
    791               }
    792             }
    793 
    794             assembler->Bind(&if_lhsisnotnumber);
    795             {
    796               // Check if {lhs} is a JSReceiver.
    797               Label if_lhsisreceiver(assembler, Label::kDeferred),
    798                   if_lhsisnotreceiver(assembler);
    799               assembler->Branch(
    800                   assembler->Int32LessThanOrEqual(
    801                       assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
    802                       lhs_instance_type),
    803                   &if_lhsisreceiver, &if_lhsisnotreceiver);
    804 
    805               assembler->Bind(&if_lhsisreceiver);
    806               {
    807                 // Convert {lhs} to a primitive first passing no hint.
    808                 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
    809                 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
    810                                                     context, lhs));
    811                 assembler->Goto(&loop);
    812               }
    813 
    814               assembler->Bind(&if_lhsisnotreceiver);
    815               {
    816                 // Check if {rhs} is a JSReceiver.
    817                 Label if_rhsisreceiver(assembler, Label::kDeferred),
    818                     if_rhsisnotreceiver(assembler, Label::kDeferred);
    819                 assembler->Branch(
    820                     assembler->Int32LessThanOrEqual(
    821                         assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
    822                         rhs_instance_type),
    823                     &if_rhsisreceiver, &if_rhsisnotreceiver);
    824 
    825                 assembler->Bind(&if_rhsisreceiver);
    826                 {
    827                   // Convert {rhs} to a primitive first passing no hint.
    828                   // TODO(bmeurer): Hook up ToPrimitiveStub here too.
    829                   var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
    830                                                       context, rhs));
    831                   assembler->Goto(&loop);
    832                 }
    833 
    834                 assembler->Bind(&if_rhsisnotreceiver);
    835                 {
    836                   // Convert {lhs} to a Number first.
    837                   Callable callable =
    838                       CodeFactory::NonNumberToNumber(assembler->isolate());
    839                   var_lhs.Bind(assembler->CallStub(callable, context, lhs));
    840                   assembler->Goto(&loop);
    841                 }
    842               }
    843             }
    844           }
    845         }
    846       }
    847     }
    848   }
    849   assembler->Bind(&string_add_convert_left);
    850   {
    851     // Convert {lhs}, which is a Smi, to a String and concatenate the
    852     // resulting string with the String {rhs}.
    853     Callable callable = CodeFactory::StringAdd(
    854         assembler->isolate(), STRING_ADD_CONVERT_LEFT, NOT_TENURED);
    855     var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
    856                                         var_rhs.value()));
    857     assembler->Goto(&end);
    858   }
    859 
    860   assembler->Bind(&string_add_convert_right);
    861   {
    862     // Convert {lhs}, which is a Smi, to a String and concatenate the
    863     // resulting string with the String {rhs}.
    864     Callable callable = CodeFactory::StringAdd(
    865         assembler->isolate(), STRING_ADD_CONVERT_RIGHT, NOT_TENURED);
    866     var_result.Bind(assembler->CallStub(callable, context, var_lhs.value(),
    867                                         var_rhs.value()));
    868     assembler->Goto(&end);
    869   }
    870 
    871   assembler->Bind(&do_fadd);
    872   {
    873     Node* lhs_value = var_fadd_lhs.value();
    874     Node* rhs_value = var_fadd_rhs.value();
    875     Node* value = assembler->Float64Add(lhs_value, rhs_value);
    876     Node* result = assembler->ChangeFloat64ToTagged(value);
    877     var_result.Bind(result);
    878     assembler->Goto(&end);
    879   }
    880   assembler->Bind(&end);
    881   return var_result.value();
    882 }
    883 
    884 // static
    885 compiler::Node* SubtractStub::Generate(CodeStubAssembler* assembler,
    886                                        compiler::Node* left,
    887                                        compiler::Node* right,
    888                                        compiler::Node* context) {
    889   typedef CodeStubAssembler::Label Label;
    890   typedef compiler::Node Node;
    891   typedef CodeStubAssembler::Variable Variable;
    892 
    893   // Shared entry for floating point subtraction.
    894   Label do_fsub(assembler), end(assembler);
    895   Variable var_fsub_lhs(assembler, MachineRepresentation::kFloat64),
    896       var_fsub_rhs(assembler, MachineRepresentation::kFloat64);
    897 
    898   // We might need to loop several times due to ToPrimitive and/or ToNumber
    899   // conversions.
    900   Variable var_lhs(assembler, MachineRepresentation::kTagged),
    901       var_rhs(assembler, MachineRepresentation::kTagged),
    902       var_result(assembler, MachineRepresentation::kTagged);
    903   Variable* loop_vars[2] = {&var_lhs, &var_rhs};
    904   Label loop(assembler, 2, loop_vars);
    905   var_lhs.Bind(left);
    906   var_rhs.Bind(right);
    907   assembler->Goto(&loop);
    908   assembler->Bind(&loop);
    909   {
    910     // Load the current {lhs} and {rhs} values.
    911     Node* lhs = var_lhs.value();
    912     Node* rhs = var_rhs.value();
    913 
    914     // Check if the {lhs} is a Smi or a HeapObject.
    915     Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
    916     assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
    917 
    918     assembler->Bind(&if_lhsissmi);
    919     {
    920       // Check if the {rhs} is also a Smi.
    921       Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
    922       assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
    923                         &if_rhsisnotsmi);
    924 
    925       assembler->Bind(&if_rhsissmi);
    926       {
    927         // Try a fast Smi subtraction first.
    928         Node* pair = assembler->SmiSubWithOverflow(lhs, rhs);
    929         Node* overflow = assembler->Projection(1, pair);
    930 
    931         // Check if the Smi subtraction overflowed.
    932         Label if_overflow(assembler), if_notoverflow(assembler);
    933         assembler->Branch(overflow, &if_overflow, &if_notoverflow);
    934 
    935         assembler->Bind(&if_overflow);
    936         {
    937           // The result doesn't fit into Smi range.
    938           var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
    939           var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
    940           assembler->Goto(&do_fsub);
    941         }
    942 
    943         assembler->Bind(&if_notoverflow);
    944         var_result.Bind(assembler->Projection(0, pair));
    945         assembler->Goto(&end);
    946       }
    947 
    948       assembler->Bind(&if_rhsisnotsmi);
    949       {
    950         // Load the map of the {rhs}.
    951         Node* rhs_map = assembler->LoadMap(rhs);
    952 
    953         // Check if {rhs} is a HeapNumber.
    954         Label if_rhsisnumber(assembler),
    955             if_rhsisnotnumber(assembler, Label::kDeferred);
    956         Node* number_map = assembler->HeapNumberMapConstant();
    957         assembler->Branch(assembler->WordEqual(rhs_map, number_map),
    958                           &if_rhsisnumber, &if_rhsisnotnumber);
    959 
    960         assembler->Bind(&if_rhsisnumber);
    961         {
    962           // Perform a floating point subtraction.
    963           var_fsub_lhs.Bind(assembler->SmiToFloat64(lhs));
    964           var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
    965           assembler->Goto(&do_fsub);
    966         }
    967 
    968         assembler->Bind(&if_rhsisnotnumber);
    969         {
    970           // Convert the {rhs} to a Number first.
    971           Callable callable =
    972               CodeFactory::NonNumberToNumber(assembler->isolate());
    973           var_rhs.Bind(assembler->CallStub(callable, context, rhs));
    974           assembler->Goto(&loop);
    975         }
    976       }
    977     }
    978 
    979     assembler->Bind(&if_lhsisnotsmi);
    980     {
    981       // Load the map of the {lhs}.
    982       Node* lhs_map = assembler->LoadMap(lhs);
    983 
    984       // Check if the {lhs} is a HeapNumber.
    985       Label if_lhsisnumber(assembler),
    986           if_lhsisnotnumber(assembler, Label::kDeferred);
    987       Node* number_map = assembler->HeapNumberMapConstant();
    988       assembler->Branch(assembler->WordEqual(lhs_map, number_map),
    989                         &if_lhsisnumber, &if_lhsisnotnumber);
    990 
    991       assembler->Bind(&if_lhsisnumber);
    992       {
    993         // Check if the {rhs} is a Smi.
    994         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
    995         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
    996                           &if_rhsisnotsmi);
    997 
    998         assembler->Bind(&if_rhsissmi);
    999         {
   1000           // Perform a floating point subtraction.
   1001           var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
   1002           var_fsub_rhs.Bind(assembler->SmiToFloat64(rhs));
   1003           assembler->Goto(&do_fsub);
   1004         }
   1005 
   1006         assembler->Bind(&if_rhsisnotsmi);
   1007         {
   1008           // Load the map of the {rhs}.
   1009           Node* rhs_map = assembler->LoadMap(rhs);
   1010 
   1011           // Check if the {rhs} is a HeapNumber.
   1012           Label if_rhsisnumber(assembler),
   1013               if_rhsisnotnumber(assembler, Label::kDeferred);
   1014           assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   1015                             &if_rhsisnumber, &if_rhsisnotnumber);
   1016 
   1017           assembler->Bind(&if_rhsisnumber);
   1018           {
   1019             // Perform a floating point subtraction.
   1020             var_fsub_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
   1021             var_fsub_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
   1022             assembler->Goto(&do_fsub);
   1023           }
   1024 
   1025           assembler->Bind(&if_rhsisnotnumber);
   1026           {
   1027             // Convert the {rhs} to a Number first.
   1028             Callable callable =
   1029                 CodeFactory::NonNumberToNumber(assembler->isolate());
   1030             var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   1031             assembler->Goto(&loop);
   1032           }
   1033         }
   1034       }
   1035 
   1036       assembler->Bind(&if_lhsisnotnumber);
   1037       {
   1038         // Convert the {lhs} to a Number first.
   1039         Callable callable =
   1040             CodeFactory::NonNumberToNumber(assembler->isolate());
   1041         var_lhs.Bind(assembler->CallStub(callable, context, lhs));
   1042         assembler->Goto(&loop);
   1043       }
   1044     }
   1045   }
   1046 
   1047   assembler->Bind(&do_fsub);
   1048   {
   1049     Node* lhs_value = var_fsub_lhs.value();
   1050     Node* rhs_value = var_fsub_rhs.value();
   1051     Node* value = assembler->Float64Sub(lhs_value, rhs_value);
   1052     var_result.Bind(assembler->ChangeFloat64ToTagged(value));
   1053     assembler->Goto(&end);
   1054   }
   1055   assembler->Bind(&end);
   1056   return var_result.value();
   1057 }
   1058 
   1059 // static
   1060 compiler::Node* MultiplyStub::Generate(CodeStubAssembler* assembler,
   1061                                        compiler::Node* left,
   1062                                        compiler::Node* right,
   1063                                        compiler::Node* context) {
   1064   using compiler::Node;
   1065   typedef CodeStubAssembler::Label Label;
   1066   typedef CodeStubAssembler::Variable Variable;
   1067 
   1068   // Shared entry point for floating point multiplication.
   1069   Label do_fmul(assembler);
   1070   Variable var_lhs_float64(assembler, MachineRepresentation::kFloat64),
   1071       var_rhs_float64(assembler, MachineRepresentation::kFloat64);
   1072 
   1073   Node* number_map = assembler->HeapNumberMapConstant();
   1074 
   1075   // We might need to loop one or two times due to ToNumber conversions.
   1076   Variable var_lhs(assembler, MachineRepresentation::kTagged),
   1077       var_rhs(assembler, MachineRepresentation::kTagged);
   1078   Variable* loop_variables[] = {&var_lhs, &var_rhs};
   1079   Label loop(assembler, 2, loop_variables);
   1080   var_lhs.Bind(left);
   1081   var_rhs.Bind(right);
   1082   assembler->Goto(&loop);
   1083   assembler->Bind(&loop);
   1084   {
   1085     Node* lhs = var_lhs.value();
   1086     Node* rhs = var_rhs.value();
   1087 
   1088     Label lhs_is_smi(assembler), lhs_is_not_smi(assembler);
   1089     assembler->Branch(assembler->WordIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
   1090 
   1091     assembler->Bind(&lhs_is_smi);
   1092     {
   1093       Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
   1094       assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
   1095                         &rhs_is_not_smi);
   1096 
   1097       assembler->Bind(&rhs_is_smi);
   1098       {
   1099         // Both {lhs} and {rhs} are Smis. Convert them to double and multiply.
   1100         // TODO(epertoso): use SmiMulWithOverflow once available.
   1101         var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
   1102         var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
   1103         assembler->Goto(&do_fmul);
   1104       }
   1105 
   1106       assembler->Bind(&rhs_is_not_smi);
   1107       {
   1108         Node* rhs_map = assembler->LoadMap(rhs);
   1109 
   1110         // Check if {rhs} is a HeapNumber.
   1111         Label rhs_is_number(assembler),
   1112             rhs_is_not_number(assembler, Label::kDeferred);
   1113         assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   1114                           &rhs_is_number, &rhs_is_not_number);
   1115 
   1116         assembler->Bind(&rhs_is_number);
   1117         {
   1118           // Convert {lhs} to a double and multiply it with the value of {rhs}.
   1119           var_lhs_float64.Bind(assembler->SmiToFloat64(lhs));
   1120           var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
   1121           assembler->Goto(&do_fmul);
   1122         }
   1123 
   1124         assembler->Bind(&rhs_is_not_number);
   1125         {
   1126           // Multiplication is commutative, swap {lhs} with {rhs} and loop.
   1127           var_lhs.Bind(rhs);
   1128           var_rhs.Bind(lhs);
   1129           assembler->Goto(&loop);
   1130         }
   1131       }
   1132     }
   1133 
   1134     assembler->Bind(&lhs_is_not_smi);
   1135     {
   1136       Node* lhs_map = assembler->LoadMap(lhs);
   1137 
   1138       // Check if {lhs} is a HeapNumber.
   1139       Label lhs_is_number(assembler),
   1140           lhs_is_not_number(assembler, Label::kDeferred);
   1141       assembler->Branch(assembler->WordEqual(lhs_map, number_map),
   1142                         &lhs_is_number, &lhs_is_not_number);
   1143 
   1144       assembler->Bind(&lhs_is_number);
   1145       {
   1146         // Check if {rhs} is a Smi.
   1147         Label rhs_is_smi(assembler), rhs_is_not_smi(assembler);
   1148         assembler->Branch(assembler->WordIsSmi(rhs), &rhs_is_smi,
   1149                           &rhs_is_not_smi);
   1150 
   1151         assembler->Bind(&rhs_is_smi);
   1152         {
   1153           // Convert {rhs} to a double and multiply it with the value of {lhs}.
   1154           var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
   1155           var_rhs_float64.Bind(assembler->SmiToFloat64(rhs));
   1156           assembler->Goto(&do_fmul);
   1157         }
   1158 
   1159         assembler->Bind(&rhs_is_not_smi);
   1160         {
   1161           Node* rhs_map = assembler->LoadMap(rhs);
   1162 
   1163           // Check if {rhs} is a HeapNumber.
   1164           Label rhs_is_number(assembler),
   1165               rhs_is_not_number(assembler, Label::kDeferred);
   1166           assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   1167                             &rhs_is_number, &rhs_is_not_number);
   1168 
   1169           assembler->Bind(&rhs_is_number);
   1170           {
   1171             // Both {lhs} and {rhs} are HeapNumbers. Load their values and
   1172             // multiply them.
   1173             var_lhs_float64.Bind(assembler->LoadHeapNumberValue(lhs));
   1174             var_rhs_float64.Bind(assembler->LoadHeapNumberValue(rhs));
   1175             assembler->Goto(&do_fmul);
   1176           }
   1177 
   1178           assembler->Bind(&rhs_is_not_number);
   1179           {
   1180             // Multiplication is commutative, swap {lhs} with {rhs} and loop.
   1181             var_lhs.Bind(rhs);
   1182             var_rhs.Bind(lhs);
   1183             assembler->Goto(&loop);
   1184           }
   1185         }
   1186       }
   1187 
   1188       assembler->Bind(&lhs_is_not_number);
   1189       {
   1190         // Convert {lhs} to a Number and loop.
   1191         Callable callable =
   1192             CodeFactory::NonNumberToNumber(assembler->isolate());
   1193         var_lhs.Bind(assembler->CallStub(callable, context, lhs));
   1194         assembler->Goto(&loop);
   1195       }
   1196     }
   1197   }
   1198 
   1199   assembler->Bind(&do_fmul);
   1200   {
   1201     Node* value =
   1202         assembler->Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
   1203     Node* result = assembler->ChangeFloat64ToTagged(value);
   1204     return result;
   1205   }
   1206 }
   1207 
   1208 // static
   1209 compiler::Node* DivideStub::Generate(CodeStubAssembler* assembler,
   1210                                      compiler::Node* left,
   1211                                      compiler::Node* right,
   1212                                      compiler::Node* context) {
   1213   using compiler::Node;
   1214   typedef CodeStubAssembler::Label Label;
   1215   typedef CodeStubAssembler::Variable Variable;
   1216 
   1217   // Shared entry point for floating point division.
   1218   Label do_fdiv(assembler), end(assembler);
   1219   Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
   1220       var_divisor_float64(assembler, MachineRepresentation::kFloat64);
   1221 
   1222   Node* number_map = assembler->HeapNumberMapConstant();
   1223 
   1224   // We might need to loop one or two times due to ToNumber conversions.
   1225   Variable var_dividend(assembler, MachineRepresentation::kTagged),
   1226       var_divisor(assembler, MachineRepresentation::kTagged),
   1227       var_result(assembler, MachineRepresentation::kTagged);
   1228   Variable* loop_variables[] = {&var_dividend, &var_divisor};
   1229   Label loop(assembler, 2, loop_variables);
   1230   var_dividend.Bind(left);
   1231   var_divisor.Bind(right);
   1232   assembler->Goto(&loop);
   1233   assembler->Bind(&loop);
   1234   {
   1235     Node* dividend = var_dividend.value();
   1236     Node* divisor = var_divisor.value();
   1237 
   1238     Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
   1239     assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
   1240                       &dividend_is_not_smi);
   1241 
   1242     assembler->Bind(&dividend_is_smi);
   1243     {
   1244       Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
   1245       assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
   1246                         &divisor_is_not_smi);
   1247 
   1248       assembler->Bind(&divisor_is_smi);
   1249       {
   1250         Label bailout(assembler);
   1251 
   1252         // Do floating point division if {divisor} is zero.
   1253         assembler->GotoIf(
   1254             assembler->WordEqual(divisor, assembler->IntPtrConstant(0)),
   1255             &bailout);
   1256 
   1257         // Do floating point division {dividend} is zero and {divisor} is
   1258         // negative.
   1259         Label dividend_is_zero(assembler), dividend_is_not_zero(assembler);
   1260         assembler->Branch(
   1261             assembler->WordEqual(dividend, assembler->IntPtrConstant(0)),
   1262             &dividend_is_zero, &dividend_is_not_zero);
   1263 
   1264         assembler->Bind(&dividend_is_zero);
   1265         {
   1266           assembler->GotoIf(
   1267               assembler->IntPtrLessThan(divisor, assembler->IntPtrConstant(0)),
   1268               &bailout);
   1269           assembler->Goto(&dividend_is_not_zero);
   1270         }
   1271         assembler->Bind(&dividend_is_not_zero);
   1272 
   1273         Node* untagged_divisor = assembler->SmiUntag(divisor);
   1274         Node* untagged_dividend = assembler->SmiUntag(dividend);
   1275 
   1276         // Do floating point division if {dividend} is kMinInt (or kMinInt - 1
   1277         // if the Smi size is 31) and {divisor} is -1.
   1278         Label divisor_is_minus_one(assembler),
   1279             divisor_is_not_minus_one(assembler);
   1280         assembler->Branch(assembler->Word32Equal(untagged_divisor,
   1281                                                  assembler->Int32Constant(-1)),
   1282                           &divisor_is_minus_one, &divisor_is_not_minus_one);
   1283 
   1284         assembler->Bind(&divisor_is_minus_one);
   1285         {
   1286           assembler->GotoIf(
   1287               assembler->Word32Equal(
   1288                   untagged_dividend,
   1289                   assembler->Int32Constant(
   1290                       kSmiValueSize == 32 ? kMinInt : (kMinInt >> 1))),
   1291               &bailout);
   1292           assembler->Goto(&divisor_is_not_minus_one);
   1293         }
   1294         assembler->Bind(&divisor_is_not_minus_one);
   1295 
   1296         // TODO(epertoso): consider adding a machine instruction that returns
   1297         // both the result and the remainder.
   1298         Node* untagged_result =
   1299             assembler->Int32Div(untagged_dividend, untagged_divisor);
   1300         Node* truncated =
   1301             assembler->IntPtrMul(untagged_result, untagged_divisor);
   1302         // Do floating point division if the remainder is not 0.
   1303         assembler->GotoIf(
   1304             assembler->Word32NotEqual(untagged_dividend, truncated), &bailout);
   1305         var_result.Bind(assembler->SmiTag(untagged_result));
   1306         assembler->Goto(&end);
   1307 
   1308         // Bailout: convert {dividend} and {divisor} to double and do double
   1309         // division.
   1310         assembler->Bind(&bailout);
   1311         {
   1312           var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
   1313           var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
   1314           assembler->Goto(&do_fdiv);
   1315         }
   1316       }
   1317 
   1318       assembler->Bind(&divisor_is_not_smi);
   1319       {
   1320         Node* divisor_map = assembler->LoadMap(divisor);
   1321 
   1322         // Check if {divisor} is a HeapNumber.
   1323         Label divisor_is_number(assembler),
   1324             divisor_is_not_number(assembler, Label::kDeferred);
   1325         assembler->Branch(assembler->WordEqual(divisor_map, number_map),
   1326                           &divisor_is_number, &divisor_is_not_number);
   1327 
   1328         assembler->Bind(&divisor_is_number);
   1329         {
   1330           // Convert {dividend} to a double and divide it with the value of
   1331           // {divisor}.
   1332           var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
   1333           var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
   1334           assembler->Goto(&do_fdiv);
   1335         }
   1336 
   1337         assembler->Bind(&divisor_is_not_number);
   1338         {
   1339           // Convert {divisor} to a number and loop.
   1340           Callable callable =
   1341               CodeFactory::NonNumberToNumber(assembler->isolate());
   1342           var_divisor.Bind(assembler->CallStub(callable, context, divisor));
   1343           assembler->Goto(&loop);
   1344         }
   1345       }
   1346     }
   1347 
   1348     assembler->Bind(&dividend_is_not_smi);
   1349     {
   1350       Node* dividend_map = assembler->LoadMap(dividend);
   1351 
   1352       // Check if {dividend} is a HeapNumber.
   1353       Label dividend_is_number(assembler),
   1354           dividend_is_not_number(assembler, Label::kDeferred);
   1355       assembler->Branch(assembler->WordEqual(dividend_map, number_map),
   1356                         &dividend_is_number, &dividend_is_not_number);
   1357 
   1358       assembler->Bind(&dividend_is_number);
   1359       {
   1360         // Check if {divisor} is a Smi.
   1361         Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
   1362         assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
   1363                           &divisor_is_not_smi);
   1364 
   1365         assembler->Bind(&divisor_is_smi);
   1366         {
   1367           // Convert {divisor} to a double and use it for a floating point
   1368           // division.
   1369           var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
   1370           var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
   1371           assembler->Goto(&do_fdiv);
   1372         }
   1373 
   1374         assembler->Bind(&divisor_is_not_smi);
   1375         {
   1376           Node* divisor_map = assembler->LoadMap(divisor);
   1377 
   1378           // Check if {divisor} is a HeapNumber.
   1379           Label divisor_is_number(assembler),
   1380               divisor_is_not_number(assembler, Label::kDeferred);
   1381           assembler->Branch(assembler->WordEqual(divisor_map, number_map),
   1382                             &divisor_is_number, &divisor_is_not_number);
   1383 
   1384           assembler->Bind(&divisor_is_number);
   1385           {
   1386             // Both {dividend} and {divisor} are HeapNumbers. Load their values
   1387             // and divide them.
   1388             var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
   1389             var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
   1390             assembler->Goto(&do_fdiv);
   1391           }
   1392 
   1393           assembler->Bind(&divisor_is_not_number);
   1394           {
   1395             // Convert {divisor} to a number and loop.
   1396             Callable callable =
   1397                 CodeFactory::NonNumberToNumber(assembler->isolate());
   1398             var_divisor.Bind(assembler->CallStub(callable, context, divisor));
   1399             assembler->Goto(&loop);
   1400           }
   1401         }
   1402       }
   1403 
   1404       assembler->Bind(&dividend_is_not_number);
   1405       {
   1406         // Convert {dividend} to a Number and loop.
   1407         Callable callable =
   1408             CodeFactory::NonNumberToNumber(assembler->isolate());
   1409         var_dividend.Bind(assembler->CallStub(callable, context, dividend));
   1410         assembler->Goto(&loop);
   1411       }
   1412     }
   1413   }
   1414 
   1415   assembler->Bind(&do_fdiv);
   1416   {
   1417     Node* value = assembler->Float64Div(var_dividend_float64.value(),
   1418                                         var_divisor_float64.value());
   1419     var_result.Bind(assembler->ChangeFloat64ToTagged(value));
   1420     assembler->Goto(&end);
   1421   }
   1422   assembler->Bind(&end);
   1423   return var_result.value();
   1424 }
   1425 
   1426 // static
   1427 compiler::Node* ModulusStub::Generate(CodeStubAssembler* assembler,
   1428                                       compiler::Node* left,
   1429                                       compiler::Node* right,
   1430                                       compiler::Node* context) {
   1431   using compiler::Node;
   1432   typedef CodeStubAssembler::Label Label;
   1433   typedef CodeStubAssembler::Variable Variable;
   1434 
   1435   // Shared entry point for floating point modulus.
   1436   Label do_fmod(assembler);
   1437   Variable var_dividend_float64(assembler, MachineRepresentation::kFloat64),
   1438       var_divisor_float64(assembler, MachineRepresentation::kFloat64);
   1439 
   1440   Node* number_map = assembler->HeapNumberMapConstant();
   1441 
   1442   // We might need to loop one or two times due to ToNumber conversions.
   1443   Variable var_dividend(assembler, MachineRepresentation::kTagged),
   1444       var_divisor(assembler, MachineRepresentation::kTagged);
   1445   Variable* loop_variables[] = {&var_dividend, &var_divisor};
   1446   Label loop(assembler, 2, loop_variables);
   1447   var_dividend.Bind(left);
   1448   var_divisor.Bind(right);
   1449   assembler->Goto(&loop);
   1450   assembler->Bind(&loop);
   1451   {
   1452     Node* dividend = var_dividend.value();
   1453     Node* divisor = var_divisor.value();
   1454 
   1455     Label dividend_is_smi(assembler), dividend_is_not_smi(assembler);
   1456     assembler->Branch(assembler->WordIsSmi(dividend), &dividend_is_smi,
   1457                       &dividend_is_not_smi);
   1458 
   1459     assembler->Bind(&dividend_is_smi);
   1460     {
   1461       Label dividend_is_not_zero(assembler);
   1462       Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
   1463       assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
   1464                         &divisor_is_not_smi);
   1465 
   1466       assembler->Bind(&divisor_is_smi);
   1467       {
   1468         var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
   1469         var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
   1470         assembler->Goto(&do_fmod);
   1471       }
   1472 
   1473       assembler->Bind(&divisor_is_not_smi);
   1474       {
   1475         Node* divisor_map = assembler->LoadMap(divisor);
   1476 
   1477         // Check if {divisor} is a HeapNumber.
   1478         Label divisor_is_number(assembler),
   1479             divisor_is_not_number(assembler, Label::kDeferred);
   1480         assembler->Branch(assembler->WordEqual(divisor_map, number_map),
   1481                           &divisor_is_number, &divisor_is_not_number);
   1482 
   1483         assembler->Bind(&divisor_is_number);
   1484         {
   1485           // Convert {dividend} to a double and compute its modulus with the
   1486           // value of {dividend}.
   1487           var_dividend_float64.Bind(assembler->SmiToFloat64(dividend));
   1488           var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
   1489           assembler->Goto(&do_fmod);
   1490         }
   1491 
   1492         assembler->Bind(&divisor_is_not_number);
   1493         {
   1494           // Convert {divisor} to a number and loop.
   1495           Callable callable =
   1496               CodeFactory::NonNumberToNumber(assembler->isolate());
   1497           var_divisor.Bind(assembler->CallStub(callable, context, divisor));
   1498           assembler->Goto(&loop);
   1499         }
   1500       }
   1501     }
   1502 
   1503     assembler->Bind(&dividend_is_not_smi);
   1504     {
   1505       Node* dividend_map = assembler->LoadMap(dividend);
   1506 
   1507       // Check if {dividend} is a HeapNumber.
   1508       Label dividend_is_number(assembler),
   1509           dividend_is_not_number(assembler, Label::kDeferred);
   1510       assembler->Branch(assembler->WordEqual(dividend_map, number_map),
   1511                         &dividend_is_number, &dividend_is_not_number);
   1512 
   1513       assembler->Bind(&dividend_is_number);
   1514       {
   1515         // Check if {divisor} is a Smi.
   1516         Label divisor_is_smi(assembler), divisor_is_not_smi(assembler);
   1517         assembler->Branch(assembler->WordIsSmi(divisor), &divisor_is_smi,
   1518                           &divisor_is_not_smi);
   1519 
   1520         assembler->Bind(&divisor_is_smi);
   1521         {
   1522           // Convert {divisor} to a double and compute {dividend}'s modulus with
   1523           // it.
   1524           var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
   1525           var_divisor_float64.Bind(assembler->SmiToFloat64(divisor));
   1526           assembler->Goto(&do_fmod);
   1527         }
   1528 
   1529         assembler->Bind(&divisor_is_not_smi);
   1530         {
   1531           Node* divisor_map = assembler->LoadMap(divisor);
   1532 
   1533           // Check if {divisor} is a HeapNumber.
   1534           Label divisor_is_number(assembler),
   1535               divisor_is_not_number(assembler, Label::kDeferred);
   1536           assembler->Branch(assembler->WordEqual(divisor_map, number_map),
   1537                             &divisor_is_number, &divisor_is_not_number);
   1538 
   1539           assembler->Bind(&divisor_is_number);
   1540           {
   1541             // Both {dividend} and {divisor} are HeapNumbers. Load their values
   1542             // and compute their modulus.
   1543             var_dividend_float64.Bind(assembler->LoadHeapNumberValue(dividend));
   1544             var_divisor_float64.Bind(assembler->LoadHeapNumberValue(divisor));
   1545             assembler->Goto(&do_fmod);
   1546           }
   1547 
   1548           assembler->Bind(&divisor_is_not_number);
   1549           {
   1550             // Convert {divisor} to a number and loop.
   1551             Callable callable =
   1552                 CodeFactory::NonNumberToNumber(assembler->isolate());
   1553             var_divisor.Bind(assembler->CallStub(callable, context, divisor));
   1554             assembler->Goto(&loop);
   1555           }
   1556         }
   1557       }
   1558 
   1559       assembler->Bind(&dividend_is_not_number);
   1560       {
   1561         // Convert {dividend} to a Number and loop.
   1562         Callable callable =
   1563             CodeFactory::NonNumberToNumber(assembler->isolate());
   1564         var_dividend.Bind(assembler->CallStub(callable, context, dividend));
   1565         assembler->Goto(&loop);
   1566       }
   1567     }
   1568   }
   1569 
   1570   assembler->Bind(&do_fmod);
   1571   {
   1572     Node* value = assembler->Float64Mod(var_dividend_float64.value(),
   1573                                         var_divisor_float64.value());
   1574     Node* result = assembler->ChangeFloat64ToTagged(value);
   1575     return result;
   1576   }
   1577 }
   1578 
   1579 // static
   1580 compiler::Node* ShiftLeftStub::Generate(CodeStubAssembler* assembler,
   1581                                         compiler::Node* left,
   1582                                         compiler::Node* right,
   1583                                         compiler::Node* context) {
   1584   using compiler::Node;
   1585 
   1586   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1587   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1588   Node* shift_count =
   1589       assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
   1590   Node* value = assembler->Word32Shl(lhs_value, shift_count);
   1591   Node* result = assembler->ChangeInt32ToTagged(value);
   1592   return result;
   1593 }
   1594 
   1595 // static
   1596 compiler::Node* ShiftRightStub::Generate(CodeStubAssembler* assembler,
   1597                                          compiler::Node* left,
   1598                                          compiler::Node* right,
   1599                                          compiler::Node* context) {
   1600   using compiler::Node;
   1601 
   1602   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1603   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1604   Node* shift_count =
   1605       assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
   1606   Node* value = assembler->Word32Sar(lhs_value, shift_count);
   1607   Node* result = assembler->ChangeInt32ToTagged(value);
   1608   return result;
   1609 }
   1610 
   1611 // static
   1612 compiler::Node* ShiftRightLogicalStub::Generate(CodeStubAssembler* assembler,
   1613                                                 compiler::Node* left,
   1614                                                 compiler::Node* right,
   1615                                                 compiler::Node* context) {
   1616   using compiler::Node;
   1617 
   1618   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1619   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1620   Node* shift_count =
   1621       assembler->Word32And(rhs_value, assembler->Int32Constant(0x1f));
   1622   Node* value = assembler->Word32Shr(lhs_value, shift_count);
   1623   Node* result = assembler->ChangeUint32ToTagged(value);
   1624   return result;
   1625 }
   1626 
   1627 // static
   1628 compiler::Node* BitwiseAndStub::Generate(CodeStubAssembler* assembler,
   1629                                          compiler::Node* left,
   1630                                          compiler::Node* right,
   1631                                          compiler::Node* context) {
   1632   using compiler::Node;
   1633 
   1634   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1635   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1636   Node* value = assembler->Word32And(lhs_value, rhs_value);
   1637   Node* result = assembler->ChangeInt32ToTagged(value);
   1638   return result;
   1639 }
   1640 
   1641 // static
   1642 compiler::Node* BitwiseOrStub::Generate(CodeStubAssembler* assembler,
   1643                                         compiler::Node* left,
   1644                                         compiler::Node* right,
   1645                                         compiler::Node* context) {
   1646   using compiler::Node;
   1647 
   1648   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1649   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1650   Node* value = assembler->Word32Or(lhs_value, rhs_value);
   1651   Node* result = assembler->ChangeInt32ToTagged(value);
   1652   return result;
   1653 }
   1654 
   1655 // static
   1656 compiler::Node* BitwiseXorStub::Generate(CodeStubAssembler* assembler,
   1657                                          compiler::Node* left,
   1658                                          compiler::Node* right,
   1659                                          compiler::Node* context) {
   1660   using compiler::Node;
   1661 
   1662   Node* lhs_value = assembler->TruncateTaggedToWord32(context, left);
   1663   Node* rhs_value = assembler->TruncateTaggedToWord32(context, right);
   1664   Node* value = assembler->Word32Xor(lhs_value, rhs_value);
   1665   Node* result = assembler->ChangeInt32ToTagged(value);
   1666   return result;
   1667 }
   1668 
   1669 // static
   1670 compiler::Node* IncStub::Generate(CodeStubAssembler* assembler,
   1671                                   compiler::Node* value,
   1672                                   compiler::Node* context) {
   1673   typedef CodeStubAssembler::Label Label;
   1674   typedef compiler::Node Node;
   1675   typedef CodeStubAssembler::Variable Variable;
   1676 
   1677   // Shared entry for floating point increment.
   1678   Label do_finc(assembler), end(assembler);
   1679   Variable var_finc_value(assembler, MachineRepresentation::kFloat64);
   1680 
   1681   // We might need to try again due to ToNumber conversion.
   1682   Variable value_var(assembler, MachineRepresentation::kTagged);
   1683   Variable result_var(assembler, MachineRepresentation::kTagged);
   1684   Label start(assembler, &value_var);
   1685   value_var.Bind(value);
   1686   assembler->Goto(&start);
   1687   assembler->Bind(&start);
   1688   {
   1689     value = value_var.value();
   1690 
   1691     Label if_issmi(assembler), if_isnotsmi(assembler);
   1692     assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
   1693 
   1694     assembler->Bind(&if_issmi);
   1695     {
   1696       // Try fast Smi addition first.
   1697       Node* one = assembler->SmiConstant(Smi::FromInt(1));
   1698       Node* pair = assembler->SmiAddWithOverflow(value, one);
   1699       Node* overflow = assembler->Projection(1, pair);
   1700 
   1701       // Check if the Smi additon overflowed.
   1702       Label if_overflow(assembler), if_notoverflow(assembler);
   1703       assembler->Branch(overflow, &if_overflow, &if_notoverflow);
   1704 
   1705       assembler->Bind(&if_notoverflow);
   1706       result_var.Bind(assembler->Projection(0, pair));
   1707       assembler->Goto(&end);
   1708 
   1709       assembler->Bind(&if_overflow);
   1710       {
   1711         var_finc_value.Bind(assembler->SmiToFloat64(value));
   1712         assembler->Goto(&do_finc);
   1713       }
   1714     }
   1715 
   1716     assembler->Bind(&if_isnotsmi);
   1717     {
   1718       // Check if the value is a HeapNumber.
   1719       Label if_valueisnumber(assembler),
   1720           if_valuenotnumber(assembler, Label::kDeferred);
   1721       Node* value_map = assembler->LoadMap(value);
   1722       Node* number_map = assembler->HeapNumberMapConstant();
   1723       assembler->Branch(assembler->WordEqual(value_map, number_map),
   1724                         &if_valueisnumber, &if_valuenotnumber);
   1725 
   1726       assembler->Bind(&if_valueisnumber);
   1727       {
   1728         // Load the HeapNumber value.
   1729         var_finc_value.Bind(assembler->LoadHeapNumberValue(value));
   1730         assembler->Goto(&do_finc);
   1731       }
   1732 
   1733       assembler->Bind(&if_valuenotnumber);
   1734       {
   1735         // Convert to a Number first and try again.
   1736         Callable callable =
   1737             CodeFactory::NonNumberToNumber(assembler->isolate());
   1738         value_var.Bind(assembler->CallStub(callable, context, value));
   1739         assembler->Goto(&start);
   1740       }
   1741     }
   1742   }
   1743 
   1744   assembler->Bind(&do_finc);
   1745   {
   1746     Node* finc_value = var_finc_value.value();
   1747     Node* one = assembler->Float64Constant(1.0);
   1748     Node* finc_result = assembler->Float64Add(finc_value, one);
   1749     result_var.Bind(assembler->ChangeFloat64ToTagged(finc_result));
   1750     assembler->Goto(&end);
   1751   }
   1752 
   1753   assembler->Bind(&end);
   1754   return result_var.value();
   1755 }
   1756 
   1757 // static
   1758 compiler::Node* DecStub::Generate(CodeStubAssembler* assembler,
   1759                                   compiler::Node* value,
   1760                                   compiler::Node* context) {
   1761   typedef CodeStubAssembler::Label Label;
   1762   typedef compiler::Node Node;
   1763   typedef CodeStubAssembler::Variable Variable;
   1764 
   1765   // Shared entry for floating point decrement.
   1766   Label do_fdec(assembler), end(assembler);
   1767   Variable var_fdec_value(assembler, MachineRepresentation::kFloat64);
   1768 
   1769   // We might need to try again due to ToNumber conversion.
   1770   Variable value_var(assembler, MachineRepresentation::kTagged);
   1771   Variable result_var(assembler, MachineRepresentation::kTagged);
   1772   Label start(assembler, &value_var);
   1773   value_var.Bind(value);
   1774   assembler->Goto(&start);
   1775   assembler->Bind(&start);
   1776   {
   1777     value = value_var.value();
   1778 
   1779     Label if_issmi(assembler), if_isnotsmi(assembler);
   1780     assembler->Branch(assembler->WordIsSmi(value), &if_issmi, &if_isnotsmi);
   1781 
   1782     assembler->Bind(&if_issmi);
   1783     {
   1784       // Try fast Smi subtraction first.
   1785       Node* one = assembler->SmiConstant(Smi::FromInt(1));
   1786       Node* pair = assembler->SmiSubWithOverflow(value, one);
   1787       Node* overflow = assembler->Projection(1, pair);
   1788 
   1789       // Check if the Smi subtraction overflowed.
   1790       Label if_overflow(assembler), if_notoverflow(assembler);
   1791       assembler->Branch(overflow, &if_overflow, &if_notoverflow);
   1792 
   1793       assembler->Bind(&if_notoverflow);
   1794       result_var.Bind(assembler->Projection(0, pair));
   1795       assembler->Goto(&end);
   1796 
   1797       assembler->Bind(&if_overflow);
   1798       {
   1799         var_fdec_value.Bind(assembler->SmiToFloat64(value));
   1800         assembler->Goto(&do_fdec);
   1801       }
   1802     }
   1803 
   1804     assembler->Bind(&if_isnotsmi);
   1805     {
   1806       // Check if the value is a HeapNumber.
   1807       Label if_valueisnumber(assembler),
   1808           if_valuenotnumber(assembler, Label::kDeferred);
   1809       Node* value_map = assembler->LoadMap(value);
   1810       Node* number_map = assembler->HeapNumberMapConstant();
   1811       assembler->Branch(assembler->WordEqual(value_map, number_map),
   1812                         &if_valueisnumber, &if_valuenotnumber);
   1813 
   1814       assembler->Bind(&if_valueisnumber);
   1815       {
   1816         // Load the HeapNumber value.
   1817         var_fdec_value.Bind(assembler->LoadHeapNumberValue(value));
   1818         assembler->Goto(&do_fdec);
   1819       }
   1820 
   1821       assembler->Bind(&if_valuenotnumber);
   1822       {
   1823         // Convert to a Number first and try again.
   1824         Callable callable =
   1825             CodeFactory::NonNumberToNumber(assembler->isolate());
   1826         value_var.Bind(assembler->CallStub(callable, context, value));
   1827         assembler->Goto(&start);
   1828       }
   1829     }
   1830   }
   1831 
   1832   assembler->Bind(&do_fdec);
   1833   {
   1834     Node* fdec_value = var_fdec_value.value();
   1835     Node* one = assembler->Float64Constant(1.0);
   1836     Node* fdec_result = assembler->Float64Sub(fdec_value, one);
   1837     result_var.Bind(assembler->ChangeFloat64ToTagged(fdec_result));
   1838     assembler->Goto(&end);
   1839   }
   1840 
   1841   assembler->Bind(&end);
   1842   return result_var.value();
   1843 }
   1844 
   1845 // static
   1846 compiler::Node* InstanceOfStub::Generate(CodeStubAssembler* assembler,
   1847                                          compiler::Node* object,
   1848                                          compiler::Node* callable,
   1849                                          compiler::Node* context) {
   1850   typedef CodeStubAssembler::Label Label;
   1851   typedef CodeStubAssembler::Variable Variable;
   1852 
   1853   Label return_runtime(assembler, Label::kDeferred), end(assembler);
   1854   Variable result(assembler, MachineRepresentation::kTagged);
   1855 
   1856   // Check if no one installed @@hasInstance somewhere.
   1857   assembler->GotoUnless(
   1858       assembler->WordEqual(
   1859           assembler->LoadObjectField(
   1860               assembler->LoadRoot(Heap::kHasInstanceProtectorRootIndex),
   1861               PropertyCell::kValueOffset),
   1862           assembler->SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))),
   1863       &return_runtime);
   1864 
   1865   // Check if {callable} is a valid receiver.
   1866   assembler->GotoIf(assembler->WordIsSmi(callable), &return_runtime);
   1867   assembler->GotoIf(
   1868       assembler->Word32Equal(
   1869           assembler->Word32And(
   1870               assembler->LoadMapBitField(assembler->LoadMap(callable)),
   1871               assembler->Int32Constant(1 << Map::kIsCallable)),
   1872           assembler->Int32Constant(0)),
   1873       &return_runtime);
   1874 
   1875   // Use the inline OrdinaryHasInstance directly.
   1876   result.Bind(assembler->OrdinaryHasInstance(context, callable, object));
   1877   assembler->Goto(&end);
   1878 
   1879   // TODO(bmeurer): Use GetPropertyStub here once available.
   1880   assembler->Bind(&return_runtime);
   1881   {
   1882     result.Bind(assembler->CallRuntime(Runtime::kInstanceOf, context, object,
   1883                                        callable));
   1884     assembler->Goto(&end);
   1885   }
   1886 
   1887   assembler->Bind(&end);
   1888   return result.value();
   1889 }
   1890 
   1891 namespace {
   1892 
   1893 enum RelationalComparisonMode {
   1894   kLessThan,
   1895   kLessThanOrEqual,
   1896   kGreaterThan,
   1897   kGreaterThanOrEqual
   1898 };
   1899 
   1900 compiler::Node* GenerateAbstractRelationalComparison(
   1901     CodeStubAssembler* assembler, RelationalComparisonMode mode,
   1902     compiler::Node* lhs, compiler::Node* rhs, compiler::Node* context) {
   1903   typedef CodeStubAssembler::Label Label;
   1904   typedef compiler::Node Node;
   1905   typedef CodeStubAssembler::Variable Variable;
   1906 
   1907   Label return_true(assembler), return_false(assembler), end(assembler);
   1908   Variable result(assembler, MachineRepresentation::kTagged);
   1909 
   1910   // Shared entry for floating point comparison.
   1911   Label do_fcmp(assembler);
   1912   Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
   1913       var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
   1914 
   1915   // We might need to loop several times due to ToPrimitive and/or ToNumber
   1916   // conversions.
   1917   Variable var_lhs(assembler, MachineRepresentation::kTagged),
   1918       var_rhs(assembler, MachineRepresentation::kTagged);
   1919   Variable* loop_vars[2] = {&var_lhs, &var_rhs};
   1920   Label loop(assembler, 2, loop_vars);
   1921   var_lhs.Bind(lhs);
   1922   var_rhs.Bind(rhs);
   1923   assembler->Goto(&loop);
   1924   assembler->Bind(&loop);
   1925   {
   1926     // Load the current {lhs} and {rhs} values.
   1927     lhs = var_lhs.value();
   1928     rhs = var_rhs.value();
   1929 
   1930     // Check if the {lhs} is a Smi or a HeapObject.
   1931     Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
   1932     assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
   1933 
   1934     assembler->Bind(&if_lhsissmi);
   1935     {
   1936       // Check if {rhs} is a Smi or a HeapObject.
   1937       Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   1938       assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   1939                         &if_rhsisnotsmi);
   1940 
   1941       assembler->Bind(&if_rhsissmi);
   1942       {
   1943         // Both {lhs} and {rhs} are Smi, so just perform a fast Smi comparison.
   1944         switch (mode) {
   1945           case kLessThan:
   1946             assembler->BranchIfSmiLessThan(lhs, rhs, &return_true,
   1947                                            &return_false);
   1948             break;
   1949           case kLessThanOrEqual:
   1950             assembler->BranchIfSmiLessThanOrEqual(lhs, rhs, &return_true,
   1951                                                   &return_false);
   1952             break;
   1953           case kGreaterThan:
   1954             assembler->BranchIfSmiLessThan(rhs, lhs, &return_true,
   1955                                            &return_false);
   1956             break;
   1957           case kGreaterThanOrEqual:
   1958             assembler->BranchIfSmiLessThanOrEqual(rhs, lhs, &return_true,
   1959                                                   &return_false);
   1960             break;
   1961         }
   1962       }
   1963 
   1964       assembler->Bind(&if_rhsisnotsmi);
   1965       {
   1966         // Load the map of {rhs}.
   1967         Node* rhs_map = assembler->LoadMap(rhs);
   1968 
   1969         // Check if the {rhs} is a HeapNumber.
   1970         Node* number_map = assembler->HeapNumberMapConstant();
   1971         Label if_rhsisnumber(assembler),
   1972             if_rhsisnotnumber(assembler, Label::kDeferred);
   1973         assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   1974                           &if_rhsisnumber, &if_rhsisnotnumber);
   1975 
   1976         assembler->Bind(&if_rhsisnumber);
   1977         {
   1978           // Convert the {lhs} and {rhs} to floating point values, and
   1979           // perform a floating point comparison.
   1980           var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
   1981           var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
   1982           assembler->Goto(&do_fcmp);
   1983         }
   1984 
   1985         assembler->Bind(&if_rhsisnotnumber);
   1986         {
   1987           // Convert the {rhs} to a Number; we don't need to perform the
   1988           // dedicated ToPrimitive(rhs, hint Number) operation, as the
   1989           // ToNumber(rhs) will by itself already invoke ToPrimitive with
   1990           // a Number hint.
   1991           Callable callable =
   1992               CodeFactory::NonNumberToNumber(assembler->isolate());
   1993           var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   1994           assembler->Goto(&loop);
   1995         }
   1996       }
   1997     }
   1998 
   1999     assembler->Bind(&if_lhsisnotsmi);
   2000     {
   2001       // Load the HeapNumber map for later comparisons.
   2002       Node* number_map = assembler->HeapNumberMapConstant();
   2003 
   2004       // Load the map of {lhs}.
   2005       Node* lhs_map = assembler->LoadMap(lhs);
   2006 
   2007       // Check if {rhs} is a Smi or a HeapObject.
   2008       Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   2009       assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   2010                         &if_rhsisnotsmi);
   2011 
   2012       assembler->Bind(&if_rhsissmi);
   2013       {
   2014         // Check if the {lhs} is a HeapNumber.
   2015         Label if_lhsisnumber(assembler),
   2016             if_lhsisnotnumber(assembler, Label::kDeferred);
   2017         assembler->Branch(assembler->WordEqual(lhs_map, number_map),
   2018                           &if_lhsisnumber, &if_lhsisnotnumber);
   2019 
   2020         assembler->Bind(&if_lhsisnumber);
   2021         {
   2022           // Convert the {lhs} and {rhs} to floating point values, and
   2023           // perform a floating point comparison.
   2024           var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
   2025           var_fcmp_rhs.Bind(assembler->SmiToFloat64(rhs));
   2026           assembler->Goto(&do_fcmp);
   2027         }
   2028 
   2029         assembler->Bind(&if_lhsisnotnumber);
   2030         {
   2031           // Convert the {lhs} to a Number; we don't need to perform the
   2032           // dedicated ToPrimitive(lhs, hint Number) operation, as the
   2033           // ToNumber(lhs) will by itself already invoke ToPrimitive with
   2034           // a Number hint.
   2035           Callable callable =
   2036               CodeFactory::NonNumberToNumber(assembler->isolate());
   2037           var_lhs.Bind(assembler->CallStub(callable, context, lhs));
   2038           assembler->Goto(&loop);
   2039         }
   2040       }
   2041 
   2042       assembler->Bind(&if_rhsisnotsmi);
   2043       {
   2044         // Load the map of {rhs}.
   2045         Node* rhs_map = assembler->LoadMap(rhs);
   2046 
   2047         // Check if {lhs} is a HeapNumber.
   2048         Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
   2049         assembler->Branch(assembler->WordEqual(lhs_map, number_map),
   2050                           &if_lhsisnumber, &if_lhsisnotnumber);
   2051 
   2052         assembler->Bind(&if_lhsisnumber);
   2053         {
   2054           // Check if {rhs} is also a HeapNumber.
   2055           Label if_rhsisnumber(assembler),
   2056               if_rhsisnotnumber(assembler, Label::kDeferred);
   2057           assembler->Branch(assembler->WordEqual(lhs_map, rhs_map),
   2058                             &if_rhsisnumber, &if_rhsisnotnumber);
   2059 
   2060           assembler->Bind(&if_rhsisnumber);
   2061           {
   2062             // Convert the {lhs} and {rhs} to floating point values, and
   2063             // perform a floating point comparison.
   2064             var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
   2065             var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
   2066             assembler->Goto(&do_fcmp);
   2067           }
   2068 
   2069           assembler->Bind(&if_rhsisnotnumber);
   2070           {
   2071             // Convert the {rhs} to a Number; we don't need to perform
   2072             // dedicated ToPrimitive(rhs, hint Number) operation, as the
   2073             // ToNumber(rhs) will by itself already invoke ToPrimitive with
   2074             // a Number hint.
   2075             Callable callable =
   2076                 CodeFactory::NonNumberToNumber(assembler->isolate());
   2077             var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   2078             assembler->Goto(&loop);
   2079           }
   2080         }
   2081 
   2082         assembler->Bind(&if_lhsisnotnumber);
   2083         {
   2084           // Load the instance type of {lhs}.
   2085           Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
   2086 
   2087           // Check if {lhs} is a String.
   2088           Label if_lhsisstring(assembler),
   2089               if_lhsisnotstring(assembler, Label::kDeferred);
   2090           assembler->Branch(assembler->Int32LessThan(
   2091                                 lhs_instance_type,
   2092                                 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
   2093                             &if_lhsisstring, &if_lhsisnotstring);
   2094 
   2095           assembler->Bind(&if_lhsisstring);
   2096           {
   2097             // Load the instance type of {rhs}.
   2098             Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
   2099 
   2100             // Check if {rhs} is also a String.
   2101             Label if_rhsisstring(assembler, Label::kDeferred),
   2102                 if_rhsisnotstring(assembler, Label::kDeferred);
   2103             assembler->Branch(assembler->Int32LessThan(
   2104                                   rhs_instance_type, assembler->Int32Constant(
   2105                                                          FIRST_NONSTRING_TYPE)),
   2106                               &if_rhsisstring, &if_rhsisnotstring);
   2107 
   2108             assembler->Bind(&if_rhsisstring);
   2109             {
   2110               // Both {lhs} and {rhs} are strings.
   2111               switch (mode) {
   2112                 case kLessThan:
   2113                   result.Bind(assembler->CallStub(
   2114                       CodeFactory::StringLessThan(assembler->isolate()),
   2115                       context, lhs, rhs));
   2116                   assembler->Goto(&end);
   2117                   break;
   2118                 case kLessThanOrEqual:
   2119                   result.Bind(assembler->CallStub(
   2120                       CodeFactory::StringLessThanOrEqual(assembler->isolate()),
   2121                       context, lhs, rhs));
   2122                   assembler->Goto(&end);
   2123                   break;
   2124                 case kGreaterThan:
   2125                   result.Bind(assembler->CallStub(
   2126                       CodeFactory::StringGreaterThan(assembler->isolate()),
   2127                       context, lhs, rhs));
   2128                   assembler->Goto(&end);
   2129                   break;
   2130                 case kGreaterThanOrEqual:
   2131                   result.Bind(
   2132                       assembler->CallStub(CodeFactory::StringGreaterThanOrEqual(
   2133                                               assembler->isolate()),
   2134                                           context, lhs, rhs));
   2135                   assembler->Goto(&end);
   2136                   break;
   2137               }
   2138             }
   2139 
   2140             assembler->Bind(&if_rhsisnotstring);
   2141             {
   2142               // The {lhs} is a String, while {rhs} is neither a Number nor a
   2143               // String, so we need to call ToPrimitive(rhs, hint Number) if
   2144               // {rhs} is a receiver or ToNumber(lhs) and ToNumber(rhs) in the
   2145               // other cases.
   2146               STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   2147               Label if_rhsisreceiver(assembler, Label::kDeferred),
   2148                   if_rhsisnotreceiver(assembler, Label::kDeferred);
   2149               assembler->Branch(
   2150                   assembler->Int32LessThanOrEqual(
   2151                       assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2152                       rhs_instance_type),
   2153                   &if_rhsisreceiver, &if_rhsisnotreceiver);
   2154 
   2155               assembler->Bind(&if_rhsisreceiver);
   2156               {
   2157                 // Convert {rhs} to a primitive first passing Number hint.
   2158                 // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
   2159                 var_rhs.Bind(assembler->CallRuntime(
   2160                     Runtime::kToPrimitive_Number, context, rhs));
   2161                 assembler->Goto(&loop);
   2162               }
   2163 
   2164               assembler->Bind(&if_rhsisnotreceiver);
   2165               {
   2166                 // Convert both {lhs} and {rhs} to Number.
   2167                 Callable callable = CodeFactory::ToNumber(assembler->isolate());
   2168                 var_lhs.Bind(assembler->CallStub(callable, context, lhs));
   2169                 var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   2170                 assembler->Goto(&loop);
   2171               }
   2172             }
   2173           }
   2174 
   2175           assembler->Bind(&if_lhsisnotstring);
   2176           {
   2177             // The {lhs} is neither a Number nor a String, so we need to call
   2178             // ToPrimitive(lhs, hint Number) if {lhs} is a receiver or
   2179             // ToNumber(lhs) and ToNumber(rhs) in the other cases.
   2180             STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   2181             Label if_lhsisreceiver(assembler, Label::kDeferred),
   2182                 if_lhsisnotreceiver(assembler, Label::kDeferred);
   2183             assembler->Branch(
   2184                 assembler->Int32LessThanOrEqual(
   2185                     assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2186                     lhs_instance_type),
   2187                 &if_lhsisreceiver, &if_lhsisnotreceiver);
   2188 
   2189             assembler->Bind(&if_lhsisreceiver);
   2190             {
   2191               // Convert {lhs} to a primitive first passing Number hint.
   2192               // TODO(bmeurer): Hook up ToPrimitiveStub here, once it's there.
   2193               var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive_Number,
   2194                                                   context, lhs));
   2195               assembler->Goto(&loop);
   2196             }
   2197 
   2198             assembler->Bind(&if_lhsisnotreceiver);
   2199             {
   2200               // Convert both {lhs} and {rhs} to Number.
   2201               Callable callable = CodeFactory::ToNumber(assembler->isolate());
   2202               var_lhs.Bind(assembler->CallStub(callable, context, lhs));
   2203               var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   2204               assembler->Goto(&loop);
   2205             }
   2206           }
   2207         }
   2208       }
   2209     }
   2210   }
   2211 
   2212   assembler->Bind(&do_fcmp);
   2213   {
   2214     // Load the {lhs} and {rhs} floating point values.
   2215     Node* lhs = var_fcmp_lhs.value();
   2216     Node* rhs = var_fcmp_rhs.value();
   2217 
   2218     // Perform a fast floating point comparison.
   2219     switch (mode) {
   2220       case kLessThan:
   2221         assembler->BranchIfFloat64LessThan(lhs, rhs, &return_true,
   2222                                            &return_false);
   2223         break;
   2224       case kLessThanOrEqual:
   2225         assembler->BranchIfFloat64LessThanOrEqual(lhs, rhs, &return_true,
   2226                                                   &return_false);
   2227         break;
   2228       case kGreaterThan:
   2229         assembler->BranchIfFloat64GreaterThan(lhs, rhs, &return_true,
   2230                                               &return_false);
   2231         break;
   2232       case kGreaterThanOrEqual:
   2233         assembler->BranchIfFloat64GreaterThanOrEqual(lhs, rhs, &return_true,
   2234                                                      &return_false);
   2235         break;
   2236     }
   2237   }
   2238 
   2239   assembler->Bind(&return_true);
   2240   {
   2241     result.Bind(assembler->BooleanConstant(true));
   2242     assembler->Goto(&end);
   2243   }
   2244 
   2245   assembler->Bind(&return_false);
   2246   {
   2247     result.Bind(assembler->BooleanConstant(false));
   2248     assembler->Goto(&end);
   2249   }
   2250 
   2251   assembler->Bind(&end);
   2252   return result.value();
   2253 }
   2254 
   2255 enum ResultMode { kDontNegateResult, kNegateResult };
   2256 
   2257 void GenerateEqual_Same(CodeStubAssembler* assembler, compiler::Node* value,
   2258                         CodeStubAssembler::Label* if_equal,
   2259                         CodeStubAssembler::Label* if_notequal) {
   2260   // In case of abstract or strict equality checks, we need additional checks
   2261   // for NaN values because they are not considered equal, even if both the
   2262   // left and the right hand side reference exactly the same value.
   2263   // TODO(bmeurer): This seems to violate the SIMD.js specification, but it
   2264   // seems to be what is tested in the current SIMD.js testsuite.
   2265 
   2266   typedef CodeStubAssembler::Label Label;
   2267   typedef compiler::Node Node;
   2268 
   2269   // Check if {value} is a Smi or a HeapObject.
   2270   Label if_valueissmi(assembler), if_valueisnotsmi(assembler);
   2271   assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
   2272                     &if_valueisnotsmi);
   2273 
   2274   assembler->Bind(&if_valueisnotsmi);
   2275   {
   2276     // Load the map of {value}.
   2277     Node* value_map = assembler->LoadMap(value);
   2278 
   2279     // Check if {value} (and therefore {rhs}) is a HeapNumber.
   2280     Node* number_map = assembler->HeapNumberMapConstant();
   2281     Label if_valueisnumber(assembler), if_valueisnotnumber(assembler);
   2282     assembler->Branch(assembler->WordEqual(value_map, number_map),
   2283                       &if_valueisnumber, &if_valueisnotnumber);
   2284 
   2285     assembler->Bind(&if_valueisnumber);
   2286     {
   2287       // Convert {value} (and therefore {rhs}) to floating point value.
   2288       Node* value_value = assembler->LoadHeapNumberValue(value);
   2289 
   2290       // Check if the HeapNumber value is a NaN.
   2291       assembler->BranchIfFloat64IsNaN(value_value, if_notequal, if_equal);
   2292     }
   2293 
   2294     assembler->Bind(&if_valueisnotnumber);
   2295     assembler->Goto(if_equal);
   2296   }
   2297 
   2298   assembler->Bind(&if_valueissmi);
   2299   assembler->Goto(if_equal);
   2300 }
   2301 
   2302 void GenerateEqual_Simd128Value_HeapObject(
   2303     CodeStubAssembler* assembler, compiler::Node* lhs, compiler::Node* lhs_map,
   2304     compiler::Node* rhs, compiler::Node* rhs_map,
   2305     CodeStubAssembler::Label* if_equal, CodeStubAssembler::Label* if_notequal) {
   2306   typedef CodeStubAssembler::Label Label;
   2307   typedef compiler::Node Node;
   2308 
   2309   // Check if {lhs} and {rhs} have the same map.
   2310   Label if_mapsame(assembler), if_mapnotsame(assembler);
   2311   assembler->Branch(assembler->WordEqual(lhs_map, rhs_map), &if_mapsame,
   2312                     &if_mapnotsame);
   2313 
   2314   assembler->Bind(&if_mapsame);
   2315   {
   2316     // Both {lhs} and {rhs} are Simd128Values with the same map, need special
   2317     // handling for Float32x4 because of NaN comparisons.
   2318     Label if_float32x4(assembler), if_notfloat32x4(assembler);
   2319     Node* float32x4_map =
   2320         assembler->HeapConstant(assembler->factory()->float32x4_map());
   2321     assembler->Branch(assembler->WordEqual(lhs_map, float32x4_map),
   2322                       &if_float32x4, &if_notfloat32x4);
   2323 
   2324     assembler->Bind(&if_float32x4);
   2325     {
   2326       // Both {lhs} and {rhs} are Float32x4, compare the lanes individually
   2327       // using a floating point comparison.
   2328       for (int offset = Float32x4::kValueOffset - kHeapObjectTag;
   2329            offset < Float32x4::kSize - kHeapObjectTag;
   2330            offset += sizeof(float)) {
   2331         // Load the floating point values for {lhs} and {rhs}.
   2332         Node* lhs_value = assembler->Load(MachineType::Float32(), lhs,
   2333                                           assembler->IntPtrConstant(offset));
   2334         Node* rhs_value = assembler->Load(MachineType::Float32(), rhs,
   2335                                           assembler->IntPtrConstant(offset));
   2336 
   2337         // Perform a floating point comparison.
   2338         Label if_valueequal(assembler), if_valuenotequal(assembler);
   2339         assembler->Branch(assembler->Float32Equal(lhs_value, rhs_value),
   2340                           &if_valueequal, &if_valuenotequal);
   2341         assembler->Bind(&if_valuenotequal);
   2342         assembler->Goto(if_notequal);
   2343         assembler->Bind(&if_valueequal);
   2344       }
   2345 
   2346       // All 4 lanes match, {lhs} and {rhs} considered equal.
   2347       assembler->Goto(if_equal);
   2348     }
   2349 
   2350     assembler->Bind(&if_notfloat32x4);
   2351     {
   2352       // For other Simd128Values we just perform a bitwise comparison.
   2353       for (int offset = Simd128Value::kValueOffset - kHeapObjectTag;
   2354            offset < Simd128Value::kSize - kHeapObjectTag;
   2355            offset += kPointerSize) {
   2356         // Load the word values for {lhs} and {rhs}.
   2357         Node* lhs_value = assembler->Load(MachineType::Pointer(), lhs,
   2358                                           assembler->IntPtrConstant(offset));
   2359         Node* rhs_value = assembler->Load(MachineType::Pointer(), rhs,
   2360                                           assembler->IntPtrConstant(offset));
   2361 
   2362         // Perform a bitwise word-comparison.
   2363         Label if_valueequal(assembler), if_valuenotequal(assembler);
   2364         assembler->Branch(assembler->WordEqual(lhs_value, rhs_value),
   2365                           &if_valueequal, &if_valuenotequal);
   2366         assembler->Bind(&if_valuenotequal);
   2367         assembler->Goto(if_notequal);
   2368         assembler->Bind(&if_valueequal);
   2369       }
   2370 
   2371       // Bitwise comparison succeeded, {lhs} and {rhs} considered equal.
   2372       assembler->Goto(if_equal);
   2373     }
   2374   }
   2375 
   2376   assembler->Bind(&if_mapnotsame);
   2377   assembler->Goto(if_notequal);
   2378 }
   2379 
   2380 // ES6 section 7.2.12 Abstract Equality Comparison
   2381 compiler::Node* GenerateEqual(CodeStubAssembler* assembler, ResultMode mode,
   2382                               compiler::Node* lhs, compiler::Node* rhs,
   2383                               compiler::Node* context) {
   2384   // This is a slightly optimized version of Object::Equals represented as
   2385   // scheduled TurboFan graph utilizing the CodeStubAssembler. Whenever you
   2386   // change something functionality wise in here, remember to update the
   2387   // Object::Equals method as well.
   2388   typedef CodeStubAssembler::Label Label;
   2389   typedef compiler::Node Node;
   2390   typedef CodeStubAssembler::Variable Variable;
   2391 
   2392   Label if_equal(assembler), if_notequal(assembler),
   2393       do_rhsstringtonumber(assembler, Label::kDeferred), end(assembler);
   2394   Variable result(assembler, MachineRepresentation::kTagged);
   2395 
   2396   // Shared entry for floating point comparison.
   2397   Label do_fcmp(assembler);
   2398   Variable var_fcmp_lhs(assembler, MachineRepresentation::kFloat64),
   2399       var_fcmp_rhs(assembler, MachineRepresentation::kFloat64);
   2400 
   2401   // We might need to loop several times due to ToPrimitive and/or ToNumber
   2402   // conversions.
   2403   Variable var_lhs(assembler, MachineRepresentation::kTagged),
   2404       var_rhs(assembler, MachineRepresentation::kTagged);
   2405   Variable* loop_vars[2] = {&var_lhs, &var_rhs};
   2406   Label loop(assembler, 2, loop_vars);
   2407   var_lhs.Bind(lhs);
   2408   var_rhs.Bind(rhs);
   2409   assembler->Goto(&loop);
   2410   assembler->Bind(&loop);
   2411   {
   2412     // Load the current {lhs} and {rhs} values.
   2413     lhs = var_lhs.value();
   2414     rhs = var_rhs.value();
   2415 
   2416     // Check if {lhs} and {rhs} refer to the same object.
   2417     Label if_same(assembler), if_notsame(assembler);
   2418     assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
   2419 
   2420     assembler->Bind(&if_same);
   2421     {
   2422       // The {lhs} and {rhs} reference the exact same value, yet we need special
   2423       // treatment for HeapNumber, as NaN is not equal to NaN.
   2424       GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
   2425     }
   2426 
   2427     assembler->Bind(&if_notsame);
   2428     {
   2429       // Check if {lhs} is a Smi or a HeapObject.
   2430       Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
   2431       assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi,
   2432                         &if_lhsisnotsmi);
   2433 
   2434       assembler->Bind(&if_lhsissmi);
   2435       {
   2436         // Check if {rhs} is a Smi or a HeapObject.
   2437         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   2438         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   2439                           &if_rhsisnotsmi);
   2440 
   2441         assembler->Bind(&if_rhsissmi);
   2442         // We have already checked for {lhs} and {rhs} being the same value, so
   2443         // if both are Smis when we get here they must not be equal.
   2444         assembler->Goto(&if_notequal);
   2445 
   2446         assembler->Bind(&if_rhsisnotsmi);
   2447         {
   2448           // Load the map of {rhs}.
   2449           Node* rhs_map = assembler->LoadMap(rhs);
   2450 
   2451           // Check if {rhs} is a HeapNumber.
   2452           Node* number_map = assembler->HeapNumberMapConstant();
   2453           Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
   2454           assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   2455                             &if_rhsisnumber, &if_rhsisnotnumber);
   2456 
   2457           assembler->Bind(&if_rhsisnumber);
   2458           {
   2459             // Convert {lhs} and {rhs} to floating point values, and
   2460             // perform a floating point comparison.
   2461             var_fcmp_lhs.Bind(assembler->SmiToFloat64(lhs));
   2462             var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
   2463             assembler->Goto(&do_fcmp);
   2464           }
   2465 
   2466           assembler->Bind(&if_rhsisnotnumber);
   2467           {
   2468             // Load the instance type of the {rhs}.
   2469             Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
   2470 
   2471             // Check if the {rhs} is a String.
   2472             Label if_rhsisstring(assembler, Label::kDeferred),
   2473                 if_rhsisnotstring(assembler);
   2474             assembler->Branch(assembler->Int32LessThan(
   2475                                   rhs_instance_type, assembler->Int32Constant(
   2476                                                          FIRST_NONSTRING_TYPE)),
   2477                               &if_rhsisstring, &if_rhsisnotstring);
   2478 
   2479             assembler->Bind(&if_rhsisstring);
   2480             {
   2481               // The {rhs} is a String and the {lhs} is a Smi; we need
   2482               // to convert the {rhs} to a Number and compare the output to
   2483               // the Number on the {lhs}.
   2484               assembler->Goto(&do_rhsstringtonumber);
   2485             }
   2486 
   2487             assembler->Bind(&if_rhsisnotstring);
   2488             {
   2489               // Check if the {rhs} is a Boolean.
   2490               Node* boolean_map = assembler->BooleanMapConstant();
   2491               Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
   2492               assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
   2493                                 &if_rhsisboolean, &if_rhsisnotboolean);
   2494 
   2495               assembler->Bind(&if_rhsisboolean);
   2496               {
   2497                 // The {rhs} is a Boolean, load its number value.
   2498                 var_rhs.Bind(
   2499                     assembler->LoadObjectField(rhs, Oddball::kToNumberOffset));
   2500                 assembler->Goto(&loop);
   2501               }
   2502 
   2503               assembler->Bind(&if_rhsisnotboolean);
   2504               {
   2505                 // Check if the {rhs} is a Receiver.
   2506                 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   2507                 Label if_rhsisreceiver(assembler, Label::kDeferred),
   2508                     if_rhsisnotreceiver(assembler);
   2509                 assembler->Branch(
   2510                     assembler->Int32LessThanOrEqual(
   2511                         assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2512                         rhs_instance_type),
   2513                     &if_rhsisreceiver, &if_rhsisnotreceiver);
   2514 
   2515                 assembler->Bind(&if_rhsisreceiver);
   2516                 {
   2517                   // Convert {rhs} to a primitive first (passing no hint).
   2518                   // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
   2519                   var_rhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
   2520                                                       context, rhs));
   2521                   assembler->Goto(&loop);
   2522                 }
   2523 
   2524                 assembler->Bind(&if_rhsisnotreceiver);
   2525                 assembler->Goto(&if_notequal);
   2526               }
   2527             }
   2528           }
   2529         }
   2530       }
   2531 
   2532       assembler->Bind(&if_lhsisnotsmi);
   2533       {
   2534         // Check if {rhs} is a Smi or a HeapObject.
   2535         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   2536         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   2537                           &if_rhsisnotsmi);
   2538 
   2539         assembler->Bind(&if_rhsissmi);
   2540         {
   2541           // The {lhs} is a HeapObject and the {rhs} is a Smi; swapping {lhs}
   2542           // and {rhs} is not observable and doesn't matter for the result, so
   2543           // we can just swap them and use the Smi handling above (for {lhs}
   2544           // being a Smi).
   2545           var_lhs.Bind(rhs);
   2546           var_rhs.Bind(lhs);
   2547           assembler->Goto(&loop);
   2548         }
   2549 
   2550         assembler->Bind(&if_rhsisnotsmi);
   2551         {
   2552           Label if_lhsisstring(assembler), if_lhsisnumber(assembler),
   2553               if_lhsissymbol(assembler), if_lhsissimd128value(assembler),
   2554               if_lhsisoddball(assembler), if_lhsisreceiver(assembler);
   2555 
   2556           // Both {lhs} and {rhs} are HeapObjects, load their maps
   2557           // and their instance types.
   2558           Node* lhs_map = assembler->LoadMap(lhs);
   2559           Node* rhs_map = assembler->LoadMap(rhs);
   2560 
   2561           // Load the instance types of {lhs} and {rhs}.
   2562           Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
   2563           Node* rhs_instance_type = assembler->LoadMapInstanceType(rhs_map);
   2564 
   2565           // Dispatch based on the instance type of {lhs}.
   2566           size_t const kNumCases = FIRST_NONSTRING_TYPE + 4;
   2567           Label* case_labels[kNumCases];
   2568           int32_t case_values[kNumCases];
   2569           for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
   2570             case_labels[i] = new Label(assembler);
   2571             case_values[i] = i;
   2572           }
   2573           case_labels[FIRST_NONSTRING_TYPE + 0] = &if_lhsisnumber;
   2574           case_values[FIRST_NONSTRING_TYPE + 0] = HEAP_NUMBER_TYPE;
   2575           case_labels[FIRST_NONSTRING_TYPE + 1] = &if_lhsissymbol;
   2576           case_values[FIRST_NONSTRING_TYPE + 1] = SYMBOL_TYPE;
   2577           case_labels[FIRST_NONSTRING_TYPE + 2] = &if_lhsissimd128value;
   2578           case_values[FIRST_NONSTRING_TYPE + 2] = SIMD128_VALUE_TYPE;
   2579           case_labels[FIRST_NONSTRING_TYPE + 3] = &if_lhsisoddball;
   2580           case_values[FIRST_NONSTRING_TYPE + 3] = ODDBALL_TYPE;
   2581           assembler->Switch(lhs_instance_type, &if_lhsisreceiver, case_values,
   2582                             case_labels, arraysize(case_values));
   2583           for (int32_t i = 0; i < FIRST_NONSTRING_TYPE; ++i) {
   2584             assembler->Bind(case_labels[i]);
   2585             assembler->Goto(&if_lhsisstring);
   2586             delete case_labels[i];
   2587           }
   2588 
   2589           assembler->Bind(&if_lhsisstring);
   2590           {
   2591             // Check if {rhs} is also a String.
   2592             Label if_rhsisstring(assembler, Label::kDeferred),
   2593                 if_rhsisnotstring(assembler);
   2594             assembler->Branch(assembler->Int32LessThan(
   2595                                   rhs_instance_type, assembler->Int32Constant(
   2596                                                          FIRST_NONSTRING_TYPE)),
   2597                               &if_rhsisstring, &if_rhsisnotstring);
   2598 
   2599             assembler->Bind(&if_rhsisstring);
   2600             {
   2601               // Both {lhs} and {rhs} are of type String, just do the
   2602               // string comparison then.
   2603               Callable callable =
   2604                   (mode == kDontNegateResult)
   2605                       ? CodeFactory::StringEqual(assembler->isolate())
   2606                       : CodeFactory::StringNotEqual(assembler->isolate());
   2607               result.Bind(assembler->CallStub(callable, context, lhs, rhs));
   2608               assembler->Goto(&end);
   2609             }
   2610 
   2611             assembler->Bind(&if_rhsisnotstring);
   2612             {
   2613               // The {lhs} is a String and the {rhs} is some other HeapObject.
   2614               // Swapping {lhs} and {rhs} is not observable and doesn't matter
   2615               // for the result, so we can just swap them and use the String
   2616               // handling below (for {rhs} being a String).
   2617               var_lhs.Bind(rhs);
   2618               var_rhs.Bind(lhs);
   2619               assembler->Goto(&loop);
   2620             }
   2621           }
   2622 
   2623           assembler->Bind(&if_lhsisnumber);
   2624           {
   2625             // Check if {rhs} is also a HeapNumber.
   2626             Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
   2627             assembler->Branch(
   2628                 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
   2629                 &if_rhsisnumber, &if_rhsisnotnumber);
   2630 
   2631             assembler->Bind(&if_rhsisnumber);
   2632             {
   2633               // Convert {lhs} and {rhs} to floating point values, and
   2634               // perform a floating point comparison.
   2635               var_fcmp_lhs.Bind(assembler->LoadHeapNumberValue(lhs));
   2636               var_fcmp_rhs.Bind(assembler->LoadHeapNumberValue(rhs));
   2637               assembler->Goto(&do_fcmp);
   2638             }
   2639 
   2640             assembler->Bind(&if_rhsisnotnumber);
   2641             {
   2642               // The {lhs} is a Number, the {rhs} is some other HeapObject.
   2643               Label if_rhsisstring(assembler, Label::kDeferred),
   2644                   if_rhsisnotstring(assembler);
   2645               assembler->Branch(
   2646                   assembler->Int32LessThan(
   2647                       rhs_instance_type,
   2648                       assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
   2649                   &if_rhsisstring, &if_rhsisnotstring);
   2650 
   2651               assembler->Bind(&if_rhsisstring);
   2652               {
   2653                 // The {rhs} is a String and the {lhs} is a HeapNumber; we need
   2654                 // to convert the {rhs} to a Number and compare the output to
   2655                 // the Number on the {lhs}.
   2656                 assembler->Goto(&do_rhsstringtonumber);
   2657               }
   2658 
   2659               assembler->Bind(&if_rhsisnotstring);
   2660               {
   2661                 // Check if the {rhs} is a JSReceiver.
   2662                 Label if_rhsisreceiver(assembler),
   2663                     if_rhsisnotreceiver(assembler);
   2664                 STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
   2665                 assembler->Branch(
   2666                     assembler->Int32LessThanOrEqual(
   2667                         assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2668                         rhs_instance_type),
   2669                     &if_rhsisreceiver, &if_rhsisnotreceiver);
   2670 
   2671                 assembler->Bind(&if_rhsisreceiver);
   2672                 {
   2673                   // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
   2674                   // Swapping {lhs} and {rhs} is not observable and doesn't
   2675                   // matter for the result, so we can just swap them and use
   2676                   // the JSReceiver handling below (for {lhs} being a
   2677                   // JSReceiver).
   2678                   var_lhs.Bind(rhs);
   2679                   var_rhs.Bind(lhs);
   2680                   assembler->Goto(&loop);
   2681                 }
   2682 
   2683                 assembler->Bind(&if_rhsisnotreceiver);
   2684                 {
   2685                   // Check if {rhs} is a Boolean.
   2686                   Label if_rhsisboolean(assembler),
   2687                       if_rhsisnotboolean(assembler);
   2688                   Node* boolean_map = assembler->BooleanMapConstant();
   2689                   assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
   2690                                     &if_rhsisboolean, &if_rhsisnotboolean);
   2691 
   2692                   assembler->Bind(&if_rhsisboolean);
   2693                   {
   2694                     // The {rhs} is a Boolean, convert it to a Smi first.
   2695                     var_rhs.Bind(assembler->LoadObjectField(
   2696                         rhs, Oddball::kToNumberOffset));
   2697                     assembler->Goto(&loop);
   2698                   }
   2699 
   2700                   assembler->Bind(&if_rhsisnotboolean);
   2701                   assembler->Goto(&if_notequal);
   2702                 }
   2703               }
   2704             }
   2705           }
   2706 
   2707           assembler->Bind(&if_lhsisoddball);
   2708           {
   2709             // The {lhs} is an Oddball and {rhs} is some other HeapObject.
   2710             Label if_lhsisboolean(assembler), if_lhsisnotboolean(assembler);
   2711             Node* boolean_map = assembler->BooleanMapConstant();
   2712             assembler->Branch(assembler->WordEqual(lhs_map, boolean_map),
   2713                               &if_lhsisboolean, &if_lhsisnotboolean);
   2714 
   2715             assembler->Bind(&if_lhsisboolean);
   2716             {
   2717               // The {lhs} is a Boolean, check if {rhs} is also a Boolean.
   2718               Label if_rhsisboolean(assembler), if_rhsisnotboolean(assembler);
   2719               assembler->Branch(assembler->WordEqual(rhs_map, boolean_map),
   2720                                 &if_rhsisboolean, &if_rhsisnotboolean);
   2721 
   2722               assembler->Bind(&if_rhsisboolean);
   2723               {
   2724                 // Both {lhs} and {rhs} are distinct Boolean values.
   2725                 assembler->Goto(&if_notequal);
   2726               }
   2727 
   2728               assembler->Bind(&if_rhsisnotboolean);
   2729               {
   2730                 // Convert the {lhs} to a Number first.
   2731                 var_lhs.Bind(
   2732                     assembler->LoadObjectField(lhs, Oddball::kToNumberOffset));
   2733                 assembler->Goto(&loop);
   2734               }
   2735             }
   2736 
   2737             assembler->Bind(&if_lhsisnotboolean);
   2738             {
   2739               // The {lhs} is either Null or Undefined; check if the {rhs} is
   2740               // undetectable (i.e. either also Null or Undefined or some
   2741               // undetectable JSReceiver).
   2742               Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
   2743               assembler->BranchIfWord32Equal(
   2744                   assembler->Word32And(
   2745                       rhs_bitfield,
   2746                       assembler->Int32Constant(1 << Map::kIsUndetectable)),
   2747                   assembler->Int32Constant(0), &if_notequal, &if_equal);
   2748             }
   2749           }
   2750 
   2751           assembler->Bind(&if_lhsissymbol);
   2752           {
   2753             // Check if the {rhs} is a JSReceiver.
   2754             Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
   2755             STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
   2756             assembler->Branch(
   2757                 assembler->Int32LessThanOrEqual(
   2758                     assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2759                     rhs_instance_type),
   2760                 &if_rhsisreceiver, &if_rhsisnotreceiver);
   2761 
   2762             assembler->Bind(&if_rhsisreceiver);
   2763             {
   2764               // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
   2765               // Swapping {lhs} and {rhs} is not observable and doesn't
   2766               // matter for the result, so we can just swap them and use
   2767               // the JSReceiver handling below (for {lhs} being a JSReceiver).
   2768               var_lhs.Bind(rhs);
   2769               var_rhs.Bind(lhs);
   2770               assembler->Goto(&loop);
   2771             }
   2772 
   2773             assembler->Bind(&if_rhsisnotreceiver);
   2774             {
   2775               // The {rhs} is not a JSReceiver and also not the same Symbol
   2776               // as the {lhs}, so this is equality check is considered false.
   2777               assembler->Goto(&if_notequal);
   2778             }
   2779           }
   2780 
   2781           assembler->Bind(&if_lhsissimd128value);
   2782           {
   2783             // Check if the {rhs} is also a Simd128Value.
   2784             Label if_rhsissimd128value(assembler),
   2785                 if_rhsisnotsimd128value(assembler);
   2786             assembler->Branch(
   2787                 assembler->Word32Equal(lhs_instance_type, rhs_instance_type),
   2788                 &if_rhsissimd128value, &if_rhsisnotsimd128value);
   2789 
   2790             assembler->Bind(&if_rhsissimd128value);
   2791             {
   2792               // Both {lhs} and {rhs} is a Simd128Value.
   2793               GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
   2794                                                     rhs, rhs_map, &if_equal,
   2795                                                     &if_notequal);
   2796             }
   2797 
   2798             assembler->Bind(&if_rhsisnotsimd128value);
   2799             {
   2800               // Check if the {rhs} is a JSReceiver.
   2801               Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
   2802               STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
   2803               assembler->Branch(
   2804                   assembler->Int32LessThanOrEqual(
   2805                       assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2806                       rhs_instance_type),
   2807                   &if_rhsisreceiver, &if_rhsisnotreceiver);
   2808 
   2809               assembler->Bind(&if_rhsisreceiver);
   2810               {
   2811                 // The {lhs} is a Primitive and the {rhs} is a JSReceiver.
   2812                 // Swapping {lhs} and {rhs} is not observable and doesn't
   2813                 // matter for the result, so we can just swap them and use
   2814                 // the JSReceiver handling below (for {lhs} being a JSReceiver).
   2815                 var_lhs.Bind(rhs);
   2816                 var_rhs.Bind(lhs);
   2817                 assembler->Goto(&loop);
   2818               }
   2819 
   2820               assembler->Bind(&if_rhsisnotreceiver);
   2821               {
   2822                 // The {rhs} is some other Primitive.
   2823                 assembler->Goto(&if_notequal);
   2824               }
   2825             }
   2826           }
   2827 
   2828           assembler->Bind(&if_lhsisreceiver);
   2829           {
   2830             // Check if the {rhs} is also a JSReceiver.
   2831             Label if_rhsisreceiver(assembler), if_rhsisnotreceiver(assembler);
   2832             STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
   2833             assembler->Branch(
   2834                 assembler->Int32LessThanOrEqual(
   2835                     assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE),
   2836                     rhs_instance_type),
   2837                 &if_rhsisreceiver, &if_rhsisnotreceiver);
   2838 
   2839             assembler->Bind(&if_rhsisreceiver);
   2840             {
   2841               // Both {lhs} and {rhs} are different JSReceiver references, so
   2842               // this cannot be considered equal.
   2843               assembler->Goto(&if_notequal);
   2844             }
   2845 
   2846             assembler->Bind(&if_rhsisnotreceiver);
   2847             {
   2848               // Check if {rhs} is Null or Undefined (an undetectable check
   2849               // is sufficient here, since we already know that {rhs} is not
   2850               // a JSReceiver).
   2851               Label if_rhsisundetectable(assembler),
   2852                   if_rhsisnotundetectable(assembler, Label::kDeferred);
   2853               Node* rhs_bitfield = assembler->LoadMapBitField(rhs_map);
   2854               assembler->BranchIfWord32Equal(
   2855                   assembler->Word32And(
   2856                       rhs_bitfield,
   2857                       assembler->Int32Constant(1 << Map::kIsUndetectable)),
   2858                   assembler->Int32Constant(0), &if_rhsisnotundetectable,
   2859                   &if_rhsisundetectable);
   2860 
   2861               assembler->Bind(&if_rhsisundetectable);
   2862               {
   2863                 // Check if {lhs} is an undetectable JSReceiver.
   2864                 Node* lhs_bitfield = assembler->LoadMapBitField(lhs_map);
   2865                 assembler->BranchIfWord32Equal(
   2866                     assembler->Word32And(
   2867                         lhs_bitfield,
   2868                         assembler->Int32Constant(1 << Map::kIsUndetectable)),
   2869                     assembler->Int32Constant(0), &if_notequal, &if_equal);
   2870               }
   2871 
   2872               assembler->Bind(&if_rhsisnotundetectable);
   2873               {
   2874                 // The {rhs} is some Primitive different from Null and
   2875                 // Undefined, need to convert {lhs} to Primitive first.
   2876                 // TODO(bmeurer): Hook up ToPrimitiveStub here once it exists.
   2877                 var_lhs.Bind(assembler->CallRuntime(Runtime::kToPrimitive,
   2878                                                     context, lhs));
   2879                 assembler->Goto(&loop);
   2880               }
   2881             }
   2882           }
   2883         }
   2884       }
   2885     }
   2886 
   2887     assembler->Bind(&do_rhsstringtonumber);
   2888     {
   2889       Callable callable = CodeFactory::StringToNumber(assembler->isolate());
   2890       var_rhs.Bind(assembler->CallStub(callable, context, rhs));
   2891       assembler->Goto(&loop);
   2892     }
   2893   }
   2894 
   2895   assembler->Bind(&do_fcmp);
   2896   {
   2897     // Load the {lhs} and {rhs} floating point values.
   2898     Node* lhs = var_fcmp_lhs.value();
   2899     Node* rhs = var_fcmp_rhs.value();
   2900 
   2901     // Perform a fast floating point comparison.
   2902     assembler->BranchIfFloat64Equal(lhs, rhs, &if_equal, &if_notequal);
   2903   }
   2904 
   2905   assembler->Bind(&if_equal);
   2906   {
   2907     result.Bind(assembler->BooleanConstant(mode == kDontNegateResult));
   2908     assembler->Goto(&end);
   2909   }
   2910 
   2911   assembler->Bind(&if_notequal);
   2912   {
   2913     result.Bind(assembler->BooleanConstant(mode == kNegateResult));
   2914     assembler->Goto(&end);
   2915   }
   2916 
   2917   assembler->Bind(&end);
   2918   return result.value();
   2919 }
   2920 
   2921 compiler::Node* GenerateStrictEqual(CodeStubAssembler* assembler,
   2922                                     ResultMode mode, compiler::Node* lhs,
   2923                                     compiler::Node* rhs,
   2924                                     compiler::Node* context) {
   2925   // Here's pseudo-code for the algorithm below in case of kDontNegateResult
   2926   // mode; for kNegateResult mode we properly negate the result.
   2927   //
   2928   // if (lhs == rhs) {
   2929   //   if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN;
   2930   //   return true;
   2931   // }
   2932   // if (!lhs->IsSmi()) {
   2933   //   if (lhs->IsHeapNumber()) {
   2934   //     if (rhs->IsSmi()) {
   2935   //       return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value();
   2936   //     } else if (rhs->IsHeapNumber()) {
   2937   //       return HeapNumber::cast(rhs)->value() ==
   2938   //       HeapNumber::cast(lhs)->value();
   2939   //     } else {
   2940   //       return false;
   2941   //     }
   2942   //   } else {
   2943   //     if (rhs->IsSmi()) {
   2944   //       return false;
   2945   //     } else {
   2946   //       if (lhs->IsString()) {
   2947   //         if (rhs->IsString()) {
   2948   //           return %StringEqual(lhs, rhs);
   2949   //         } else {
   2950   //           return false;
   2951   //         }
   2952   //       } else if (lhs->IsSimd128()) {
   2953   //         if (rhs->IsSimd128()) {
   2954   //           return %StrictEqual(lhs, rhs);
   2955   //         }
   2956   //       } else {
   2957   //         return false;
   2958   //       }
   2959   //     }
   2960   //   }
   2961   // } else {
   2962   //   if (rhs->IsSmi()) {
   2963   //     return false;
   2964   //   } else {
   2965   //     if (rhs->IsHeapNumber()) {
   2966   //       return Smi::cast(lhs)->value() == HeapNumber::cast(rhs)->value();
   2967   //     } else {
   2968   //       return false;
   2969   //     }
   2970   //   }
   2971   // }
   2972 
   2973   typedef CodeStubAssembler::Label Label;
   2974   typedef CodeStubAssembler::Variable Variable;
   2975   typedef compiler::Node Node;
   2976 
   2977   Label if_equal(assembler), if_notequal(assembler), end(assembler);
   2978   Variable result(assembler, MachineRepresentation::kTagged);
   2979 
   2980   // Check if {lhs} and {rhs} refer to the same object.
   2981   Label if_same(assembler), if_notsame(assembler);
   2982   assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
   2983 
   2984   assembler->Bind(&if_same);
   2985   {
   2986     // The {lhs} and {rhs} reference the exact same value, yet we need special
   2987     // treatment for HeapNumber, as NaN is not equal to NaN.
   2988     GenerateEqual_Same(assembler, lhs, &if_equal, &if_notequal);
   2989   }
   2990 
   2991   assembler->Bind(&if_notsame);
   2992   {
   2993     // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber,
   2994     // String and Simd128Value they can still be considered equal.
   2995     Node* number_map = assembler->HeapNumberMapConstant();
   2996 
   2997     // Check if {lhs} is a Smi or a HeapObject.
   2998     Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler);
   2999     assembler->Branch(assembler->WordIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
   3000 
   3001     assembler->Bind(&if_lhsisnotsmi);
   3002     {
   3003       // Load the map of {lhs}.
   3004       Node* lhs_map = assembler->LoadMap(lhs);
   3005 
   3006       // Check if {lhs} is a HeapNumber.
   3007       Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler);
   3008       assembler->Branch(assembler->WordEqual(lhs_map, number_map),
   3009                         &if_lhsisnumber, &if_lhsisnotnumber);
   3010 
   3011       assembler->Bind(&if_lhsisnumber);
   3012       {
   3013         // Check if {rhs} is a Smi or a HeapObject.
   3014         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   3015         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   3016                           &if_rhsisnotsmi);
   3017 
   3018         assembler->Bind(&if_rhsissmi);
   3019         {
   3020           // Convert {lhs} and {rhs} to floating point values.
   3021           Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
   3022           Node* rhs_value = assembler->SmiToFloat64(rhs);
   3023 
   3024           // Perform a floating point comparison of {lhs} and {rhs}.
   3025           assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
   3026                                           &if_notequal);
   3027         }
   3028 
   3029         assembler->Bind(&if_rhsisnotsmi);
   3030         {
   3031           // Load the map of {rhs}.
   3032           Node* rhs_map = assembler->LoadMap(rhs);
   3033 
   3034           // Check if {rhs} is also a HeapNumber.
   3035           Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
   3036           assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   3037                             &if_rhsisnumber, &if_rhsisnotnumber);
   3038 
   3039           assembler->Bind(&if_rhsisnumber);
   3040           {
   3041             // Convert {lhs} and {rhs} to floating point values.
   3042             Node* lhs_value = assembler->LoadHeapNumberValue(lhs);
   3043             Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
   3044 
   3045             // Perform a floating point comparison of {lhs} and {rhs}.
   3046             assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
   3047                                             &if_notequal);
   3048           }
   3049 
   3050           assembler->Bind(&if_rhsisnotnumber);
   3051           assembler->Goto(&if_notequal);
   3052         }
   3053       }
   3054 
   3055       assembler->Bind(&if_lhsisnotnumber);
   3056       {
   3057         // Check if {rhs} is a Smi or a HeapObject.
   3058         Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   3059         assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   3060                           &if_rhsisnotsmi);
   3061 
   3062         assembler->Bind(&if_rhsissmi);
   3063         assembler->Goto(&if_notequal);
   3064 
   3065         assembler->Bind(&if_rhsisnotsmi);
   3066         {
   3067           // Load the instance type of {lhs}.
   3068           Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map);
   3069 
   3070           // Check if {lhs} is a String.
   3071           Label if_lhsisstring(assembler), if_lhsisnotstring(assembler);
   3072           assembler->Branch(assembler->Int32LessThan(
   3073                                 lhs_instance_type,
   3074                                 assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
   3075                             &if_lhsisstring, &if_lhsisnotstring);
   3076 
   3077           assembler->Bind(&if_lhsisstring);
   3078           {
   3079             // Load the instance type of {rhs}.
   3080             Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
   3081 
   3082             // Check if {rhs} is also a String.
   3083             Label if_rhsisstring(assembler, Label::kDeferred),
   3084                 if_rhsisnotstring(assembler);
   3085             assembler->Branch(assembler->Int32LessThan(
   3086                                   rhs_instance_type, assembler->Int32Constant(
   3087                                                          FIRST_NONSTRING_TYPE)),
   3088                               &if_rhsisstring, &if_rhsisnotstring);
   3089 
   3090             assembler->Bind(&if_rhsisstring);
   3091             {
   3092               Callable callable =
   3093                   (mode == kDontNegateResult)
   3094                       ? CodeFactory::StringEqual(assembler->isolate())
   3095                       : CodeFactory::StringNotEqual(assembler->isolate());
   3096               result.Bind(assembler->CallStub(callable, context, lhs, rhs));
   3097               assembler->Goto(&end);
   3098             }
   3099 
   3100             assembler->Bind(&if_rhsisnotstring);
   3101             assembler->Goto(&if_notequal);
   3102           }
   3103 
   3104           assembler->Bind(&if_lhsisnotstring);
   3105           {
   3106             // Check if {lhs} is a Simd128Value.
   3107             Label if_lhsissimd128value(assembler),
   3108                 if_lhsisnotsimd128value(assembler);
   3109             assembler->Branch(assembler->Word32Equal(
   3110                                   lhs_instance_type,
   3111                                   assembler->Int32Constant(SIMD128_VALUE_TYPE)),
   3112                               &if_lhsissimd128value, &if_lhsisnotsimd128value);
   3113 
   3114             assembler->Bind(&if_lhsissimd128value);
   3115             {
   3116               // Load the map of {rhs}.
   3117               Node* rhs_map = assembler->LoadMap(rhs);
   3118 
   3119               // Check if {rhs} is also a Simd128Value that is equal to {lhs}.
   3120               GenerateEqual_Simd128Value_HeapObject(assembler, lhs, lhs_map,
   3121                                                     rhs, rhs_map, &if_equal,
   3122                                                     &if_notequal);
   3123             }
   3124 
   3125             assembler->Bind(&if_lhsisnotsimd128value);
   3126             assembler->Goto(&if_notequal);
   3127           }
   3128         }
   3129       }
   3130     }
   3131 
   3132     assembler->Bind(&if_lhsissmi);
   3133     {
   3134       // We already know that {lhs} and {rhs} are not reference equal, and {lhs}
   3135       // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a
   3136       // HeapNumber with an equal floating point value.
   3137 
   3138       // Check if {rhs} is a Smi or a HeapObject.
   3139       Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler);
   3140       assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi,
   3141                         &if_rhsisnotsmi);
   3142 
   3143       assembler->Bind(&if_rhsissmi);
   3144       assembler->Goto(&if_notequal);
   3145 
   3146       assembler->Bind(&if_rhsisnotsmi);
   3147       {
   3148         // Load the map of the {rhs}.
   3149         Node* rhs_map = assembler->LoadMap(rhs);
   3150 
   3151         // The {rhs} could be a HeapNumber with the same value as {lhs}.
   3152         Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler);
   3153         assembler->Branch(assembler->WordEqual(rhs_map, number_map),
   3154                           &if_rhsisnumber, &if_rhsisnotnumber);
   3155 
   3156         assembler->Bind(&if_rhsisnumber);
   3157         {
   3158           // Convert {lhs} and {rhs} to floating point values.
   3159           Node* lhs_value = assembler->SmiToFloat64(lhs);
   3160           Node* rhs_value = assembler->LoadHeapNumberValue(rhs);
   3161 
   3162           // Perform a floating point comparison of {lhs} and {rhs}.
   3163           assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal,
   3164                                           &if_notequal);
   3165         }
   3166 
   3167         assembler->Bind(&if_rhsisnotnumber);
   3168         assembler->Goto(&if_notequal);
   3169       }
   3170     }
   3171   }
   3172 
   3173   assembler->Bind(&if_equal);
   3174   {
   3175     result.Bind(assembler->BooleanConstant(mode == kDontNegateResult));
   3176     assembler->Goto(&end);
   3177   }
   3178 
   3179   assembler->Bind(&if_notequal);
   3180   {
   3181     result.Bind(assembler->BooleanConstant(mode == kNegateResult));
   3182     assembler->Goto(&end);
   3183   }
   3184 
   3185   assembler->Bind(&end);
   3186   return result.value();
   3187 }
   3188 
   3189 void GenerateStringRelationalComparison(CodeStubAssembler* assembler,
   3190                                         RelationalComparisonMode mode) {
   3191   typedef CodeStubAssembler::Label Label;
   3192   typedef compiler::Node Node;
   3193   typedef CodeStubAssembler::Variable Variable;
   3194 
   3195   Node* lhs = assembler->Parameter(0);
   3196   Node* rhs = assembler->Parameter(1);
   3197   Node* context = assembler->Parameter(2);
   3198 
   3199   Label if_less(assembler), if_equal(assembler), if_greater(assembler);
   3200 
   3201   // Fast check to see if {lhs} and {rhs} refer to the same String object.
   3202   Label if_same(assembler), if_notsame(assembler);
   3203   assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
   3204 
   3205   assembler->Bind(&if_same);
   3206   assembler->Goto(&if_equal);
   3207 
   3208   assembler->Bind(&if_notsame);
   3209   {
   3210     // Load instance types of {lhs} and {rhs}.
   3211     Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
   3212     Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
   3213 
   3214     // Combine the instance types into a single 16-bit value, so we can check
   3215     // both of them at once.
   3216     Node* both_instance_types = assembler->Word32Or(
   3217         lhs_instance_type,
   3218         assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
   3219 
   3220     // Check that both {lhs} and {rhs} are flat one-byte strings.
   3221     int const kBothSeqOneByteStringMask =
   3222         kStringEncodingMask | kStringRepresentationMask |
   3223         ((kStringEncodingMask | kStringRepresentationMask) << 8);
   3224     int const kBothSeqOneByteStringTag =
   3225         kOneByteStringTag | kSeqStringTag |
   3226         ((kOneByteStringTag | kSeqStringTag) << 8);
   3227     Label if_bothonebyteseqstrings(assembler),
   3228         if_notbothonebyteseqstrings(assembler);
   3229     assembler->Branch(assembler->Word32Equal(
   3230                           assembler->Word32And(both_instance_types,
   3231                                                assembler->Int32Constant(
   3232                                                    kBothSeqOneByteStringMask)),
   3233                           assembler->Int32Constant(kBothSeqOneByteStringTag)),
   3234                       &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
   3235 
   3236     assembler->Bind(&if_bothonebyteseqstrings);
   3237     {
   3238       // Load the length of {lhs} and {rhs}.
   3239       Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
   3240       Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
   3241 
   3242       // Determine the minimum length.
   3243       Node* length = assembler->SmiMin(lhs_length, rhs_length);
   3244 
   3245       // Compute the effective offset of the first character.
   3246       Node* begin = assembler->IntPtrConstant(SeqOneByteString::kHeaderSize -
   3247                                               kHeapObjectTag);
   3248 
   3249       // Compute the first offset after the string from the length.
   3250       Node* end = assembler->IntPtrAdd(begin, assembler->SmiUntag(length));
   3251 
   3252       // Loop over the {lhs} and {rhs} strings to see if they are equal.
   3253       Variable var_offset(assembler, MachineType::PointerRepresentation());
   3254       Label loop(assembler, &var_offset);
   3255       var_offset.Bind(begin);
   3256       assembler->Goto(&loop);
   3257       assembler->Bind(&loop);
   3258       {
   3259         // Check if {offset} equals {end}.
   3260         Node* offset = var_offset.value();
   3261         Label if_done(assembler), if_notdone(assembler);
   3262         assembler->Branch(assembler->WordEqual(offset, end), &if_done,
   3263                           &if_notdone);
   3264 
   3265         assembler->Bind(&if_notdone);
   3266         {
   3267           // Load the next characters from {lhs} and {rhs}.
   3268           Node* lhs_value = assembler->Load(MachineType::Uint8(), lhs, offset);
   3269           Node* rhs_value = assembler->Load(MachineType::Uint8(), rhs, offset);
   3270 
   3271           // Check if the characters match.
   3272           Label if_valueissame(assembler), if_valueisnotsame(assembler);
   3273           assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
   3274                             &if_valueissame, &if_valueisnotsame);
   3275 
   3276           assembler->Bind(&if_valueissame);
   3277           {
   3278             // Advance to next character.
   3279             var_offset.Bind(
   3280                 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
   3281           }
   3282           assembler->Goto(&loop);
   3283 
   3284           assembler->Bind(&if_valueisnotsame);
   3285           assembler->BranchIf(assembler->Uint32LessThan(lhs_value, rhs_value),
   3286                               &if_less, &if_greater);
   3287         }
   3288 
   3289         assembler->Bind(&if_done);
   3290         {
   3291           // All characters up to the min length are equal, decide based on
   3292           // string length.
   3293           Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
   3294           assembler->Branch(assembler->SmiEqual(lhs_length, rhs_length),
   3295                             &if_lengthisequal, &if_lengthisnotequal);
   3296 
   3297           assembler->Bind(&if_lengthisequal);
   3298           assembler->Goto(&if_equal);
   3299 
   3300           assembler->Bind(&if_lengthisnotequal);
   3301           assembler->BranchIfSmiLessThan(lhs_length, rhs_length, &if_less,
   3302                                          &if_greater);
   3303         }
   3304       }
   3305     }
   3306 
   3307     assembler->Bind(&if_notbothonebyteseqstrings);
   3308     {
   3309       // TODO(bmeurer): Add fast case support for flattened cons strings;
   3310       // also add support for two byte string relational comparisons.
   3311       switch (mode) {
   3312         case kLessThan:
   3313           assembler->TailCallRuntime(Runtime::kStringLessThan, context, lhs,
   3314                                      rhs);
   3315           break;
   3316         case kLessThanOrEqual:
   3317           assembler->TailCallRuntime(Runtime::kStringLessThanOrEqual, context,
   3318                                      lhs, rhs);
   3319           break;
   3320         case kGreaterThan:
   3321           assembler->TailCallRuntime(Runtime::kStringGreaterThan, context, lhs,
   3322                                      rhs);
   3323           break;
   3324         case kGreaterThanOrEqual:
   3325           assembler->TailCallRuntime(Runtime::kStringGreaterThanOrEqual,
   3326                                      context, lhs, rhs);
   3327           break;
   3328       }
   3329     }
   3330   }
   3331 
   3332   assembler->Bind(&if_less);
   3333   switch (mode) {
   3334     case kLessThan:
   3335     case kLessThanOrEqual:
   3336       assembler->Return(assembler->BooleanConstant(true));
   3337       break;
   3338 
   3339     case kGreaterThan:
   3340     case kGreaterThanOrEqual:
   3341       assembler->Return(assembler->BooleanConstant(false));
   3342       break;
   3343   }
   3344 
   3345   assembler->Bind(&if_equal);
   3346   switch (mode) {
   3347     case kLessThan:
   3348     case kGreaterThan:
   3349       assembler->Return(assembler->BooleanConstant(false));
   3350       break;
   3351 
   3352     case kLessThanOrEqual:
   3353     case kGreaterThanOrEqual:
   3354       assembler->Return(assembler->BooleanConstant(true));
   3355       break;
   3356   }
   3357 
   3358   assembler->Bind(&if_greater);
   3359   switch (mode) {
   3360     case kLessThan:
   3361     case kLessThanOrEqual:
   3362       assembler->Return(assembler->BooleanConstant(false));
   3363       break;
   3364 
   3365     case kGreaterThan:
   3366     case kGreaterThanOrEqual:
   3367       assembler->Return(assembler->BooleanConstant(true));
   3368       break;
   3369   }
   3370 }
   3371 
   3372 void GenerateStringEqual(CodeStubAssembler* assembler, ResultMode mode) {
   3373   // Here's pseudo-code for the algorithm below in case of kDontNegateResult
   3374   // mode; for kNegateResult mode we properly negate the result.
   3375   //
   3376   // if (lhs == rhs) return true;
   3377   // if (lhs->length() != rhs->length()) return false;
   3378   // if (lhs->IsInternalizedString() && rhs->IsInternalizedString()) {
   3379   //   return false;
   3380   // }
   3381   // if (lhs->IsSeqOneByteString() && rhs->IsSeqOneByteString()) {
   3382   //   for (i = 0; i != lhs->length(); ++i) {
   3383   //     if (lhs[i] != rhs[i]) return false;
   3384   //   }
   3385   //   return true;
   3386   // }
   3387   // return %StringEqual(lhs, rhs);
   3388 
   3389   typedef CodeStubAssembler::Label Label;
   3390   typedef compiler::Node Node;
   3391   typedef CodeStubAssembler::Variable Variable;
   3392 
   3393   Node* lhs = assembler->Parameter(0);
   3394   Node* rhs = assembler->Parameter(1);
   3395   Node* context = assembler->Parameter(2);
   3396 
   3397   Label if_equal(assembler), if_notequal(assembler);
   3398 
   3399   // Fast check to see if {lhs} and {rhs} refer to the same String object.
   3400   Label if_same(assembler), if_notsame(assembler);
   3401   assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame);
   3402 
   3403   assembler->Bind(&if_same);
   3404   assembler->Goto(&if_equal);
   3405 
   3406   assembler->Bind(&if_notsame);
   3407   {
   3408     // The {lhs} and {rhs} don't refer to the exact same String object.
   3409 
   3410     // Load the length of {lhs} and {rhs}.
   3411     Node* lhs_length = assembler->LoadObjectField(lhs, String::kLengthOffset);
   3412     Node* rhs_length = assembler->LoadObjectField(rhs, String::kLengthOffset);
   3413 
   3414     // Check if the lengths of {lhs} and {rhs} are equal.
   3415     Label if_lengthisequal(assembler), if_lengthisnotequal(assembler);
   3416     assembler->Branch(assembler->WordEqual(lhs_length, rhs_length),
   3417                       &if_lengthisequal, &if_lengthisnotequal);
   3418 
   3419     assembler->Bind(&if_lengthisequal);
   3420     {
   3421       // Load instance types of {lhs} and {rhs}.
   3422       Node* lhs_instance_type = assembler->LoadInstanceType(lhs);
   3423       Node* rhs_instance_type = assembler->LoadInstanceType(rhs);
   3424 
   3425       // Combine the instance types into a single 16-bit value, so we can check
   3426       // both of them at once.
   3427       Node* both_instance_types = assembler->Word32Or(
   3428           lhs_instance_type,
   3429           assembler->Word32Shl(rhs_instance_type, assembler->Int32Constant(8)));
   3430 
   3431       // Check if both {lhs} and {rhs} are internalized.
   3432       int const kBothInternalizedMask =
   3433           kIsNotInternalizedMask | (kIsNotInternalizedMask << 8);
   3434       int const kBothInternalizedTag =
   3435           kInternalizedTag | (kInternalizedTag << 8);
   3436       Label if_bothinternalized(assembler), if_notbothinternalized(assembler);
   3437       assembler->Branch(assembler->Word32Equal(
   3438                             assembler->Word32And(both_instance_types,
   3439                                                  assembler->Int32Constant(
   3440                                                      kBothInternalizedMask)),
   3441                             assembler->Int32Constant(kBothInternalizedTag)),
   3442                         &if_bothinternalized, &if_notbothinternalized);
   3443 
   3444       assembler->Bind(&if_bothinternalized);
   3445       {
   3446         // Fast negative check for internalized-to-internalized equality.
   3447         assembler->Goto(&if_notequal);
   3448       }
   3449 
   3450       assembler->Bind(&if_notbothinternalized);
   3451       {
   3452         // Check that both {lhs} and {rhs} are flat one-byte strings.
   3453         int const kBothSeqOneByteStringMask =
   3454             kStringEncodingMask | kStringRepresentationMask |
   3455             ((kStringEncodingMask | kStringRepresentationMask) << 8);
   3456         int const kBothSeqOneByteStringTag =
   3457             kOneByteStringTag | kSeqStringTag |
   3458             ((kOneByteStringTag | kSeqStringTag) << 8);
   3459         Label if_bothonebyteseqstrings(assembler),
   3460             if_notbothonebyteseqstrings(assembler);
   3461         assembler->Branch(
   3462             assembler->Word32Equal(
   3463                 assembler->Word32And(
   3464                     both_instance_types,
   3465                     assembler->Int32Constant(kBothSeqOneByteStringMask)),
   3466                 assembler->Int32Constant(kBothSeqOneByteStringTag)),
   3467             &if_bothonebyteseqstrings, &if_notbothonebyteseqstrings);
   3468 
   3469         assembler->Bind(&if_bothonebyteseqstrings);
   3470         {
   3471           // Compute the effective offset of the first character.
   3472           Node* begin = assembler->IntPtrConstant(
   3473               SeqOneByteString::kHeaderSize - kHeapObjectTag);
   3474 
   3475           // Compute the first offset after the string from the length.
   3476           Node* end =
   3477               assembler->IntPtrAdd(begin, assembler->SmiUntag(lhs_length));
   3478 
   3479           // Loop over the {lhs} and {rhs} strings to see if they are equal.
   3480           Variable var_offset(assembler, MachineType::PointerRepresentation());
   3481           Label loop(assembler, &var_offset);
   3482           var_offset.Bind(begin);
   3483           assembler->Goto(&loop);
   3484           assembler->Bind(&loop);
   3485           {
   3486             // Check if {offset} equals {end}.
   3487             Node* offset = var_offset.value();
   3488             Label if_done(assembler), if_notdone(assembler);
   3489             assembler->Branch(assembler->WordEqual(offset, end), &if_done,
   3490                               &if_notdone);
   3491 
   3492             assembler->Bind(&if_notdone);
   3493             {
   3494               // Load the next characters from {lhs} and {rhs}.
   3495               Node* lhs_value =
   3496                   assembler->Load(MachineType::Uint8(), lhs, offset);
   3497               Node* rhs_value =
   3498                   assembler->Load(MachineType::Uint8(), rhs, offset);
   3499 
   3500               // Check if the characters match.
   3501               Label if_valueissame(assembler), if_valueisnotsame(assembler);
   3502               assembler->Branch(assembler->Word32Equal(lhs_value, rhs_value),
   3503                                 &if_valueissame, &if_valueisnotsame);
   3504 
   3505               assembler->Bind(&if_valueissame);
   3506               {
   3507                 // Advance to next character.
   3508                 var_offset.Bind(
   3509                     assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1)));
   3510               }
   3511               assembler->Goto(&loop);
   3512 
   3513               assembler->Bind(&if_valueisnotsame);
   3514               assembler->Goto(&if_notequal);
   3515             }
   3516 
   3517             assembler->Bind(&if_done);
   3518             assembler->Goto(&if_equal);
   3519           }
   3520         }
   3521 
   3522         assembler->Bind(&if_notbothonebyteseqstrings);
   3523         {
   3524           // TODO(bmeurer): Add fast case support for flattened cons strings;
   3525           // also add support for two byte string equality checks.
   3526           Runtime::FunctionId function_id = (mode == kDontNegateResult)
   3527                                                 ? Runtime::kStringEqual
   3528                                                 : Runtime::kStringNotEqual;
   3529           assembler->TailCallRuntime(function_id, context, lhs, rhs);
   3530         }
   3531       }
   3532     }
   3533 
   3534     assembler->Bind(&if_lengthisnotequal);
   3535     {
   3536       // Mismatch in length of {lhs} and {rhs}, cannot be equal.
   3537       assembler->Goto(&if_notequal);
   3538     }
   3539   }
   3540 
   3541   assembler->Bind(&if_equal);
   3542   assembler->Return(assembler->BooleanConstant(mode == kDontNegateResult));
   3543 
   3544   assembler->Bind(&if_notequal);
   3545   assembler->Return(assembler->BooleanConstant(mode == kNegateResult));
   3546 }
   3547 
   3548 }  // namespace
   3549 
   3550 void LoadApiGetterStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3551   typedef compiler::Node Node;
   3552   Node* context = assembler->Parameter(3);
   3553   Node* receiver = assembler->Parameter(0);
   3554   // For now we only support receiver_is_holder.
   3555   DCHECK(receiver_is_holder());
   3556   Node* holder = receiver;
   3557   Node* map = assembler->LoadMap(receiver);
   3558   Node* descriptors = assembler->LoadMapDescriptors(map);
   3559   Node* offset =
   3560       assembler->Int32Constant(DescriptorArray::ToValueIndex(index()));
   3561   Node* callback = assembler->LoadFixedArrayElement(descriptors, offset);
   3562   assembler->TailCallStub(CodeFactory::ApiGetter(isolate()), context, receiver,
   3563                           holder, callback);
   3564 }
   3565 
   3566 // static
   3567 compiler::Node* LessThanStub::Generate(CodeStubAssembler* assembler,
   3568                                        compiler::Node* lhs, compiler::Node* rhs,
   3569                                        compiler::Node* context) {
   3570   return GenerateAbstractRelationalComparison(assembler, kLessThan, lhs, rhs,
   3571                                               context);
   3572 }
   3573 
   3574 // static
   3575 compiler::Node* LessThanOrEqualStub::Generate(CodeStubAssembler* assembler,
   3576                                               compiler::Node* lhs,
   3577                                               compiler::Node* rhs,
   3578                                               compiler::Node* context) {
   3579   return GenerateAbstractRelationalComparison(assembler, kLessThanOrEqual, lhs,
   3580                                               rhs, context);
   3581 }
   3582 
   3583 // static
   3584 compiler::Node* GreaterThanStub::Generate(CodeStubAssembler* assembler,
   3585                                           compiler::Node* lhs,
   3586                                           compiler::Node* rhs,
   3587                                           compiler::Node* context) {
   3588   return GenerateAbstractRelationalComparison(assembler, kGreaterThan, lhs, rhs,
   3589                                               context);
   3590 }
   3591 
   3592 // static
   3593 compiler::Node* GreaterThanOrEqualStub::Generate(CodeStubAssembler* assembler,
   3594                                                  compiler::Node* lhs,
   3595                                                  compiler::Node* rhs,
   3596                                                  compiler::Node* context) {
   3597   return GenerateAbstractRelationalComparison(assembler, kGreaterThanOrEqual,
   3598                                               lhs, rhs, context);
   3599 }
   3600 
   3601 // static
   3602 compiler::Node* EqualStub::Generate(CodeStubAssembler* assembler,
   3603                                     compiler::Node* lhs, compiler::Node* rhs,
   3604                                     compiler::Node* context) {
   3605   return GenerateEqual(assembler, kDontNegateResult, lhs, rhs, context);
   3606 }
   3607 
   3608 // static
   3609 compiler::Node* NotEqualStub::Generate(CodeStubAssembler* assembler,
   3610                                        compiler::Node* lhs, compiler::Node* rhs,
   3611                                        compiler::Node* context) {
   3612   return GenerateEqual(assembler, kNegateResult, lhs, rhs, context);
   3613 }
   3614 
   3615 // static
   3616 compiler::Node* StrictEqualStub::Generate(CodeStubAssembler* assembler,
   3617                                           compiler::Node* lhs,
   3618                                           compiler::Node* rhs,
   3619                                           compiler::Node* context) {
   3620   return GenerateStrictEqual(assembler, kDontNegateResult, lhs, rhs, context);
   3621 }
   3622 
   3623 // static
   3624 compiler::Node* StrictNotEqualStub::Generate(CodeStubAssembler* assembler,
   3625                                              compiler::Node* lhs,
   3626                                              compiler::Node* rhs,
   3627                                              compiler::Node* context) {
   3628   return GenerateStrictEqual(assembler, kNegateResult, lhs, rhs, context);
   3629 }
   3630 
   3631 void StringEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3632   GenerateStringEqual(assembler, kDontNegateResult);
   3633 }
   3634 
   3635 void StringNotEqualStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3636   GenerateStringEqual(assembler, kNegateResult);
   3637 }
   3638 
   3639 void StringLessThanStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3640   GenerateStringRelationalComparison(assembler, kLessThan);
   3641 }
   3642 
   3643 void StringLessThanOrEqualStub::GenerateAssembly(
   3644     CodeStubAssembler* assembler) const {
   3645   GenerateStringRelationalComparison(assembler, kLessThanOrEqual);
   3646 }
   3647 
   3648 void StringGreaterThanStub::GenerateAssembly(
   3649     CodeStubAssembler* assembler) const {
   3650   GenerateStringRelationalComparison(assembler, kGreaterThan);
   3651 }
   3652 
   3653 void StringGreaterThanOrEqualStub::GenerateAssembly(
   3654     CodeStubAssembler* assembler) const {
   3655   GenerateStringRelationalComparison(assembler, kGreaterThanOrEqual);
   3656 }
   3657 
   3658 void ToLengthStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3659   typedef CodeStubAssembler::Label Label;
   3660   typedef compiler::Node Node;
   3661   typedef CodeStubAssembler::Variable Variable;
   3662 
   3663   Node* context = assembler->Parameter(1);
   3664 
   3665   // We might need to loop once for ToNumber conversion.
   3666   Variable var_len(assembler, MachineRepresentation::kTagged);
   3667   Label loop(assembler, &var_len);
   3668   var_len.Bind(assembler->Parameter(0));
   3669   assembler->Goto(&loop);
   3670   assembler->Bind(&loop);
   3671   {
   3672     // Shared entry points.
   3673     Label return_len(assembler),
   3674         return_two53minus1(assembler, Label::kDeferred),
   3675         return_zero(assembler, Label::kDeferred);
   3676 
   3677     // Load the current {len} value.
   3678     Node* len = var_len.value();
   3679 
   3680     // Check if {len} is a positive Smi.
   3681     assembler->GotoIf(assembler->WordIsPositiveSmi(len), &return_len);
   3682 
   3683     // Check if {len} is a (negative) Smi.
   3684     assembler->GotoIf(assembler->WordIsSmi(len), &return_zero);
   3685 
   3686     // Check if {len} is a HeapNumber.
   3687     Label if_lenisheapnumber(assembler),
   3688         if_lenisnotheapnumber(assembler, Label::kDeferred);
   3689     assembler->Branch(assembler->WordEqual(assembler->LoadMap(len),
   3690                                            assembler->HeapNumberMapConstant()),
   3691                       &if_lenisheapnumber, &if_lenisnotheapnumber);
   3692 
   3693     assembler->Bind(&if_lenisheapnumber);
   3694     {
   3695       // Load the floating-point value of {len}.
   3696       Node* len_value = assembler->LoadHeapNumberValue(len);
   3697 
   3698       // Check if {len} is not greater than zero.
   3699       assembler->GotoUnless(assembler->Float64GreaterThan(
   3700                                 len_value, assembler->Float64Constant(0.0)),
   3701                             &return_zero);
   3702 
   3703       // Check if {len} is greater than or equal to 2^53-1.
   3704       assembler->GotoIf(
   3705           assembler->Float64GreaterThanOrEqual(
   3706               len_value, assembler->Float64Constant(kMaxSafeInteger)),
   3707           &return_two53minus1);
   3708 
   3709       // Round the {len} towards -Infinity.
   3710       Node* value = assembler->Float64Floor(len_value);
   3711       Node* result = assembler->ChangeFloat64ToTagged(value);
   3712       assembler->Return(result);
   3713     }
   3714 
   3715     assembler->Bind(&if_lenisnotheapnumber);
   3716     {
   3717       // Need to convert {len} to a Number first.
   3718       Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
   3719       var_len.Bind(assembler->CallStub(callable, context, len));
   3720       assembler->Goto(&loop);
   3721     }
   3722 
   3723     assembler->Bind(&return_len);
   3724     assembler->Return(var_len.value());
   3725 
   3726     assembler->Bind(&return_two53minus1);
   3727     assembler->Return(assembler->NumberConstant(kMaxSafeInteger));
   3728 
   3729     assembler->Bind(&return_zero);
   3730     assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
   3731   }
   3732 }
   3733 
   3734 // static
   3735 compiler::Node* ToBooleanStub::Generate(CodeStubAssembler* assembler,
   3736                                         compiler::Node* value,
   3737                                         compiler::Node* context) {
   3738   typedef compiler::Node Node;
   3739   typedef CodeStubAssembler::Label Label;
   3740   typedef CodeStubAssembler::Variable Variable;
   3741 
   3742   Variable result(assembler, MachineRepresentation::kTagged);
   3743   Label if_valueissmi(assembler), if_valueisnotsmi(assembler),
   3744       return_true(assembler), return_false(assembler), end(assembler);
   3745 
   3746   // Check if {value} is a Smi or a HeapObject.
   3747   assembler->Branch(assembler->WordIsSmi(value), &if_valueissmi,
   3748                     &if_valueisnotsmi);
   3749 
   3750   assembler->Bind(&if_valueissmi);
   3751   {
   3752     // The {value} is a Smi, only need to check against zero.
   3753     assembler->Branch(assembler->SmiEqual(value, assembler->SmiConstant(0)),
   3754                       &return_false, &return_true);
   3755   }
   3756 
   3757   assembler->Bind(&if_valueisnotsmi);
   3758   {
   3759     Label if_valueisstring(assembler), if_valueisnotstring(assembler),
   3760         if_valueisheapnumber(assembler), if_valueisoddball(assembler),
   3761         if_valueisother(assembler);
   3762 
   3763     // The {value} is a HeapObject, load its map.
   3764     Node* value_map = assembler->LoadMap(value);
   3765 
   3766     // Load the {value}s instance type.
   3767     Node* value_instance_type = assembler->Load(
   3768         MachineType::Uint8(), value_map,
   3769         assembler->IntPtrConstant(Map::kInstanceTypeOffset - kHeapObjectTag));
   3770 
   3771     // Dispatch based on the instance type; we distinguish all String instance
   3772     // types, the HeapNumber type and the Oddball type.
   3773     assembler->Branch(assembler->Int32LessThan(
   3774                           value_instance_type,
   3775                           assembler->Int32Constant(FIRST_NONSTRING_TYPE)),
   3776                       &if_valueisstring, &if_valueisnotstring);
   3777     assembler->Bind(&if_valueisnotstring);
   3778     size_t const kNumCases = 2;
   3779     Label* case_labels[kNumCases];
   3780     int32_t case_values[kNumCases];
   3781     case_labels[0] = &if_valueisheapnumber;
   3782     case_values[0] = HEAP_NUMBER_TYPE;
   3783     case_labels[1] = &if_valueisoddball;
   3784     case_values[1] = ODDBALL_TYPE;
   3785     assembler->Switch(value_instance_type, &if_valueisother, case_values,
   3786                       case_labels, arraysize(case_values));
   3787 
   3788     assembler->Bind(&if_valueisstring);
   3789     {
   3790       // Load the string length field of the {value}.
   3791       Node* value_length =
   3792           assembler->LoadObjectField(value, String::kLengthOffset);
   3793 
   3794       // Check if the {value} is the empty string.
   3795       assembler->Branch(
   3796           assembler->SmiEqual(value_length, assembler->SmiConstant(0)),
   3797           &return_false, &return_true);
   3798     }
   3799 
   3800     assembler->Bind(&if_valueisheapnumber);
   3801     {
   3802       Node* value_value = assembler->Load(
   3803           MachineType::Float64(), value,
   3804           assembler->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
   3805 
   3806       Label if_valueisnotpositive(assembler);
   3807       assembler->Branch(assembler->Float64LessThan(
   3808                             assembler->Float64Constant(0.0), value_value),
   3809                         &return_true, &if_valueisnotpositive);
   3810 
   3811       assembler->Bind(&if_valueisnotpositive);
   3812       assembler->Branch(assembler->Float64LessThan(
   3813                             value_value, assembler->Float64Constant(0.0)),
   3814                         &return_true, &return_false);
   3815     }
   3816 
   3817     assembler->Bind(&if_valueisoddball);
   3818     {
   3819       // The {value} is an Oddball, and every Oddball knows its boolean value.
   3820       Node* value_toboolean =
   3821           assembler->LoadObjectField(value, Oddball::kToBooleanOffset);
   3822       result.Bind(value_toboolean);
   3823       assembler->Goto(&end);
   3824     }
   3825 
   3826     assembler->Bind(&if_valueisother);
   3827     {
   3828       Node* value_map_bitfield = assembler->Load(
   3829           MachineType::Uint8(), value_map,
   3830           assembler->IntPtrConstant(Map::kBitFieldOffset - kHeapObjectTag));
   3831       Node* value_map_undetectable = assembler->Word32And(
   3832           value_map_bitfield,
   3833           assembler->Int32Constant(1 << Map::kIsUndetectable));
   3834 
   3835       // Check if the {value} is undetectable.
   3836       assembler->Branch(assembler->Word32Equal(value_map_undetectable,
   3837                                                assembler->Int32Constant(0)),
   3838                         &return_true, &return_false);
   3839     }
   3840   }
   3841 
   3842   assembler->Bind(&return_false);
   3843   {
   3844     result.Bind(assembler->BooleanConstant(false));
   3845     assembler->Goto(&end);
   3846   }
   3847 
   3848   assembler->Bind(&return_true);
   3849   {
   3850     result.Bind(assembler->BooleanConstant(true));
   3851     assembler->Goto(&end);
   3852   }
   3853 
   3854   assembler->Bind(&end);
   3855   return result.value();
   3856 }
   3857 
   3858 void ToIntegerStub::GenerateAssembly(CodeStubAssembler* assembler) const {
   3859   typedef CodeStubAssembler::Label Label;
   3860   typedef compiler::Node Node;
   3861   typedef CodeStubAssembler::Variable Variable;
   3862 
   3863   Node* context = assembler->Parameter(1);
   3864 
   3865   // We might need to loop once for ToNumber conversion.
   3866   Variable var_arg(assembler, MachineRepresentation::kTagged);
   3867   Label loop(assembler, &var_arg);
   3868   var_arg.Bind(assembler->Parameter(0));
   3869   assembler->Goto(&loop);
   3870   assembler->Bind(&loop);
   3871   {
   3872     // Shared entry points.
   3873     Label return_arg(assembler), return_zero(assembler, Label::kDeferred);
   3874 
   3875     // Load the current {arg} value.
   3876     Node* arg = var_arg.value();
   3877 
   3878     // Check if {arg} is a Smi.
   3879     assembler->GotoIf(assembler->WordIsSmi(arg), &return_arg);
   3880 
   3881     // Check if {arg} is a HeapNumber.
   3882     Label if_argisheapnumber(assembler),
   3883         if_argisnotheapnumber(assembler, Label::kDeferred);
   3884     assembler->Branch(assembler->WordEqual(assembler->LoadMap(arg),
   3885                                            assembler->HeapNumberMapConstant()),
   3886                       &if_argisheapnumber, &if_argisnotheapnumber);
   3887 
   3888     assembler->Bind(&if_argisheapnumber);
   3889     {
   3890       // Load the floating-point value of {arg}.
   3891       Node* arg_value = assembler->LoadHeapNumberValue(arg);
   3892 
   3893       // Check if {arg} is NaN.
   3894       assembler->GotoUnless(assembler->Float64Equal(arg_value, arg_value),
   3895                             &return_zero);
   3896 
   3897       // Truncate {arg} towards zero.
   3898       Node* value = assembler->Float64Trunc(arg_value);
   3899       var_arg.Bind(assembler->ChangeFloat64ToTagged(value));
   3900       assembler->Goto(&return_arg);
   3901     }
   3902 
   3903     assembler->Bind(&if_argisnotheapnumber);
   3904     {
   3905       // Need to convert {arg} to a Number first.
   3906       Callable callable = CodeFactory::NonNumberToNumber(assembler->isolate());
   3907       var_arg.Bind(assembler->CallStub(callable, context, arg));
   3908       assembler->Goto(&loop);
   3909     }
   3910 
   3911     assembler->Bind(&return_arg);
   3912     assembler->Return(var_arg.value());
   3913 
   3914     assembler->Bind(&return_zero);
   3915     assembler->Return(assembler->SmiConstant(Smi::FromInt(0)));
   3916   }
   3917 }
   3918 
   3919 void StoreInterceptorStub::GenerateAssembly(
   3920     CodeStubAssembler* assembler) const {
   3921   typedef compiler::Node Node;
   3922   Node* receiver = assembler->Parameter(0);
   3923   Node* name = assembler->Parameter(1);
   3924   Node* value = assembler->Parameter(2);
   3925   Node* context = assembler->Parameter(3);
   3926   assembler->TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context,
   3927                              receiver, name, value);
   3928 }
   3929 
   3930 void LoadIndexedInterceptorStub::GenerateAssembly(
   3931     CodeStubAssembler* assembler) const {
   3932   typedef compiler::Node Node;
   3933   typedef CodeStubAssembler::Label Label;
   3934   Node* receiver = assembler->Parameter(0);
   3935   Node* key = assembler->Parameter(1);
   3936   Node* slot = assembler->Parameter(2);
   3937   Node* vector = assembler->Parameter(3);
   3938   Node* context = assembler->Parameter(4);
   3939 
   3940   Label if_keyispositivesmi(assembler), if_keyisinvalid(assembler);
   3941   assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositivesmi,
   3942                     &if_keyisinvalid);
   3943   assembler->Bind(&if_keyispositivesmi);
   3944   assembler->TailCallRuntime(Runtime::kLoadElementWithInterceptor, context,
   3945                              receiver, key);
   3946 
   3947   assembler->Bind(&if_keyisinvalid);
   3948   assembler->TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key,
   3949                              slot, vector);
   3950 }
   3951 
   3952 // static
   3953 bool FastCloneShallowObjectStub::IsSupported(ObjectLiteral* expr) {
   3954   // FastCloneShallowObjectStub doesn't copy elements, and object literals don't
   3955   // support copy-on-write (COW) elements for now.
   3956   // TODO(mvstanton): make object literals support COW elements.
   3957   return expr->fast_elements() && expr->has_shallow_properties() &&
   3958          expr->properties_count() <= kMaximumClonedProperties;
   3959 }
   3960 
   3961 // static
   3962 int FastCloneShallowObjectStub::PropertiesCount(int literal_length) {
   3963   // This heuristic of setting empty literals to have
   3964   // kInitialGlobalObjectUnusedPropertiesCount must remain in-sync with the
   3965   // runtime.
   3966   // TODO(verwaest): Unify this with the heuristic in the runtime.
   3967   return literal_length == 0
   3968              ? JSObject::kInitialGlobalObjectUnusedPropertiesCount
   3969              : literal_length;
   3970 }
   3971 
   3972 // static
   3973 compiler::Node* FastCloneShallowObjectStub::GenerateFastPath(
   3974     CodeStubAssembler* assembler, compiler::CodeAssembler::Label* call_runtime,
   3975     compiler::Node* closure, compiler::Node* literals_index,
   3976     compiler::Node* properties_count) {
   3977   typedef compiler::Node Node;
   3978   typedef compiler::CodeAssembler::Label Label;
   3979   typedef compiler::CodeAssembler::Variable Variable;
   3980 
   3981   Node* undefined = assembler->UndefinedConstant();
   3982   Node* literals_array =
   3983       assembler->LoadObjectField(closure, JSFunction::kLiteralsOffset);
   3984   Node* allocation_site = assembler->LoadFixedArrayElement(
   3985       literals_array, literals_index,
   3986       LiteralsArray::kFirstLiteralIndex * kPointerSize,
   3987       CodeStubAssembler::SMI_PARAMETERS);
   3988   assembler->GotoIf(assembler->WordEqual(allocation_site, undefined),
   3989                     call_runtime);
   3990 
   3991   // Calculate the object and allocation size based on the properties count.
   3992   Node* object_size = assembler->IntPtrAdd(
   3993       assembler->WordShl(properties_count, kPointerSizeLog2),
   3994       assembler->IntPtrConstant(JSObject::kHeaderSize));
   3995   Node* allocation_size = object_size;
   3996   if (FLAG_allocation_site_pretenuring) {
   3997     allocation_size = assembler->IntPtrAdd(
   3998         object_size, assembler->IntPtrConstant(AllocationMemento::kSize));
   3999   }
   4000   Node* boilerplate = assembler->LoadObjectField(
   4001       allocation_site, AllocationSite::kTransitionInfoOffset);
   4002   Node* boilerplate_map = assembler->LoadMap(boilerplate);
   4003   Node* instance_size = assembler->LoadMapInstanceSize(boilerplate_map);
   4004   Node* size_in_words = assembler->WordShr(object_size, kPointerSizeLog2);
   4005   assembler->GotoUnless(assembler->Word32Equal(instance_size, size_in_words),
   4006                         call_runtime);
   4007 
   4008   Node* copy = assembler->Allocate(allocation_size);
   4009 
   4010   // Copy boilerplate elements.
   4011   Variable offset(assembler, MachineType::PointerRepresentation());
   4012   offset.Bind(assembler->IntPtrConstant(-kHeapObjectTag));
   4013   Node* end_offset = assembler->IntPtrAdd(object_size, offset.value());
   4014   Label loop_body(assembler, &offset), loop_check(assembler, &offset);
   4015   // We should always have an object size greater than zero.
   4016   assembler->Goto(&loop_body);
   4017   assembler->Bind(&loop_body);
   4018   {
   4019     // The Allocate above guarantees that the copy lies in new space. This
   4020     // allows us to skip write barriers. This is necessary since we may also be
   4021     // copying unboxed doubles.
   4022     Node* field =
   4023         assembler->Load(MachineType::IntPtr(), boilerplate, offset.value());
   4024     assembler->StoreNoWriteBarrier(MachineType::PointerRepresentation(), copy,
   4025                                    offset.value(), field);
   4026     assembler->Goto(&loop_check);
   4027   }
   4028   assembler->Bind(&loop_check);
   4029   {
   4030     offset.Bind(assembler->IntPtrAdd(offset.value(),
   4031                                      assembler->IntPtrConstant(kPointerSize)));
   4032     assembler->GotoUnless(
   4033         assembler->IntPtrGreaterThanOrEqual(offset.value(), end_offset),
   4034         &loop_body);
   4035   }
   4036 
   4037   if (FLAG_allocation_site_pretenuring) {
   4038     Node* memento = assembler->InnerAllocate(copy, object_size);
   4039     assembler->StoreObjectFieldNoWriteBarrier(
   4040         memento, HeapObject::kMapOffset,
   4041         assembler->LoadRoot(Heap::kAllocationMementoMapRootIndex));
   4042     assembler->StoreObjectFieldNoWriteBarrier(
   4043         memento, AllocationMemento::kAllocationSiteOffset, allocation_site);
   4044     Node* memento_create_count = assembler->LoadObjectField(
   4045         allocation_site, AllocationSite::kPretenureCreateCountOffset);
   4046     memento_create_count = assembler->SmiAdd(
   4047         memento_create_count, assembler->SmiConstant(Smi::FromInt(1)));
   4048     assembler->StoreObjectFieldNoWriteBarrier(
   4049         allocation_site, AllocationSite::kPretenureCreateCountOffset,
   4050         memento_create_count);
   4051   }
   4052 
   4053   // TODO(verwaest): Allocate and fill in double boxes.
   4054   return copy;
   4055 }
   4056 
   4057 void FastCloneShallowObjectStub::GenerateAssembly(
   4058     CodeStubAssembler* assembler) const {
   4059   typedef CodeStubAssembler::Label Label;
   4060   typedef compiler::Node Node;
   4061   Label call_runtime(assembler);
   4062   Node* closure = assembler->Parameter(0);
   4063   Node* literals_index = assembler->Parameter(1);
   4064 
   4065   Node* properties_count =
   4066       assembler->IntPtrConstant(PropertiesCount(this->length()));
   4067   Node* copy = GenerateFastPath(assembler, &call_runtime, closure,
   4068                                 literals_index, properties_count);
   4069   assembler->Return(copy);
   4070 
   4071   assembler->Bind(&call_runtime);
   4072   Node* constant_properties = assembler->Parameter(2);
   4073   Node* flags = assembler->Parameter(3);
   4074   Node* context = assembler->Parameter(4);
   4075   assembler->TailCallRuntime(Runtime::kCreateObjectLiteral, context, closure,
   4076                              literals_index, constant_properties, flags);
   4077 }
   4078 
   4079 template<class StateType>
   4080 void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
   4081   // Note: Although a no-op transition is semantically OK, it is hinting at a
   4082   // bug somewhere in our state transition machinery.
   4083   DCHECK(from != to);
   4084   if (!FLAG_trace_ic) return;
   4085   OFStream os(stdout);
   4086   os << "[";
   4087   PrintBaseName(os);
   4088   os << ": " << from << "=>" << to << "]" << std::endl;
   4089 }
   4090 
   4091 
   4092 // TODO(svenpanne) Make this a real infix_ostream_iterator.
   4093 class SimpleListPrinter {
   4094  public:
   4095   explicit SimpleListPrinter(std::ostream& os) : os_(os), first_(true) {}
   4096 
   4097   void Add(const char* s) {
   4098     if (first_) {
   4099       first_ = false;
   4100     } else {
   4101       os_ << ",";
   4102     }
   4103     os_ << s;
   4104   }
   4105 
   4106  private:
   4107   std::ostream& os_;
   4108   bool first_;
   4109 };
   4110 
   4111 
   4112 void CallICStub::PrintState(std::ostream& os) const {  // NOLINT
   4113   os << state();
   4114 }
   4115 
   4116 
   4117 void JSEntryStub::FinishCode(Handle<Code> code) {
   4118   Handle<FixedArray> handler_table =
   4119       code->GetIsolate()->factory()->NewFixedArray(1, TENURED);
   4120   handler_table->set(0, Smi::FromInt(handler_offset_));
   4121   code->set_handler_table(*handler_table);
   4122 }
   4123 
   4124 
   4125 void LoadDictionaryElementStub::InitializeDescriptor(
   4126     CodeStubDescriptor* descriptor) {
   4127   descriptor->Initialize(
   4128       FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
   4129 }
   4130 
   4131 
   4132 void KeyedLoadGenericStub::InitializeDescriptor(
   4133     CodeStubDescriptor* descriptor) {
   4134   descriptor->Initialize(
   4135       Runtime::FunctionForId(Runtime::kKeyedGetProperty)->entry);
   4136 }
   4137 
   4138 
   4139 void HandlerStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4140   if (kind() == Code::STORE_IC) {
   4141     descriptor->Initialize(FUNCTION_ADDR(Runtime_StoreIC_MissFromStubFailure));
   4142   } else if (kind() == Code::KEYED_LOAD_IC) {
   4143     descriptor->Initialize(
   4144         FUNCTION_ADDR(Runtime_KeyedLoadIC_MissFromStubFailure));
   4145   } else if (kind() == Code::KEYED_STORE_IC) {
   4146     descriptor->Initialize(
   4147         FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
   4148   }
   4149 }
   4150 
   4151 
   4152 CallInterfaceDescriptor HandlerStub::GetCallInterfaceDescriptor() const {
   4153   if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
   4154     return LoadWithVectorDescriptor(isolate());
   4155   } else {
   4156     DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
   4157     return VectorStoreICDescriptor(isolate());
   4158   }
   4159 }
   4160 
   4161 
   4162 void StoreFastElementStub::InitializeDescriptor(
   4163     CodeStubDescriptor* descriptor) {
   4164   descriptor->Initialize(
   4165       FUNCTION_ADDR(Runtime_KeyedStoreIC_MissFromStubFailure));
   4166 }
   4167 
   4168 
   4169 void ElementsTransitionAndStoreStub::InitializeDescriptor(
   4170     CodeStubDescriptor* descriptor) {
   4171   descriptor->Initialize(
   4172       FUNCTION_ADDR(Runtime_ElementsTransitionAndStoreIC_Miss));
   4173 }
   4174 
   4175 
   4176 void ToObjectStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4177   descriptor->Initialize(Runtime::FunctionForId(Runtime::kToObject)->entry);
   4178 }
   4179 
   4180 
   4181 CallInterfaceDescriptor StoreTransitionStub::GetCallInterfaceDescriptor()
   4182     const {
   4183   return VectorStoreTransitionDescriptor(isolate());
   4184 }
   4185 
   4186 
   4187 CallInterfaceDescriptor
   4188 ElementsTransitionAndStoreStub::GetCallInterfaceDescriptor() const {
   4189   return VectorStoreTransitionDescriptor(isolate());
   4190 }
   4191 
   4192 void FastNewClosureStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
   4193 
   4194 void FastNewContextStub::InitializeDescriptor(CodeStubDescriptor* d) {}
   4195 
   4196 
   4197 void TypeofStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {}
   4198 
   4199 
   4200 void NumberToStringStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4201   descriptor->Initialize(
   4202       Runtime::FunctionForId(Runtime::kNumberToString)->entry);
   4203 }
   4204 
   4205 
   4206 void FastCloneRegExpStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4207   FastCloneRegExpDescriptor call_descriptor(isolate());
   4208   descriptor->Initialize(
   4209       Runtime::FunctionForId(Runtime::kCreateRegExpLiteral)->entry);
   4210 }
   4211 
   4212 
   4213 void FastCloneShallowArrayStub::InitializeDescriptor(
   4214     CodeStubDescriptor* descriptor) {
   4215   FastCloneShallowArrayDescriptor call_descriptor(isolate());
   4216   descriptor->Initialize(
   4217       Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry);
   4218 }
   4219 
   4220 
   4221 void CreateAllocationSiteStub::InitializeDescriptor(CodeStubDescriptor* d) {}
   4222 
   4223 
   4224 void CreateWeakCellStub::InitializeDescriptor(CodeStubDescriptor* d) {}
   4225 
   4226 
   4227 void RegExpConstructResultStub::InitializeDescriptor(
   4228     CodeStubDescriptor* descriptor) {
   4229   descriptor->Initialize(
   4230       Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry);
   4231 }
   4232 
   4233 
   4234 void TransitionElementsKindStub::InitializeDescriptor(
   4235     CodeStubDescriptor* descriptor) {
   4236   descriptor->Initialize(
   4237       Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry);
   4238 }
   4239 
   4240 
   4241 void AllocateHeapNumberStub::InitializeDescriptor(
   4242     CodeStubDescriptor* descriptor) {
   4243   descriptor->Initialize(
   4244       Runtime::FunctionForId(Runtime::kAllocateHeapNumber)->entry);
   4245 }
   4246 
   4247 
   4248 #define SIMD128_INIT_DESC(TYPE, Type, type, lane_count, lane_type) \
   4249   void Allocate##Type##Stub::InitializeDescriptor(                 \
   4250       CodeStubDescriptor* descriptor) {                            \
   4251     descriptor->Initialize(                                        \
   4252         Runtime::FunctionForId(Runtime::kCreate##Type)->entry);    \
   4253   }
   4254 SIMD128_TYPES(SIMD128_INIT_DESC)
   4255 #undef SIMD128_INIT_DESC
   4256 
   4257 void ToBooleanICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4258   descriptor->Initialize(FUNCTION_ADDR(Runtime_ToBooleanIC_Miss));
   4259   descriptor->SetMissHandler(ExternalReference(
   4260       Runtime::FunctionForId(Runtime::kToBooleanIC_Miss), isolate()));
   4261 }
   4262 
   4263 
   4264 void BinaryOpICStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4265   descriptor->Initialize(FUNCTION_ADDR(Runtime_BinaryOpIC_Miss));
   4266   descriptor->SetMissHandler(ExternalReference(
   4267       Runtime::FunctionForId(Runtime::kBinaryOpIC_Miss), isolate()));
   4268 }
   4269 
   4270 
   4271 void BinaryOpWithAllocationSiteStub::InitializeDescriptor(
   4272     CodeStubDescriptor* descriptor) {
   4273   descriptor->Initialize(
   4274       FUNCTION_ADDR(Runtime_BinaryOpIC_MissWithAllocationSite));
   4275 }
   4276 
   4277 
   4278 void StringAddStub::InitializeDescriptor(CodeStubDescriptor* descriptor) {
   4279   descriptor->Initialize(Runtime::FunctionForId(Runtime::kStringAdd)->entry);
   4280 }
   4281 
   4282 
   4283 void GrowArrayElementsStub::InitializeDescriptor(
   4284     CodeStubDescriptor* descriptor) {
   4285   descriptor->Initialize(
   4286       Runtime::FunctionForId(Runtime::kGrowArrayElements)->entry);
   4287 }
   4288 
   4289 
   4290 void TypeofStub::GenerateAheadOfTime(Isolate* isolate) {
   4291   TypeofStub stub(isolate);
   4292   stub.GetCode();
   4293 }
   4294 
   4295 // static
   4296 compiler::Node* HasPropertyStub::Generate(CodeStubAssembler* assembler,
   4297                                           compiler::Node* key,
   4298                                           compiler::Node* object,
   4299                                           compiler::Node* context) {
   4300   typedef compiler::Node Node;
   4301   typedef CodeStubAssembler::Label Label;
   4302   typedef CodeStubAssembler::Variable Variable;
   4303 
   4304   Label call_runtime(assembler, Label::kDeferred), return_true(assembler),
   4305       return_false(assembler), end(assembler);
   4306 
   4307   // Ensure object is JSReceiver, otherwise call runtime to throw error.
   4308   Label if_objectisnotsmi(assembler);
   4309   assembler->Branch(assembler->WordIsSmi(object), &call_runtime,
   4310                     &if_objectisnotsmi);
   4311   assembler->Bind(&if_objectisnotsmi);
   4312 
   4313   Node* map = assembler->LoadMap(object);
   4314   Node* instance_type = assembler->LoadMapInstanceType(map);
   4315   {
   4316     Label if_objectisreceiver(assembler);
   4317     STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   4318     assembler->Branch(
   4319         assembler->Int32GreaterThanOrEqual(
   4320             instance_type, assembler->Int32Constant(FIRST_JS_RECEIVER_TYPE)),
   4321         &if_objectisreceiver, &call_runtime);
   4322     assembler->Bind(&if_objectisreceiver);
   4323   }
   4324 
   4325   Variable var_index(assembler, MachineRepresentation::kWord32);
   4326 
   4327   Label keyisindex(assembler), if_iskeyunique(assembler);
   4328   assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique,
   4329                        &call_runtime);
   4330 
   4331   assembler->Bind(&if_iskeyunique);
   4332   {
   4333     Variable var_object(assembler, MachineRepresentation::kTagged);
   4334     Variable var_map(assembler, MachineRepresentation::kTagged);
   4335     Variable var_instance_type(assembler, MachineRepresentation::kWord8);
   4336 
   4337     Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
   4338     Label loop(assembler, arraysize(merged_variables), merged_variables);
   4339     var_object.Bind(object);
   4340     var_map.Bind(map);
   4341     var_instance_type.Bind(instance_type);
   4342     assembler->Goto(&loop);
   4343     assembler->Bind(&loop);
   4344     {
   4345       Label next_proto(assembler);
   4346       assembler->TryHasOwnProperty(var_object.value(), var_map.value(),
   4347                                    var_instance_type.value(), key, &return_true,
   4348                                    &next_proto, &call_runtime);
   4349       assembler->Bind(&next_proto);
   4350 
   4351       Node* proto = assembler->LoadMapPrototype(var_map.value());
   4352 
   4353       Label if_not_null(assembler);
   4354       assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
   4355                         &return_false, &if_not_null);
   4356       assembler->Bind(&if_not_null);
   4357 
   4358       Node* map = assembler->LoadMap(proto);
   4359       Node* instance_type = assembler->LoadMapInstanceType(map);
   4360 
   4361       var_object.Bind(proto);
   4362       var_map.Bind(map);
   4363       var_instance_type.Bind(instance_type);
   4364       assembler->Goto(&loop);
   4365     }
   4366   }
   4367   assembler->Bind(&keyisindex);
   4368   {
   4369     Variable var_object(assembler, MachineRepresentation::kTagged);
   4370     Variable var_map(assembler, MachineRepresentation::kTagged);
   4371     Variable var_instance_type(assembler, MachineRepresentation::kWord8);
   4372 
   4373     Variable* merged_variables[] = {&var_object, &var_map, &var_instance_type};
   4374     Label loop(assembler, arraysize(merged_variables), merged_variables);
   4375     var_object.Bind(object);
   4376     var_map.Bind(map);
   4377     var_instance_type.Bind(instance_type);
   4378     assembler->Goto(&loop);
   4379     assembler->Bind(&loop);
   4380     {
   4381       Label next_proto(assembler);
   4382       assembler->TryLookupElement(var_object.value(), var_map.value(),
   4383                                   var_instance_type.value(), var_index.value(),
   4384                                   &return_true, &next_proto, &call_runtime);
   4385       assembler->Bind(&next_proto);
   4386 
   4387       Node* proto = assembler->LoadMapPrototype(var_map.value());
   4388 
   4389       Label if_not_null(assembler);
   4390       assembler->Branch(assembler->WordEqual(proto, assembler->NullConstant()),
   4391                         &return_false, &if_not_null);
   4392       assembler->Bind(&if_not_null);
   4393 
   4394       Node* map = assembler->LoadMap(proto);
   4395       Node* instance_type = assembler->LoadMapInstanceType(map);
   4396 
   4397       var_object.Bind(proto);
   4398       var_map.Bind(map);
   4399       var_instance_type.Bind(instance_type);
   4400       assembler->Goto(&loop);
   4401     }
   4402   }
   4403 
   4404   Variable result(assembler, MachineRepresentation::kTagged);
   4405   assembler->Bind(&return_true);
   4406   {
   4407     result.Bind(assembler->BooleanConstant(true));
   4408     assembler->Goto(&end);
   4409   }
   4410 
   4411   assembler->Bind(&return_false);
   4412   {
   4413     result.Bind(assembler->BooleanConstant(false));
   4414     assembler->Goto(&end);
   4415   }
   4416 
   4417   assembler->Bind(&call_runtime);
   4418   {
   4419     result.Bind(
   4420         assembler->CallRuntime(Runtime::kHasProperty, context, key, object));
   4421     assembler->Goto(&end);
   4422   }
   4423 
   4424   assembler->Bind(&end);
   4425   return result.value();
   4426 }
   4427 
   4428 void CreateAllocationSiteStub::GenerateAheadOfTime(Isolate* isolate) {
   4429   CreateAllocationSiteStub stub(isolate);
   4430   stub.GetCode();
   4431 }
   4432 
   4433 
   4434 void CreateWeakCellStub::GenerateAheadOfTime(Isolate* isolate) {
   4435   CreateWeakCellStub stub(isolate);
   4436   stub.GetCode();
   4437 }
   4438 
   4439 
   4440 void StoreElementStub::Generate(MacroAssembler* masm) {
   4441   DCHECK_EQ(DICTIONARY_ELEMENTS, elements_kind());
   4442   ElementHandlerCompiler::GenerateStoreSlow(masm);
   4443 }
   4444 
   4445 
   4446 // static
   4447 void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
   4448   StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS, STANDARD_STORE)
   4449       .GetCode();
   4450   StoreFastElementStub(isolate, false, FAST_HOLEY_ELEMENTS,
   4451                        STORE_AND_GROW_NO_TRANSITION).GetCode();
   4452   for (int i = FIRST_FAST_ELEMENTS_KIND; i <= LAST_FAST_ELEMENTS_KIND; i++) {
   4453     ElementsKind kind = static_cast<ElementsKind>(i);
   4454     StoreFastElementStub(isolate, true, kind, STANDARD_STORE).GetCode();
   4455     StoreFastElementStub(isolate, true, kind, STORE_AND_GROW_NO_TRANSITION)
   4456         .GetCode();
   4457   }
   4458 }
   4459 
   4460 
   4461 void ArrayConstructorStub::PrintName(std::ostream& os) const {  // NOLINT
   4462   os << "ArrayConstructorStub";
   4463   switch (argument_count()) {
   4464     case ANY:
   4465       os << "_Any";
   4466       break;
   4467     case NONE:
   4468       os << "_None";
   4469       break;
   4470     case ONE:
   4471       os << "_One";
   4472       break;
   4473     case MORE_THAN_ONE:
   4474       os << "_More_Than_One";
   4475       break;
   4476   }
   4477   return;
   4478 }
   4479 
   4480 
   4481 bool ToBooleanICStub::UpdateStatus(Handle<Object> object) {
   4482   Types new_types = types();
   4483   Types old_types = new_types;
   4484   bool to_boolean_value = new_types.UpdateStatus(isolate(), object);
   4485   TraceTransition(old_types, new_types);
   4486   set_sub_minor_key(TypesBits::update(sub_minor_key(), new_types.ToIntegral()));
   4487   return to_boolean_value;
   4488 }
   4489 
   4490 void ToBooleanICStub::PrintState(std::ostream& os) const {  // NOLINT
   4491   os << types();
   4492 }
   4493 
   4494 std::ostream& operator<<(std::ostream& os, const ToBooleanICStub::Types& s) {
   4495   os << "(";
   4496   SimpleListPrinter p(os);
   4497   if (s.IsEmpty()) p.Add("None");
   4498   if (s.Contains(ToBooleanICStub::UNDEFINED)) p.Add("Undefined");
   4499   if (s.Contains(ToBooleanICStub::BOOLEAN)) p.Add("Bool");
   4500   if (s.Contains(ToBooleanICStub::NULL_TYPE)) p.Add("Null");
   4501   if (s.Contains(ToBooleanICStub::SMI)) p.Add("Smi");
   4502   if (s.Contains(ToBooleanICStub::SPEC_OBJECT)) p.Add("SpecObject");
   4503   if (s.Contains(ToBooleanICStub::STRING)) p.Add("String");
   4504   if (s.Contains(ToBooleanICStub::SYMBOL)) p.Add("Symbol");
   4505   if (s.Contains(ToBooleanICStub::HEAP_NUMBER)) p.Add("HeapNumber");
   4506   if (s.Contains(ToBooleanICStub::SIMD_VALUE)) p.Add("SimdValue");
   4507   return os << ")";
   4508 }
   4509 
   4510 bool ToBooleanICStub::Types::UpdateStatus(Isolate* isolate,
   4511                                           Handle<Object> object) {
   4512   if (object->IsUndefined(isolate)) {
   4513     Add(UNDEFINED);
   4514     return false;
   4515   } else if (object->IsBoolean()) {
   4516     Add(BOOLEAN);
   4517     return object->IsTrue(isolate);
   4518   } else if (object->IsNull(isolate)) {
   4519     Add(NULL_TYPE);
   4520     return false;
   4521   } else if (object->IsSmi()) {
   4522     Add(SMI);
   4523     return Smi::cast(*object)->value() != 0;
   4524   } else if (object->IsJSReceiver()) {
   4525     Add(SPEC_OBJECT);
   4526     return !object->IsUndetectable();
   4527   } else if (object->IsString()) {
   4528     DCHECK(!object->IsUndetectable());
   4529     Add(STRING);
   4530     return String::cast(*object)->length() != 0;
   4531   } else if (object->IsSymbol()) {
   4532     Add(SYMBOL);
   4533     return true;
   4534   } else if (object->IsHeapNumber()) {
   4535     DCHECK(!object->IsUndetectable());
   4536     Add(HEAP_NUMBER);
   4537     double value = HeapNumber::cast(*object)->value();
   4538     return value != 0 && !std::isnan(value);
   4539   } else if (object->IsSimd128Value()) {
   4540     Add(SIMD_VALUE);
   4541     return true;
   4542   } else {
   4543     // We should never see an internal object at runtime here!
   4544     UNREACHABLE();
   4545     return true;
   4546   }
   4547 }
   4548 
   4549 bool ToBooleanICStub::Types::NeedsMap() const {
   4550   return Contains(ToBooleanICStub::SPEC_OBJECT) ||
   4551          Contains(ToBooleanICStub::STRING) ||
   4552          Contains(ToBooleanICStub::SYMBOL) ||
   4553          Contains(ToBooleanICStub::HEAP_NUMBER) ||
   4554          Contains(ToBooleanICStub::SIMD_VALUE);
   4555 }
   4556 
   4557 
   4558 void StubFailureTrampolineStub::GenerateAheadOfTime(Isolate* isolate) {
   4559   StubFailureTrampolineStub stub1(isolate, NOT_JS_FUNCTION_STUB_MODE);
   4560   StubFailureTrampolineStub stub2(isolate, JS_FUNCTION_STUB_MODE);
   4561   stub1.GetCode();
   4562   stub2.GetCode();
   4563 }
   4564 
   4565 
   4566 void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
   4567                                                intptr_t stack_pointer,
   4568                                                Isolate* isolate) {
   4569   FunctionEntryHook entry_hook = isolate->function_entry_hook();
   4570   DCHECK(entry_hook != NULL);
   4571   entry_hook(function, stack_pointer);
   4572 }
   4573 
   4574 void ArrayNoArgumentConstructorStub::GenerateAssembly(
   4575     CodeStubAssembler* assembler) const {
   4576   typedef compiler::Node Node;
   4577   Node* native_context = assembler->LoadObjectField(
   4578       assembler->Parameter(
   4579           ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
   4580       JSFunction::kContextOffset);
   4581   bool track_allocation_site =
   4582       AllocationSite::GetMode(elements_kind()) == TRACK_ALLOCATION_SITE &&
   4583       override_mode() != DISABLE_ALLOCATION_SITES;
   4584   Node* allocation_site =
   4585       track_allocation_site
   4586           ? assembler->Parameter(
   4587                 ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex)
   4588           : nullptr;
   4589   Node* array_map =
   4590       assembler->LoadJSArrayElementsMap(elements_kind(), native_context);
   4591   Node* array = assembler->AllocateJSArray(
   4592       elements_kind(), array_map,
   4593       assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
   4594       assembler->IntPtrConstant(0), allocation_site);
   4595   assembler->Return(array);
   4596 }
   4597 
   4598 void InternalArrayNoArgumentConstructorStub::GenerateAssembly(
   4599     CodeStubAssembler* assembler) const {
   4600   typedef compiler::Node Node;
   4601   Node* array_map = assembler->LoadObjectField(
   4602       assembler->Parameter(
   4603           ArrayNoArgumentConstructorDescriptor::kFunctionIndex),
   4604       JSFunction::kPrototypeOrInitialMapOffset);
   4605   Node* array = assembler->AllocateJSArray(
   4606       elements_kind(), array_map,
   4607       assembler->IntPtrConstant(JSArray::kPreallocatedArrayElements),
   4608       assembler->IntPtrConstant(0), nullptr);
   4609   assembler->Return(array);
   4610 }
   4611 
   4612 namespace {
   4613 
   4614 void SingleArgumentConstructorCommon(CodeStubAssembler* assembler,
   4615                                      ElementsKind elements_kind,
   4616                                      compiler::Node* array_map,
   4617                                      compiler::Node* allocation_site,
   4618                                      AllocationSiteMode mode) {
   4619   typedef compiler::Node Node;
   4620   typedef CodeStubAssembler::Label Label;
   4621 
   4622   Label ok(assembler);
   4623   Label smi_size(assembler);
   4624   Label small_smi_size(assembler);
   4625   Label call_runtime(assembler, Label::kDeferred);
   4626 
   4627   Node* size = assembler->Parameter(
   4628       ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex);
   4629   assembler->Branch(assembler->WordIsSmi(size), &smi_size, &call_runtime);
   4630 
   4631   assembler->Bind(&smi_size);
   4632   int element_size =
   4633       IsFastDoubleElementsKind(elements_kind) ? kDoubleSize : kPointerSize;
   4634   int max_fast_elements =
   4635       (Page::kMaxRegularHeapObjectSize - FixedArray::kHeaderSize -
   4636        JSArray::kSize - AllocationMemento::kSize) /
   4637       element_size;
   4638   assembler->Branch(
   4639       assembler->SmiAboveOrEqual(
   4640           size, assembler->SmiConstant(Smi::FromInt(max_fast_elements))),
   4641       &call_runtime, &small_smi_size);
   4642 
   4643   assembler->Bind(&small_smi_size);
   4644   {
   4645     Node* array = assembler->AllocateJSArray(
   4646         elements_kind, array_map, size, size,
   4647         mode == DONT_TRACK_ALLOCATION_SITE ? nullptr : allocation_site,
   4648         CodeStubAssembler::SMI_PARAMETERS);
   4649     assembler->Return(array);
   4650   }
   4651 
   4652   assembler->Bind(&call_runtime);
   4653   {
   4654     Node* context = assembler->Parameter(
   4655         ArraySingleArgumentConstructorDescriptor::kContextIndex);
   4656     Node* function = assembler->Parameter(
   4657         ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
   4658     Node* array_size = assembler->Parameter(
   4659         ArraySingleArgumentConstructorDescriptor::kArraySizeSmiParameterIndex);
   4660     Node* allocation_site = assembler->Parameter(
   4661         ArraySingleArgumentConstructorDescriptor::kAllocationSiteIndex);
   4662     assembler->TailCallRuntime(Runtime::kNewArray, context, function,
   4663                                array_size, function, allocation_site);
   4664   }
   4665 }
   4666 }  // namespace
   4667 
   4668 void ArraySingleArgumentConstructorStub::GenerateAssembly(
   4669     CodeStubAssembler* assembler) const {
   4670   typedef compiler::Node Node;
   4671   Node* function = assembler->Parameter(
   4672       ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
   4673   Node* native_context =
   4674       assembler->LoadObjectField(function, JSFunction::kContextOffset);
   4675   Node* array_map =
   4676       assembler->LoadJSArrayElementsMap(elements_kind(), native_context);
   4677   AllocationSiteMode mode = override_mode() == DISABLE_ALLOCATION_SITES
   4678                                 ? DONT_TRACK_ALLOCATION_SITE
   4679                                 : AllocationSite::GetMode(elements_kind());
   4680   Node* allocation_site = assembler->Parameter(
   4681       ArrayNoArgumentConstructorDescriptor::kAllocationSiteIndex);
   4682   SingleArgumentConstructorCommon(assembler, elements_kind(), array_map,
   4683                                   allocation_site, mode);
   4684 }
   4685 
   4686 void InternalArraySingleArgumentConstructorStub::GenerateAssembly(
   4687     CodeStubAssembler* assembler) const {
   4688   typedef compiler::Node Node;
   4689   Node* function = assembler->Parameter(
   4690       ArraySingleArgumentConstructorDescriptor::kFunctionIndex);
   4691   Node* array_map = assembler->LoadObjectField(
   4692       function, JSFunction::kPrototypeOrInitialMapOffset);
   4693   SingleArgumentConstructorCommon(assembler, elements_kind(), array_map,
   4694                                   assembler->UndefinedConstant(),
   4695                                   DONT_TRACK_ALLOCATION_SITE);
   4696 }
   4697 
   4698 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate)
   4699     : PlatformCodeStub(isolate) {
   4700   minor_key_ = ArgumentCountBits::encode(ANY);
   4701 }
   4702 
   4703 
   4704 ArrayConstructorStub::ArrayConstructorStub(Isolate* isolate,
   4705                                            int argument_count)
   4706     : PlatformCodeStub(isolate) {
   4707   if (argument_count == 0) {
   4708     minor_key_ = ArgumentCountBits::encode(NONE);
   4709   } else if (argument_count == 1) {
   4710     minor_key_ = ArgumentCountBits::encode(ONE);
   4711   } else if (argument_count >= 2) {
   4712     minor_key_ = ArgumentCountBits::encode(MORE_THAN_ONE);
   4713   } else {
   4714     UNREACHABLE();
   4715   }
   4716 }
   4717 
   4718 InternalArrayConstructorStub::InternalArrayConstructorStub(Isolate* isolate)
   4719     : PlatformCodeStub(isolate) {}
   4720 
   4721 Representation RepresentationFromType(Type* type) {
   4722   if (type->Is(Type::UntaggedIntegral())) {
   4723     return Representation::Integer32();
   4724   }
   4725 
   4726   if (type->Is(Type::TaggedSigned())) {
   4727     return Representation::Smi();
   4728   }
   4729 
   4730   if (type->Is(Type::UntaggedPointer())) {
   4731     return Representation::External();
   4732   }
   4733 
   4734   DCHECK(!type->Is(Type::Untagged()));
   4735   return Representation::Tagged();
   4736 }
   4737 
   4738 }  // namespace internal
   4739 }  // namespace v8
   4740