Home | History | Annotate | Download | only in ic
      1 // Copyright 2016 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/ic/accessor-assembler.h"
      6 
      7 #include "src/code-factory.h"
      8 #include "src/code-stubs.h"
      9 #include "src/counters.h"
     10 #include "src/ic/handler-configuration.h"
     11 #include "src/ic/stub-cache.h"
     12 #include "src/objects-inl.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 using compiler::CodeAssemblerState;
     18 using compiler::Node;
     19 
     20 //////////////////// Private helpers.
     21 
     22 Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector,
     23                                             Node* receiver_map,
     24                                             Label* if_handler,
     25                                             Variable* var_handler,
     26                                             Label* if_miss) {
     27   Comment("TryMonomorphicCase");
     28   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
     29 
     30   // TODO(ishell): add helper class that hides offset computations for a series
     31   // of loads.
     32   int32_t header_size = FixedArray::kHeaderSize - kHeapObjectTag;
     33   // Adding |header_size| with a separate IntPtrAdd rather than passing it
     34   // into ElementOffsetFromIndex() allows it to be folded into a single
     35   // [base, index, offset] indirect memory access on x64.
     36   Node* offset =
     37       ElementOffsetFromIndex(slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS);
     38   Node* feedback = Load(MachineType::AnyTagged(), vector,
     39                         IntPtrAdd(offset, IntPtrConstant(header_size)));
     40 
     41   // Try to quickly handle the monomorphic case without knowing for sure
     42   // if we have a weak cell in feedback. We do know it's safe to look
     43   // at WeakCell::kValueOffset.
     44   GotoIf(WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback)),
     45          if_miss);
     46 
     47   Node* handler =
     48       Load(MachineType::AnyTagged(), vector,
     49            IntPtrAdd(offset, IntPtrConstant(header_size + kPointerSize)));
     50 
     51   var_handler->Bind(handler);
     52   Goto(if_handler);
     53   return feedback;
     54 }
     55 
     56 void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
     57                                               Node* feedback, Label* if_handler,
     58                                               Variable* var_handler,
     59                                               Label* if_miss,
     60                                               int unroll_count) {
     61   Comment("HandlePolymorphicCase");
     62   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
     63 
     64   // Iterate {feedback} array.
     65   const int kEntrySize = 2;
     66 
     67   for (int i = 0; i < unroll_count; i++) {
     68     Label next_entry(this);
     69     Node* cached_map =
     70         LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize));
     71     GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
     72 
     73     // Found, now call handler.
     74     Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1);
     75     var_handler->Bind(handler);
     76     Goto(if_handler);
     77 
     78     Bind(&next_entry);
     79   }
     80 
     81   // Loop from {unroll_count}*kEntrySize to {length}.
     82   Node* init = IntPtrConstant(unroll_count * kEntrySize);
     83   Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
     84   BuildFastLoop(
     85       init, length,
     86       [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
     87         Node* cached_map =
     88             LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
     89 
     90         Label next_entry(this);
     91         GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
     92 
     93         // Found, now call handler.
     94         Node* handler = LoadFixedArrayElement(feedback, index, kPointerSize);
     95         var_handler->Bind(handler);
     96         Goto(if_handler);
     97 
     98         Bind(&next_entry);
     99       },
    100       kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    101   // The loop falls through if no handler was found.
    102   Goto(if_miss);
    103 }
    104 
    105 void AccessorAssembler::HandleKeyedStorePolymorphicCase(
    106     Node* receiver_map, Node* feedback, Label* if_handler,
    107     Variable* var_handler, Label* if_transition_handler,
    108     Variable* var_transition_map_cell, Label* if_miss) {
    109   DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
    110   DCHECK_EQ(MachineRepresentation::kTagged, var_transition_map_cell->rep());
    111 
    112   const int kEntrySize = 3;
    113 
    114   Node* init = IntPtrConstant(0);
    115   Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
    116   BuildFastLoop(init, length,
    117                 [this, receiver_map, feedback, if_handler, var_handler,
    118                  if_transition_handler, var_transition_map_cell](Node* index) {
    119                   Node* cached_map =
    120                       LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
    121                   Label next_entry(this);
    122                   GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
    123 
    124                   Node* maybe_transition_map_cell =
    125                       LoadFixedArrayElement(feedback, index, kPointerSize);
    126 
    127                   var_handler->Bind(
    128                       LoadFixedArrayElement(feedback, index, 2 * kPointerSize));
    129                   GotoIf(WordEqual(maybe_transition_map_cell,
    130                                    LoadRoot(Heap::kUndefinedValueRootIndex)),
    131                          if_handler);
    132                   var_transition_map_cell->Bind(maybe_transition_map_cell);
    133                   Goto(if_transition_handler);
    134 
    135                   Bind(&next_entry);
    136                 },
    137                 kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    138   // The loop falls through if no handler was found.
    139   Goto(if_miss);
    140 }
    141 
    142 void AccessorAssembler::HandleLoadICHandlerCase(
    143     const LoadICParameters* p, Node* handler, Label* miss,
    144     ElementSupport support_elements) {
    145   Comment("have_handler");
    146   ExitPoint direct_exit(this);
    147 
    148   Variable var_holder(this, MachineRepresentation::kTagged);
    149   var_holder.Bind(p->receiver);
    150   Variable var_smi_handler(this, MachineRepresentation::kTagged);
    151   var_smi_handler.Bind(handler);
    152 
    153   Variable* vars[] = {&var_holder, &var_smi_handler};
    154   Label if_smi_handler(this, 2, vars);
    155   Label try_proto_handler(this), call_handler(this);
    156 
    157   Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
    158 
    159   // |handler| is a Smi, encoding what to do. See SmiHandler methods
    160   // for the encoding format.
    161   Bind(&if_smi_handler);
    162   {
    163     HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
    164                                miss, &direct_exit, support_elements);
    165   }
    166 
    167   Bind(&try_proto_handler);
    168   {
    169     GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
    170     HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
    171                                  &if_smi_handler, miss, &direct_exit, false);
    172   }
    173 
    174   Bind(&call_handler);
    175   {
    176     typedef LoadWithVectorDescriptor Descriptor;
    177     TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver,
    178                  p->name, p->slot, p->vector);
    179   }
    180 }
    181 
    182 void AccessorAssembler::HandleLoadICSmiHandlerCase(
    183     const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
    184     ExitPoint* exit_point, ElementSupport support_elements) {
    185   Variable var_double_value(this, MachineRepresentation::kFloat64);
    186   Label rebox_double(this, &var_double_value);
    187 
    188   Node* handler_word = SmiUntag(smi_handler);
    189   Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
    190   if (support_elements == kSupportElements) {
    191     Label property(this);
    192     GotoIfNot(
    193         WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
    194         &property);
    195 
    196     Comment("element_load");
    197     Node* intptr_index = TryToIntptr(p->name, miss);
    198     Node* elements = LoadElements(holder);
    199     Node* is_jsarray_condition =
    200         IsSetWord<LoadHandler::IsJsArrayBits>(handler_word);
    201     Node* elements_kind =
    202         DecodeWord32FromWord<LoadHandler::ElementsKindBits>(handler_word);
    203     Label if_hole(this), unimplemented_elements_kind(this);
    204     Label* out_of_bounds = miss;
    205     EmitElementLoad(holder, elements, elements_kind, intptr_index,
    206                     is_jsarray_condition, &if_hole, &rebox_double,
    207                     &var_double_value, &unimplemented_elements_kind,
    208                     out_of_bounds, miss, exit_point);
    209 
    210     Bind(&unimplemented_elements_kind);
    211     {
    212       // Smi handlers should only be installed for supported elements kinds.
    213       // Crash if we get here.
    214       DebugBreak();
    215       Goto(miss);
    216     }
    217 
    218     Bind(&if_hole);
    219     {
    220       Comment("convert hole");
    221       GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
    222       Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
    223       DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
    224       GotoIfNot(
    225           WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
    226                     SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
    227           miss);
    228       exit_point->Return(UndefinedConstant());
    229     }
    230 
    231     Bind(&property);
    232     Comment("property_load");
    233   }
    234 
    235   Label constant(this), field(this);
    236   Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)),
    237          &field, &constant);
    238 
    239   Bind(&field);
    240   {
    241     Comment("field_load");
    242     Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word);
    243 
    244     Label inobject(this), out_of_object(this);
    245     Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
    246            &out_of_object);
    247 
    248     Bind(&inobject);
    249     {
    250       Label is_double(this);
    251       GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
    252       exit_point->Return(LoadObjectField(holder, offset));
    253 
    254       Bind(&is_double);
    255       if (FLAG_unbox_double_fields) {
    256         var_double_value.Bind(
    257             LoadObjectField(holder, offset, MachineType::Float64()));
    258       } else {
    259         Node* mutable_heap_number = LoadObjectField(holder, offset);
    260         var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number));
    261       }
    262       Goto(&rebox_double);
    263     }
    264 
    265     Bind(&out_of_object);
    266     {
    267       Label is_double(this);
    268       Node* properties = LoadProperties(holder);
    269       Node* value = LoadObjectField(properties, offset);
    270       GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
    271       exit_point->Return(value);
    272 
    273       Bind(&is_double);
    274       var_double_value.Bind(LoadHeapNumberValue(value));
    275       Goto(&rebox_double);
    276     }
    277 
    278     Bind(&rebox_double);
    279     exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
    280   }
    281 
    282   Bind(&constant);
    283   {
    284     Comment("constant_load");
    285     Node* descriptors = LoadMapDescriptors(LoadMap(holder));
    286     Node* descriptor =
    287         DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word);
    288     CSA_ASSERT(this,
    289                UintPtrLessThan(descriptor,
    290                                LoadAndUntagFixedArrayBaseLength(descriptors)));
    291     Node* value = LoadFixedArrayElement(descriptors, descriptor);
    292 
    293     Label if_accessor_info(this);
    294     GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
    295            &if_accessor_info);
    296     exit_point->Return(value);
    297 
    298     Bind(&if_accessor_info);
    299     Callable callable = CodeFactory::ApiGetter(isolate());
    300     exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
    301                                value);
    302   }
    303 }
    304 
    305 void AccessorAssembler::HandleLoadICProtoHandlerCase(
    306     const LoadICParameters* p, Node* handler, Variable* var_holder,
    307     Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
    308     ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
    309   DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
    310   DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
    311 
    312   // IC dispatchers rely on these assumptions to be held.
    313   STATIC_ASSERT(FixedArray::kLengthOffset == LoadHandler::kHolderCellOffset);
    314   DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kSmiHandlerIndex),
    315             LoadHandler::kSmiHandlerOffset);
    316   DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kValidityCellIndex),
    317             LoadHandler::kValidityCellOffset);
    318 
    319   // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
    320   Label validity_cell_check_done(this);
    321   Node* validity_cell =
    322       LoadObjectField(handler, LoadHandler::kValidityCellOffset);
    323   GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
    324          &validity_cell_check_done);
    325   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
    326   GotoIf(WordNotEqual(cell_value,
    327                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
    328          miss);
    329   Goto(&validity_cell_check_done);
    330 
    331   Bind(&validity_cell_check_done);
    332   Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
    333   CSA_ASSERT(this, TaggedIsSmi(smi_handler));
    334   Node* handler_flags = SmiUntag(smi_handler);
    335 
    336   Label check_prototypes(this);
    337   GotoIfNot(
    338       IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
    339       &check_prototypes);
    340   {
    341     CSA_ASSERT(this, Word32BinaryNot(
    342                          HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE)));
    343     // We have a dictionary receiver, do a negative lookup check.
    344     NameDictionaryNegativeLookup(p->receiver, p->name, miss);
    345     Goto(&check_prototypes);
    346   }
    347 
    348   Bind(&check_prototypes);
    349   Node* maybe_holder_cell =
    350       LoadObjectField(handler, LoadHandler::kHolderCellOffset);
    351   Label array_handler(this), tuple_handler(this);
    352   Branch(TaggedIsSmi(maybe_holder_cell), &array_handler, &tuple_handler);
    353 
    354   Bind(&tuple_handler);
    355   {
    356     Label load_existent(this);
    357     GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
    358     // This is a handler for a load of a non-existent value.
    359     if (throw_reference_error_if_nonexistent) {
    360       exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
    361                                     p->name);
    362     } else {
    363       exit_point->Return(UndefinedConstant());
    364     }
    365 
    366     Bind(&load_existent);
    367     Node* holder = LoadWeakCellValue(maybe_holder_cell);
    368     // The |holder| is guaranteed to be alive at this point since we passed
    369     // both the receiver map check and the validity cell check.
    370     CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
    371 
    372     var_holder->Bind(holder);
    373     var_smi_handler->Bind(smi_handler);
    374     Goto(if_smi_handler);
    375   }
    376 
    377   Bind(&array_handler);
    378   {
    379     exit_point->ReturnCallStub(
    380         CodeFactory::LoadICProtoArray(isolate(),
    381                                       throw_reference_error_if_nonexistent),
    382         p->context, p->receiver, p->name, p->slot, p->vector, handler);
    383   }
    384 }
    385 
    386 Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
    387     const LoadICParameters* p, Node* handler, Node* handler_length,
    388     Node* handler_flags, Label* miss,
    389     bool throw_reference_error_if_nonexistent) {
    390   Variable start_index(this, MachineType::PointerRepresentation());
    391   start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
    392 
    393   Label can_access(this);
    394   GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
    395             &can_access);
    396   {
    397     // Skip this entry of a handler.
    398     start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
    399 
    400     int offset =
    401         FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex);
    402     Node* expected_native_context =
    403         LoadWeakCellValue(LoadObjectField(handler, offset), miss);
    404     CSA_ASSERT(this, IsNativeContext(expected_native_context));
    405 
    406     Node* native_context = LoadNativeContext(p->context);
    407     GotoIf(WordEqual(expected_native_context, native_context), &can_access);
    408     // If the receiver is not a JSGlobalProxy then we miss.
    409     GotoIfNot(IsJSGlobalProxy(p->receiver), miss);
    410     // For JSGlobalProxy receiver try to compare security tokens of current
    411     // and expected native contexts.
    412     Node* expected_token = LoadContextElement(expected_native_context,
    413                                               Context::SECURITY_TOKEN_INDEX);
    414     Node* current_token =
    415         LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
    416     Branch(WordEqual(expected_token, current_token), &can_access, miss);
    417   }
    418   Bind(&can_access);
    419 
    420   BuildFastLoop(start_index.value(), handler_length,
    421                 [this, p, handler, miss](Node* current) {
    422                   Node* prototype_cell =
    423                       LoadFixedArrayElement(handler, current);
    424                   CheckPrototype(prototype_cell, p->name, miss);
    425                 },
    426                 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    427 
    428   Node* maybe_holder_cell =
    429       LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
    430   Label load_existent(this);
    431   GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
    432   // This is a handler for a load of a non-existent value.
    433   if (throw_reference_error_if_nonexistent) {
    434     TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name);
    435   } else {
    436     Return(UndefinedConstant());
    437   }
    438 
    439   Bind(&load_existent);
    440   Node* holder = LoadWeakCellValue(maybe_holder_cell);
    441   // The |holder| is guaranteed to be alive at this point since we passed
    442   // the receiver map check, the validity cell check and the prototype chain
    443   // check.
    444   CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
    445   return holder;
    446 }
    447 
    448 void AccessorAssembler::HandleLoadGlobalICHandlerCase(
    449     const LoadICParameters* pp, Node* handler, Label* miss,
    450     ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
    451   LoadICParameters p = *pp;
    452   DCHECK_NULL(p.receiver);
    453   Node* native_context = LoadNativeContext(p.context);
    454   p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX);
    455 
    456   Variable var_holder(this, MachineRepresentation::kTagged);
    457   Variable var_smi_handler(this, MachineRepresentation::kTagged);
    458   Label if_smi_handler(this);
    459   HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
    460                                &if_smi_handler, miss, exit_point,
    461                                throw_reference_error_if_nonexistent);
    462   Bind(&if_smi_handler);
    463   HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
    464                              miss, exit_point, kOnlyProperties);
    465 }
    466 
    467 void AccessorAssembler::HandleStoreICHandlerCase(
    468     const StoreICParameters* p, Node* handler, Label* miss,
    469     ElementSupport support_elements) {
    470   Label if_smi_handler(this), if_nonsmi_handler(this);
    471   Label if_proto_handler(this), if_element_handler(this), call_handler(this);
    472 
    473   Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
    474 
    475   // |handler| is a Smi, encoding what to do. See SmiHandler methods
    476   // for the encoding format.
    477   Bind(&if_smi_handler);
    478   {
    479     Node* holder = p->receiver;
    480     Node* handler_word = SmiUntag(handler);
    481 
    482     // Handle non-transitioning field stores.
    483     HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
    484   }
    485 
    486   Bind(&if_nonsmi_handler);
    487   {
    488     Node* handler_map = LoadMap(handler);
    489     if (support_elements == kSupportElements) {
    490       GotoIf(IsTuple2Map(handler_map), &if_element_handler);
    491     }
    492     Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
    493   }
    494 
    495   if (support_elements == kSupportElements) {
    496     Bind(&if_element_handler);
    497     { HandleStoreICElementHandlerCase(p, handler, miss); }
    498   }
    499 
    500   Bind(&if_proto_handler);
    501   {
    502     HandleStoreICProtoHandler(p, handler, miss);
    503   }
    504 
    505   // |handler| is a heap object. Must be code, call it.
    506   Bind(&call_handler);
    507   {
    508     StoreWithVectorDescriptor descriptor(isolate());
    509     TailCallStub(descriptor, handler, p->context, p->receiver, p->name,
    510                  p->value, p->slot, p->vector);
    511   }
    512 }
    513 
    514 void AccessorAssembler::HandleStoreICElementHandlerCase(
    515     const StoreICParameters* p, Node* handler, Label* miss) {
    516   Comment("HandleStoreICElementHandlerCase");
    517   Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
    518   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
    519   GotoIf(WordNotEqual(cell_value,
    520                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
    521          miss);
    522 
    523   Node* code_handler = LoadObjectField(handler, Tuple2::kValue2Offset);
    524   CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
    525 
    526   StoreWithVectorDescriptor descriptor(isolate());
    527   TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name,
    528                p->value, p->slot, p->vector);
    529 }
    530 
    531 void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
    532                                                   Node* handler, Label* miss) {
    533   // IC dispatchers rely on these assumptions to be held.
    534   STATIC_ASSERT(FixedArray::kLengthOffset ==
    535                 StoreHandler::kTransitionCellOffset);
    536   DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
    537             StoreHandler::kSmiHandlerOffset);
    538   DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
    539             StoreHandler::kValidityCellOffset);
    540 
    541   // Both FixedArray and Tuple3 handlers have validity cell at the same offset.
    542   Label validity_cell_check_done(this);
    543   Node* validity_cell =
    544       LoadObjectField(handler, StoreHandler::kValidityCellOffset);
    545   GotoIf(WordEqual(validity_cell, IntPtrConstant(0)),
    546          &validity_cell_check_done);
    547   Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
    548   GotoIf(WordNotEqual(cell_value,
    549                       SmiConstant(Smi::FromInt(Map::kPrototypeChainValid))),
    550          miss);
    551   Goto(&validity_cell_check_done);
    552 
    553   Bind(&validity_cell_check_done);
    554   Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
    555   CSA_ASSERT(this, TaggedIsSmi(smi_handler));
    556 
    557   Node* maybe_transition_cell =
    558       LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
    559   Label array_handler(this), tuple_handler(this);
    560   Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
    561 
    562   Variable var_transition(this, MachineRepresentation::kTagged);
    563   Label if_transition(this), if_transition_to_constant(this);
    564   Bind(&tuple_handler);
    565   {
    566     Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
    567     var_transition.Bind(transition);
    568     Goto(&if_transition);
    569   }
    570 
    571   Bind(&array_handler);
    572   {
    573     Node* length = SmiUntag(maybe_transition_cell);
    574     BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
    575                   [this, p, handler, miss](Node* current) {
    576                     Node* prototype_cell =
    577                         LoadFixedArrayElement(handler, current);
    578                     CheckPrototype(prototype_cell, p->name, miss);
    579                   },
    580                   1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
    581 
    582     Node* maybe_transition_cell =
    583         LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
    584     Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
    585     var_transition.Bind(transition);
    586     Goto(&if_transition);
    587   }
    588 
    589   Bind(&if_transition);
    590   {
    591     Node* holder = p->receiver;
    592     Node* transition = var_transition.value();
    593     Node* handler_word = SmiUntag(smi_handler);
    594 
    595     GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
    596 
    597     Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
    598     GotoIf(WordEqual(handler_kind,
    599                      IntPtrConstant(StoreHandler::kTransitionToConstant)),
    600            &if_transition_to_constant);
    601 
    602     // Handle transitioning field stores.
    603     HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
    604                                 miss);
    605 
    606     Bind(&if_transition_to_constant);
    607     {
    608       // Check that constant matches value.
    609       Node* value_index_in_descriptor =
    610           DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
    611       Node* descriptors = LoadMapDescriptors(transition);
    612       Node* constant =
    613           LoadFixedArrayElement(descriptors, value_index_in_descriptor);
    614       GotoIf(WordNotEqual(p->value, constant), miss);
    615 
    616       StoreMap(p->receiver, transition);
    617       Return(p->value);
    618     }
    619   }
    620 }
    621 
    622 void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
    623                                                     Node* holder, Node* value,
    624                                                     Node* transition,
    625                                                     Label* miss) {
    626   Comment(transition ? "transitioning field store" : "field store");
    627 
    628 #ifdef DEBUG
    629   Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
    630   if (transition) {
    631     CSA_ASSERT(
    632         this,
    633         Word32Or(
    634             WordEqual(handler_kind,
    635                       IntPtrConstant(StoreHandler::kTransitionToField)),
    636             WordEqual(handler_kind,
    637                       IntPtrConstant(StoreHandler::kTransitionToConstant))));
    638   } else {
    639     if (FLAG_track_constant_fields) {
    640       CSA_ASSERT(
    641           this,
    642           Word32Or(WordEqual(handler_kind,
    643                              IntPtrConstant(StoreHandler::kStoreField)),
    644                    WordEqual(handler_kind,
    645                              IntPtrConstant(StoreHandler::kStoreConstField))));
    646     } else {
    647       CSA_ASSERT(this, WordEqual(handler_kind,
    648                                  IntPtrConstant(StoreHandler::kStoreField)));
    649     }
    650   }
    651 #endif
    652 
    653   Node* field_representation =
    654       DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
    655 
    656   Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
    657       if_tagged_field(this);
    658 
    659   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
    660          &if_tagged_field);
    661   GotoIf(WordEqual(field_representation,
    662                    IntPtrConstant(StoreHandler::kHeapObject)),
    663          &if_heap_object_field);
    664   GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
    665          &if_double_field);
    666   CSA_ASSERT(this, WordEqual(field_representation,
    667                              IntPtrConstant(StoreHandler::kSmi)));
    668   Goto(&if_smi_field);
    669 
    670   Bind(&if_tagged_field);
    671   {
    672     Comment("store tagged field");
    673     HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
    674                               value, transition, miss);
    675   }
    676 
    677   Bind(&if_double_field);
    678   {
    679     Comment("store double field");
    680     HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
    681                               value, transition, miss);
    682   }
    683 
    684   Bind(&if_heap_object_field);
    685   {
    686     Comment("store heap object field");
    687     HandleStoreFieldAndReturn(handler_word, holder,
    688                               Representation::HeapObject(), value, transition,
    689                               miss);
    690   }
    691 
    692   Bind(&if_smi_field);
    693   {
    694     Comment("store smi field");
    695     HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
    696                               value, transition, miss);
    697   }
    698 }
    699 
    700 void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
    701                                                   Node* holder,
    702                                                   Representation representation,
    703                                                   Node* value, Node* transition,
    704                                                   Label* miss) {
    705   bool transition_to_field = transition != nullptr;
    706   Node* prepared_value = PrepareValueForStore(
    707       handler_word, holder, representation, transition, value, miss);
    708 
    709   Label if_inobject(this), if_out_of_object(this);
    710   Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
    711          &if_out_of_object);
    712 
    713   Bind(&if_inobject);
    714   {
    715     StoreNamedField(handler_word, holder, true, representation, prepared_value,
    716                     transition_to_field, miss);
    717     if (transition_to_field) {
    718       StoreMap(holder, transition);
    719     }
    720     Return(value);
    721   }
    722 
    723   Bind(&if_out_of_object);
    724   {
    725     if (transition_to_field) {
    726       Label storage_extended(this);
    727       GotoIfNot(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
    728                 &storage_extended);
    729       Comment("[ Extend storage");
    730       ExtendPropertiesBackingStore(holder);
    731       Comment("] Extend storage");
    732       Goto(&storage_extended);
    733 
    734       Bind(&storage_extended);
    735     }
    736 
    737     StoreNamedField(handler_word, holder, false, representation, prepared_value,
    738                     transition_to_field, miss);
    739     if (transition_to_field) {
    740       StoreMap(holder, transition);
    741     }
    742     Return(value);
    743   }
    744 }
    745 
    746 Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
    747                                               Representation representation,
    748                                               Node* transition, Node* value,
    749                                               Label* bailout) {
    750   if (representation.IsDouble()) {
    751     value = TryTaggedToFloat64(value, bailout);
    752 
    753   } else if (representation.IsHeapObject()) {
    754     GotoIf(TaggedIsSmi(value), bailout);
    755 
    756     Label done(this);
    757     if (FLAG_track_constant_fields && !transition) {
    758       // Skip field type check in favor of constant value check when storing
    759       // to constant field.
    760       GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
    761                        IntPtrConstant(StoreHandler::kStoreConstField)),
    762              &done);
    763     }
    764     Node* value_index_in_descriptor =
    765         DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
    766     Node* descriptors =
    767         LoadMapDescriptors(transition ? transition : LoadMap(holder));
    768     Node* maybe_field_type =
    769         LoadFixedArrayElement(descriptors, value_index_in_descriptor);
    770 
    771     GotoIf(TaggedIsSmi(maybe_field_type), &done);
    772     // Check that value type matches the field type.
    773     {
    774       Node* field_type = LoadWeakCellValue(maybe_field_type, bailout);
    775       Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
    776     }
    777     Bind(&done);
    778 
    779   } else if (representation.IsSmi()) {
    780     GotoIfNot(TaggedIsSmi(value), bailout);
    781 
    782   } else {
    783     DCHECK(representation.IsTagged());
    784   }
    785   return value;
    786 }
    787 
    788 void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) {
    789   Node* properties = LoadProperties(object);
    790   Node* length = LoadFixedArrayBaseLength(properties);
    791 
    792   ParameterMode mode = OptimalParameterMode();
    793   length = TaggedToParameter(length, mode);
    794 
    795   Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
    796   Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
    797 
    798   // Grow properties array.
    799   ElementsKind kind = FAST_ELEMENTS;
    800   DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded <
    801          FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind));
    802   // The size of a new properties backing store is guaranteed to be small
    803   // enough that the new backing store will be allocated in new space.
    804   CSA_ASSERT(this,
    805              UintPtrOrSmiLessThan(
    806                  new_capacity,
    807                  IntPtrOrSmiConstant(
    808                      kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode),
    809                  mode));
    810 
    811   Node* new_properties = AllocateFixedArray(kind, new_capacity, mode);
    812 
    813   FillFixedArrayWithValue(kind, new_properties, length, new_capacity,
    814                           Heap::kUndefinedValueRootIndex, mode);
    815 
    816   // |new_properties| is guaranteed to be in new space, so we can skip
    817   // the write barrier.
    818   CopyFixedArrayElements(kind, properties, new_properties, length,
    819                          SKIP_WRITE_BARRIER, mode);
    820 
    821   StoreObjectField(object, JSObject::kPropertiesOffset, new_properties);
    822 }
    823 
    824 void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
    825                                         bool is_inobject,
    826                                         Representation representation,
    827                                         Node* value, bool transition_to_field,
    828                                         Label* bailout) {
    829   bool store_value_as_double = representation.IsDouble();
    830   Node* property_storage = object;
    831   if (!is_inobject) {
    832     property_storage = LoadProperties(object);
    833   }
    834 
    835   Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word);
    836   if (representation.IsDouble()) {
    837     if (!FLAG_unbox_double_fields || !is_inobject) {
    838       if (transition_to_field) {
    839         Node* heap_number = AllocateHeapNumberWithValue(value, MUTABLE);
    840         // Store the new mutable heap number into the object.
    841         value = heap_number;
    842         store_value_as_double = false;
    843       } else {
    844         // Load the heap number.
    845         property_storage = LoadObjectField(property_storage, offset);
    846         // Store the double value into it.
    847         offset = IntPtrConstant(HeapNumber::kValueOffset);
    848       }
    849     }
    850   }
    851 
    852   // Do constant value check if necessary.
    853   if (FLAG_track_constant_fields && !transition_to_field) {
    854     Label done(this);
    855     GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
    856                         IntPtrConstant(StoreHandler::kStoreConstField)),
    857               &done);
    858     {
    859       if (store_value_as_double) {
    860         Node* current_value =
    861             LoadObjectField(property_storage, offset, MachineType::Float64());
    862         GotoIfNot(Float64Equal(current_value, value), bailout);
    863       } else {
    864         Node* current_value = LoadObjectField(property_storage, offset);
    865         GotoIfNot(WordEqual(current_value, value), bailout);
    866       }
    867       Goto(&done);
    868     }
    869     Bind(&done);
    870   }
    871 
    872   // Do the store.
    873   if (store_value_as_double) {
    874     StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
    875                                    MachineRepresentation::kFloat64);
    876   } else if (representation.IsSmi()) {
    877     StoreObjectFieldNoWriteBarrier(property_storage, offset, value);
    878   } else {
    879     StoreObjectField(property_storage, offset, value);
    880   }
    881 }
    882 
    883 void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
    884                                                     Node* elements,
    885                                                     Node* intptr_index,
    886                                                     Node* is_jsarray_condition,
    887                                                     Label* miss) {
    888   Variable var_length(this, MachineType::PointerRepresentation());
    889   Comment("Fast elements bounds check");
    890   Label if_array(this), length_loaded(this, &var_length);
    891   GotoIf(is_jsarray_condition, &if_array);
    892   {
    893     var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
    894     Goto(&length_loaded);
    895   }
    896   Bind(&if_array);
    897   {
    898     var_length.Bind(SmiUntag(LoadJSArrayLength(object)));
    899     Goto(&length_loaded);
    900   }
    901   Bind(&length_loaded);
    902   GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
    903 }
    904 
    905 void AccessorAssembler::EmitElementLoad(
    906     Node* object, Node* elements, Node* elements_kind, Node* intptr_index,
    907     Node* is_jsarray_condition, Label* if_hole, Label* rebox_double,
    908     Variable* var_double_value, Label* unimplemented_elements_kind,
    909     Label* out_of_bounds, Label* miss, ExitPoint* exit_point) {
    910   Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
    911       if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
    912       if_dictionary(this);
    913   GotoIf(
    914       Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
    915       &if_nonfast);
    916 
    917   EmitFastElementsBoundsCheck(object, elements, intptr_index,
    918                               is_jsarray_condition, out_of_bounds);
    919   int32_t kinds[] = {// Handled by if_fast_packed.
    920                      FAST_SMI_ELEMENTS, FAST_ELEMENTS,
    921                      // Handled by if_fast_holey.
    922                      FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS,
    923                      // Handled by if_fast_double.
    924                      FAST_DOUBLE_ELEMENTS,
    925                      // Handled by if_fast_holey_double.
    926                      FAST_HOLEY_DOUBLE_ELEMENTS};
    927   Label* labels[] = {// FAST_{SMI,}_ELEMENTS
    928                      &if_fast_packed, &if_fast_packed,
    929                      // FAST_HOLEY_{SMI,}_ELEMENTS
    930                      &if_fast_holey, &if_fast_holey,
    931                      // FAST_DOUBLE_ELEMENTS
    932                      &if_fast_double,
    933                      // FAST_HOLEY_DOUBLE_ELEMENTS
    934                      &if_fast_holey_double};
    935   Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
    936          arraysize(kinds));
    937 
    938   Bind(&if_fast_packed);
    939   {
    940     Comment("fast packed elements");
    941     exit_point->Return(LoadFixedArrayElement(elements, intptr_index));
    942   }
    943 
    944   Bind(&if_fast_holey);
    945   {
    946     Comment("fast holey elements");
    947     Node* element = LoadFixedArrayElement(elements, intptr_index);
    948     GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
    949     exit_point->Return(element);
    950   }
    951 
    952   Bind(&if_fast_double);
    953   {
    954     Comment("packed double elements");
    955     var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
    956                                                        MachineType::Float64()));
    957     Goto(rebox_double);
    958   }
    959 
    960   Bind(&if_fast_holey_double);
    961   {
    962     Comment("holey double elements");
    963     Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
    964                                               MachineType::Float64(), 0,
    965                                               INTPTR_PARAMETERS, if_hole);
    966     var_double_value->Bind(value);
    967     Goto(rebox_double);
    968   }
    969 
    970   Bind(&if_nonfast);
    971   {
    972     STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
    973     GotoIf(Int32GreaterThanOrEqual(
    974                elements_kind,
    975                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
    976            &if_typed_array);
    977     GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
    978            &if_dictionary);
    979     Goto(unimplemented_elements_kind);
    980   }
    981 
    982   Bind(&if_dictionary);
    983   {
    984     Comment("dictionary elements");
    985     GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
    986     Variable var_entry(this, MachineType::PointerRepresentation());
    987     Label if_found(this);
    988     NumberDictionaryLookup<SeededNumberDictionary>(
    989         elements, intptr_index, &if_found, &var_entry, if_hole);
    990     Bind(&if_found);
    991     // Check that the value is a data property.
    992     Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value());
    993     Node* details =
    994         LoadDetailsByKeyIndex<SeededNumberDictionary>(elements, index);
    995     Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
    996     // TODO(jkummerow): Support accessors without missing?
    997     GotoIfNot(Word32Equal(kind, Int32Constant(kData)), miss);
    998     // Finally, load the value.
    999     exit_point->Return(
   1000         LoadValueByKeyIndex<SeededNumberDictionary>(elements, index));
   1001   }
   1002 
   1003   Bind(&if_typed_array);
   1004   {
   1005     Comment("typed elements");
   1006     // Check if buffer has been neutered.
   1007     Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
   1008     GotoIf(IsDetachedBuffer(buffer), miss);
   1009 
   1010     // Bounds check.
   1011     Node* length =
   1012         SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
   1013     GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
   1014 
   1015     // Backing store = external_pointer + base_pointer.
   1016     Node* external_pointer =
   1017         LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset,
   1018                         MachineType::Pointer());
   1019     Node* base_pointer =
   1020         LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset);
   1021     Node* backing_store =
   1022         IntPtrAdd(external_pointer, BitcastTaggedToWord(base_pointer));
   1023 
   1024     Label uint8_elements(this), int8_elements(this), uint16_elements(this),
   1025         int16_elements(this), uint32_elements(this), int32_elements(this),
   1026         float32_elements(this), float64_elements(this);
   1027     Label* elements_kind_labels[] = {
   1028         &uint8_elements,  &uint8_elements,   &int8_elements,
   1029         &uint16_elements, &int16_elements,   &uint32_elements,
   1030         &int32_elements,  &float32_elements, &float64_elements};
   1031     int32_t elements_kinds[] = {
   1032         UINT8_ELEMENTS,  UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
   1033         UINT16_ELEMENTS, INT16_ELEMENTS,         UINT32_ELEMENTS,
   1034         INT32_ELEMENTS,  FLOAT32_ELEMENTS,       FLOAT64_ELEMENTS};
   1035     const size_t kTypedElementsKindCount =
   1036         LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
   1037         FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
   1038     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
   1039     DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
   1040     Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
   1041            kTypedElementsKindCount);
   1042     Bind(&uint8_elements);
   1043     {
   1044       Comment("UINT8_ELEMENTS");  // Handles UINT8_CLAMPED_ELEMENTS too.
   1045       Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
   1046       exit_point->Return(SmiFromWord32(element));
   1047     }
   1048     Bind(&int8_elements);
   1049     {
   1050       Comment("INT8_ELEMENTS");
   1051       Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
   1052       exit_point->Return(SmiFromWord32(element));
   1053     }
   1054     Bind(&uint16_elements);
   1055     {
   1056       Comment("UINT16_ELEMENTS");
   1057       Node* index = WordShl(intptr_index, IntPtrConstant(1));
   1058       Node* element = Load(MachineType::Uint16(), backing_store, index);
   1059       exit_point->Return(SmiFromWord32(element));
   1060     }
   1061     Bind(&int16_elements);
   1062     {
   1063       Comment("INT16_ELEMENTS");
   1064       Node* index = WordShl(intptr_index, IntPtrConstant(1));
   1065       Node* element = Load(MachineType::Int16(), backing_store, index);
   1066       exit_point->Return(SmiFromWord32(element));
   1067     }
   1068     Bind(&uint32_elements);
   1069     {
   1070       Comment("UINT32_ELEMENTS");
   1071       Node* index = WordShl(intptr_index, IntPtrConstant(2));
   1072       Node* element = Load(MachineType::Uint32(), backing_store, index);
   1073       exit_point->Return(ChangeUint32ToTagged(element));
   1074     }
   1075     Bind(&int32_elements);
   1076     {
   1077       Comment("INT32_ELEMENTS");
   1078       Node* index = WordShl(intptr_index, IntPtrConstant(2));
   1079       Node* element = Load(MachineType::Int32(), backing_store, index);
   1080       exit_point->Return(ChangeInt32ToTagged(element));
   1081     }
   1082     Bind(&float32_elements);
   1083     {
   1084       Comment("FLOAT32_ELEMENTS");
   1085       Node* index = WordShl(intptr_index, IntPtrConstant(2));
   1086       Node* element = Load(MachineType::Float32(), backing_store, index);
   1087       var_double_value->Bind(ChangeFloat32ToFloat64(element));
   1088       Goto(rebox_double);
   1089     }
   1090     Bind(&float64_elements);
   1091     {
   1092       Comment("FLOAT64_ELEMENTS");
   1093       Node* index = WordShl(intptr_index, IntPtrConstant(3));
   1094       Node* element = Load(MachineType::Float64(), backing_store, index);
   1095       var_double_value->Bind(element);
   1096       Goto(rebox_double);
   1097     }
   1098   }
   1099 }
   1100 
   1101 void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name,
   1102                                        Label* miss) {
   1103   Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss);
   1104 
   1105   Label done(this);
   1106   Label if_property_cell(this), if_dictionary_object(this);
   1107 
   1108   // |maybe_prototype| is either a PropertyCell or a slow-mode prototype.
   1109   Branch(WordEqual(LoadMap(maybe_prototype),
   1110                    LoadRoot(Heap::kGlobalPropertyCellMapRootIndex)),
   1111          &if_property_cell, &if_dictionary_object);
   1112 
   1113   Bind(&if_dictionary_object);
   1114   {
   1115     CSA_ASSERT(this, IsDictionaryMap(LoadMap(maybe_prototype)));
   1116     NameDictionaryNegativeLookup(maybe_prototype, name, miss);
   1117     Goto(&done);
   1118   }
   1119 
   1120   Bind(&if_property_cell);
   1121   {
   1122     // Ensure the property cell still contains the hole.
   1123     Node* value = LoadObjectField(maybe_prototype, PropertyCell::kValueOffset);
   1124     GotoIf(WordNotEqual(value, LoadRoot(Heap::kTheHoleValueRootIndex)), miss);
   1125     Goto(&done);
   1126   }
   1127 
   1128   Bind(&done);
   1129 }
   1130 
   1131 void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
   1132                                                      Label* miss) {
   1133   CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
   1134   Node* properties = LoadProperties(object);
   1135   // Ensure the property does not exist in a dictionary-mode object.
   1136   Variable var_name_index(this, MachineType::PointerRepresentation());
   1137   Label done(this);
   1138   NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
   1139                                        &done);
   1140   Bind(&done);
   1141 }
   1142 
   1143 void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
   1144                                            Node* instance_type, Node* index,
   1145                                            Label* slow) {
   1146   Comment("integer index");
   1147 
   1148   ExitPoint direct_exit(this);
   1149 
   1150   Label if_element_hole(this), if_oob(this);
   1151   // Receivers requiring non-standard element accesses (interceptors, access
   1152   // checks, strings and string wrappers, proxies) are handled in the runtime.
   1153   GotoIf(Int32LessThanOrEqual(instance_type,
   1154                               Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
   1155          slow);
   1156   Node* elements = LoadElements(receiver);
   1157   Node* elements_kind = LoadMapElementsKind(receiver_map);
   1158   Node* is_jsarray_condition =
   1159       Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
   1160   Variable var_double_value(this, MachineRepresentation::kFloat64);
   1161   Label rebox_double(this, &var_double_value);
   1162 
   1163   // Unimplemented elements kinds fall back to a runtime call.
   1164   Label* unimplemented_elements_kind = slow;
   1165   IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
   1166   EmitElementLoad(receiver, elements, elements_kind, index,
   1167                   is_jsarray_condition, &if_element_hole, &rebox_double,
   1168                   &var_double_value, unimplemented_elements_kind, &if_oob, slow,
   1169                   &direct_exit);
   1170 
   1171   Bind(&rebox_double);
   1172   Return(AllocateHeapNumberWithValue(var_double_value.value()));
   1173 
   1174   Bind(&if_oob);
   1175   {
   1176     Comment("out of bounds");
   1177     // Negative keys can't take the fast OOB path.
   1178     GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow);
   1179     // Positive OOB indices are effectively the same as hole loads.
   1180     Goto(&if_element_hole);
   1181   }
   1182 
   1183   Bind(&if_element_hole);
   1184   {
   1185     Comment("found the hole");
   1186     Label return_undefined(this);
   1187     BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
   1188 
   1189     Bind(&return_undefined);
   1190     Return(UndefinedConstant());
   1191   }
   1192 }
   1193 
   1194 void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
   1195                                             Node* instance_type, Node* key,
   1196                                             const LoadICParameters* p,
   1197                                             Label* slow) {
   1198   Comment("key is unique name");
   1199   Label if_found_on_receiver(this), if_property_dictionary(this),
   1200       lookup_prototype_chain(this);
   1201   Variable var_details(this, MachineRepresentation::kWord32);
   1202   Variable var_value(this, MachineRepresentation::kTagged);
   1203 
   1204   // Receivers requiring non-standard accesses (interceptors, access
   1205   // checks, strings and string wrappers, proxies) are handled in the runtime.
   1206   GotoIf(Int32LessThanOrEqual(instance_type,
   1207                               Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
   1208          slow);
   1209 
   1210   // Check if the receiver has fast or slow properties.
   1211   Node* properties = LoadProperties(receiver);
   1212   Node* properties_map = LoadMap(properties);
   1213   GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
   1214          &if_property_dictionary);
   1215 
   1216   // Try looking up the property on the receiver; if unsuccessful, look
   1217   // for a handler in the stub cache.
   1218   Node* bitfield3 = LoadMapBitField3(receiver_map);
   1219   Node* descriptors = LoadMapDescriptors(receiver_map);
   1220 
   1221   Label if_descriptor_found(this), stub_cache(this);
   1222   Variable var_name_index(this, MachineType::PointerRepresentation());
   1223   DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found,
   1224                    &var_name_index, &stub_cache);
   1225 
   1226   Bind(&if_descriptor_found);
   1227   {
   1228     LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
   1229                                var_name_index.value(), &var_details,
   1230                                &var_value);
   1231     Goto(&if_found_on_receiver);
   1232   }
   1233 
   1234   Bind(&stub_cache);
   1235   {
   1236     Comment("stub cache probe for fast property load");
   1237     Variable var_handler(this, MachineRepresentation::kTagged);
   1238     Label found_handler(this, &var_handler), stub_cache_miss(this);
   1239     TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
   1240                       &found_handler, &var_handler, &stub_cache_miss);
   1241     Bind(&found_handler);
   1242     { HandleLoadICHandlerCase(p, var_handler.value(), slow); }
   1243 
   1244     Bind(&stub_cache_miss);
   1245     {
   1246       // TODO(jkummerow): Check if the property exists on the prototype
   1247       // chain. If it doesn't, then there's no point in missing.
   1248       Comment("KeyedLoadGeneric_miss");
   1249       TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
   1250                       p->name, p->slot, p->vector);
   1251     }
   1252   }
   1253 
   1254   Bind(&if_property_dictionary);
   1255   {
   1256     Comment("dictionary property load");
   1257     // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
   1258     // seeing global objects here (which would need special handling).
   1259 
   1260     Variable var_name_index(this, MachineType::PointerRepresentation());
   1261     Label dictionary_found(this, &var_name_index);
   1262     NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
   1263                                          &var_name_index,
   1264                                          &lookup_prototype_chain);
   1265     Bind(&dictionary_found);
   1266     {
   1267       LoadPropertyFromNameDictionary(properties, var_name_index.value(),
   1268                                      &var_details, &var_value);
   1269       Goto(&if_found_on_receiver);
   1270     }
   1271   }
   1272 
   1273   Bind(&if_found_on_receiver);
   1274   {
   1275     Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
   1276                                        p->context, receiver, slow);
   1277     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
   1278     Return(value);
   1279   }
   1280 
   1281   Bind(&lookup_prototype_chain);
   1282   {
   1283     Variable var_holder_map(this, MachineRepresentation::kTagged);
   1284     Variable var_holder_instance_type(this, MachineRepresentation::kWord32);
   1285     Label return_undefined(this);
   1286     Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
   1287     Label loop(this, arraysize(merged_variables), merged_variables);
   1288 
   1289     var_holder_map.Bind(receiver_map);
   1290     var_holder_instance_type.Bind(instance_type);
   1291     // Private symbols must not be looked up on the prototype chain.
   1292     GotoIf(IsPrivateSymbol(key), &return_undefined);
   1293     Goto(&loop);
   1294     Bind(&loop);
   1295     {
   1296       // Bailout if it can be an integer indexed exotic case.
   1297       GotoIf(Word32Equal(var_holder_instance_type.value(),
   1298                          Int32Constant(JS_TYPED_ARRAY_TYPE)),
   1299              slow);
   1300       Node* proto = LoadMapPrototype(var_holder_map.value());
   1301       GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
   1302       Node* proto_map = LoadMap(proto);
   1303       Node* proto_instance_type = LoadMapInstanceType(proto_map);
   1304       var_holder_map.Bind(proto_map);
   1305       var_holder_instance_type.Bind(proto_instance_type);
   1306       Label next_proto(this), return_value(this, &var_value), goto_slow(this);
   1307       TryGetOwnProperty(p->context, receiver, proto, proto_map,
   1308                         proto_instance_type, key, &return_value, &var_value,
   1309                         &next_proto, &goto_slow);
   1310 
   1311       // This trampoline and the next are required to appease Turbofan's
   1312       // variable merging.
   1313       Bind(&next_proto);
   1314       Goto(&loop);
   1315 
   1316       Bind(&goto_slow);
   1317       Goto(slow);
   1318 
   1319       Bind(&return_value);
   1320       Return(var_value.value());
   1321     }
   1322 
   1323     Bind(&return_undefined);
   1324     Return(UndefinedConstant());
   1325   }
   1326 }
   1327 
   1328 //////////////////// Stub cache access helpers.
   1329 
   1330 enum AccessorAssembler::StubCacheTable : int {
   1331   kPrimary = static_cast<int>(StubCache::kPrimary),
   1332   kSecondary = static_cast<int>(StubCache::kSecondary)
   1333 };
   1334 
   1335 Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
   1336   // See v8::internal::StubCache::PrimaryOffset().
   1337   STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
   1338   // Compute the hash of the name (use entire hash field).
   1339   Node* hash_field = LoadNameHashField(name);
   1340   CSA_ASSERT(this,
   1341              Word32Equal(Word32And(hash_field,
   1342                                    Int32Constant(Name::kHashNotComputedMask)),
   1343                          Int32Constant(0)));
   1344 
   1345   // Using only the low bits in 64-bit mode is unlikely to increase the
   1346   // risk of collision even if the heap is spread over an area larger than
   1347   // 4Gb (and not at all if it isn't).
   1348   Node* map32 = TruncateWordToWord32(BitcastTaggedToWord(map));
   1349   Node* hash = Int32Add(hash_field, map32);
   1350   // Base the offset on a simple combination of name and map.
   1351   hash = Word32Xor(hash, Int32Constant(StubCache::kPrimaryMagic));
   1352   uint32_t mask = (StubCache::kPrimaryTableSize - 1)
   1353                   << StubCache::kCacheIndexShift;
   1354   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
   1355 }
   1356 
   1357 Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
   1358   // See v8::internal::StubCache::SecondaryOffset().
   1359 
   1360   // Use the seed from the primary cache in the secondary cache.
   1361   Node* name32 = TruncateWordToWord32(BitcastTaggedToWord(name));
   1362   Node* hash = Int32Sub(TruncateWordToWord32(seed), name32);
   1363   hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
   1364   int32_t mask = (StubCache::kSecondaryTableSize - 1)
   1365                  << StubCache::kCacheIndexShift;
   1366   return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
   1367 }
   1368 
   1369 void AccessorAssembler::TryProbeStubCacheTable(StubCache* stub_cache,
   1370                                                StubCacheTable table_id,
   1371                                                Node* entry_offset, Node* name,
   1372                                                Node* map, Label* if_handler,
   1373                                                Variable* var_handler,
   1374                                                Label* if_miss) {
   1375   StubCache::Table table = static_cast<StubCache::Table>(table_id);
   1376 #ifdef DEBUG
   1377   if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
   1378     Goto(if_miss);
   1379     return;
   1380   } else if (FLAG_test_primary_stub_cache && table == StubCache::kSecondary) {
   1381     Goto(if_miss);
   1382     return;
   1383   }
   1384 #endif
   1385   // The {table_offset} holds the entry offset times four (due to masking
   1386   // and shifting optimizations).
   1387   const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
   1388   entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
   1389 
   1390   // Check that the key in the entry matches the name.
   1391   Node* key_base =
   1392       ExternalConstant(ExternalReference(stub_cache->key_reference(table)));
   1393   Node* entry_key = Load(MachineType::Pointer(), key_base, entry_offset);
   1394   GotoIf(WordNotEqual(name, entry_key), if_miss);
   1395 
   1396   // Get the map entry from the cache.
   1397   DCHECK_EQ(kPointerSize * 2, stub_cache->map_reference(table).address() -
   1398                                   stub_cache->key_reference(table).address());
   1399   Node* entry_map =
   1400       Load(MachineType::Pointer(), key_base,
   1401            IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize * 2)));
   1402   GotoIf(WordNotEqual(map, entry_map), if_miss);
   1403 
   1404   DCHECK_EQ(kPointerSize, stub_cache->value_reference(table).address() -
   1405                               stub_cache->key_reference(table).address());
   1406   Node* handler = Load(MachineType::TaggedPointer(), key_base,
   1407                        IntPtrAdd(entry_offset, IntPtrConstant(kPointerSize)));
   1408 
   1409   // We found the handler.
   1410   var_handler->Bind(handler);
   1411   Goto(if_handler);
   1412 }
   1413 
   1414 void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
   1415                                           Node* name, Label* if_handler,
   1416                                           Variable* var_handler,
   1417                                           Label* if_miss) {
   1418   Label try_secondary(this), miss(this);
   1419 
   1420   Counters* counters = isolate()->counters();
   1421   IncrementCounter(counters->megamorphic_stub_cache_probes(), 1);
   1422 
   1423   // Check that the {receiver} isn't a smi.
   1424   GotoIf(TaggedIsSmi(receiver), &miss);
   1425 
   1426   Node* receiver_map = LoadMap(receiver);
   1427 
   1428   // Probe the primary table.
   1429   Node* primary_offset = StubCachePrimaryOffset(name, receiver_map);
   1430   TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
   1431                          receiver_map, if_handler, var_handler, &try_secondary);
   1432 
   1433   Bind(&try_secondary);
   1434   {
   1435     // Probe the secondary table.
   1436     Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
   1437     TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name,
   1438                            receiver_map, if_handler, var_handler, &miss);
   1439   }
   1440 
   1441   Bind(&miss);
   1442   {
   1443     IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
   1444     Goto(if_miss);
   1445   }
   1446 }
   1447 
   1448 //////////////////// Entry points into private implementation (one per stub).
   1449 
   1450 void AccessorAssembler::LoadIC(const LoadICParameters* p) {
   1451   Variable var_handler(this, MachineRepresentation::kTagged);
   1452   // TODO(ishell): defer blocks when it works.
   1453   Label if_handler(this, &var_handler), try_polymorphic(this),
   1454       try_megamorphic(this /*, Label::kDeferred*/),
   1455       miss(this /*, Label::kDeferred*/);
   1456 
   1457   Node* receiver_map = LoadReceiverMap(p->receiver);
   1458   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
   1459 
   1460   // Check monomorphic case.
   1461   Node* feedback =
   1462       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
   1463                          &var_handler, &try_polymorphic);
   1464   Bind(&if_handler);
   1465   { HandleLoadICHandlerCase(p, var_handler.value(), &miss); }
   1466 
   1467   Bind(&try_polymorphic);
   1468   {
   1469     // Check polymorphic case.
   1470     Comment("LoadIC_try_polymorphic");
   1471     GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
   1472               &try_megamorphic);
   1473     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
   1474                           &miss, 2);
   1475   }
   1476 
   1477   Bind(&try_megamorphic);
   1478   {
   1479     // Check megamorphic case.
   1480     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
   1481               &miss);
   1482 
   1483     TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
   1484                       &if_handler, &var_handler, &miss);
   1485   }
   1486   Bind(&miss);
   1487   {
   1488     TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
   1489                     p->slot, p->vector);
   1490   }
   1491 }
   1492 
   1493 void AccessorAssembler::LoadICProtoArray(
   1494     const LoadICParameters* p, Node* handler,
   1495     bool throw_reference_error_if_nonexistent) {
   1496   Label miss(this);
   1497   CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
   1498   CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler)));
   1499 
   1500   ExitPoint direct_exit(this);
   1501 
   1502   Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
   1503   Node* handler_flags = SmiUntag(smi_handler);
   1504 
   1505   Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler);
   1506 
   1507   Node* holder =
   1508       EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
   1509                                 &miss, throw_reference_error_if_nonexistent);
   1510 
   1511   HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
   1512                              kOnlyProperties);
   1513 
   1514   Bind(&miss);
   1515   {
   1516     TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
   1517                     p->slot, p->vector);
   1518   }
   1519 }
   1520 
   1521 void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
   1522     Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
   1523     Label* miss, ParameterMode slot_mode) {
   1524   Comment("LoadGlobalIC_TryPropertyCellCase");
   1525 
   1526   Node* weak_cell = LoadFixedArrayElement(vector, slot, 0, slot_mode);
   1527   CSA_ASSERT(this, HasInstanceType(weak_cell, WEAK_CELL_TYPE));
   1528 
   1529   // Load value or try handler case if the {weak_cell} is cleared.
   1530   Node* property_cell = LoadWeakCellValue(weak_cell, try_handler);
   1531   CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
   1532 
   1533   Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
   1534   GotoIf(WordEqual(value, TheHoleConstant()), miss);
   1535   exit_point->Return(value);
   1536 }
   1537 
   1538 void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
   1539                                                     TypeofMode typeof_mode,
   1540                                                     ExitPoint* exit_point,
   1541                                                     Label* miss) {
   1542   Comment("LoadGlobalIC_TryHandlerCase");
   1543 
   1544   Label call_handler(this);
   1545 
   1546   Node* handler =
   1547       LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
   1548   CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
   1549   GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
   1550          miss);
   1551   GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
   1552 
   1553   bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF;
   1554   HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point,
   1555                                 throw_reference_error_if_nonexistent);
   1556 
   1557   Bind(&call_handler);
   1558   {
   1559     LoadWithVectorDescriptor descriptor(isolate());
   1560     Node* native_context = LoadNativeContext(p->context);
   1561     Node* receiver =
   1562         LoadContextElement(native_context, Context::EXTENSION_INDEX);
   1563     exit_point->ReturnCallStub(descriptor, handler, p->context, receiver,
   1564                                p->name, p->slot, p->vector);
   1565   }
   1566 }
   1567 
   1568 void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p,
   1569                                               ExitPoint* exit_point) {
   1570   Comment("LoadGlobalIC_MissCase");
   1571 
   1572   exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context,
   1573                                 p->name, p->slot, p->vector);
   1574 }
   1575 
   1576 void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p,
   1577                                      TypeofMode typeof_mode) {
   1578   ExitPoint direct_exit(this);
   1579 
   1580   Label try_handler(this), miss(this);
   1581   LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit,
   1582                                    &try_handler, &miss);
   1583 
   1584   Bind(&try_handler);
   1585   LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss);
   1586 
   1587   Bind(&miss);
   1588   LoadGlobalIC_MissCase(p, &direct_exit);
   1589 }
   1590 
   1591 void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
   1592   Variable var_handler(this, MachineRepresentation::kTagged);
   1593   // TODO(ishell): defer blocks when it works.
   1594   Label if_handler(this, &var_handler), try_polymorphic(this),
   1595       try_megamorphic(this /*, Label::kDeferred*/),
   1596       try_polymorphic_name(this /*, Label::kDeferred*/),
   1597       miss(this /*, Label::kDeferred*/);
   1598 
   1599   Node* receiver_map = LoadReceiverMap(p->receiver);
   1600   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
   1601 
   1602   // Check monomorphic case.
   1603   Node* feedback =
   1604       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
   1605                          &var_handler, &try_polymorphic);
   1606   Bind(&if_handler);
   1607   { HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); }
   1608 
   1609   Bind(&try_polymorphic);
   1610   {
   1611     // Check polymorphic case.
   1612     Comment("KeyedLoadIC_try_polymorphic");
   1613     GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
   1614               &try_megamorphic);
   1615     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
   1616                           &miss, 2);
   1617   }
   1618 
   1619   Bind(&try_megamorphic);
   1620   {
   1621     // Check megamorphic case.
   1622     Comment("KeyedLoadIC_try_megamorphic");
   1623     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
   1624               &try_polymorphic_name);
   1625     // TODO(jkummerow): Inline this? Or some of it?
   1626     TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
   1627                  p->receiver, p->name, p->slot, p->vector);
   1628   }
   1629   Bind(&try_polymorphic_name);
   1630   {
   1631     // We might have a name in feedback, and a fixed array in the next slot.
   1632     Comment("KeyedLoadIC_try_polymorphic_name");
   1633     GotoIfNot(WordEqual(feedback, p->name), &miss);
   1634     // If the name comparison succeeded, we know we have a fixed array with
   1635     // at least one map/handler pair.
   1636     Node* offset = ElementOffsetFromIndex(
   1637         p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
   1638         FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
   1639     Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
   1640     HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
   1641                           1);
   1642   }
   1643   Bind(&miss);
   1644   {
   1645     Comment("KeyedLoadIC_miss");
   1646     TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
   1647                     p->name, p->slot, p->vector);
   1648   }
   1649 }
   1650 
   1651 void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
   1652   Variable var_index(this, MachineType::PointerRepresentation());
   1653   Variable var_unique(this, MachineRepresentation::kTagged);
   1654   var_unique.Bind(p->name);  // Dummy initialization.
   1655   Label if_index(this), if_unique_name(this), slow(this);
   1656 
   1657   Node* receiver = p->receiver;
   1658   GotoIf(TaggedIsSmi(receiver), &slow);
   1659   Node* receiver_map = LoadMap(receiver);
   1660   Node* instance_type = LoadMapInstanceType(receiver_map);
   1661 
   1662   TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
   1663             &slow);
   1664 
   1665   Bind(&if_index);
   1666   {
   1667     GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
   1668                        &slow);
   1669   }
   1670 
   1671   Bind(&if_unique_name);
   1672   {
   1673     GenericPropertyLoad(receiver, receiver_map, instance_type,
   1674                         var_unique.value(), p, &slow);
   1675   }
   1676 
   1677   Bind(&slow);
   1678   {
   1679     Comment("KeyedLoadGeneric_slow");
   1680     IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
   1681     // TODO(jkummerow): Should we use the GetProperty TF stub instead?
   1682     TailCallRuntime(Runtime::kKeyedGetProperty, p->context, p->receiver,
   1683                     p->name);
   1684   }
   1685 }
   1686 
   1687 void AccessorAssembler::StoreIC(const StoreICParameters* p) {
   1688   Variable var_handler(this, MachineRepresentation::kTagged);
   1689   // TODO(ishell): defer blocks when it works.
   1690   Label if_handler(this, &var_handler), try_polymorphic(this),
   1691       try_megamorphic(this /*, Label::kDeferred*/),
   1692       miss(this /*, Label::kDeferred*/);
   1693 
   1694   Node* receiver_map = LoadReceiverMap(p->receiver);
   1695   GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
   1696 
   1697   // Check monomorphic case.
   1698   Node* feedback =
   1699       TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
   1700                          &var_handler, &try_polymorphic);
   1701   Bind(&if_handler);
   1702   {
   1703     Comment("StoreIC_if_handler");
   1704     HandleStoreICHandlerCase(p, var_handler.value(), &miss);
   1705   }
   1706 
   1707   Bind(&try_polymorphic);
   1708   {
   1709     // Check polymorphic case.
   1710     Comment("StoreIC_try_polymorphic");
   1711     GotoIfNot(
   1712         WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
   1713         &try_megamorphic);
   1714     HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
   1715                           &miss, 2);
   1716   }
   1717 
   1718   Bind(&try_megamorphic);
   1719   {
   1720     // Check megamorphic case.
   1721     GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
   1722               &miss);
   1723 
   1724     TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
   1725                       &if_handler, &var_handler, &miss);
   1726   }
   1727   Bind(&miss);
   1728   {
   1729     TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
   1730                     p->vector, p->receiver, p->name);
   1731   }
   1732 }
   1733 
   1734 void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
   1735                                      LanguageMode language_mode) {
   1736   // TODO(ishell): defer blocks when it works.
   1737   Label miss(this /*, Label::kDeferred*/);
   1738   {
   1739     Variable var_handler(this, MachineRepresentation::kTagged);
   1740 
   1741     // TODO(ishell): defer blocks when it works.
   1742     Label if_handler(this, &var_handler), try_polymorphic(this),
   1743         try_megamorphic(this /*, Label::kDeferred*/),
   1744         try_polymorphic_name(this /*, Label::kDeferred*/);
   1745 
   1746     Node* receiver_map = LoadReceiverMap(p->receiver);
   1747     GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
   1748 
   1749     // Check monomorphic case.
   1750     Node* feedback =
   1751         TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
   1752                            &var_handler, &try_polymorphic);
   1753     Bind(&if_handler);
   1754     {
   1755       Comment("KeyedStoreIC_if_handler");
   1756       HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
   1757     }
   1758 
   1759     Bind(&try_polymorphic);
   1760     {
   1761       // CheckPolymorphic case.
   1762       Comment("KeyedStoreIC_try_polymorphic");
   1763       GotoIfNot(
   1764           WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
   1765           &try_megamorphic);
   1766       Label if_transition_handler(this);
   1767       Variable var_transition_map_cell(this, MachineRepresentation::kTagged);
   1768       HandleKeyedStorePolymorphicCase(receiver_map, feedback, &if_handler,
   1769                                       &var_handler, &if_transition_handler,
   1770                                       &var_transition_map_cell, &miss);
   1771       Bind(&if_transition_handler);
   1772       Comment("KeyedStoreIC_polymorphic_transition");
   1773       {
   1774         Node* handler = var_handler.value();
   1775 
   1776         Label call_handler(this);
   1777         Variable var_code_handler(this, MachineRepresentation::kTagged);
   1778         var_code_handler.Bind(handler);
   1779         GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler);
   1780         {
   1781           CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
   1782 
   1783           // Check validity cell.
   1784           Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
   1785           Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
   1786           GotoIf(
   1787               WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
   1788               &miss);
   1789 
   1790           var_code_handler.Bind(
   1791               LoadObjectField(handler, Tuple2::kValue2Offset));
   1792           Goto(&call_handler);
   1793         }
   1794 
   1795         Bind(&call_handler);
   1796         {
   1797           Node* code_handler = var_code_handler.value();
   1798           CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
   1799 
   1800           Node* transition_map =
   1801               LoadWeakCellValue(var_transition_map_cell.value(), &miss);
   1802           StoreTransitionDescriptor descriptor(isolate());
   1803           TailCallStub(descriptor, code_handler, p->context, p->receiver,
   1804                        p->name, transition_map, p->value, p->slot, p->vector);
   1805         }
   1806       }
   1807     }
   1808 
   1809     Bind(&try_megamorphic);
   1810     {
   1811       // Check megamorphic case.
   1812       Comment("KeyedStoreIC_try_megamorphic");
   1813       GotoIfNot(
   1814           WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
   1815           &try_polymorphic_name);
   1816       TailCallStub(
   1817           CodeFactory::KeyedStoreIC_Megamorphic(isolate(), language_mode),
   1818           p->context, p->receiver, p->name, p->value, p->slot, p->vector);
   1819     }
   1820 
   1821     Bind(&try_polymorphic_name);
   1822     {
   1823       // We might have a name in feedback, and a fixed array in the next slot.
   1824       Comment("KeyedStoreIC_try_polymorphic_name");
   1825       GotoIfNot(WordEqual(feedback, p->name), &miss);
   1826       // If the name comparison succeeded, we know we have a FixedArray with
   1827       // at least one map/handler pair.
   1828       Node* offset = ElementOffsetFromIndex(
   1829           p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
   1830           FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
   1831       Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
   1832       HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
   1833                             &miss, 1);
   1834     }
   1835   }
   1836   Bind(&miss);
   1837   {
   1838     Comment("KeyedStoreIC_miss");
   1839     TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
   1840                     p->vector, p->receiver, p->name);
   1841   }
   1842 }
   1843 
   1844 //////////////////// Public methods.
   1845 
   1846 void AccessorAssembler::GenerateLoadIC() {
   1847   typedef LoadWithVectorDescriptor Descriptor;
   1848 
   1849   Node* receiver = Parameter(Descriptor::kReceiver);
   1850   Node* name = Parameter(Descriptor::kName);
   1851   Node* slot = Parameter(Descriptor::kSlot);
   1852   Node* vector = Parameter(Descriptor::kVector);
   1853   Node* context = Parameter(Descriptor::kContext);
   1854 
   1855   LoadICParameters p(context, receiver, name, slot, vector);
   1856   LoadIC(&p);
   1857 }
   1858 
   1859 void AccessorAssembler::GenerateLoadICTrampoline() {
   1860   typedef LoadDescriptor Descriptor;
   1861 
   1862   Node* receiver = Parameter(Descriptor::kReceiver);
   1863   Node* name = Parameter(Descriptor::kName);
   1864   Node* slot = Parameter(Descriptor::kSlot);
   1865   Node* context = Parameter(Descriptor::kContext);
   1866   Node* vector = LoadFeedbackVectorForStub();
   1867 
   1868   LoadICParameters p(context, receiver, name, slot, vector);
   1869   LoadIC(&p);
   1870 }
   1871 
   1872 void AccessorAssembler::GenerateLoadICProtoArray(
   1873     bool throw_reference_error_if_nonexistent) {
   1874   typedef LoadICProtoArrayDescriptor Descriptor;
   1875 
   1876   Node* receiver = Parameter(Descriptor::kReceiver);
   1877   Node* name = Parameter(Descriptor::kName);
   1878   Node* slot = Parameter(Descriptor::kSlot);
   1879   Node* vector = Parameter(Descriptor::kVector);
   1880   Node* handler = Parameter(Descriptor::kHandler);
   1881   Node* context = Parameter(Descriptor::kContext);
   1882 
   1883   LoadICParameters p(context, receiver, name, slot, vector);
   1884   LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
   1885 }
   1886 
   1887 void AccessorAssembler::GenerateLoadField() {
   1888   typedef LoadFieldDescriptor Descriptor;
   1889 
   1890   Node* receiver = Parameter(Descriptor::kReceiver);
   1891   Node* name = nullptr;
   1892   Node* slot = nullptr;
   1893   Node* vector = nullptr;
   1894   Node* context = Parameter(Descriptor::kContext);
   1895   LoadICParameters p(context, receiver, name, slot, vector);
   1896 
   1897   ExitPoint direct_exit(this);
   1898 
   1899   HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
   1900                              nullptr, &direct_exit, kOnlyProperties);
   1901 }
   1902 
   1903 void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
   1904   typedef LoadGlobalWithVectorDescriptor Descriptor;
   1905 
   1906   Node* name = Parameter(Descriptor::kName);
   1907   Node* slot = Parameter(Descriptor::kSlot);
   1908   Node* vector = Parameter(Descriptor::kVector);
   1909   Node* context = Parameter(Descriptor::kContext);
   1910 
   1911   LoadICParameters p(context, nullptr, name, slot, vector);
   1912   LoadGlobalIC(&p, typeof_mode);
   1913 }
   1914 
   1915 void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
   1916   typedef LoadGlobalDescriptor Descriptor;
   1917 
   1918   Node* name = Parameter(Descriptor::kName);
   1919   Node* slot = Parameter(Descriptor::kSlot);
   1920   Node* context = Parameter(Descriptor::kContext);
   1921   Node* vector = LoadFeedbackVectorForStub();
   1922 
   1923   LoadICParameters p(context, nullptr, name, slot, vector);
   1924   LoadGlobalIC(&p, typeof_mode);
   1925 }
   1926 
   1927 void AccessorAssembler::GenerateKeyedLoadIC() {
   1928   typedef LoadWithVectorDescriptor Descriptor;
   1929 
   1930   Node* receiver = Parameter(Descriptor::kReceiver);
   1931   Node* name = Parameter(Descriptor::kName);
   1932   Node* slot = Parameter(Descriptor::kSlot);
   1933   Node* vector = Parameter(Descriptor::kVector);
   1934   Node* context = Parameter(Descriptor::kContext);
   1935 
   1936   LoadICParameters p(context, receiver, name, slot, vector);
   1937   KeyedLoadIC(&p);
   1938 }
   1939 
   1940 void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
   1941   typedef LoadDescriptor Descriptor;
   1942 
   1943   Node* receiver = Parameter(Descriptor::kReceiver);
   1944   Node* name = Parameter(Descriptor::kName);
   1945   Node* slot = Parameter(Descriptor::kSlot);
   1946   Node* context = Parameter(Descriptor::kContext);
   1947   Node* vector = LoadFeedbackVectorForStub();
   1948 
   1949   LoadICParameters p(context, receiver, name, slot, vector);
   1950   KeyedLoadIC(&p);
   1951 }
   1952 
   1953 void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
   1954   typedef LoadWithVectorDescriptor Descriptor;
   1955 
   1956   Node* receiver = Parameter(Descriptor::kReceiver);
   1957   Node* name = Parameter(Descriptor::kName);
   1958   Node* slot = Parameter(Descriptor::kSlot);
   1959   Node* vector = Parameter(Descriptor::kVector);
   1960   Node* context = Parameter(Descriptor::kContext);
   1961 
   1962   LoadICParameters p(context, receiver, name, slot, vector);
   1963   KeyedLoadICGeneric(&p);
   1964 }
   1965 
   1966 void AccessorAssembler::GenerateStoreIC() {
   1967   typedef StoreWithVectorDescriptor Descriptor;
   1968 
   1969   Node* receiver = Parameter(Descriptor::kReceiver);
   1970   Node* name = Parameter(Descriptor::kName);
   1971   Node* value = Parameter(Descriptor::kValue);
   1972   Node* slot = Parameter(Descriptor::kSlot);
   1973   Node* vector = Parameter(Descriptor::kVector);
   1974   Node* context = Parameter(Descriptor::kContext);
   1975 
   1976   StoreICParameters p(context, receiver, name, value, slot, vector);
   1977   StoreIC(&p);
   1978 }
   1979 
   1980 void AccessorAssembler::GenerateStoreICTrampoline() {
   1981   typedef StoreDescriptor Descriptor;
   1982 
   1983   Node* receiver = Parameter(Descriptor::kReceiver);
   1984   Node* name = Parameter(Descriptor::kName);
   1985   Node* value = Parameter(Descriptor::kValue);
   1986   Node* slot = Parameter(Descriptor::kSlot);
   1987   Node* context = Parameter(Descriptor::kContext);
   1988   Node* vector = LoadFeedbackVectorForStub();
   1989 
   1990   StoreICParameters p(context, receiver, name, value, slot, vector);
   1991   StoreIC(&p);
   1992 }
   1993 
   1994 void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) {
   1995   typedef StoreWithVectorDescriptor Descriptor;
   1996 
   1997   Node* receiver = Parameter(Descriptor::kReceiver);
   1998   Node* name = Parameter(Descriptor::kName);
   1999   Node* value = Parameter(Descriptor::kValue);
   2000   Node* slot = Parameter(Descriptor::kSlot);
   2001   Node* vector = Parameter(Descriptor::kVector);
   2002   Node* context = Parameter(Descriptor::kContext);
   2003 
   2004   StoreICParameters p(context, receiver, name, value, slot, vector);
   2005   KeyedStoreIC(&p, language_mode);
   2006 }
   2007 
   2008 void AccessorAssembler::GenerateKeyedStoreICTrampoline(
   2009     LanguageMode language_mode) {
   2010   typedef StoreDescriptor Descriptor;
   2011 
   2012   Node* receiver = Parameter(Descriptor::kReceiver);
   2013   Node* name = Parameter(Descriptor::kName);
   2014   Node* value = Parameter(Descriptor::kValue);
   2015   Node* slot = Parameter(Descriptor::kSlot);
   2016   Node* context = Parameter(Descriptor::kContext);
   2017   Node* vector = LoadFeedbackVectorForStub();
   2018 
   2019   StoreICParameters p(context, receiver, name, value, slot, vector);
   2020   KeyedStoreIC(&p, language_mode);
   2021 }
   2022 
   2023 }  // namespace internal
   2024 }  // namespace v8
   2025