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