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