v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
keyed-store-generic.cc
Go to the documentation of this file.
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
6
7#include <optional>
8
12#include "src/common/globals.h"
18
19namespace v8 {
20namespace internal {
21
23
24enum class StoreMode {
25 // kSet implements [[Set]] in the spec and traverses the prototype
26 // chain to invoke setters. it's used by KeyedStoreIC and StoreIC to
27 // set the properties when there is no feedback.
28 kSet,
29 // kDefineKeyedOwnInLiteral implements [[CreateDataProperty]] in the spec,
30 // and it assumes that the receiver is a JSObject that is created by us.
31 // It is used by Object.fromEntries(), CloneObjectIC and
32 // StoreInArrayLiteralIC to define a property in an object without
33 // traversing the prototype chain.
34 // TODO(v8:12548): merge this into the more generic kDefineKeyedOwn.
36 // kDefineNamedOwn implements [[CreateDataProperty]] but it can deal with
37 // user-defined receivers such as a JSProxy. It also assumes that the key
38 // is statically known. It's used to initialize named roperties in object
39 // literals and named public class fields.
41 // kDefineKeyedOwn implements [[CreateDataProperty]], but it can deal with
42 // user-defined receivers such as a JSProxy, and for private class fields,
43 // it will throw if the field does already exist. It's different from
44 // kDefineNamedOwn in that it does not assume the key is statically known.
45 // It's used to initialized computed public class fields and private
46 // class fields.
48};
49
50// With private symbols, 'define' semantics will throw if the field already
51// exists, while 'update' semantics will throw if the field does not exist.
53
55 public:
59
60 void KeyedStoreGeneric();
62
63 void StoreIC_NoFeedback();
64
65 // Generates code for [[Set]] or [[CreateDataProperty]] operation,
66 // the |unique_name| is supposed to be unique otherwise this code will
67 // always go to runtime.
69 TNode<BoolT> is_simple_receiver, TNode<Name> unique_name,
70 TNode<Object> value, LanguageMode language_mode);
71
72 // This does [[Set]] or [[CreateDataProperty]] but it's more generic than
73 // the above. It is essentially the same as "KeyedStoreGeneric" but does not
74 // use feedback slot and uses a hardcoded LanguageMode instead of trying
75 // to deduce it from the feedback slot's kind.
78 LanguageMode language_mode);
79
80 private:
82
88
90
91 // Helper that is used by the public KeyedStoreGeneric, KeyedStoreMegamorphic
92 // and StoreProperty.
95 Maybe<LanguageMode> language_mode,
96 UseStubCache use_stub_cache = kDontUseStubCache,
97 TNode<TaggedIndex> slot = {},
98 TNode<HeapObject> maybe_vector = {});
99
100 void EmitGenericElementStore(TNode<JSObject> receiver,
101 TNode<Map> receiver_map,
102 TNode<Uint16T> instance_type,
103 TNode<IntPtrT> index, TNode<Object> value,
104 TNode<Context> context, Label* slow);
105
106 // If language mode is not provided it is deduced from the feedback slot's
107 // kind.
108 void EmitGenericPropertyStore(TNode<JSReceiver> receiver,
109 TNode<Map> receiver_map,
110 TNode<Uint16T> instance_type,
111 const StoreICParameters* p,
112 ExitPoint* exit_point, Label* slow,
113 Maybe<LanguageMode> maybe_language_mode,
114 UseStubCache use_stub_cache);
115
117 TNode<Map> receiver_map,
118 TNode<Uint16T> instance_type,
119 const StoreICParameters* p, Label* slow) {
120 ExitPoint direct_exit(this);
121 EmitGenericPropertyStore(receiver, receiver_map, instance_type, p,
122 &direct_exit, slow, Nothing<LanguageMode>(),
124 }
125
127 TNode<Map> receiver_map, Label* maybe_read_only_elements,
128 Label* only_fast_writable_elements);
129
131 TNode<FixedArrayBase> elements,
133 ElementsKind from_kind, ElementsKind to_kind,
134 Label* bailout);
135
137 TNode<FixedArrayBase> elements,
138 TNode<IntPtrT> index, TNode<Object> value);
139
141 TNode<Map> receiver_map,
142 TNode<FixedArrayBase> elements,
143 TNode<Word32T> elements_kind,
144 TNode<IntPtrT> index, TNode<Object> value,
145 TNode<Context> context, Label* slow,
146 UpdateLength update_length);
147
149 TNode<IntPtrT> index, TNode<Object> value,
150 UpdateLength update_length);
151
153 TNode<Map> receiver_map,
155 ElementsKind packed_kind,
156 ElementsKind holey_kind, Label* done,
157 Label* map_mismatch, Label* bailout);
159 TNode<Word32T> current_elements_kind,
160 TNode<Context> context, ElementsKind packed_kind,
161 Label* bailout);
163 TNode<Map> receiver_map,
164 TNode<Word32T> current_elements_kind,
165 TNode<Context> context,
166 ElementsKind packed_kind,
167 ElementsKind packed_kind_2, Label* bailout);
168
170 TNode<Map> receiver_map, TNode<Name> name, Label* accessor,
171 TVariable<Object>* var_accessor_pair,
172 TVariable<HeapObject>* var_accessor_holder, Label* readonly,
173 Label* bailout);
174
176 TNode<Name> name,
177 Label* slow);
178
179 bool IsSet() const { return mode_ == StoreMode::kSet; }
185 bool IsAnyDefineOwn() const {
187 }
188
189 bool ShouldCheckPrototype() const { return IsSet(); }
191 bool ShouldCallSetter() const { return IsSet(); }
193 // We don't do this for "in-literal" stores, because it is impossible for
194 // the target object to be a "prototype".
195 // We don't need the prototype validity check for "own" stores, because
196 // we don't care about the prototype chain.
197 // Thus, we need the prototype check only for ordinary stores.
200 return IsSet();
201 }
202};
203
204// static
208 assembler.KeyedStoreMegamorphic();
209}
210
211// static
216
217// static
223
224// static
229
230// static
233 // TODO(v8:12548): it's a hack to reuse KeyedStoreGenericAssembler for
234 // DefineNamedOwnIC, we should separate it out.
236 assembler.StoreIC_NoFeedback();
237}
238
239// static
242 TNode<JSReceiver> receiver, TNode<BoolT> is_simple_receiver,
243 TNode<Name> name, TNode<Object> value, LanguageMode language_mode) {
245 assembler.StoreProperty(context, receiver, is_simple_receiver, name, value,
246 language_mode);
247}
248
249// static
253 LanguageMode language_mode) {
255 assembler.StoreProperty(context, receiver, key, value, language_mode);
256}
257
258// static
266
268 TNode<Map> receiver_map, Label* maybe_read_only_elements,
269 Label* only_fast_writable_elements) {
270 TVARIABLE(Map, var_map);
271 var_map = receiver_map;
272 Label loop_body(this, &var_map);
273 Goto(&loop_body);
274
275 BIND(&loop_body);
276 {
277 TNode<Map> map = var_map.value();
278 TNode<HeapObject> prototype = LoadMapPrototype(map);
279 GotoIf(IsNull(prototype), only_fast_writable_elements);
280 TNode<Map> prototype_map = LoadMap(prototype);
281 var_map = prototype_map;
282 TNode<Uint16T> instance_type = LoadMapInstanceType(prototype_map);
284 maybe_read_only_elements);
285 TNode<Int32T> elements_kind = LoadMapElementsKind(prototype_map);
287 &loop_body);
288 GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
289 Goto(maybe_read_only_elements);
290 }
291}
292
294 TNode<JSObject> receiver, TNode<Map> receiver_map,
296 ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
298 ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
299 ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
300 if (AllocationSite::ShouldTrack(from_kind, to_kind)) {
302 }
303 Label perform_transition(this), check_holey_map(this);
304 TVARIABLE(Map, var_target_map);
305 // Check if the receiver has the default |from_kind| map.
306 {
307 TNode<Map> packed_map = LoadJSArrayElementsMap(from_kind, native_context);
308 GotoIf(TaggedNotEqual(receiver_map, packed_map), &check_holey_map);
309 var_target_map = CAST(
310 LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
311 Goto(&perform_transition);
312 }
313
314 // Check if the receiver has the default |holey_from_kind| map.
315 BIND(&check_holey_map);
316 {
317 TNode<Object> holey_map = LoadContextElement(
318 native_context, Context::ArrayMapIndex(holey_from_kind));
319 GotoIf(TaggedNotEqual(receiver_map, holey_map), bailout);
320 var_target_map = CAST(LoadContextElement(
321 native_context, Context::ArrayMapIndex(holey_to_kind)));
322 Goto(&perform_transition);
323 }
324
325 // Found a supported transition target map, perform the transition!
326 BIND(&perform_transition);
327 {
328 if (IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind)) {
330 GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
331 capacity, bailout);
332 }
333 StoreMap(receiver, var_target_map.value());
334 }
335}
336
338 TNode<JSObject> receiver, TNode<Map> receiver_map,
340 ElementsKind holey_kind, Label* done, Label* map_mismatch, Label* bailout) {
341 TNode<Map> packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
342 GotoIf(TaggedNotEqual(receiver_map, packed_map), map_mismatch);
343 if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) {
345 }
346 TNode<Map> holey_map = CAST(
347 LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind)));
348 StoreMap(receiver, holey_map);
349 Goto(done);
350}
351
353 TNode<JSObject> receiver, TNode<Map> receiver_map,
354 TNode<Word32T> current_elements_kind, TNode<Context> context,
355 ElementsKind packed_kind, Label* bailout) {
356 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
357 Label already_holey(this);
358
359 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
360 &already_holey);
362 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
363 holey_kind, &already_holey, bailout, bailout);
364 BIND(&already_holey);
365}
366
368 TNode<JSObject> receiver, TNode<Map> receiver_map,
369 TNode<Word32T> current_elements_kind, TNode<Context> context,
370 ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout) {
371 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
372 ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
373 Label already_holey(this), check_other_kind(this);
374
375 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
376 &already_holey);
377 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
378 &already_holey);
379
381 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
382 holey_kind, &already_holey, &check_other_kind,
383 bailout);
384 BIND(&check_other_kind);
386 packed_kind_2, holey_kind_2, &already_holey,
387 bailout, bailout);
388 BIND(&already_holey);
389}
390
393 UpdateLength update_length) {
394 if (update_length != kDontChangeLength) {
396 StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset,
397 new_length);
398 }
399 Return(value);
400}
401
403 TNode<Context> context, TNode<FixedArrayBase> elements,
404 TNode<IntPtrT> index, TNode<Object> value) {
405 TVARIABLE(Object, shared_value, value);
406 SharedValueBarrier(context, &shared_value);
407 UnsafeStoreFixedArrayElement(CAST(elements), index, shared_value.value());
408 Return(value);
409}
410
412 TNode<JSObject> receiver, TNode<Map> receiver_map,
413 TNode<FixedArrayBase> elements, TNode<Word32T> elements_kind,
414 TNode<IntPtrT> index, TNode<Object> value, TNode<Context> context,
415 Label* slow, UpdateLength update_length) {
416 if (update_length != kDontChangeLength) {
417 CSA_DCHECK(this, IsJSArrayMap(receiver_map));
418 // Check if the length property is writable. The fast check is only
419 // supported for fast properties.
420 GotoIf(IsDictionaryMap(receiver_map), slow);
421 // The length property is non-configurable, so it's guaranteed to always
422 // be the first property.
423 TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
424 TNode<Uint32T> details = LoadDetailsByDescriptorEntry(descriptors, 0);
426 slow);
427 }
428 static_assert(OFFSET_OF_DATA_START(FixedArray) ==
430 const int kHeaderSize = OFFSET_OF_DATA_START(FixedArray) - kHeapObjectTag;
431
432 Label check_double_elements(this), check_cow_elements(this);
433 TNode<Map> elements_map = LoadMap(elements);
434 GotoIf(IsNotFixedArrayMap(elements_map), &check_double_elements);
435
436 // FixedArray backing store -> Smi or object elements.
437 {
439 ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize);
441 // Check if we're about to overwrite the hole. We can safely do that
442 // only if there can be no setters on the prototype chain.
443 // If we know that we're storing beyond the previous array length, we
444 // can skip the hole check (and always assume the hole).
445 {
446 Label hole_check_passed(this);
447 if (update_length == kDontChangeLength) {
448 TNode<Object> element =
449 CAST(Load(MachineType::AnyTagged(), elements, offset));
450 GotoIf(IsNotTheHole(element), &hole_check_passed);
451 }
453 &hole_check_passed);
454 BIND(&hole_check_passed);
455 }
456 }
457
458 // Check if the value we're storing matches the elements_kind. Smis
459 // can always be stored.
460 {
461 Label non_smi_value(this);
462 GotoIfNot(TaggedIsSmi(value), &non_smi_value);
463 // If we're about to introduce holes, ensure holey elements.
464 if (update_length == kBumpLengthWithGap) {
465 TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context,
467 }
469 offset, value);
470 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
471
472 BIND(&non_smi_value);
473 }
474
475 // Check if we already have object elements; just do the store if so.
476 {
477 Label must_transition(this);
478 static_assert(PACKED_SMI_ELEMENTS == 0);
479 static_assert(HOLEY_SMI_ELEMENTS == 1);
480 GotoIf(Int32LessThanOrEqual(elements_kind,
482 &must_transition);
483 if (update_length == kBumpLengthWithGap) {
484 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
485 PACKED_ELEMENTS, slow);
486 }
487 Store(elements, offset, value);
488 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
489
490 BIND(&must_transition);
491 }
492
493 // Transition to the required ElementsKind.
494 {
495 Label transition_to_double(this), transition_to_object(this);
497#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
498 GotoIf(IsHeapNumber(CAST(value)), &transition_to_double);
499 GotoIfNot(IsUndefined(value), &transition_to_object);
500 TryRewriteElements(receiver, receiver_map, elements, native_context,
502 // Reload migrated elements.
504 TNode<IntPtrT> double_offset =
506 // Make sure we do not store signalling NaNs into double arrays.
508 double_offset, Uint64Constant(kUndefinedNanInt64));
509 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
510#else
511 Branch(IsHeapNumber(CAST(value)), &transition_to_double,
512 &transition_to_object);
513#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
514
515 BIND(&transition_to_double);
516 {
517 // If we're adding holes at the end, always transition to a holey
518 // elements kind, otherwise try to remain packed.
519 ElementsKind target_kind = update_length == kBumpLengthWithGap
522 TryRewriteElements(receiver, receiver_map, elements, native_context,
523 PACKED_SMI_ELEMENTS, target_kind, slow);
524 // Reload migrated elements.
526 TNode<IntPtrT> double_offset =
528 // Make sure we do not store signalling NaNs into double arrays.
529 TNode<Float64T> double_value =
530 Float64SilenceNaN(LoadHeapNumberValue(CAST(value)));
532 double_offset, double_value);
533 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
534 }
535
536 BIND(&transition_to_object);
537 {
538 // If we're adding holes at the end, always transition to a holey
539 // elements kind, otherwise try to remain packed.
540 ElementsKind target_kind = update_length == kBumpLengthWithGap
543 TryRewriteElements(receiver, receiver_map, elements, native_context,
544 PACKED_SMI_ELEMENTS, target_kind, slow);
545 // The elements backing store didn't change, no reload necessary.
546 CSA_DCHECK(this, TaggedEqual(elements, LoadElements(receiver)));
547 Store(elements, offset, value);
548 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
549 }
550 }
551 }
552
553 BIND(&check_double_elements);
554 GotoIf(IsNotFixedDoubleArrayMap(elements_map), &check_cow_elements);
555 // FixedDoubleArray backing store -> double elements.
556 {
560 // Check if we're about to overwrite the hole. We can safely do that
561 // only if there can be no setters on the prototype chain.
562 {
563 Label hole_check_passed(this);
564 // If we know that we're storing beyond the previous array length, we
565 // can skip the hole check (and always assume the hole).
566 if (update_length == kDontChangeLength) {
567 Label found_hole(this);
568 LoadDoubleWithHoleCheck(elements, offset, &found_hole,
570 Goto(&hole_check_passed);
571 BIND(&found_hole);
572 }
574 &hole_check_passed);
575 BIND(&hole_check_passed);
576 }
577 }
578
579 // Try to store the value as a double.
580 {
581 Label non_number_value(this);
582 Label undefined_value(this);
583 TNode<Float64T> double_value = TryTaggedToFloat64(value,
584#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
585 &undefined_value,
586#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
587 &non_number_value);
588
589 // Make sure we do not store signalling NaNs into double arrays.
590 double_value = Float64SilenceNaN(double_value);
591 // If we're about to introduce holes, ensure holey elements.
592 if (update_length == kBumpLengthWithGap) {
593 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
595 }
597 double_value);
598 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
599
600 // Convert undefined to double value.
601#ifdef V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
602 BIND(&undefined_value);
603 // FIXME(nicohartmann): Unify with above.
604
605 // If we're about to introduce holes, ensure holey elements.
606 if (update_length == kBumpLengthWithGap) {
607 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
609 }
611 Uint64Constant(kUndefinedNanInt64));
612 // double_value);
613 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
614#endif // V8_ENABLE_EXPERIMENTAL_UNDEFINED_DOUBLE
615
616 BIND(&non_number_value);
617 }
618
619 // Transition to object elements.
620 {
622 ElementsKind target_kind = update_length == kBumpLengthWithGap
625 TryRewriteElements(receiver, receiver_map, elements, native_context,
626 PACKED_DOUBLE_ELEMENTS, target_kind, slow);
627 // Reload migrated elements.
629 TNode<IntPtrT> fast_offset =
630 ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize);
631 Store(fast_elements, fast_offset, value);
632 MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
633 }
634 }
635
636 BIND(&check_cow_elements);
637 {
638 // TODO(jkummerow): Use GrowElementsCapacity instead of bailing out.
639 Goto(slow);
640 }
641}
642
644 TNode<JSObject> receiver, TNode<Map> receiver_map,
645 TNode<Uint16T> instance_type, TNode<IntPtrT> index, TNode<Object> value,
646 TNode<Context> context, Label* slow) {
647 Label if_fast(this), if_in_bounds(this), if_increment_length_by_one(this),
648 if_bump_length_with_gap(this), if_grow(this), if_nonfast(this),
649 if_typed_array(this), if_dictionary(this), if_shared_array(this);
651 TNode<Int32T> elements_kind = LoadMapElementsKind(receiver_map);
652 Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
653 BIND(&if_fast);
654 Label if_array(this);
655 GotoIf(IsJSArrayInstanceType(instance_type), &if_array);
656 {
658 Branch(UintPtrLessThan(index, capacity), &if_in_bounds, &if_grow);
659 }
660 BIND(&if_array);
661 {
662 TNode<IntPtrT> length =
664 GotoIf(UintPtrLessThan(index, length), &if_in_bounds);
666 GotoIf(UintPtrGreaterThanOrEqual(index, capacity), &if_grow);
667 Branch(WordEqual(index, length), &if_increment_length_by_one,
668 &if_bump_length_with_gap);
669 }
670
671 BIND(&if_in_bounds);
672 {
673 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
674 index, value, context, slow, kDontChangeLength);
675 }
676
677 BIND(&if_increment_length_by_one);
678 {
679 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
680 index, value, context, slow,
682 }
683
684 BIND(&if_bump_length_with_gap);
685 {
686 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
687 index, value, context, slow, kBumpLengthWithGap);
688 }
689
690 // Out-of-capacity accesses (index >= capacity) jump here. Additionally,
691 // an ElementsKind transition might be necessary.
692 // The index can also be negative or larger than kMaxElementIndex at this
693 // point! Jump to the runtime in that case to convert it to a named property.
694 BIND(&if_grow);
695 {
696 Comment("Grow backing store");
697 // TODO(jkummerow): Support inline backing store growth.
698 Goto(slow);
699 }
700
701 // Any ElementsKind > LAST_FAST_ELEMENTS_KIND jumps here for further
702 // dispatch.
703 BIND(&if_nonfast);
704 {
705 static_assert(LAST_ELEMENTS_KIND ==
707 GotoIf(Int32GreaterThanOrEqual(
708 elements_kind,
710 &if_typed_array);
712 &if_dictionary);
714 &if_shared_array);
715 Goto(slow);
716 }
717
718 BIND(&if_dictionary);
719 {
720 Comment("Dictionary");
721 // TODO(jkummerow): Support storing to dictionary elements.
722 Goto(slow);
723 }
724
725 BIND(&if_typed_array);
726 {
727 Comment("Typed array");
728 // TODO(jkummerow): Support typed arrays. Note: RAB / GSAB backed typed
729 // arrays end up here too.
730 Goto(slow);
731 }
732
733 BIND(&if_shared_array);
734 {
736 GotoIf(UintPtrGreaterThanOrEqual(index, length), slow);
737 StoreSharedArrayElement(context, elements, index, value);
738 }
739}
740
742 TNode<Map> receiver_map, TNode<Name> name, Label* accessor,
743 TVariable<Object>* var_accessor_pair,
744 TVariable<HeapObject>* var_accessor_holder, Label* readonly,
745 Label* bailout) {
746 Label ok_to_write(this);
747 TVARIABLE(HeapObject, var_holder);
748 TVARIABLE(Map, var_holder_map);
749 var_holder = LoadMapPrototype(receiver_map);
750 var_holder_map = LoadMap(var_holder.value());
751
752 Label loop(this, {&var_holder, &var_holder_map});
753 Goto(&loop);
754 BIND(&loop);
755 {
756 TNode<HeapObject> holder = var_holder.value();
757 GotoIf(IsNull(holder), &ok_to_write);
758 TNode<Map> holder_map = var_holder_map.value();
759 TNode<Uint16T> instance_type = LoadMapInstanceType(holder_map);
760 Label next_proto(this);
761 {
762 Label found(this), found_fast(this), found_dict(this), found_global(this);
763 TVARIABLE(HeapObject, var_meta_storage);
764 TVARIABLE(IntPtrT, var_entry);
765 TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
766 &found_dict, &found_global, &var_meta_storage,
767 &var_entry, &next_proto, bailout);
768 BIND(&found_fast);
769 {
770 TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
771 TNode<IntPtrT> name_index = var_entry.value();
772 TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, name_index);
773 JumpIfDataProperty(details, &ok_to_write, readonly);
774
775 // Accessor case.
776 // TODO(jkummerow): Implement a trimmed-down
777 // LoadAccessorFromFastObject.
778 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
779 details, var_accessor_pair);
780 *var_accessor_holder = holder;
781 Goto(accessor);
782 }
783
784 BIND(&found_dict);
785 {
786 TNode<PropertyDictionary> dictionary = CAST(var_meta_storage.value());
787 TNode<IntPtrT> entry = var_entry.value();
788 TNode<Uint32T> details = LoadDetailsByKeyIndex(dictionary, entry);
789 JumpIfDataProperty(details, &ok_to_write, readonly);
790
791 if (accessor != nullptr) {
792 // Accessor case.
793 *var_accessor_pair = LoadValueByKeyIndex(dictionary, entry);
794 *var_accessor_holder = holder;
795 Goto(accessor);
796 } else {
797 Goto(&ok_to_write);
798 }
799 }
800
801 BIND(&found_global);
802 {
803 TNode<GlobalDictionary> dictionary = CAST(var_meta_storage.value());
804 TNode<IntPtrT> entry = var_entry.value();
805 TNode<PropertyCell> property_cell =
806 CAST(LoadValueByKeyIndex(dictionary, entry));
807 TNode<Object> value =
808 LoadObjectField(property_cell, PropertyCell::kValueOffset);
809 GotoIf(TaggedEqual(value, TheHoleConstant()), &next_proto);
811 property_cell, PropertyCell::kPropertyDetailsRawOffset));
812 JumpIfDataProperty(details, &ok_to_write, readonly);
813
814 if (accessor != nullptr) {
815 // Accessor case.
816 *var_accessor_pair = value;
817 *var_accessor_holder = holder;
818 Goto(accessor);
819 } else {
820 Goto(&ok_to_write);
821 }
822 }
823 }
824
825 BIND(&next_proto);
826 // Bailout if it can be an integer indexed exotic case.
827 GotoIf(IsJSTypedArrayInstanceType(instance_type), bailout);
828 TNode<HeapObject> proto = LoadMapPrototype(holder_map);
829 GotoIf(IsNull(proto), &ok_to_write);
830 var_holder = proto;
831 var_holder_map = LoadMap(proto);
832 Goto(&loop);
833 }
834 BIND(&ok_to_write);
835}
836
838 TNode<Map> map, TNode<Name> name, Label* slow) {
839 TVARIABLE(Map, var_transition_map);
840 Label simple_transition(this), transition_array(this),
841 found_handler_candidate(this);
842
843 TNode<MaybeObject> maybe_handler =
844 LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
845
846 // Smi -> slow,
847 // Cleared weak reference -> slow
848 // weak reference -> simple_transition
849 // strong reference -> transition_array
850 TVARIABLE(Object, var_transition_map_or_array);
851 DispatchMaybeObject(maybe_handler, slow, slow, &simple_transition,
852 &transition_array, &var_transition_map_or_array);
853
854 BIND(&simple_transition);
855 {
856 var_transition_map = CAST(var_transition_map_or_array.value());
857 Goto(&found_handler_candidate);
858 }
859
860 BIND(&transition_array);
861 {
862 TNode<Map> maybe_handler_map =
863 LoadMap(CAST(var_transition_map_or_array.value()));
864 GotoIfNot(IsTransitionArrayMap(maybe_handler_map), slow);
865
866 TVARIABLE(IntPtrT, var_name_index);
867 Label if_found_candidate(this);
868 TNode<TransitionArray> transitions =
869 CAST(var_transition_map_or_array.value());
870 TransitionLookup(name, transitions, &if_found_candidate, &var_name_index,
871 slow);
872
873 BIND(&if_found_candidate);
874 {
875 // Given that
876 // 1) transitions with the same name are ordered in the transition
877 // array by PropertyKind and then by PropertyAttributes values,
878 // 2) kData < kAccessor,
879 // 3) NONE == 0,
880 // 4) properties with private symbol names are guaranteed to be
881 // non-enumerable (so DONT_ENUM bit in attributes is always set),
882 // the resulting map of transitioning store if it exists in the
883 // transition array is expected to be the first among the transitions
884 // with the same name.
885 // See TransitionArray::CompareDetails() for details.
886 static_assert(static_cast<int>(PropertyKind::kData) == 0);
887 static_assert(NONE == 0);
888 const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex -
891 var_transition_map = CAST(GetHeapObjectAssumeWeak(
893 var_name_index.value(), kKeyToTargetOffset)));
894 Goto(&found_handler_candidate);
895 }
896 }
897
898 BIND(&found_handler_candidate);
899 return var_transition_map.value();
900}
901
904 TNode<Uint16T> instance_type, const StoreICParameters* p,
905 ExitPoint* exit_point, Label* slow, Maybe<LanguageMode> maybe_language_mode,
906 UseStubCache use_stub_cache) {
907 CSA_DCHECK(this, IsSimpleObjectMap(receiver_map));
908 // TODO(rmcilroy) Type as Struct once we use a trimmed down
909 // LoadAccessorFromFastObject instead of LoadPropertyFromFastObject.
910 TVARIABLE(Object, var_accessor_pair);
911 TVARIABLE(HeapObject, var_accessor_holder);
912 Label fast_properties(this), dictionary_properties(this), accessor(this),
913 readonly(this), try_stub_cache(this);
914 TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
915 TNode<Name> name = CAST(p->name());
917 &dictionary_properties, &fast_properties);
918
919 BIND(&fast_properties);
920 {
921 Comment("fast property store");
922 TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
923 Label descriptor_found(this), lookup_transition(this);
924 TVARIABLE(IntPtrT, var_name_index);
925 DescriptorLookup(name, descriptors, bitfield3,
926 IsAnyDefineOwn() ? slow : &descriptor_found,
927 &var_name_index, &lookup_transition);
928
929 // When dealing with class fields defined with DefineKeyedOwnIC or
930 // DefineNamedOwnIC, use the slow path to check the existing property.
931 if (!IsAnyDefineOwn()) {
932 BIND(&descriptor_found);
933 {
934 TNode<IntPtrT> name_index = var_name_index.value();
935 TNode<Uint32T> details = LoadDetailsByKeyIndex(descriptors, name_index);
936 Label data_property(this);
937 JumpIfDataProperty(details, &data_property,
938 ShouldReconfigureExisting() ? nullptr : &readonly);
939
940 if (ShouldCallSetter()) {
941 // Accessor case.
942 // TODO(jkummerow): Implement a trimmed-down
943 // LoadAccessorFromFastObject.
944 LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
945 name_index, details, &var_accessor_pair);
946 var_accessor_holder = receiver;
947 Goto(&accessor);
948 } else {
949 // Handle accessor to data property reconfiguration in runtime.
950 Goto(slow);
951 }
952
953 BIND(&data_property);
954 {
955 Label shared(this);
956 GotoIf(IsJSSharedStructInstanceType(instance_type), &shared);
957
958 CheckForAssociatedProtector(name, slow);
959 OverwriteExistingFastDataProperty(receiver, receiver_map, descriptors,
960 name_index, details, p->value(),
961 slow, false);
962 exit_point->Return(p->value());
963
964 BIND(&shared);
965 {
966 StoreJSSharedStructField(p->context(), receiver, receiver_map,
967 descriptors, name_index, details,
968 p->value());
969 exit_point->Return(p->value());
970 }
971 }
972 }
973 }
974
975 BIND(&lookup_transition);
976 {
977 Comment("lookup transition");
978 CheckForAssociatedProtector(name, slow);
979
980 DCHECK_IMPLIES(use_stub_cache == kUseStubCache, IsSet());
981 Label* if_not_found =
982 use_stub_cache == kUseStubCache ? &try_stub_cache : slow;
983
985 receiver_map, name, if_not_found);
986
987 // Validate the transition handler candidate and apply the transition.
991 }
992 HandleStoreICTransitionMapHandlerCase(p, transition_map, slow, flags);
993 exit_point->Return(p->value());
994 }
995 }
996
997 BIND(&dictionary_properties);
998 {
999 Comment("dictionary property store");
1000 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
1001 // seeing global objects here (which would need special handling).
1002
1003 TVARIABLE(IntPtrT, var_name_index);
1004 Label dictionary_found(this, &var_name_index),
1005 not_found(this, &var_name_index);
1007
1008 // When dealing with class fields defined with DefineKeyedOwnIC or
1009 // DefineNamedOwnIC, use the slow path to check the existing property.
1011 properties, name, IsAnyDefineOwn() ? slow : &dictionary_found,
1012 &var_name_index, &not_found, kFindExistingOrInsertionIndex);
1013
1014 if (!IsAnyDefineOwn()) {
1015 BIND(&dictionary_found);
1016 {
1017 Label check_const(this), overwrite(this), done(this);
1018 TNode<Uint32T> details =
1019 LoadDetailsByKeyIndex(properties, var_name_index.value());
1020 JumpIfDataProperty(details, &check_const,
1021 ShouldReconfigureExisting() ? nullptr : &readonly);
1022
1023 if (ShouldCallSetter()) {
1024 // Accessor case.
1025 var_accessor_pair =
1026 LoadValueByKeyIndex(properties, var_name_index.value());
1027 var_accessor_holder = receiver;
1028 Goto(&accessor);
1029 } else {
1030 // We must reconfigure an accessor property to a data property
1031 // here, let the runtime take care of that.
1032 Goto(slow);
1033 }
1034
1035 BIND(&check_const);
1036 {
1038 GotoIfNot(IsPropertyDetailsConst(details), &overwrite);
1039 TNode<Object> prev_value =
1040 LoadValueByKeyIndex(properties, var_name_index.value());
1041
1042 Branch(TaggedEqual(prev_value, p->value()), &done, slow);
1043 } else {
1044 Goto(&overwrite);
1045 }
1046 }
1047
1048 BIND(&overwrite);
1049 {
1050 CheckForAssociatedProtector(name, slow);
1052 properties, var_name_index.value(), p->value());
1053 Goto(&done);
1054 }
1055
1056 BIND(&done);
1057 exit_point->Return(p->value());
1058 }
1059 }
1060
1061 BIND(&not_found);
1062 {
1063 // TODO(jkummerow): Also add support to correctly handle integer exotic
1064 // cases for typed arrays and remove this check here.
1065 GotoIf(IsJSTypedArrayMap(receiver_map), slow);
1066 CheckForAssociatedProtector(name, slow);
1067 Label extensible(this), is_private_symbol(this);
1068 GotoIf(IsPrivateSymbol(name), &is_private_symbol);
1069 Branch(IsSetWord32<Map::Bits3::IsExtensibleBit>(bitfield3), &extensible,
1070 slow);
1071
1072 BIND(&is_private_symbol);
1073 {
1074 CSA_DCHECK(this, IsPrivateSymbol(name));
1075 // For private names, we miss to the runtime which will throw.
1076 // For private symbols, we extend and store an own property.
1077 Branch(IsPrivateName(CAST(name)), slow, &extensible);
1078 }
1079
1080 BIND(&extensible);
1081 if (ShouldCheckPrototype()) {
1084 receiver_map, name, &accessor, &var_accessor_pair,
1085 &var_accessor_holder,
1086 ShouldReconfigureExisting() ? nullptr : &readonly, slow);
1087 }
1088 Label add_dictionary_property_slow(this);
1089 InvalidateValidityCellIfPrototype(receiver_map, bitfield3);
1090 UpdateMayHaveInterestingProperty(properties, name);
1091 AddToDictionary<PropertyDictionary>(properties, name, p->value(),
1092 &add_dictionary_property_slow,
1093 var_name_index.value());
1094 exit_point->Return(p->value());
1095
1096 BIND(&add_dictionary_property_slow);
1097 exit_point->ReturnCallRuntime(Runtime::kAddDictionaryProperty,
1098 p->context(), p->receiver(), name,
1099 p->value());
1100 }
1101 }
1102
1103 if (ShouldCallSetter()) {
1104 BIND(&accessor);
1105 {
1106 Label not_callable(this);
1107 TNode<HeapObject> accessor_pair = CAST(var_accessor_pair.value());
1108 GotoIf(IsAccessorInfo(accessor_pair), slow);
1109 CSA_DCHECK(this, IsAccessorPair(accessor_pair));
1111 CAST(LoadAccessorPairSetter(CAST(accessor_pair)));
1112 TNode<Map> setter_map = LoadMap(setter);
1113 // FunctionTemplateInfo setters are not supported yet.
1114 GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
1115 GotoIfNot(IsCallableMap(setter_map), &not_callable);
1116
1117 Call(p->context(), setter, receiver, p->value());
1118 exit_point->Return(p->value());
1119
1120 BIND(&not_callable);
1121 {
1122 LanguageMode language_mode;
1123 if (maybe_language_mode.To(&language_mode)) {
1124 if (language_mode == LanguageMode::kStrict) {
1125 exit_point->ReturnCallRuntime(
1126 Runtime::kThrowTypeError, p->context(),
1127 SmiConstant(MessageTemplate::kNoSetterInCallback), name,
1128 var_accessor_holder.value());
1129 } else {
1130 exit_point->Return(p->value());
1131 }
1132 } else {
1133 CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context(),
1134 SmiConstant(MessageTemplate::kNoSetterInCallback), name,
1135 var_accessor_holder.value());
1136 exit_point->Return(p->value());
1137 }
1138 }
1139 }
1140 }
1141
1143 BIND(&readonly);
1144 {
1145 LanguageMode language_mode;
1146 if (maybe_language_mode.To(&language_mode)) {
1147 if (language_mode == LanguageMode::kStrict) {
1148 TNode<String> type = Typeof(p->receiver());
1149 ThrowTypeError(p->context(), MessageTemplate::kStrictReadOnlyProperty,
1150 name, type, p->receiver());
1151 } else {
1152 exit_point->Return(p->value());
1153 }
1154 } else {
1155 CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context(),
1156 SmiConstant(MessageTemplate::kStrictReadOnlyProperty), name,
1157 Typeof(p->receiver()), p->receiver());
1158 exit_point->Return(p->value());
1159 }
1160 }
1161 }
1162
1163 if (use_stub_cache == kUseStubCache) {
1164 DCHECK(IsSet());
1165 BIND(&try_stub_cache);
1166 // Do megamorphic cache lookup only for Api objects where it definitely
1167 // pays off.
1168 GotoIfNot(IsJSApiObjectInstanceType(instance_type), slow);
1169
1170 Comment("stub cache probe");
1171 TVARIABLE(MaybeObject, var_handler);
1172 Label found_handler(this, &var_handler), stub_cache_miss(this);
1173
1174 TryProbeStubCache(p->stub_cache(isolate()), receiver, name, &found_handler,
1175 &var_handler, &stub_cache_miss);
1176
1177 BIND(&found_handler);
1178 {
1179 Comment("KeyedStoreGeneric found handler");
1180 HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss,
1182 }
1183 BIND(&stub_cache_miss);
1184 {
1185 Comment("KeyedStoreGeneric_miss");
1186 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context(), p->value(),
1187 p->slot(), p->vector(), p->receiver(), name);
1188 }
1189 }
1190}
1191
1192// Helper that is used by the public KeyedStoreGeneric and by StoreProperty.
1194 TNode<Context> context, TNode<JSAny> receiver_maybe_smi, TNode<Object> key,
1195 TNode<Object> value, Maybe<LanguageMode> language_mode,
1196 UseStubCache use_stub_cache, TNode<TaggedIndex> slot,
1197 TNode<HeapObject> maybe_vector) {
1198 DCHECK_IMPLIES(use_stub_cache == kUseStubCache, IsSet());
1199 TVARIABLE(IntPtrT, var_index);
1200 TVARIABLE(Name, var_unique);
1201 Label if_index(this, &var_index), if_unique_name(this),
1202 not_internalized(this), slow(this);
1203
1204 GotoIf(TaggedIsSmi(receiver_maybe_smi), &slow);
1205 TNode<JSAnyNotSmi> receiver = CAST(receiver_maybe_smi);
1206 TNode<Map> receiver_map = LoadMap(receiver);
1207 TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
1208 // Receivers requiring non-standard element accesses (interceptors, access
1209 // checks, strings and string wrappers, proxies) are handled in the runtime.
1210 GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
1211
1212 TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
1213 &not_internalized);
1214
1215 BIND(&if_index);
1216 {
1217 Comment("integer index");
1218 EmitGenericElementStore(CAST(receiver), receiver_map, instance_type,
1219 var_index.value(), value, context, &slow);
1220 }
1221
1222 BIND(&if_unique_name);
1223 {
1224 Comment("key is unique name");
1225 StoreICParameters p(context, receiver, var_unique.value(), value,
1226 std::nullopt, slot, maybe_vector,
1228 ExitPoint direct_exit(this);
1229 EmitGenericPropertyStore(CAST(receiver), receiver_map, instance_type, &p,
1230 &direct_exit, &slow, language_mode,
1231 use_stub_cache);
1232 }
1233
1234 BIND(&not_internalized);
1235 {
1236 if (v8_flags.internalize_on_the_fly) {
1237 TryInternalizeString(CAST(key), &if_index, &var_index, &if_unique_name,
1238 &var_unique, &slow, &slow);
1239 } else {
1240 Goto(&slow);
1241 }
1242 }
1243
1244 BIND(&slow);
1245 {
1246 if (IsSet() || IsDefineNamedOwn()) {
1247 // The DefineNamedOwnIC hacky reuse should never reach here.
1249 Comment("KeyedStoreGeneric_slow");
1250 TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
1251 value);
1252 } else if (IsDefineKeyedOwn()) {
1253 TailCallRuntime(Runtime::kDefineObjectOwnProperty, context, receiver, key,
1254 value);
1255 } else {
1257 TNode<Smi> flags =
1259 TNode<TaggedIndex> invalid_slot =
1261 TailCallRuntime(Runtime::kDefineKeyedOwnPropertyInLiteral, context,
1262 receiver, key, value, flags, UndefinedConstant(),
1263 invalid_slot);
1264 }
1265 }
1266}
1267
1270
1271 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
1272 auto name = Parameter<Object>(Descriptor::kName);
1273 auto value = Parameter<Object>(Descriptor::kValue);
1274 auto context = Parameter<Context>(Descriptor::kContext);
1275
1276 KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>());
1277}
1278
1280 DCHECK(IsSet()); // Only [[Set]] handlers are stored in the stub cache.
1282
1283 auto receiver = Parameter<JSAny>(Descriptor::kReceiver);
1284 auto name = Parameter<Object>(Descriptor::kName);
1285 auto value = Parameter<Object>(Descriptor::kValue);
1286 auto context = Parameter<Context>(Descriptor::kContext);
1287 auto slot = Parameter<TaggedIndex>(Descriptor::kSlot);
1288 auto maybe_vector = Parameter<HeapObject>(Descriptor::kVector);
1289
1290 KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>(),
1291 kUseStubCache, slot, maybe_vector);
1292}
1293
1297 TNode<Object> value,
1298 LanguageMode language_mode) {
1299 KeyedStoreGeneric(context, receiver, key, value, Just(language_mode));
1300}
1301
1304
1305 auto receiver_maybe_smi = Parameter<JSAny>(Descriptor::kReceiver);
1306 auto name = Parameter<Object>(Descriptor::kName);
1307 auto value = Parameter<Object>(Descriptor::kValue);
1308 auto context = Parameter<Context>(Descriptor::kContext);
1309
1310 Label miss(this, Label::kDeferred), store_property(this);
1311
1312 GotoIf(TaggedIsSmi(receiver_maybe_smi), &miss);
1313
1314 {
1315 TNode<JSAnyNotSmi> receiver = CAST(receiver_maybe_smi);
1316 TNode<Map> receiver_map = LoadMap(receiver);
1317 TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
1318 // Receivers requiring non-standard element accesses (interceptors, access
1319 // checks, strings and string wrappers, proxies) are handled in the runtime.
1320 GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
1321 {
1322 StoreICParameters p(context, receiver, name, value, std::nullopt, {},
1323 UndefinedConstant(),
1326 EmitGenericPropertyStore(CAST(receiver), receiver_map, instance_type, &p,
1327 &miss);
1328 }
1329 }
1330
1331 BIND(&miss);
1332 {
1333 auto runtime = IsDefineNamedOwn() ? Runtime::kDefineNamedOwnIC_Miss
1334 : Runtime::kStoreIC_Miss;
1335 TNode<TaggedIndex> slot =
1337 TailCallRuntime(runtime, context, value, slot, UndefinedConstant(),
1338 receiver_maybe_smi, name);
1339 }
1340}
1341
1344 TNode<BoolT> is_simple_receiver,
1345 TNode<Name> unique_name,
1346 TNode<Object> value,
1347 LanguageMode language_mode) {
1348 StoreICParameters p(context, receiver, unique_name, value, std::nullopt, {},
1349 UndefinedConstant(), StoreICMode::kDefault);
1350
1351 Label done(this), slow(this, Label::kDeferred);
1352 ExitPoint exit_point(this, [&](TNode<Object> result) { Goto(&done); });
1353
1354 CSA_DCHECK(this, Word32Equal(is_simple_receiver,
1355 IsSimpleObjectMap(LoadMap(receiver))));
1356 GotoIfNot(is_simple_receiver, &slow);
1357
1359 TNode<Uint16T> instance_type = LoadMapInstanceType(map);
1360 EmitGenericPropertyStore(receiver, map, instance_type, &p, &exit_point, &slow,
1361 Just(language_mode), kDontUseStubCache);
1362
1363 BIND(&slow);
1364 {
1366 TNode<Smi> flags =
1368 TNode<TaggedIndex> slot =
1370 CallRuntime(Runtime::kDefineKeyedOwnPropertyInLiteral, context, receiver,
1371 unique_name, value, flags, p.vector(), slot);
1372 } else {
1373 CallRuntime(Runtime::kSetKeyedProperty, context, receiver, unique_name,
1374 value);
1375 }
1376 Goto(&done);
1377 }
1378
1379 BIND(&done);
1380}
1381
1383
1384} // namespace internal
1385} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define CSA_DCHECK(csa,...)
V8_WARN_UNUSED_RESULT V8_INLINE bool To(T *out) const
Definition v8-maybe.h:55
void UpdateMayHaveInterestingProperty(TNode< PropertyDictionary > dict, TNode< Name > name)
void InvalidateValidityCellIfPrototype(TNode< Map > map, std::optional< TNode< Uint32T > > bitfield3=std::nullopt)
void JumpIfDataProperty(TNode< Uint32T > details, Label *writable, Label *readonly)
void HandleStoreICTransitionMapHandlerCase(const StoreICParameters *p, TNode< Map > transition_map, Label *miss, StoreTransitionMapFlags flags)
TNode< BoolT > IsPropertyDetailsConst(TNode< Uint32T > details)
void OverwriteExistingFastDataProperty(TNode< HeapObject > object, TNode< Map > object_map, TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor_name_index, TNode< Uint32T > details, TNode< Object > value, Label *slow, bool do_transitioning_store)
void HandleStoreICHandlerCase(const StoreICParameters *p, TNode< MaybeObject > handler, Label *miss, ICMode ic_mode, ElementSupport support_elements=kOnlyProperties)
void TryProbeStubCache(StubCache *stub_cache, TNode< JSAny > lookup_start_object, TNode< Map > lookup_start_object_map, TNode< Name > name, Label *if_handler, TVariable< MaybeObject > *var_handler, Label *if_miss)
void StoreJSSharedStructField(TNode< Context > context, TNode< HeapObject > shared_struct, TNode< Map > shared_struct_map, TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor_name_index, TNode< Uint32T > details, TNode< Object > value)
static bool ShouldTrack(ElementsKind boilerplate_elements_kind)
TNode< BoolT > IsJSArrayInstanceType(TNode< Int32T > instance_type)
TNode< IntPtrT > LoadAndUntagFixedArrayBaseLength(TNode< FixedArrayBase > array)
TNode< MaybeObject > LoadMaybeWeakObjectField(TNode< HeapObject > object, int offset)
TNode< BoolT > IsJSTypedArrayMap(TNode< Map > map)
TNode< BoolT > IsCallableMap(TNode< Map > map)
void NameDictionaryLookup(TNode< Dictionary > dictionary, TNode< Name > unique_name, Label *if_found, TVariable< IntPtrT > *var_name_index, Label *if_not_found, LookupMode mode=kFindExisting)
TNode< FixedArrayBase > GrowElementsCapacity(TNode< HeapObject > object, TNode< FixedArrayBase > elements, ElementsKind from_kind, ElementsKind to_kind, TNode< TIndex > capacity, TNode< TIndex > new_capacity, Label *bailout)
TNode< BoolT > IsJSApiObjectInstanceType(TNode< Int32T > instance_type)
TNode< Float64T > TryTaggedToFloat64(TNode< Object > value, Label *if_valueisnotnumber)
TNode< Uint32T > LoadDetailsByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index)
TNode< BoolT > IsPrivateName(TNode< Symbol > symbol)
TNode< BoolT > IsFastElementsKind(TNode< Int32T > elements_kind)
TNode< DescriptorArray > LoadMapDescriptors(TNode< Map > map)
TNode< HeapObject > LoadSlowProperties(TNode< JSReceiver > object)
TNode< BoolT > IsFastOrNonExtensibleOrSealedElementsKind(TNode< Int32T > elements_kind)
void ThrowTypeError(TNode< Context > context, MessageTemplate message, char const *arg0=nullptr, char const *arg1=nullptr)
TNode< Smi > SmiTag(TNode< IntPtrT > value)
TNode< BoolT > TaggedEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< FixedArrayBase > LoadElements(TNode< JSObject > object)
TNode< T > LoadObjectField(TNode< HeapObject > object, int offset)
TNode< BoolT > TaggedNotEqual(TNode< AnyTaggedT > a, TNode< AnyTaggedT > b)
TNode< Uint32T > LoadMapBitField3(TNode< Map > map)
void TrapAllocationMemento(TNode< JSObject > object, Label *memento_found)
TNode< BoolT > IsDoubleElementsKind(TNode< Int32T > elements_kind)
void TryToName(TNode< Object > key, Label *if_keyisindex, TVariable< IntPtrT > *var_index, Label *if_keyisunique, TVariable< Name > *var_unique, Label *if_bailout, Label *if_notinternalized=nullptr)
TNode< Uint32T > LoadDetailsByDescriptorEntry(TNode< DescriptorArray > descriptors, TNode< IntPtrT > descriptor)
void StoreValueByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index, TNode< Object > value, WriteBarrierMode write_barrier=UPDATE_WRITE_BARRIER)
void TryInternalizeString(TNode< String > string, Label *if_index, TVariable< IntPtrT > *var_index, Label *if_internalized, TVariable< Name > *var_internalized, Label *if_not_internalized, Label *if_bailout)
void CheckForAssociatedProtector(TNode< Name > name, Label *if_protector)
TNode< BoolT > IsFastPackedElementsKind(TNode< Int32T > elements_kind)
TNode< JSPrototype > LoadMapPrototype(TNode< Map > map)
TNode< BoolT > IsSetWord32(TNode< Word32T > word32)
TNode< Map > LoadJSArrayElementsMap(ElementsKind kind, TNode< NativeContext > native_context)
void TryLookupProperty(TNode< HeapObject > object, TNode< Map > map, TNode< Int32T > instance_type, TNode< Name > unique_name, Label *if_found_fast, Label *if_found_dict, Label *if_found_global, TVariable< HeapObject > *var_meta_storage, TVariable< IntPtrT > *var_name_index, Label *if_not_found, Label *if_bailout)
void StoreMap(TNode< HeapObject > object, TNode< Map > map)
void DispatchMaybeObject(TNode< MaybeObject > maybe_object, Label *if_smi, Label *if_cleared, Label *if_weak, Label *if_strong, TVariable< Object > *extracted)
TNode< Object > LoadValueByKeyIndex(TNode< ContainerType > container, TNode< IntPtrT > key_index)
TNode< BoolT > IsCustomElementsReceiverInstanceType(TNode< Int32T > instance_type)
void DescriptorLookup(TNode< Name > unique_name, TNode< DescriptorArray > descriptors, TNode< Uint32T > bitfield3, Label *if_found, TVariable< IntPtrT > *var_name_index, Label *if_not_found)
TNode< Int32T > LoadAndUntagToWord32ObjectField(TNode< HeapObject > object, int offset)
void StoreObjectFieldNoWriteBarrier(TNode< HeapObject > object, TNode< IntPtrT > offset, TNode< T > value)
TNode< JSAny > Call(TNode< Context > context, TNode< TCallable > callable, ConvertReceiverMode mode, TNode< JSAny > receiver, TArgs... args)
TNode< Uint16T > LoadMapInstanceType(TNode< Map > map)
TNode< BoolT > IsJSArrayMap(TNode< Map > map)
TNode< Float64T > LoadDoubleWithHoleCheck(TNode< FixedDoubleArray > array, TNode< IntPtrT > index, Label *if_hole=nullptr)
TNode< IntPtrT > ElementOffsetFromIndex(TNode< TIndex > index, ElementsKind kind, int base_size=0)
void UnsafeStoreFixedArrayElement(TNode< FixedArray > object, int index, TNode< Object > value, WriteBarrierMode barrier_mode=UPDATE_WRITE_BARRIER)
void TransitionLookup(TNode< Name > unique_name, TNode< TransitionArray > transitions, Label *if_found, TVariable< IntPtrT > *var_name_index, Label *if_not_found)
void SharedValueBarrier(TNode< Context > context, TVariable< Object > *var_shared_value)
TNode< NativeContext > LoadNativeContext(TNode< Context > context)
TNode< BoolT > TaggedIsSmi(TNode< MaybeObject > a)
TNode< Smi > LoadFastJSArrayLength(TNode< JSArray > array)
TNode< BoolT > IsSpecialReceiverInstanceType(TNode< Int32T > instance_type)
TNode< Float64T > LoadHeapNumberValue(TNode< HeapObject > object)
TNode< BoolT > IsJSSharedStructInstanceType(TNode< Int32T > instance_type)
TNode< String > Typeof(TNode< Object > value, std::optional< TNode< UintPtrT > > slot_id={}, std::optional< TNode< HeapObject > > maybe_feedback_vector={})
TNode< Map > LoadMap(TNode< HeapObject > object)
TNode< BoolT > IsDictionaryMap(TNode< Map > map)
TNode< Int32T > LoadMapElementsKind(TNode< Map > map)
TNode< Object > LoadAccessorPairSetter(TNode< AccessorPair > accessor_pair)
TNode< IntPtrT > PositiveSmiUntag(TNode< Smi > value)
TNode< TValue > LoadArrayElement(TNode< Array > array, int array_header_size, TNode< TIndex > index, int additional_offset=0)
void LoadPropertyFromFastObject(TNode< HeapObject > object, TNode< Map > map, TNode< DescriptorArray > descriptors, TNode< IntPtrT > name_index, TVariable< Uint32T > *var_details, TVariable< Object > *var_value)
TNode< BoolT > IsJSTypedArrayInstanceType(TNode< Int32T > instance_type)
TNode< HeapObject > GetHeapObjectAssumeWeak(TNode< MaybeObject > value)
void AddToDictionary(TNode< Dictionary > dictionary, TNode< Name > key, TNode< Object > value, Label *bailout, std::optional< TNode< IntPtrT > > insertion_index=std::nullopt)
static int ArrayMapIndex(ElementsKind elements_kind)
Definition contexts.h:676
static void Generate(compiler::CodeAssemblerState *state)
static void Generate(compiler::CodeAssemblerState *state)
void Return(const TNode< Object > result)
void ReturnCallRuntime(Runtime::FunctionId function, TNode< Context > context, TArgs... args)
static FeedbackSlot Invalid()
Definition utils.h:648
void EmitGenericPropertyStore(TNode< JSReceiver > receiver, TNode< Map > receiver_map, TNode< Uint16T > instance_type, const StoreICParameters *p, ExitPoint *exit_point, Label *slow, Maybe< LanguageMode > maybe_language_mode, UseStubCache use_stub_cache)
void MaybeUpdateLengthAndReturn(TNode< JSObject > receiver, TNode< IntPtrT > index, TNode< Object > value, UpdateLength update_length)
void TryRewriteElements(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< FixedArrayBase > elements, TNode< NativeContext > native_context, ElementsKind from_kind, ElementsKind to_kind, Label *bailout)
void EmitGenericElementStore(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< Uint16T > instance_type, TNode< IntPtrT > index, TNode< Object > value, TNode< Context > context, Label *slow)
void StoreElementWithCapacity(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< FixedArrayBase > elements, TNode< Word32T > elements_kind, TNode< IntPtrT > index, TNode< Object > value, TNode< Context > context, Label *slow, UpdateLength update_length)
TNode< Map > FindCandidateStoreICTransitionMapHandler(TNode< Map > map, TNode< Name > name, Label *slow)
void TryChangeToHoleyMapMulti(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< Word32T > current_elements_kind, TNode< Context > context, ElementsKind packed_kind, ElementsKind packed_kind_2, Label *bailout)
KeyedStoreGenericAssembler(compiler::CodeAssemblerState *state, StoreMode mode)
void TryChangeToHoleyMapHelper(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< NativeContext > native_context, ElementsKind packed_kind, ElementsKind holey_kind, Label *done, Label *map_mismatch, Label *bailout)
void EmitGenericPropertyStore(TNode< JSReceiver > receiver, TNode< Map > receiver_map, TNode< Uint16T > instance_type, const StoreICParameters *p, Label *slow)
void StoreSharedArrayElement(TNode< Context > context, TNode< FixedArrayBase > elements, TNode< IntPtrT > index, TNode< Object > value)
void BranchIfPrototypesMayHaveReadOnlyElements(TNode< Map > receiver_map, Label *maybe_read_only_elements, Label *only_fast_writable_elements)
void StoreProperty(TNode< Context > context, TNode< JSReceiver > receiver, TNode< BoolT > is_simple_receiver, TNode< Name > unique_name, TNode< Object > value, LanguageMode language_mode)
void LookupPropertyOnPrototypeChain(TNode< Map > receiver_map, TNode< Name > name, Label *accessor, TVariable< Object > *var_accessor_pair, TVariable< HeapObject > *var_accessor_holder, Label *readonly, Label *bailout)
void TryChangeToHoleyMap(TNode< JSObject > receiver, TNode< Map > receiver_map, TNode< Word32T > current_elements_kind, TNode< Context > context, ElementsKind packed_kind, Label *bailout)
static void SetProperty(compiler::CodeAssemblerState *state, TNode< Context > context, TNode< JSReceiver > receiver, TNode< BoolT > is_simple_receiver, TNode< Name > name, TNode< Object > value, LanguageMode language_mode)
static void CreateDataProperty(compiler::CodeAssemblerState *state, TNode< Context > context, TNode< JSObject > receiver, TNode< Object > key, TNode< Object > value)
static void Generate(compiler::CodeAssemblerState *state)
static void Generate(compiler::CodeAssemblerState *state)
static constexpr MachineType AnyTagged()
static constexpr MachineType None()
static const int kAttributesReadOnlyMask
static void Generate(compiler::CodeAssemblerState *state)
static const int kEntryKeyIndex
static const int kEntryTargetIndex
TNode< IntPtrT > IntPtrAdd(TNode< IntPtrT > left, TNode< IntPtrT > right)
TNode< Int32T > Signed(TNode< Word32T > x)
void Comment(MessageWithSourceLocation message, Args &&... args)
TNode< IntPtrT > IntPtrConstant(intptr_t value)
TNode< BoolT > WordEqual(TNode< WordT > left, TNode< WordT > right)
void GotoIfNot(TNode< IntegralT > condition, Label *false_label, GotoHint goto_hint=GotoHint::kNone)
void Return(TNode< Object > value)
TNode< Uint32T > Unsigned(TNode< Word32T > x)
TNode< Uint64T > Uint64Constant(uint64_t value)
void TailCallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
TNode< Smi > SmiConstant(Tagged< Smi > value)
void GotoIf(TNode< IntegralT > condition, Label *true_label, GotoHint goto_hint=GotoHint::kNone)
Node * Load(MachineType type, Node *base)
TNode< BoolT > BoolConstant(bool value)
TNode< TaggedIndex > TaggedIndexConstant(intptr_t value)
TNode< Int32T > Int32Constant(int32_t value)
TNode< BoolT > Word32Equal(TNode< Word32T > left, TNode< Word32T > right)
TNode< T > CallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
void Store(Node *base, Node *value)
void Branch(TNode< IntegralT > condition, Label *true_label, Label *false_label, BranchHint branch_hint=BranchHint::kNone)
void StoreNoWriteBarrier(MachineRepresentation rep, Node *base, Node *value)
TNode< T > Parameter(int value, const SourceLocation &loc=SourceLocation::Current())
#define CAST(x)
#define V8_DICT_PROPERTY_CONST_TRACKING_BOOL
Definition globals.h:249
AssemblerT assembler
int32_t offset
TNode< Object > receiver
SharedFunctionInfoRef shared
ZoneVector< RpoNumber > & result
constexpr int kTaggedSize
Definition globals.h:542
@ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND
@ LAST_RAB_GSAB_FIXED_TYPED_ARRAY_ELEMENTS_KIND
ElementsKind GetHoleyElementsKind(ElementsKind packed_kind)
DONT_OVERRIDE DISABLE_ALLOCATION_SITES HOLEY_ELEMENTS
DONT_OVERRIDE DISABLE_ALLOCATION_SITES DISABLE_ALLOCATION_SITES HOLEY_DOUBLE_ELEMENTS
const int kHeapObjectTag
Definition v8-internal.h:72
V8_EXPORT_PRIVATE FlagValues v8_flags
return value
Definition map-inl.h:893
bool IsPrivateSymbol(Tagged< Object > obj)
kInstanceDescriptorsOffset kTransitionsOrPrototypeInfoOffset IsNull(value)||IsJSProxy(value)||IsWasmObject(value)||(IsJSObject(value) &&(HeapLayout
Definition map-inl.h:70
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK(condition)
Definition logging.h:482
#define OFFSET_OF_DATA_START(Type)