LCOV - code coverage report
Current view: top level - src/ic - keyed-store-generic.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 554 559 99.1 %
Date: 2019-03-21 Functions: 33 33 100.0 %

          Line data    Source code
       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/keyed-store-generic.h"
       6             : 
       7             : #include "src/code-factory.h"
       8             : #include "src/code-stub-assembler.h"
       9             : #include "src/contexts.h"
      10             : #include "src/feedback-vector.h"
      11             : #include "src/ic/accessor-assembler.h"
      12             : #include "src/interface-descriptors.h"
      13             : #include "src/isolate.h"
      14             : #include "src/objects-inl.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : 
      19             : using Node = compiler::Node;
      20             : template <class T>
      21             : using TNode = compiler::TNode<T>;
      22             : 
      23             : enum class StoreMode { kOrdinary, kInLiteral };
      24             : 
      25         280 : class KeyedStoreGenericAssembler : public AccessorAssembler {
      26             :  public:
      27         280 :   explicit KeyedStoreGenericAssembler(compiler::CodeAssemblerState* state,
      28             :                                       StoreMode mode)
      29         280 :       : AccessorAssembler(state), mode_(mode) {}
      30             : 
      31             :   void KeyedStoreGeneric();
      32             : 
      33             :   void StoreIC_Uninitialized();
      34             : 
      35             :   // Generates code for [[Set]] operation, the |unique_name| is supposed to be
      36             :   // unique otherwise this code will always go to runtime.
      37             :   void SetProperty(TNode<Context> context, TNode<JSReceiver> receiver,
      38             :                    TNode<BoolT> is_simple_receiver, TNode<Name> unique_name,
      39             :                    TNode<Object> value, LanguageMode language_mode);
      40             : 
      41             :   // [[Set]], but more generic than the above. This impl does essentially the
      42             :   // same as "KeyedStoreGeneric" but does not use feedback slot and uses a
      43             :   // hardcoded LanguageMode instead of trying to deduce it from the feedback
      44             :   // slot's kind.
      45             :   void SetProperty(TNode<Context> context, TNode<Object> receiver,
      46             :                    TNode<Object> key, TNode<Object> value,
      47             :                    LanguageMode language_mode);
      48             : 
      49             :  private:
      50             :   StoreMode mode_;
      51             : 
      52             :   enum UpdateLength {
      53             :     kDontChangeLength,
      54             :     kIncrementLengthByOne,
      55             :     kBumpLengthWithGap
      56             :   };
      57             : 
      58             :   enum UseStubCache { kUseStubCache, kDontUseStubCache };
      59             : 
      60             :   // Helper that is used by the public KeyedStoreGeneric and by SetProperty.
      61             :   void KeyedStoreGeneric(TNode<Context> context, TNode<Object> receiver,
      62             :                          TNode<Object> key, TNode<Object> value,
      63             :                          Maybe<LanguageMode> language_mode);
      64             : 
      65             :   void EmitGenericElementStore(Node* receiver, Node* receiver_map,
      66             :                                Node* instance_type, Node* intptr_index,
      67             :                                Node* value, Node* context, Label* slow);
      68             : 
      69             :   // If language mode is not provided it is deduced from the feedback slot's
      70             :   // kind.
      71             :   void EmitGenericPropertyStore(TNode<JSReceiver> receiver,
      72             :                                 TNode<Map> receiver_map,
      73             :                                 const StoreICParameters* p,
      74             :                                 ExitPoint* exit_point, Label* slow,
      75             :                                 Maybe<LanguageMode> maybe_language_mode);
      76             : 
      77          56 :   void EmitGenericPropertyStore(SloppyTNode<JSReceiver> receiver,
      78             :                                 SloppyTNode<Map> receiver_map,
      79             :                                 const StoreICParameters* p, Label* slow) {
      80         112 :     ExitPoint direct_exit(this);
      81          56 :     EmitGenericPropertyStore(receiver, receiver_map, p, &direct_exit, slow,
      82          56 :                              Nothing<LanguageMode>());
      83          56 :   }
      84             : 
      85             :   void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
      86             :                                              Label* non_fast_elements,
      87             :                                              Label* only_fast_elements);
      88             : 
      89             :   void TryRewriteElements(Node* receiver, Node* receiver_map, Node* elements,
      90             :                           Node* native_context, ElementsKind from_kind,
      91             :                           ElementsKind to_kind, Label* bailout);
      92             : 
      93             :   void StoreElementWithCapacity(Node* receiver, Node* receiver_map,
      94             :                                 Node* elements, Node* elements_kind,
      95             :                                 Node* intptr_index, Node* value, Node* context,
      96             :                                 Label* slow, UpdateLength update_length);
      97             : 
      98             :   void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value,
      99             :                                   UpdateLength update_length);
     100             : 
     101             :   void TryChangeToHoleyMapHelper(Node* receiver, Node* receiver_map,
     102             :                                  Node* native_context, ElementsKind packed_kind,
     103             :                                  ElementsKind holey_kind, Label* done,
     104             :                                  Label* map_mismatch, Label* bailout);
     105             :   void TryChangeToHoleyMap(Node* receiver, Node* receiver_map,
     106             :                            Node* current_elements_kind, Node* context,
     107             :                            ElementsKind packed_kind, Label* bailout);
     108             :   void TryChangeToHoleyMapMulti(Node* receiver, Node* receiver_map,
     109             :                                 Node* current_elements_kind, Node* context,
     110             :                                 ElementsKind packed_kind,
     111             :                                 ElementsKind packed_kind_2, Label* bailout);
     112             : 
     113             :   void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name,
     114             :                                       Label* accessor,
     115             :                                       Variable* var_accessor_pair,
     116             :                                       Variable* var_accessor_holder,
     117             :                                       Label* readonly, Label* bailout);
     118             : 
     119             :   TNode<Map> FindCandidateStoreICTransitionMapHandler(TNode<Map> map,
     120             :                                                       TNode<Name> name,
     121             :                                                       Label* slow);
     122             : 
     123        1288 :   bool IsKeyedStore() const { return mode_ == StoreMode::kOrdinary; }
     124        1400 :   bool IsStoreInLiteral() const { return mode_ == StoreMode::kInLiteral; }
     125             : 
     126         280 :   bool ShouldCheckPrototype() const { return IsKeyedStore(); }
     127        1064 :   bool ShouldReconfigureExisting() const { return IsStoreInLiteral(); }
     128         840 :   bool ShouldCallSetter() const { return IsKeyedStore(); }
     129         280 :   bool ShouldCheckPrototypeValidity() const {
     130             :     // We don't do this for "in-literal" stores, because it is impossible for
     131             :     // the target object to be a "prototype"
     132         280 :     return !IsStoreInLiteral();
     133             :   }
     134             : };
     135             : 
     136          56 : void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state) {
     137         112 :   KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
     138          56 :   assembler.KeyedStoreGeneric();
     139          56 : }
     140             : 
     141          56 : void StoreICUninitializedGenerator::Generate(
     142             :     compiler::CodeAssemblerState* state) {
     143         112 :   KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
     144          56 :   assembler.StoreIC_Uninitialized();
     145          56 : }
     146             : 
     147          56 : void KeyedStoreGenericGenerator::SetProperty(
     148             :     compiler::CodeAssemblerState* state, TNode<Context> context,
     149             :     TNode<JSReceiver> receiver, TNode<BoolT> is_simple_receiver,
     150             :     TNode<Name> name, TNode<Object> value, LanguageMode language_mode) {
     151         112 :   KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
     152             :   assembler.SetProperty(context, receiver, is_simple_receiver, name, value,
     153          56 :                         language_mode);
     154          56 : }
     155             : 
     156          56 : void KeyedStoreGenericGenerator::SetProperty(
     157             :     compiler::CodeAssemblerState* state, TNode<Context> context,
     158             :     TNode<Object> receiver, TNode<Object> key, TNode<Object> value,
     159             :     LanguageMode language_mode) {
     160         112 :   KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
     161          56 :   assembler.SetProperty(context, receiver, key, value, language_mode);
     162          56 : }
     163             : 
     164          56 : void KeyedStoreGenericGenerator::SetPropertyInLiteral(
     165             :     compiler::CodeAssemblerState* state, TNode<Context> context,
     166             :     TNode<JSObject> receiver, TNode<Object> key, TNode<Object> value) {
     167         112 :   KeyedStoreGenericAssembler assembler(state, StoreMode::kInLiteral);
     168          56 :   assembler.SetProperty(context, receiver, key, value, LanguageMode::kStrict);
     169          56 : }
     170             : 
     171        1008 : void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
     172             :     Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
     173        2016 :   VARIABLE(var_map, MachineRepresentation::kTagged);
     174        1008 :   var_map.Bind(receiver_map);
     175        2016 :   Label loop_body(this, &var_map);
     176        1008 :   Goto(&loop_body);
     177             : 
     178        1008 :   BIND(&loop_body);
     179             :   {
     180        1008 :     Node* map = var_map.value();
     181        1008 :     Node* prototype = LoadMapPrototype(map);
     182        1008 :     GotoIf(IsNull(prototype), only_fast_elements);
     183        1008 :     Node* prototype_map = LoadMap(prototype);
     184        1008 :     var_map.Bind(prototype_map);
     185        1008 :     TNode<Int32T> instance_type = LoadMapInstanceType(prototype_map);
     186        2016 :     GotoIf(IsCustomElementsReceiverInstanceType(instance_type),
     187        1008 :            non_fast_elements);
     188        1008 :     Node* elements_kind = LoadMapElementsKind(prototype_map);
     189        1008 :     GotoIf(IsFastElementsKind(elements_kind), &loop_body);
     190        1008 :     GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
     191        1008 :     Goto(non_fast_elements);
     192             :   }
     193        1008 : }
     194             : 
     195        1512 : void KeyedStoreGenericAssembler::TryRewriteElements(
     196             :     Node* receiver, Node* receiver_map, Node* elements, Node* native_context,
     197             :     ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
     198             :   DCHECK(IsFastPackedElementsKind(from_kind));
     199        1512 :   ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
     200        1512 :   ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
     201        1512 :   if (AllocationSite::ShouldTrack(from_kind, to_kind)) {
     202        1008 :     TrapAllocationMemento(receiver, bailout);
     203             :   }
     204        3024 :   Label perform_transition(this), check_holey_map(this);
     205        3024 :   VARIABLE(var_target_map, MachineRepresentation::kTagged);
     206             :   // Check if the receiver has the default |from_kind| map.
     207             :   {
     208        1512 :     Node* packed_map = LoadJSArrayElementsMap(from_kind, native_context);
     209        1512 :     GotoIf(WordNotEqual(receiver_map, packed_map), &check_holey_map);
     210        1512 :     var_target_map.Bind(
     211        3024 :         LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
     212        1512 :     Goto(&perform_transition);
     213             :   }
     214             : 
     215             :   // Check if the receiver has the default |holey_from_kind| map.
     216        1512 :   BIND(&check_holey_map);
     217             :   {
     218        3024 :     Node* holey_map = LoadContextElement(
     219        4536 :         native_context, Context::ArrayMapIndex(holey_from_kind));
     220        1512 :     GotoIf(WordNotEqual(receiver_map, holey_map), bailout);
     221        3024 :     var_target_map.Bind(LoadContextElement(
     222        4536 :         native_context, Context::ArrayMapIndex(holey_to_kind)));
     223        1512 :     Goto(&perform_transition);
     224             :   }
     225             : 
     226             :   // Found a supported transition target map, perform the transition!
     227        1512 :   BIND(&perform_transition);
     228             :   {
     229        1512 :     if (IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind)) {
     230        1008 :       Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     231        1008 :       GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
     232        1008 :                            capacity, INTPTR_PARAMETERS, bailout);
     233             :     }
     234        1512 :     StoreMap(receiver, var_target_map.value());
     235             :   }
     236        1512 : }
     237             : 
     238         672 : void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
     239             :     Node* receiver, Node* receiver_map, Node* native_context,
     240             :     ElementsKind packed_kind, ElementsKind holey_kind, Label* done,
     241             :     Label* map_mismatch, Label* bailout) {
     242         672 :   Node* packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
     243         672 :   GotoIf(WordNotEqual(receiver_map, packed_map), map_mismatch);
     244         672 :   if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) {
     245         168 :     TrapAllocationMemento(receiver, bailout);
     246             :   }
     247             :   Node* holey_map =
     248         672 :       LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind));
     249         672 :   StoreMap(receiver, holey_map);
     250         672 :   Goto(done);
     251         672 : }
     252             : 
     253         336 : void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
     254             :     Node* receiver, Node* receiver_map, Node* current_elements_kind,
     255             :     Node* context, ElementsKind packed_kind, Label* bailout) {
     256         336 :   ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
     257         672 :   Label already_holey(this);
     258             : 
     259         672 :   GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
     260         336 :          &already_holey);
     261         336 :   Node* native_context = LoadNativeContext(context);
     262         336 :   TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
     263         336 :                             holey_kind, &already_holey, bailout, bailout);
     264         336 :   BIND(&already_holey);
     265         336 : }
     266             : 
     267         168 : void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
     268             :     Node* receiver, Node* receiver_map, Node* current_elements_kind,
     269             :     Node* context, ElementsKind packed_kind, ElementsKind packed_kind_2,
     270             :     Label* bailout) {
     271         168 :   ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
     272         168 :   ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
     273         336 :   Label already_holey(this), check_other_kind(this);
     274             : 
     275         336 :   GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
     276         168 :          &already_holey);
     277         336 :   GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
     278         168 :          &already_holey);
     279             : 
     280         168 :   Node* native_context = LoadNativeContext(context);
     281         168 :   TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
     282             :                             holey_kind, &already_holey, &check_other_kind,
     283         168 :                             bailout);
     284         168 :   BIND(&check_other_kind);
     285         168 :   TryChangeToHoleyMapHelper(receiver, receiver_map, native_context,
     286             :                             packed_kind_2, holey_kind_2, &already_holey,
     287         168 :                             bailout, bailout);
     288         168 :   BIND(&already_holey);
     289         168 : }
     290             : 
     291        3024 : void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
     292             :     Node* receiver, Node* index, Node* value, UpdateLength update_length) {
     293        3024 :   if (update_length != kDontChangeLength) {
     294        2016 :     Node* new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1))));
     295        2016 :     StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length,
     296        2016 :                                    MachineRepresentation::kTagged);
     297             :   }
     298        3024 :   Return(value);
     299        3024 : }
     300             : 
     301         504 : void KeyedStoreGenericAssembler::StoreElementWithCapacity(
     302             :     Node* receiver, Node* receiver_map, Node* elements, Node* elements_kind,
     303             :     Node* intptr_index, Node* value, Node* context, Label* slow,
     304             :     UpdateLength update_length) {
     305         504 :   if (update_length != kDontChangeLength) {
     306             :     CSA_ASSERT(this, InstanceTypeEqual(LoadMapInstanceType(receiver_map),
     307             :                                        JS_ARRAY_TYPE));
     308             :     // Check if the length property is writable. The fast check is only
     309             :     // supported for fast properties.
     310         336 :     GotoIf(IsDictionaryMap(receiver_map), slow);
     311             :     // The length property is non-configurable, so it's guaranteed to always
     312             :     // be the first property.
     313         336 :     TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
     314         336 :     TNode<Uint32T> details = LoadDetailsByDescriptorEntry(descriptors, 0);
     315         672 :     GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
     316         336 :            slow);
     317             :   }
     318             :   STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
     319         504 :   const int kHeaderSize = FixedArray::kHeaderSize - kHeapObjectTag;
     320             : 
     321        1008 :   Label check_double_elements(this), check_cow_elements(this);
     322         504 :   Node* elements_map = LoadMap(elements);
     323        1008 :   GotoIf(WordNotEqual(elements_map, LoadRoot(RootIndex::kFixedArrayMap)),
     324         504 :          &check_double_elements);
     325             : 
     326             :   // FixedArray backing store -> Smi or object elements.
     327             :   {
     328        1008 :     Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_ELEMENTS,
     329        1008 :                                           INTPTR_PARAMETERS, kHeaderSize);
     330             :     // Check if we're about to overwrite the hole. We can safely do that
     331             :     // only if there can be no setters on the prototype chain.
     332             :     // If we know that we're storing beyond the previous array length, we
     333             :     // can skip the hole check (and always assume the hole).
     334             :     {
     335        1008 :       Label hole_check_passed(this);
     336         504 :       if (update_length == kDontChangeLength) {
     337         168 :         Node* element = Load(MachineType::AnyTagged(), elements, offset);
     338         168 :         GotoIf(WordNotEqual(element, TheHoleConstant()), &hole_check_passed);
     339             :       }
     340             :       BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
     341         504 :                                             &hole_check_passed);
     342         504 :       BIND(&hole_check_passed);
     343             :     }
     344             : 
     345             :     // Check if the value we're storing matches the elements_kind. Smis
     346             :     // can always be stored.
     347             :     {
     348        1008 :       Label non_smi_value(this);
     349         504 :       GotoIfNot(TaggedIsSmi(value), &non_smi_value);
     350             :       // If we're about to introduce holes, ensure holey elements.
     351         504 :       if (update_length == kBumpLengthWithGap) {
     352             :         TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context,
     353         168 :                                  PACKED_SMI_ELEMENTS, PACKED_ELEMENTS, slow);
     354             :       }
     355         504 :       StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
     356         504 :                           value);
     357         504 :       MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
     358             : 
     359         504 :       BIND(&non_smi_value);
     360             :     }
     361             : 
     362             :     // Check if we already have object elements; just do the store if so.
     363             :     {
     364        1008 :       Label must_transition(this);
     365             :       STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
     366             :       STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
     367        1008 :       GotoIf(Int32LessThanOrEqual(elements_kind,
     368        1008 :                                   Int32Constant(HOLEY_SMI_ELEMENTS)),
     369         504 :              &must_transition);
     370         504 :       if (update_length == kBumpLengthWithGap) {
     371             :         TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
     372         168 :                             PACKED_ELEMENTS, slow);
     373             :       }
     374         504 :       Store(elements, offset, value);
     375         504 :       MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
     376             : 
     377         504 :       BIND(&must_transition);
     378             :     }
     379             : 
     380             :     // Transition to the required ElementsKind.
     381             :     {
     382        1008 :       Label transition_to_double(this), transition_to_object(this);
     383         504 :       Node* native_context = LoadNativeContext(context);
     384        1008 :       Branch(WordEqual(LoadMap(value), LoadRoot(RootIndex::kHeapNumberMap)),
     385         504 :              &transition_to_double, &transition_to_object);
     386         504 :       BIND(&transition_to_double);
     387             :       {
     388             :         // If we're adding holes at the end, always transition to a holey
     389             :         // elements kind, otherwise try to remain packed.
     390             :         ElementsKind target_kind = update_length == kBumpLengthWithGap
     391             :                                        ? HOLEY_DOUBLE_ELEMENTS
     392         504 :                                        : PACKED_DOUBLE_ELEMENTS;
     393         504 :         TryRewriteElements(receiver, receiver_map, elements, native_context,
     394         504 :                            PACKED_SMI_ELEMENTS, target_kind, slow);
     395             :         // Reload migrated elements.
     396         504 :         Node* double_elements = LoadElements(receiver);
     397             :         Node* double_offset =
     398        1008 :             ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
     399        1008 :                                    INTPTR_PARAMETERS, kHeaderSize);
     400             :         // Make sure we do not store signalling NaNs into double arrays.
     401         504 :         Node* double_value = Float64SilenceNaN(LoadHeapNumberValue(value));
     402         504 :         StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
     403         504 :                             double_offset, double_value);
     404             :         MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
     405         504 :                                    update_length);
     406             :       }
     407             : 
     408         504 :       BIND(&transition_to_object);
     409             :       {
     410             :         // If we're adding holes at the end, always transition to a holey
     411             :         // elements kind, otherwise try to remain packed.
     412             :         ElementsKind target_kind = update_length == kBumpLengthWithGap
     413             :                                        ? HOLEY_ELEMENTS
     414         504 :                                        : PACKED_ELEMENTS;
     415         504 :         TryRewriteElements(receiver, receiver_map, elements, native_context,
     416         504 :                            PACKED_SMI_ELEMENTS, target_kind, slow);
     417             :         // The elements backing store didn't change, no reload necessary.
     418             :         CSA_ASSERT(this, WordEqual(elements, LoadElements(receiver)));
     419         504 :         Store(elements, offset, value);
     420             :         MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
     421         504 :                                    update_length);
     422             :       }
     423             :     }
     424             :   }
     425             : 
     426         504 :   BIND(&check_double_elements);
     427         504 :   Node* fixed_double_array_map = LoadRoot(RootIndex::kFixedDoubleArrayMap);
     428        1008 :   GotoIf(WordNotEqual(elements_map, fixed_double_array_map),
     429         504 :          &check_cow_elements);
     430             :   // FixedDoubleArray backing store -> double elements.
     431             :   {
     432        1008 :     Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
     433        1008 :                                           INTPTR_PARAMETERS, kHeaderSize);
     434             :     // Check if we're about to overwrite the hole. We can safely do that
     435             :     // only if there can be no setters on the prototype chain.
     436             :     {
     437        1008 :       Label hole_check_passed(this);
     438             :       // If we know that we're storing beyond the previous array length, we
     439             :       // can skip the hole check (and always assume the hole).
     440         504 :       if (update_length == kDontChangeLength) {
     441         336 :         Label found_hole(this);
     442             :         LoadDoubleWithHoleCheck(elements, offset, &found_hole,
     443         168 :                                 MachineType::None());
     444         168 :         Goto(&hole_check_passed);
     445         168 :         BIND(&found_hole);
     446             :       }
     447             :       BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
     448         504 :                                             &hole_check_passed);
     449         504 :       BIND(&hole_check_passed);
     450             :     }
     451             : 
     452             :     // Try to store the value as a double.
     453             :     {
     454        1008 :       Label non_number_value(this);
     455         504 :       Node* double_value = TryTaggedToFloat64(value, &non_number_value);
     456             : 
     457             :       // Make sure we do not store signalling NaNs into double arrays.
     458         504 :       double_value = Float64SilenceNaN(double_value);
     459             :       // If we're about to introduce holes, ensure holey elements.
     460         504 :       if (update_length == kBumpLengthWithGap) {
     461             :         TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
     462         168 :                             PACKED_DOUBLE_ELEMENTS, slow);
     463             :       }
     464         504 :       StoreNoWriteBarrier(MachineRepresentation::kFloat64, elements, offset,
     465         504 :                           double_value);
     466         504 :       MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
     467             : 
     468         504 :       BIND(&non_number_value);
     469             :     }
     470             : 
     471             :     // Transition to object elements.
     472             :     {
     473         504 :       Node* native_context = LoadNativeContext(context);
     474             :       ElementsKind target_kind = update_length == kBumpLengthWithGap
     475             :                                      ? HOLEY_ELEMENTS
     476         504 :                                      : PACKED_ELEMENTS;
     477         504 :       TryRewriteElements(receiver, receiver_map, elements, native_context,
     478         504 :                          PACKED_DOUBLE_ELEMENTS, target_kind, slow);
     479             :       // Reload migrated elements.
     480         504 :       Node* fast_elements = LoadElements(receiver);
     481        1008 :       Node* fast_offset = ElementOffsetFromIndex(
     482        1008 :           intptr_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
     483         504 :       Store(fast_elements, fast_offset, value);
     484         504 :       MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
     485             :     }
     486             :   }
     487             : 
     488         504 :   BIND(&check_cow_elements);
     489             :   {
     490             :     // TODO(jkummerow): Use GrowElementsCapacity instead of bailing out.
     491         504 :     Goto(slow);
     492             :   }
     493         504 : }
     494             : 
     495         168 : void KeyedStoreGenericAssembler::EmitGenericElementStore(
     496             :     Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
     497             :     Node* value, Node* context, Label* slow) {
     498         336 :   Label if_fast(this), if_in_bounds(this), if_out_of_bounds(this),
     499         336 :       if_increment_length_by_one(this), if_bump_length_with_gap(this),
     500         336 :       if_grow(this), if_nonfast(this), if_typed_array(this),
     501         336 :       if_dictionary(this);
     502         168 :   Node* elements = LoadElements(receiver);
     503         168 :   Node* elements_kind = LoadMapElementsKind(receiver_map);
     504         168 :   Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
     505         168 :   BIND(&if_fast);
     506             : 
     507         336 :   Label if_array(this);
     508         168 :   GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &if_array);
     509             :   {
     510         168 :     Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     511         336 :     Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds,
     512         168 :            &if_out_of_bounds);
     513             :   }
     514         168 :   BIND(&if_array);
     515             :   {
     516         168 :     Node* length = SmiUntag(LoadFastJSArrayLength(receiver));
     517         168 :     GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds);
     518         168 :     Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
     519         168 :     GotoIf(UintPtrGreaterThanOrEqual(intptr_index, capacity), &if_grow);
     520         336 :     Branch(WordEqual(intptr_index, length), &if_increment_length_by_one,
     521         168 :            &if_bump_length_with_gap);
     522             :   }
     523             : 
     524         168 :   BIND(&if_in_bounds);
     525             :   {
     526             :     StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
     527             :                              intptr_index, value, context, slow,
     528         168 :                              kDontChangeLength);
     529             :   }
     530             : 
     531         168 :   BIND(&if_out_of_bounds);
     532             :   {
     533             :     // Integer indexed out-of-bounds accesses to typed arrays are simply
     534             :     // ignored, since we never look up integer indexed properties on the
     535             :     // prototypes of typed arrays. For all other types, we may need to
     536             :     // grow the backing store.
     537         168 :     GotoIfNot(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), &if_grow);
     538         168 :     Return(value);
     539             :   }
     540             : 
     541         168 :   BIND(&if_increment_length_by_one);
     542             :   {
     543             :     StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
     544             :                              intptr_index, value, context, slow,
     545         168 :                              kIncrementLengthByOne);
     546             :   }
     547             : 
     548         168 :   BIND(&if_bump_length_with_gap);
     549             :   {
     550             :     StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
     551             :                              intptr_index, value, context, slow,
     552         168 :                              kBumpLengthWithGap);
     553             :   }
     554             : 
     555             :   // Out-of-capacity accesses (index >= capacity) jump here. Additionally,
     556             :   // an ElementsKind transition might be necessary.
     557             :   // The index can also be negative at this point! Jump to the runtime in that
     558             :   // case to convert it to a named property.
     559         168 :   BIND(&if_grow);
     560             :   {
     561         168 :     Comment("Grow backing store");
     562             :     // TODO(jkummerow): Support inline backing store growth.
     563         168 :     Goto(slow);
     564             :   }
     565             : 
     566             :   // Any ElementsKind > LAST_FAST_ELEMENTS_KIND jumps here for further
     567             :   // dispatch.
     568         168 :   BIND(&if_nonfast);
     569             :   {
     570             :     STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
     571         336 :     GotoIf(Int32GreaterThanOrEqual(
     572             :                elements_kind,
     573         336 :                Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
     574         168 :            &if_typed_array);
     575         336 :     GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
     576         168 :            &if_dictionary);
     577         168 :     Goto(slow);
     578             :   }
     579             : 
     580         168 :   BIND(&if_dictionary);
     581             :   {
     582         168 :     Comment("Dictionary");
     583             :     // TODO(jkummerow): Support storing to dictionary elements.
     584         168 :     Goto(slow);
     585             :   }
     586             : 
     587         168 :   BIND(&if_typed_array);
     588             :   {
     589         168 :     Comment("Typed array");
     590             :     // TODO(jkummerow): Support typed arrays.
     591         168 :     Goto(slow);
     592             :   }
     593         168 : }
     594             : 
     595         224 : void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
     596             :     Node* receiver_map, Node* name, Label* accessor,
     597             :     Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
     598             :     Label* bailout) {
     599         448 :   Label ok_to_write(this);
     600         448 :   VARIABLE(var_holder, MachineRepresentation::kTagged);
     601         224 :   var_holder.Bind(LoadMapPrototype(receiver_map));
     602         448 :   VARIABLE(var_holder_map, MachineRepresentation::kTagged);
     603         224 :   var_holder_map.Bind(LoadMap(var_holder.value()));
     604             : 
     605         224 :   Variable* merged_variables[] = {&var_holder, &var_holder_map};
     606         448 :   Label loop(this, arraysize(merged_variables), merged_variables);
     607         224 :   Goto(&loop);
     608         224 :   BIND(&loop);
     609             :   {
     610         224 :     Node* holder = var_holder.value();
     611         224 :     GotoIf(IsNull(holder), &ok_to_write);
     612         224 :     Node* holder_map = var_holder_map.value();
     613         224 :     Node* instance_type = LoadMapInstanceType(holder_map);
     614         448 :     Label next_proto(this);
     615             :     {
     616         448 :       Label found(this), found_fast(this), found_dict(this), found_global(this);
     617         448 :       TVARIABLE(HeapObject, var_meta_storage);
     618         448 :       TVARIABLE(IntPtrT, var_entry);
     619         448 :       TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
     620             :                         &found_dict, &found_global, &var_meta_storage,
     621         224 :                         &var_entry, &next_proto, bailout);
     622         224 :       BIND(&found_fast);
     623             :       {
     624         224 :         TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
     625         224 :         TNode<IntPtrT> name_index = var_entry.value();
     626         224 :         Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
     627         224 :         JumpIfDataProperty(details, &ok_to_write, readonly);
     628             : 
     629             :         // Accessor case.
     630             :         // TODO(jkummerow): Implement a trimmed-down
     631             :         // LoadAccessorFromFastObject.
     632         448 :         VARIABLE(var_details, MachineRepresentation::kWord32);
     633         224 :         LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
     634         224 :                                    &var_details, var_accessor_pair);
     635         224 :         var_accessor_holder->Bind(holder);
     636         224 :         Goto(accessor);
     637             :       }
     638             : 
     639         224 :       BIND(&found_dict);
     640             :       {
     641         224 :         Node* dictionary = var_meta_storage.value();
     642         224 :         Node* entry = var_entry.value();
     643             :         Node* details =
     644         224 :             LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry);
     645         224 :         JumpIfDataProperty(details, &ok_to_write, readonly);
     646             : 
     647         224 :         if (accessor != nullptr) {
     648             :           // Accessor case.
     649         224 :           var_accessor_pair->Bind(
     650         448 :               LoadValueByKeyIndex<NameDictionary>(dictionary, entry));
     651         224 :           var_accessor_holder->Bind(holder);
     652         224 :           Goto(accessor);
     653             :         } else {
     654           0 :           Goto(&ok_to_write);
     655             :         }
     656             :       }
     657             : 
     658         224 :       BIND(&found_global);
     659             :       {
     660         224 :         Node* dictionary = var_meta_storage.value();
     661         224 :         Node* entry = var_entry.value();
     662             :         Node* property_cell =
     663         224 :             LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry);
     664             :         Node* value =
     665         224 :             LoadObjectField(property_cell, PropertyCell::kValueOffset);
     666         224 :         GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
     667         448 :         Node* details = LoadAndUntagToWord32ObjectField(
     668         448 :             property_cell, PropertyCell::kDetailsOffset);
     669         224 :         JumpIfDataProperty(details, &ok_to_write, readonly);
     670             : 
     671         224 :         if (accessor != nullptr) {
     672             :           // Accessor case.
     673         224 :           var_accessor_pair->Bind(value);
     674         224 :           var_accessor_holder->Bind(holder);
     675         224 :           Goto(accessor);
     676             :         } else {
     677           0 :           Goto(&ok_to_write);
     678             :         }
     679             :       }
     680             :     }
     681             : 
     682         224 :     BIND(&next_proto);
     683             :     // Bailout if it can be an integer indexed exotic case.
     684         224 :     GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout);
     685         224 :     Node* proto = LoadMapPrototype(holder_map);
     686         224 :     GotoIf(IsNull(proto), &ok_to_write);
     687         224 :     var_holder.Bind(proto);
     688         224 :     var_holder_map.Bind(LoadMap(proto));
     689         224 :     Goto(&loop);
     690             :   }
     691         224 :   BIND(&ok_to_write);
     692         224 : }
     693             : 
     694         280 : TNode<Map> KeyedStoreGenericAssembler::FindCandidateStoreICTransitionMapHandler(
     695             :     TNode<Map> map, TNode<Name> name, Label* slow) {
     696         560 :   TVARIABLE(Map, var_transition_map);
     697         560 :   Label simple_transition(this), transition_array(this),
     698         560 :       found_handler_candidate(this);
     699             : 
     700             :   TNode<MaybeObject> maybe_handler =
     701         280 :       LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
     702             : 
     703             :   // Smi -> slow,
     704             :   // Cleared weak reference -> slow
     705             :   // weak reference -> simple_transition
     706             :   // strong reference -> transition_array
     707         560 :   TVARIABLE(Object, var_transition_map_or_array);
     708         280 :   DispatchMaybeObject(maybe_handler, slow, slow, &simple_transition,
     709         280 :                       &transition_array, &var_transition_map_or_array);
     710             : 
     711         280 :   BIND(&simple_transition);
     712             :   {
     713         280 :     var_transition_map = CAST(var_transition_map_or_array.value());
     714         280 :     Goto(&found_handler_candidate);
     715             :   }
     716             : 
     717         280 :   BIND(&transition_array);
     718             :   {
     719             :     TNode<Map> maybe_handler_map =
     720         280 :         LoadMap(CAST(var_transition_map_or_array.value()));
     721         280 :     GotoIfNot(IsTransitionArrayMap(maybe_handler_map), slow);
     722             : 
     723         560 :     TVARIABLE(IntPtrT, var_name_index);
     724         560 :     Label if_found_candidate(this);
     725             :     TNode<TransitionArray> transitions =
     726         280 :         CAST(var_transition_map_or_array.value());
     727         560 :     TransitionLookup(name, transitions, &if_found_candidate, &var_name_index,
     728         280 :                      slow);
     729             : 
     730         280 :     BIND(&if_found_candidate);
     731             :     {
     732             :       // Given that
     733             :       // 1) transitions with the same name are ordered in the transition
     734             :       //    array by PropertyKind and then by PropertyAttributes values,
     735             :       // 2) kData < kAccessor,
     736             :       // 3) NONE == 0,
     737             :       // 4) properties with private symbol names are guaranteed to be
     738             :       //    non-enumerable (so DONT_ENUM bit in attributes is always set),
     739             :       // the resulting map of transitioning store if it exists in the
     740             :       // transition array is expected to be the first among the transitions
     741             :       // with the same name.
     742             :       // See TransitionArray::CompareDetails() for details.
     743             :       STATIC_ASSERT(kData == 0);
     744             :       STATIC_ASSERT(NONE == 0);
     745             :       const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex -
     746             :                                       TransitionArray::kEntryKeyIndex) *
     747         280 :                                      kTaggedSize;
     748         560 :       var_transition_map = CAST(GetHeapObjectAssumeWeak(
     749             :           LoadArrayElement(transitions, WeakFixedArray::kHeaderSize,
     750         280 :                            var_name_index.value(), kKeyToTargetOffset)));
     751         280 :       Goto(&found_handler_candidate);
     752             :     }
     753             :   }
     754             : 
     755         280 :   BIND(&found_handler_candidate);
     756         560 :   return var_transition_map.value();
     757             : }
     758             : 
     759         280 : void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
     760             :     TNode<JSReceiver> receiver, TNode<Map> receiver_map,
     761             :     const StoreICParameters* p, ExitPoint* exit_point, Label* slow,
     762             :     Maybe<LanguageMode> maybe_language_mode) {
     763             :   CSA_ASSERT(this, IsSimpleObjectMap(receiver_map));
     764         560 :   VARIABLE(var_accessor_pair, MachineRepresentation::kTagged);
     765         560 :   VARIABLE(var_accessor_holder, MachineRepresentation::kTagged);
     766         560 :   Label fast_properties(this), dictionary_properties(this), accessor(this),
     767         560 :       readonly(this);
     768         280 :   Node* bitfield3 = LoadMapBitField3(receiver_map);
     769         560 :   Branch(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
     770         280 :          &dictionary_properties, &fast_properties);
     771             : 
     772         280 :   BIND(&fast_properties);
     773             :   {
     774         280 :     Comment("fast property store");
     775         280 :     TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
     776         560 :     Label descriptor_found(this), lookup_transition(this);
     777         560 :     TVARIABLE(IntPtrT, var_name_index);
     778         560 :     DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found,
     779         280 :                      &var_name_index, &lookup_transition);
     780             : 
     781         280 :     BIND(&descriptor_found);
     782             :     {
     783         280 :       TNode<IntPtrT> name_index = var_name_index.value();
     784         280 :       Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
     785         560 :       Label data_property(this);
     786         280 :       JumpIfDataProperty(details, &data_property,
     787         560 :                          ShouldReconfigureExisting() ? nullptr : &readonly);
     788             : 
     789         280 :       if (ShouldCallSetter()) {
     790             :         // Accessor case.
     791             :         // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
     792         448 :         VARIABLE(var_details, MachineRepresentation::kWord32);
     793         224 :         LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
     794             :                                    name_index, &var_details,
     795         224 :                                    &var_accessor_pair);
     796         224 :         var_accessor_holder.Bind(receiver);
     797         224 :         Goto(&accessor);
     798             :       } else {
     799          56 :         Goto(&data_property);
     800             :       }
     801             : 
     802         280 :       BIND(&data_property);
     803             :       {
     804         280 :         CheckForAssociatedProtector(p->name, slow);
     805         280 :         OverwriteExistingFastDataProperty(receiver, receiver_map, descriptors,
     806             :                                           name_index, details, p->value, slow,
     807         280 :                                           false);
     808         280 :         exit_point->Return(p->value);
     809             :       }
     810             :     }
     811         280 :     BIND(&lookup_transition);
     812             :     {
     813         280 :       Comment("lookup transition");
     814             :       TNode<Map> transition_map = FindCandidateStoreICTransitionMapHandler(
     815         280 :           receiver_map, CAST(p->name), slow);
     816             : 
     817             :       // Validate the transition handler candidate and apply the transition.
     818         280 :       StoreTransitionMapFlags flags = kValidateTransitionHandler;
     819         280 :       if (ShouldCheckPrototypeValidity()) {
     820         224 :         flags = StoreTransitionMapFlags(flags | kCheckPrototypeValidity);
     821             :       }
     822         280 :       HandleStoreICTransitionMapHandlerCase(p, transition_map, slow, flags);
     823         280 :       exit_point->Return(p->value);
     824             :     }
     825             :   }
     826             : 
     827         280 :   BIND(&dictionary_properties);
     828             :   {
     829         280 :     Comment("dictionary property store");
     830             :     // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
     831             :     // seeing global objects here (which would need special handling).
     832             : 
     833         560 :     TVARIABLE(IntPtrT, var_name_index);
     834         560 :     Label dictionary_found(this, &var_name_index), not_found(this);
     835         280 :     TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver)));
     836         560 :     NameDictionaryLookup<NameDictionary>(properties, CAST(p->name),
     837             :                                          &dictionary_found, &var_name_index,
     838         280 :                                          &not_found);
     839         280 :     BIND(&dictionary_found);
     840             :     {
     841         560 :       Label overwrite(this);
     842             :       TNode<Uint32T> details = LoadDetailsByKeyIndex<NameDictionary>(
     843         280 :           properties, var_name_index.value());
     844         280 :       JumpIfDataProperty(details, &overwrite,
     845         560 :                          ShouldReconfigureExisting() ? nullptr : &readonly);
     846             : 
     847         280 :       if (ShouldCallSetter()) {
     848             :         // Accessor case.
     849         448 :         var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>(
     850         672 :             properties, var_name_index.value()));
     851         224 :         var_accessor_holder.Bind(receiver);
     852         224 :         Goto(&accessor);
     853             :       } else {
     854          56 :         Goto(&overwrite);
     855             :       }
     856             : 
     857         280 :       BIND(&overwrite);
     858             :       {
     859         280 :         CheckForAssociatedProtector(p->name, slow);
     860         280 :         StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
     861         280 :                                              p->value);
     862         280 :         exit_point->Return(p->value);
     863             :       }
     864             :     }
     865             : 
     866         280 :     BIND(&not_found);
     867             :     {
     868         280 :       CheckForAssociatedProtector(p->name, slow);
     869         560 :       Label extensible(this);
     870         280 :       Node* bitfield2 = LoadMapBitField2(receiver_map);
     871         280 :       GotoIf(IsPrivateSymbol(p->name), &extensible);
     872         280 :       Branch(IsSetWord32<Map::IsExtensibleBit>(bitfield2), &extensible, slow);
     873             : 
     874         280 :       BIND(&extensible);
     875         280 :       if (ShouldCheckPrototype()) {
     876             :         DCHECK(ShouldCallSetter());
     877         448 :         LookupPropertyOnPrototypeChain(
     878         224 :             receiver_map, p->name, &accessor, &var_accessor_pair,
     879             :             &var_accessor_holder,
     880         448 :             ShouldReconfigureExisting() ? nullptr : &readonly, slow);
     881             :       }
     882         560 :       Label add_dictionary_property_slow(this);
     883         280 :       InvalidateValidityCellIfPrototype(receiver_map, bitfield2);
     884         560 :       Add<NameDictionary>(properties, CAST(p->name), p->value,
     885         280 :                           &add_dictionary_property_slow);
     886         280 :       exit_point->Return(p->value);
     887             : 
     888         280 :       BIND(&add_dictionary_property_slow);
     889         280 :       exit_point->ReturnCallRuntime(Runtime::kAddDictionaryProperty, p->context,
     890         560 :                                     p->receiver, p->name, p->value);
     891             :     }
     892             :   }
     893             : 
     894         280 :   if (ShouldCallSetter()) {
     895         224 :     BIND(&accessor);
     896             :     {
     897         448 :       Label not_callable(this);
     898         224 :       Node* accessor_pair = var_accessor_pair.value();
     899         224 :       GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow);
     900             :       CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
     901             :       Node* setter =
     902         224 :           LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
     903         224 :       Node* setter_map = LoadMap(setter);
     904             :       // FunctionTemplateInfo setters are not supported yet.
     905         224 :       GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
     906         224 :       GotoIfNot(IsCallableMap(setter_map), &not_callable);
     907             : 
     908         448 :       Callable callable = CodeFactory::Call(isolate());
     909         224 :       CallJS(callable, p->context, setter, receiver, p->value);
     910         224 :       exit_point->Return(p->value);
     911             : 
     912         224 :       BIND(&not_callable);
     913             :       {
     914             :         LanguageMode language_mode;
     915         224 :         if (maybe_language_mode.To(&language_mode)) {
     916         112 :           if (language_mode == LanguageMode::kStrict) {
     917         224 :             exit_point->ReturnCallRuntime(
     918         112 :                 Runtime::kThrowTypeError, p->context,
     919         112 :                 SmiConstant(MessageTemplate::kNoSetterInCallback), p->name,
     920         112 :                 var_accessor_holder.value());
     921             :           } else {
     922           0 :             exit_point->Return(p->value);
     923             :           }
     924             :         } else {
     925         112 :           CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
     926             :                       SmiConstant(MessageTemplate::kNoSetterInCallback),
     927         224 :                       p->name, var_accessor_holder.value());
     928         112 :           exit_point->Return(p->value);
     929             :         }
     930             :       }
     931             :     }
     932             :   }
     933             : 
     934         280 :   if (!ShouldReconfigureExisting()) {
     935         224 :     BIND(&readonly);
     936             :     {
     937             :       LanguageMode language_mode;
     938         224 :       if (maybe_language_mode.To(&language_mode)) {
     939         112 :         if (language_mode == LanguageMode::kStrict) {
     940         112 :           Node* type = Typeof(p->receiver);
     941         112 :           ThrowTypeError(p->context, MessageTemplate::kStrictReadOnlyProperty,
     942         224 :                          p->name, type, p->receiver);
     943             :         } else {
     944           0 :           exit_point->Return(p->value);
     945             :         }
     946             :       } else {
     947         112 :         CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
     948             :                     SmiConstant(MessageTemplate::kStrictReadOnlyProperty),
     949         224 :                     p->name, Typeof(p->receiver), p->receiver);
     950         112 :         exit_point->Return(p->value);
     951             :       }
     952             :     }
     953             :   }
     954         280 : }
     955             : 
     956             : // Helper that is used by the public KeyedStoreGeneric and by SetProperty.
     957         168 : void KeyedStoreGenericAssembler::KeyedStoreGeneric(
     958             :     TNode<Context> context, TNode<Object> receiver, TNode<Object> key,
     959             :     TNode<Object> value, Maybe<LanguageMode> language_mode) {
     960         336 :   TVARIABLE(IntPtrT, var_index);
     961         336 :   TVARIABLE(Object, var_unique, key);
     962         336 :   Label if_index(this), if_unique_name(this), not_internalized(this),
     963         336 :       slow(this);
     964             : 
     965         168 :   GotoIf(TaggedIsSmi(receiver), &slow);
     966         168 :   TNode<Map> receiver_map = LoadMap(CAST(receiver));
     967         168 :   TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
     968             :   // Receivers requiring non-standard element accesses (interceptors, access
     969             :   // checks, strings and string wrappers, proxies) are handled in the runtime.
     970         168 :   GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
     971             : 
     972         168 :   TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
     973         168 :             &not_internalized);
     974             : 
     975         168 :   BIND(&if_index);
     976             :   {
     977         168 :     Comment("integer index");
     978         336 :     EmitGenericElementStore(receiver, receiver_map, instance_type,
     979         336 :                             var_index.value(), value, context, &slow);
     980             :   }
     981             : 
     982         168 :   BIND(&if_unique_name);
     983             :   {
     984         168 :     Comment("key is unique name");
     985         336 :     StoreICParameters p(context, receiver, var_unique.value(), value, nullptr,
     986         504 :                         nullptr);
     987         336 :     ExitPoint direct_exit(this);
     988         336 :     EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit,
     989         168 :                              &slow, language_mode);
     990             :   }
     991             : 
     992         168 :   BIND(&not_internalized);
     993             :   {
     994             :     if (FLAG_internalize_on_the_fly) {
     995         168 :       TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
     996         168 :                            &var_unique, &slow, &slow);
     997             :     } else {
     998             :       Goto(&slow);
     999             :     }
    1000             :   }
    1001             : 
    1002         168 :   BIND(&slow);
    1003             :   {
    1004         168 :     if (IsKeyedStore()) {
    1005         112 :       Comment("KeyedStoreGeneric_slow");
    1006         224 :       TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
    1007         112 :                       value);
    1008             :     } else {
    1009             :       DCHECK(IsStoreInLiteral());
    1010         112 :       TailCallRuntime(Runtime::kStoreDataPropertyInLiteral, context, receiver,
    1011          56 :                       key, value);
    1012             :     }
    1013             :   }
    1014         168 : }
    1015             : 
    1016          56 : void KeyedStoreGenericAssembler::KeyedStoreGeneric() {
    1017             :   typedef StoreDescriptor Descriptor;
    1018             : 
    1019          56 :   TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
    1020          56 :   TNode<Object> name = CAST(Parameter(Descriptor::kName));
    1021          56 :   TNode<Object> value = CAST(Parameter(Descriptor::kValue));
    1022          56 :   TNode<Context> context = CAST(Parameter(Descriptor::kContext));
    1023             : 
    1024          56 :   KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>());
    1025          56 : }
    1026             : 
    1027         112 : void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
    1028             :                                              TNode<Object> receiver,
    1029             :                                              TNode<Object> key,
    1030             :                                              TNode<Object> value,
    1031             :                                              LanguageMode language_mode) {
    1032         112 :   KeyedStoreGeneric(context, receiver, key, value, Just(language_mode));
    1033         112 : }
    1034             : 
    1035          56 : void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
    1036             :   typedef StoreWithVectorDescriptor Descriptor;
    1037             : 
    1038          56 :   Node* receiver = Parameter(Descriptor::kReceiver);
    1039          56 :   Node* name = Parameter(Descriptor::kName);
    1040          56 :   Node* value = Parameter(Descriptor::kValue);
    1041          56 :   Node* slot = Parameter(Descriptor::kSlot);
    1042          56 :   Node* vector = Parameter(Descriptor::kVector);
    1043          56 :   Node* context = Parameter(Descriptor::kContext);
    1044             : 
    1045         112 :   Label miss(this, Label::kDeferred), store_property(this);
    1046             : 
    1047          56 :   GotoIf(TaggedIsSmi(receiver), &miss);
    1048          56 :   Node* receiver_map = LoadMap(receiver);
    1049          56 :   TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
    1050             :   // Receivers requiring non-standard element accesses (interceptors, access
    1051             :   // checks, strings and string wrappers, proxies) are handled in the runtime.
    1052          56 :   GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
    1053             : 
    1054             :   // Optimistically write the state transition to the vector.
    1055          56 :   GotoIf(IsUndefined(vector), &store_property);
    1056          56 :   StoreFeedbackVectorSlot(vector, slot,
    1057         112 :                           LoadRoot(RootIndex::kpremonomorphic_symbol),
    1058          56 :                           SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
    1059          56 :   Goto(&store_property);
    1060             : 
    1061          56 :   BIND(&store_property);
    1062             :   {
    1063          56 :     StoreICParameters p(context, receiver, name, value, slot, vector);
    1064          56 :     EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
    1065             :   }
    1066             : 
    1067          56 :   BIND(&miss);
    1068             :   {
    1069         112 :     Label call_runtime(this);
    1070             :     // Undo the optimistic state transition.
    1071          56 :     GotoIf(IsUndefined(vector), &call_runtime);
    1072          56 :     StoreFeedbackVectorSlot(vector, slot,
    1073         112 :                             LoadRoot(RootIndex::kuninitialized_symbol),
    1074          56 :                             SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
    1075          56 :     Goto(&call_runtime);
    1076             : 
    1077          56 :     BIND(&call_runtime);
    1078         112 :     TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
    1079          56 :                     receiver, name);
    1080             :   }
    1081          56 : }
    1082             : 
    1083          56 : void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
    1084             :                                              TNode<JSReceiver> receiver,
    1085             :                                              TNode<BoolT> is_simple_receiver,
    1086             :                                              TNode<Name> unique_name,
    1087             :                                              TNode<Object> value,
    1088             :                                              LanguageMode language_mode) {
    1089          56 :   StoreICParameters p(context, receiver, unique_name, value, nullptr, nullptr);
    1090             : 
    1091         112 :   Label done(this), slow(this, Label::kDeferred);
    1092         504 :   ExitPoint exit_point(this, [&](Node* result) { Goto(&done); });
    1093             : 
    1094             :   CSA_ASSERT(this, Word32Equal(is_simple_receiver,
    1095             :                                IsSimpleObjectMap(LoadMap(receiver))));
    1096          56 :   GotoIfNot(is_simple_receiver, &slow);
    1097             : 
    1098         112 :   EmitGenericPropertyStore(receiver, LoadMap(receiver), &p, &exit_point, &slow,
    1099          56 :                            Just(language_mode));
    1100             : 
    1101          56 :   BIND(&slow);
    1102             :   {
    1103          56 :     if (IsStoreInLiteral()) {
    1104             :       CallRuntime(Runtime::kStoreDataPropertyInLiteral, context, receiver,
    1105           0 :                   unique_name, value);
    1106             :     } else {
    1107             :       CallRuntime(Runtime::kSetKeyedProperty, context, receiver, unique_name,
    1108          56 :                   value);
    1109             :     }
    1110          56 :     Goto(&done);
    1111             :   }
    1112             : 
    1113          56 :   BIND(&done);
    1114          56 : }
    1115             : 
    1116             : }  // namespace internal
    1117       87414 : }  // namespace v8

Generated by: LCOV version 1.10