v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-heap-broker.cc
Go to the documentation of this file.
1// Copyright 2018 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
9#ifdef ENABLE_SLOW_DCHECKS
10#include <algorithm>
11#endif
12
16#include "src/heap/heap-inl.h"
24
25namespace v8 {
26namespace internal {
27namespace compiler {
28
29#define TRACE(broker, x) TRACE_BROKER(broker, x)
30
32
34
36 bool tracing_enabled, CodeKind code_kind)
37 : isolate_(isolate),
38#if V8_COMPRESS_POINTERS
39 cage_base_(isolate),
40#endif // V8_COMPRESS_POINTERS
41 zone_(broker_zone),
42 // Note that this initialization of {refs_} with the minimal initial
43 // capacity is redundant in the normal use case (concurrent compilation
44 // enabled, standard objects to be serialized), as the map is going to be
45 // replaced immediately with a larger-capacity one. It doesn't seem to
46 // affect the performance in a noticeable way though.
47 refs_(zone()->New<RefsMap>(kMinimalRefsBucketCount, AddressMatcher(),
48 zone())),
49 root_index_map_(isolate),
50 array_and_object_prototypes_(zone()),
51 tracing_enabled_(tracing_enabled),
52 code_kind_(code_kind),
53 feedback_(zone()),
54 property_access_infos_(zone()) {
55 TRACE(this, "Constructing heap broker");
56}
57
59
60std::string JSHeapBroker::Trace() const {
61 std::ostringstream oss;
62 oss << "[" << this << "] ";
63 for (unsigned i = 0; i < trace_indentation_ * 2; ++i) oss.put(' ');
64 return oss.str();
65}
66
67#ifdef DEBUG
68static thread_local JSHeapBroker* current_broker = nullptr;
69
71 : prev_broker_(current_broker) {
72 current_broker = broker;
73}
75 current_broker = prev_broker_;
76}
77
78// static
79JSHeapBroker* JSHeapBroker::Current() {
80 DCHECK_NOT_NULL(current_broker);
81 return current_broker;
82}
83#endif
84
93
97 std::unique_ptr<PersistentHandles> ph =
99 local_isolate_ = nullptr;
100 info->set_persistent_handles(std::move(ph));
101}
102
105 TRACE(this, "Stopping serialization");
107}
108
111 TRACE(this, "Retiring");
112 mode_ = kRetired;
113}
114
120
125
126 Tagged<Object> maybe_context = isolate()->heap()->native_contexts_list();
127 while (!IsUndefined(maybe_context, isolate())) {
128 Tagged<Context> context = Cast<Context>(maybe_context);
129 Tagged<Object> array_prot =
130 context->get(Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
131 Tagged<Object> object_prot =
132 context->get(Context::INITIAL_OBJECT_PROTOTYPE_INDEX);
137 maybe_context = context->next_context_link();
138 }
139
141}
142
145 switch (kind) {
146#define TYPED_ARRAY_STRING_TAG(Type, type, TYPE, ctype) \
147 case ElementsKind::TYPE##_ELEMENTS: \
148 return Type##Array_string();
151#undef TYPED_ARRAY_STRING_TAG
152 default:
153 UNREACHABLE();
154 }
155}
156
158 return IsArrayOrObjectPrototype(object.object());
159}
160
162 if (mode() == kDisabled) {
164 *object, Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
165 object->map(isolate_)->instance_type() == JS_OBJECT_PROTOTYPE_TYPE;
166 }
168 return array_and_object_prototypes_.find(object) !=
170}
171
176
178 GetOrCreateDataFlags flags) {
179 ObjectData* return_value = TryGetOrCreateData(object, flags | kCrashOnError);
180 DCHECK_NOT_NULL(return_value);
181 return return_value;
182}
183
188
196
200
202 if (!IsHeapObject(object)) return false;
204}
205
209
210#define V(Type, name, Name) \
211 void JSHeapBroker::Init##Name() { \
212 DCHECK(!name##_); \
213 name##_ = MakeRefAssumeMemoryFence(this, isolate()->factory()->name()); \
214 }
216#undef V
217
219 : kind_(kind), slot_kind_(slot_kind) {}
220
224
229
231 JSHeapBroker* broker, ZoneVector<MapRef> const& inferred_maps) const {
232 if (inferred_maps.empty()) {
233 return *broker->zone()->New<ElementAccessFeedback>(
234 broker->zone(), keyed_mode(), slot_kind());
235 }
236
237 ZoneRefSet<Map> inferred(inferred_maps.begin(), inferred_maps.end(),
238 broker->zone());
239 return Refine(broker, inferred, false);
240}
241
243 NameRef name) const {
244 // Allow swapping megamorphic elements accesses for named accesses when the
245 // key is know to be a known name.
246 CHECK(transition_groups_.empty());
247 ZoneVector<MapRef> maps(broker->zone());
248 return *broker->zone()->New<NamedAccessFeedback>(name, maps, slot_kind());
249}
250
252 JSHeapBroker* broker, ZoneRefSet<Map> const& inferred_maps,
253 bool always_keep_group_target) const {
254 ElementAccessFeedback& refined_feedback =
255 *broker->zone()->New<ElementAccessFeedback>(broker->zone(), keyed_mode(),
256 slot_kind());
257 if (inferred_maps.size() == 0) return refined_feedback;
258
259 for (auto const& group : transition_groups()) {
260 DCHECK(!group.empty());
261 TransitionGroup new_group(broker->zone());
262 for (size_t i = 1; i < group.size(); ++i) {
263 MapRef source = group[i];
264 if (inferred_maps.contains(source)) {
265 new_group.push_back(source);
266 }
267 }
268
269 MapRef target = group.front();
270 bool const keep_target = always_keep_group_target ||
271 inferred_maps.contains(target) ||
272 new_group.size() > 1;
273 if (keep_target) {
274 new_group.push_back(target);
275 // The target must be at the front, the order of sources doesn't matter.
276 std::swap(new_group[0], new_group[new_group.size() - 1]);
277 }
278
279 if (!new_group.empty()) {
280 DCHECK(new_group.size() == 1 || new_group.front().equals(target));
281 refined_feedback.transition_groups_.push_back(std::move(new_group));
282 }
283 }
284 return refined_feedback;
285}
286
289
291 FeedbackSlotKind slot_kind)
292 : ProcessedFeedback(kGlobalAccess, slot_kind),
293 cell_or_context_(cell),
294 index_and_immutable_(0 /* doesn't matter */) {
296}
297
299 : ProcessedFeedback(kGlobalAccess, slot_kind),
300 index_and_immutable_(0 /* doesn't matter */) {
302}
303
305 int slot_index, bool immutable,
306 FeedbackSlotKind slot_kind)
307 : ProcessedFeedback(kGlobalAccess, slot_kind),
308 cell_or_context_(script_context),
309 index_and_immutable_(FeedbackNexus::SlotIndexBits::encode(slot_index) |
310 FeedbackNexus::ImmutabilityBit::encode(immutable)) {
311 DCHECK_EQ(this->slot_index(), slot_index);
312 DCHECK_EQ(this->immutable(), immutable);
314}
315
317 return !cell_or_context_.has_value();
318}
320 return cell_or_context_.has_value() && cell_or_context_->IsPropertyCell();
321}
323 return cell_or_context_.has_value() && cell_or_context_->IsContext();
324}
335 return FeedbackNexus::SlotIndexBits::decode(index_and_immutable_);
336}
339 return FeedbackNexus::ImmutabilityBit::decode(index_and_immutable_);
340}
341
343 JSHeapBroker* broker) const {
344 if (IsPropertyCell()) {
345 bool cell_cached = property_cell().Cache(broker);
346 CHECK(cell_cached); // Can't fail on the main thread.
347 return property_cell().value(broker);
348 } else if (IsScriptContextSlot() && immutable()) {
349 return script_context().get(broker, slot_index());
350 } else {
351 return std::nullopt;
352 }
353}
354
377
379
388
393
398
403
411 KeyedAccessStoreMode store_mode)
412 : access_mode_(access_mode), load_store_mode_(store_mode) {
413 CHECK(!IsLoad());
414 CHECK(IsStore());
415}
416
418 KeyedAccessMode const& keyed_mode,
419 FeedbackSlotKind slot_kind)
420 : ProcessedFeedback(kElementAccess, slot_kind),
421 keyed_mode_(keyed_mode),
422 transition_groups_(zone) {
428}
429
431 for (auto const& group : transition_groups()) {
432 for (MapRef map : group) {
433 if (!map.IsStringMap()) return false;
434 }
435 }
436 return true;
437}
438
444
446 NameRef name, ZoneVector<MapRef> const& maps, FeedbackSlotKind slot_kind,
447 bool has_deprecated_map_without_migration_target)
448 : ProcessedFeedback(kNamedAccess, slot_kind),
449 name_(name),
450 maps_(maps),
451 has_deprecated_map_without_migration_target_(
452 has_deprecated_map_without_migration_target) {
459}
460
462 ProcessedFeedback const* feedback) {
463 CHECK(source.IsValid());
464 auto insertion = feedback_.insert({source, feedback});
465 CHECK(insertion.second);
466}
467
468bool JSHeapBroker::HasFeedback(FeedbackSource const& source) const {
469 DCHECK(source.IsValid());
470 return feedback_.find(source) != feedback_.end();
471}
472
474 FeedbackSource const& source) const {
475 DCHECK(source.IsValid());
476 auto it = feedback_.find(source);
477 CHECK_NE(it, feedback_.end());
478 return *it->second;
479}
480
482 FeedbackSource const& source) const {
483 if (HasFeedback(source)) return GetFeedback(source).slot_kind();
484 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
485 return nexus.kind();
486}
487
489 if (HasFeedback(source)) return GetFeedback(source).IsInsufficient();
490 return FeedbackNexus(source.vector, source.slot, feedback_nexus_config())
492}
493
498
500 FeedbackSource const& source, AccessMode mode,
501 OptionalNameRef static_name) {
502 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
503 FeedbackSlotKind kind = nexus.kind();
504 if (nexus.IsUninitialized()) return NewInsufficientFeedback(kind);
505
506 ZoneVector<MapRef> maps(zone());
507 bool has_deprecated_map_without_migration_target = false;
509 [this, &maps, &has_deprecated_map_without_migration_target](
510 DirectHandle<Map> map_handle) {
511 MapRef map = MakeRefAssumeMemoryFence(this, *map_handle);
512 // May change concurrently at any time - must be guarded by a
513 // dependency if non-deprecation is important.
514 if (map.is_deprecated()) {
515 // TODO(ishell): support fast map updating if we enable it.
516 CHECK(!v8_flags.fast_map_update);
517 std::optional<Tagged<Map>> maybe_map = MapUpdater::TryUpdateNoLock(
518 isolate(), *map.object(), ConcurrencyMode::kConcurrent);
519 if (maybe_map.has_value()) {
520 map = MakeRefAssumeMemoryFence(this, maybe_map.value());
521 } else {
522 return; // Couldn't update the deprecated map.
523 }
524 if (!map.is_migration_target()) {
525 // Maps are marked as migration targets only when an object
526 // migrates, so it's possible to have a deprecated map whose updated
527 // counterpart is not a migration target.
528 has_deprecated_map_without_migration_target = true;
529 }
530 }
531 if (map.is_abandoned_prototype_map()) return;
532 maps.push_back(map);
533 });
534
535 OptionalNameRef name =
536 static_name.has_value() ? static_name : GetNameFeedback(nexus);
537
538 if (nexus.ic_state() == InlineCacheState::MEGADOM) {
539 DCHECK(maps.empty());
540 MaybeObjectHandle maybe_handler = nexus.ExtractMegaDOMHandler();
541 if (!maybe_handler.is_null()) {
543 Cast<MegaDomHandler>(maybe_handler.object());
544 if (!handler->accessor(kAcquireLoad).IsCleared()) {
547 handler->accessor(kAcquireLoad).GetHeapObject()));
549 }
550 }
551 }
552
553 // If no maps were found for a non-megamorphic access, then our maps died
554 // and we should soft-deopt.
555 if (maps.empty() && nexus.ic_state() != InlineCacheState::MEGAMORPHIC) {
557 }
558
559 if (name.has_value()) {
560 // We rely on this invariant in JSGenericLowering.
561 DCHECK_IMPLIES(maps.empty(),
563 return *zone()->New<NamedAccessFeedback>(
564 *name, maps, kind, has_deprecated_map_without_migration_target);
565 } else if (nexus.GetKeyType() == IcCheckType::kElement && !maps.empty()) {
567 maps, KeyedAccessMode::FromNexus(nexus), kind);
568 } else {
569 // No actionable feedback.
570 DCHECK(maps.empty());
572 // TODO(neis): Using ElementAccessFeedback here is kind of an abuse.
573 return *zone()->New<ElementAccessFeedback>(
575 }
576}
577
579 JSHeapBroker* broker, FeedbackSource const& source) {
580 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
585 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
587 nexus.GetFeedback().IsCleared()) {
588 return *zone()->New<GlobalAccessFeedback>(nexus.kind());
589 }
590
591 Handle<Object> feedback_value =
592 CanonicalPersistentHandle(nexus.GetFeedback().GetHeapObjectOrSmi());
593
594 if (IsSmi(*feedback_value)) {
595 // The wanted name belongs to a script-scope variable and the feedback
596 // tells us where to find its value.
597 int const number = Object::NumberValue(*feedback_value);
598 int const script_context_index =
599 FeedbackNexus::ContextIndexBits::decode(number);
600 int const context_slot_index = FeedbackNexus::SlotIndexBits::decode(number);
602 this,
603 target_native_context().script_context_table(broker).object()->get(
604 script_context_index, kAcquireLoad));
605
606 OptionalObjectRef contents = context.get(broker, context_slot_index);
607 if (contents.has_value()) CHECK(!contents->IsTheHole());
608
609 return *zone()->New<GlobalAccessFeedback>(
610 context, context_slot_index,
611 FeedbackNexus::ImmutabilityBit::decode(number), nexus.kind());
612 }
613
614 CHECK(IsPropertyCell(*feedback_value));
615 // The wanted name belongs (or did belong) to a property on the global
616 // object and the feedback is the cell holding its value.
617 return *zone()->New<GlobalAccessFeedback>(
618 MakeRefAssumeMemoryFence(this, Cast<PropertyCell>(feedback_value)),
619 nexus.kind());
620}
621
623 FeedbackSource const& source) const {
624 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
625 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
627 DCHECK_NE(hint, BinaryOperationHint::kNone); // Not uninitialized.
628 return *zone()->New<BinaryOperationFeedback>(hint, nexus.kind());
629}
630
632 FeedbackSource const& source) const {
633 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
634 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
635 return *zone()->New<TypeOfOpFeedback>(nexus.GetTypeOfFeedback(),
636 nexus.kind());
637}
638
640 FeedbackSource const& source) const {
641 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
642 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
644 DCHECK_NE(hint, CompareOperationHint::kNone); // Not uninitialized.
645 return *zone()->New<CompareOperationFeedback>(hint, nexus.kind());
646}
647
649 FeedbackSource const& source) const {
650 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
651 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
652 ForInHint hint = nexus.GetForInFeedback();
653 DCHECK_NE(hint, ForInHint::kNone); // Not uninitialized.
654 return *zone()->New<ForInFeedback>(hint, nexus.kind());
655}
656
658 FeedbackSource const& source) {
659 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
660 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
661
662 OptionalJSObjectRef optional_constructor;
663 {
664 MaybeDirectHandle<JSObject> maybe_constructor =
666 DirectHandle<JSObject> constructor;
667 if (maybe_constructor.ToHandle(&constructor)) {
668 optional_constructor = MakeRefAssumeMemoryFence(this, *constructor);
669 }
670 }
671 return *zone()->New<InstanceOfFeedback>(optional_constructor, nexus.kind());
672}
673
675 FeedbackSource const& source) {
676 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
677 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
678
679 Tagged<HeapObject> object;
680 if (!nexus.GetFeedback().GetHeapObject(&object)) {
681 return NewInsufficientFeedback(nexus.kind());
682 }
683
684 AllocationSiteRef site =
686 return *zone()->New<LiteralFeedback>(site, nexus.kind());
687}
688
690 FeedbackSource const& source) {
691 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
692 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
693
694 Tagged<HeapObject> object;
695 if (!nexus.GetFeedback().GetHeapObject(&object)) {
696 return NewInsufficientFeedback(nexus.kind());
697 }
698
701 return *zone()->New<RegExpLiteralFeedback>(boilerplate, nexus.kind());
702}
703
705 FeedbackSource const& source) {
706 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
707 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
708
709 Tagged<HeapObject> object;
710 if (!nexus.GetFeedback().GetHeapObject(&object)) {
711 return NewInsufficientFeedback(nexus.kind());
712 }
713
715 return *zone()->New<TemplateObjectFeedback>(array, nexus.kind());
716}
717
719 FeedbackSource const& source) {
720 FeedbackNexus nexus(source.vector, source.slot, feedback_nexus_config());
721 if (nexus.IsUninitialized()) return NewInsufficientFeedback(nexus.kind());
722
723 OptionalHeapObjectRef target_ref;
724 {
725 Tagged<MaybeObject> maybe_target = nexus.GetFeedback();
726 Tagged<HeapObject> target_object;
727 if (maybe_target.GetHeapObject(&target_object)) {
728 target_ref = TryMakeRef(this, target_object);
729 }
730 }
731
732 float frequency = nexus.ComputeCallFrequency();
733 SpeculationMode mode = nexus.GetSpeculationMode();
735 return *zone()->New<CallFeedback>(target_ref, frequency, mode, content,
736 nexus.kind());
737}
738
740 FeedbackSource const& source) {
742 return feedback.IsInsufficient() ? BinaryOperationHint::kNone
743 : feedback.AsBinaryOperation().value();
744}
745
747 FeedbackSource const& source) {
748 ProcessedFeedback const& feedback = ProcessFeedbackForTypeOf(source);
749 return feedback.IsInsufficient() ? TypeOfFeedback::kNone
750 : feedback.AsTypeOf().value();
751}
752
754 FeedbackSource const& source) {
755 ProcessedFeedback const& feedback =
757 return feedback.IsInsufficient() ? CompareOperationHint::kNone
758 : feedback.AsCompareOperation().value();
759}
760
762 ProcessedFeedback const& feedback = ProcessFeedbackForForIn(source);
763 return feedback.IsInsufficient() ? ForInHint::kNone
764 : feedback.AsForIn().value();
765}
766
768 FeedbackSource const& source) {
769 if (HasFeedback(source)) return GetFeedback(source);
770 ProcessedFeedback const& feedback =
772 SetFeedback(source, &feedback);
773 return feedback;
774}
775
777 FeedbackSource const& source) {
778 if (HasFeedback(source)) return GetFeedback(source);
779 ProcessedFeedback const& feedback = ReadFeedbackForRegExpLiteral(source);
780 SetFeedback(source, &feedback);
781 return feedback;
782}
783
785 FeedbackSource const& source) {
786 if (HasFeedback(source)) return GetFeedback(source);
787 ProcessedFeedback const& feedback = ReadFeedbackForTemplateObject(source);
788 SetFeedback(source, &feedback);
789 return feedback;
790}
791
793 FeedbackSource const& source) {
794 if (HasFeedback(source)) return GetFeedback(source);
795 ProcessedFeedback const& feedback = ReadFeedbackForTypeOf(source);
796 SetFeedback(source, &feedback);
797 return feedback;
798}
799
801 FeedbackSource const& source) {
802 if (HasFeedback(source)) return GetFeedback(source);
803 ProcessedFeedback const& feedback = ReadFeedbackForBinaryOperation(source);
804 SetFeedback(source, &feedback);
805 return feedback;
806}
807
809 FeedbackSource const& source) {
810 if (HasFeedback(source)) return GetFeedback(source);
811 ProcessedFeedback const& feedback = ReadFeedbackForCompareOperation(source);
812 SetFeedback(source, &feedback);
813 return feedback;
814}
815
817 FeedbackSource const& source) {
818 if (HasFeedback(source)) return GetFeedback(source);
819 ProcessedFeedback const& feedback = ReadFeedbackForForIn(source);
820 SetFeedback(source, &feedback);
821 return feedback;
822}
823
825 FeedbackSource const& source, AccessMode mode,
826 OptionalNameRef static_name) {
827 if (HasFeedback(source)) return GetFeedback(source);
828 ProcessedFeedback const& feedback =
829 ReadFeedbackForPropertyAccess(source, mode, static_name);
830 SetFeedback(source, &feedback);
831 return feedback;
832}
833
835 FeedbackSource const& source) {
836 if (HasFeedback(source)) return GetFeedback(source);
837 ProcessedFeedback const& feedback = ReadFeedbackForInstanceOf(source);
838 SetFeedback(source, &feedback);
839 return feedback;
840}
841
843 FeedbackSource const& source) {
844 if (HasFeedback(source)) return GetFeedback(source);
845 ProcessedFeedback const& feedback = ReadFeedbackForCall(source);
846 SetFeedback(source, &feedback);
847 return feedback;
848}
849
851 FeedbackSource const& source) {
852 if (HasFeedback(source)) return GetFeedback(source);
853 ProcessedFeedback const& feedback = ReadFeedbackForGlobalAccess(this, source);
854 SetFeedback(source, &feedback);
855 return feedback;
856}
857
859 ZoneVector<MapRef>& maps, KeyedAccessMode const& keyed_mode,
860 FeedbackSlotKind slot_kind) {
861 DCHECK(!maps.empty());
862
863 // Collect possible transition targets.
864 MapHandles possible_transition_targets(isolate());
865 possible_transition_targets.reserve(maps.size());
866 for (MapRef& map : maps) {
867 if (map.CanInlineElementAccess() &&
868 IsFastElementsKind(map.elements_kind()) &&
869 GetInitialFastElementsKind() != map.elements_kind()) {
870 possible_transition_targets.push_back(map.object());
871 }
872 }
873
874 using TransitionGroup = ElementAccessFeedback::TransitionGroup;
875 ZoneRefMap<MapRef, TransitionGroup> transition_groups(zone());
876
877 // Separate the actual receiver maps and the possible transition sources.
878 for (MapRef map : maps) {
879 Tagged<Map> transition_target;
880
881 // Don't generate elements kind transitions from stable maps.
882 if (!map.is_stable()) {
883 // The lock is needed for UnusedPropertyFields (called deep inside
884 // FindElementsKindTransitionedMap).
885 MapUpdaterGuardIfNeeded mumd_scope(this);
886
887 transition_target = map.object()->FindElementsKindTransitionedMap(
888 isolate(),
889 MapHandlesSpan(possible_transition_targets.begin(),
890 possible_transition_targets.end()),
892 }
893
894 if (transition_target.is_null()) {
895 TransitionGroup group(1, map, zone());
896 transition_groups.insert({map, group});
897 } else {
898 MapRef target = MakeRefAssumeMemoryFence(this, transition_target);
899 TransitionGroup new_group(1, target, zone());
900 TransitionGroup& actual_group =
901 transition_groups.insert({target, new_group}).first->second;
902 actual_group.push_back(map);
903 }
904 }
905
907 zone()->New<ElementAccessFeedback>(zone(), keyed_mode, slot_kind);
908 for (auto& entry : transition_groups) {
909 result->AddGroup(std::move(entry.second));
910 }
911
912 CHECK(!result->transition_groups().empty());
913 return *result;
914}
915
917 CHECK(!group.empty());
918 transition_groups_.push_back(std::move(group));
919
920#ifdef ENABLE_SLOW_DCHECKS
921 // Check that each of the group's maps occurs exactly once in the whole
922 // feedback. This implies that "a source is not a target".
923 for (MapRef map : group) {
924 int count = 0;
925 for (TransitionGroup const& some_group : transition_groups()) {
926 count +=
927 std::count_if(some_group.begin(), some_group.end(),
928 [&](MapRef some_map) { return some_map.equals(map); });
929 }
930 CHECK_EQ(count, 1);
931 }
932#endif
933}
934
935OptionalNameRef JSHeapBroker::GetNameFeedback(FeedbackNexus const& nexus) {
936 Tagged<Name> raw_name = nexus.GetName();
937 if (raw_name.is_null()) return std::nullopt;
938 return MakeRefAssumeMemoryFence(this, raw_name);
939}
940
942 AccessMode access_mode) {
944
945 PropertyAccessTarget target({map, name, access_mode});
946 auto it = property_access_infos_.find(target);
947 if (it != property_access_infos_.end()) return it->second;
948
949 AccessInfoFactory factory(this, zone());
950 PropertyAccessInfo access_info =
951 factory.ComputePropertyAccessInfo(map, name, access_mode);
952 TRACE(this, "Storing PropertyAccessInfo for "
953 << access_mode << " of property " << name << " on map "
954 << map);
955 property_access_infos_.insert({target, access_info});
956 return access_info;
957}
958
961 return *static_cast<TypeOfOpFeedback const*>(this);
962}
963
966 return *static_cast<BinaryOperationFeedback const*>(this);
967}
968
970 CHECK_EQ(kCall, kind());
971 return *static_cast<CallFeedback const*>(this);
972}
973
978
981 return *static_cast<ElementAccessFeedback const*>(this);
982}
983
985 CHECK_EQ(kForIn, kind());
986 return *static_cast<ForInFeedback const*>(this);
987}
988
991 return *static_cast<GlobalAccessFeedback const*>(this);
992}
993
996 return *static_cast<InstanceOfFeedback const*>(this);
997}
998
1001 return *static_cast<NamedAccessFeedback const*>(this);
1002}
1003
1009
1012 return *static_cast<LiteralFeedback const*>(this);
1013}
1014
1017 return *static_cast<RegExpLiteralFeedback const*>(this);
1018}
1019
1022 return *static_cast<TemplateObjectFeedback const*>(this);
1023}
1024
1025#undef TRACE
1026
1027} // namespace compiler
1028} // namespace internal
1029} // namespace v8
Isolate * isolate_
Builtins::Kind kind
Definition builtins.cc:40
void push_back(const_reference x)
Definition handles.h:1092
CompareOperationHint GetCompareOperationFeedback() const
FeedbackSlotKind kind() const
KeyedAccessStoreMode GetKeyedAccessStoreMode() const
Tagged< Name > GetName() const
MaybeDirectHandle< JSObject > GetConstructorFeedback() const
MaybeObjectHandle ExtractMegaDOMHandler()
Tagged< MaybeObject > GetFeedback() const
CallFeedbackContent GetCallFeedbackContent()
KeyedAccessLoadMode GetKeyedAccessLoadMode() const
TypeOfFeedback::Result GetTypeOfFeedback() const
InlineCacheState ic_state() const
SpeculationMode GetSpeculationMode()
BinaryOperationHint GetBinaryOperationFeedback() const
bool IsPendingAllocation(Tagged< HeapObject > object)
Definition heap-inl.h:344
Tagged< Object > native_contexts_list() const
Definition heap.h:461
bool IsInCreationContext(Tagged< JSObject > object, uint32_t index)
Definition isolate.cc:6228
ThreadId thread_id() const
Definition isolate.h:821
std::unique_ptr< PersistentHandles > DetachPersistentHandles()
void AttachPersistentHandles(std::unique_ptr< PersistentHandles > persistent_handles)
static std::optional< Tagged< Map > > TryUpdateNoLock(Isolate *isolate, Tagged< Map > old_map, ConcurrencyMode cmode) V8_WARN_UNUSED_RESULT
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(DirectHandle< S > *out) const
IndirectHandle< Object > object() const
static double NumberValue(Tagged< Number > obj)
bool GetHeapObject(Tagged< HeapObject > *result) const
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
static ThreadId Current()
Definition thread-id.h:32
bool contains(ZoneCompactSet< T > const &other) const
void push_back(const T &value)
T * New(Args &&... args)
Definition zone.h:114
PropertyAccessInfo ComputePropertyAccessInfo(MapRef map, NameRef name, AccessMode access_mode) const
OptionalObjectRef get(JSHeapBroker *broker, int index) const
ElementAccessFeedback(Zone *zone, KeyedAccessMode const &keyed_mode, FeedbackSlotKind slot_kind)
bool HasOnlyStringMaps(JSHeapBroker *broker) const
ZoneVector< TransitionGroup > const & transition_groups() const
ElementAccessFeedback const & Refine(JSHeapBroker *broker, ZoneVector< MapRef > const &inferred_maps) const
OptionalObjectRef GetConstantHint(JSHeapBroker *broker) const
GlobalAccessFeedback(PropertyCellRef cell, FeedbackSlotKind slot_kind)
InsufficientFeedback(FeedbackSlotKind slot_kind)
ProcessedFeedback const & ReadFeedbackForInstanceOf(FeedbackSource const &source)
Handle< T > CanonicalPersistentHandle(Tagged< T > object)
ProcessedFeedback const & ReadFeedbackForForIn(FeedbackSource const &source) const
ProcessedFeedback const & ReadFeedbackForCall(FeedbackSource const &source)
BinaryOperationHint GetFeedbackForBinaryOperation(FeedbackSource const &source)
ProcessedFeedback const & GetFeedbackForPropertyAccess(FeedbackSource const &source, AccessMode mode, OptionalNameRef static_name)
OptionalNameRef GetNameFeedback(FeedbackNexus const &nexus)
ProcessedFeedback const & ProcessFeedbackForBinaryOperation(FeedbackSource const &source)
JSHeapBroker(Isolate *isolate, Zone *broker_zone, bool tracing_enabled, CodeKind code_kind)
ProcessedFeedback const & GetFeedback(FeedbackSource const &source) const
ProcessedFeedback const & GetFeedbackForArrayOrObjectLiteral(FeedbackSource const &source)
bool FeedbackIsInsufficient(FeedbackSource const &source) const
ProcessedFeedback const & ReadFeedbackForArrayOrObjectLiteral(FeedbackSource const &source)
void DetachLocalIsolate(OptimizedCompilationInfo *info)
ProcessedFeedback const & ProcessFeedbackForCompareOperation(FeedbackSource const &source)
std::unique_ptr< PersistentHandles > ph_
ProcessedFeedback const & ReadFeedbackForCompareOperation(FeedbackSource const &source) const
TypeOfFeedback::Result GetFeedbackForTypeOf(FeedbackSource const &source)
ProcessedFeedback const & ReadFeedbackForRegExpLiteral(FeedbackSource const &source)
const ProcessedFeedback & NewInsufficientFeedback(FeedbackSlotKind kind) const
ProcessedFeedback const & ReadFeedbackForTemplateObject(FeedbackSource const &source)
ObjectData * GetOrCreateData(Handle< Object > object, GetOrCreateDataFlags flags={})
ProcessedFeedback const & ProcessFeedbackForForIn(FeedbackSource const &source)
ProcessedFeedback const & GetFeedbackForGlobalAccess(FeedbackSource const &source)
ZoneUnorderedMap< FeedbackSource, ProcessedFeedback const *, FeedbackSource::Hash, FeedbackSource::Equal > feedback_
CompilationDependencies * dependencies_
ProcessedFeedback const & GetFeedbackForInstanceOf(FeedbackSource const &source)
ProcessedFeedback const & ProcessFeedbackForTypeOf(FeedbackSource const &source)
ForInHint GetFeedbackForForIn(FeedbackSource const &source)
bool ObjectMayBeUninitialized(DirectHandle< Object > object) const
void SetFeedback(FeedbackSource const &source, ProcessedFeedback const *feedback)
ProcessedFeedback const & GetFeedbackForCall(FeedbackSource const &source)
ElementAccessFeedback const & ProcessFeedbackMapsForElementAccess(ZoneVector< MapRef > &maps, KeyedAccessMode const &keyed_mode, FeedbackSlotKind slot_kind)
PropertyAccessInfo GetPropertyAccessInfo(MapRef map, NameRef name, AccessMode access_mode)
ZoneUnorderedMap< PropertyAccessTarget, PropertyAccessInfo, PropertyAccessTarget::Hash, PropertyAccessTarget::Equal > property_access_infos_
void SetTargetNativeContextRef(DirectHandle< NativeContext > native_context)
NativeContextRef target_native_context() const
bool IsArrayOrObjectPrototype(JSObjectRef object) const
ObjectData * TryGetOrCreateData(Handle< Object > object, GetOrCreateDataFlags flags={})
ProcessedFeedback const & GetFeedbackForTemplateObject(FeedbackSource const &source)
FeedbackSlotKind GetFeedbackSlotKind(FeedbackSource const &source) const
ProcessedFeedback const & ReadFeedbackForPropertyAccess(FeedbackSource const &source, AccessMode mode, OptionalNameRef static_name)
bool HasFeedback(FeedbackSource const &source) const
OptionalNativeContextRef target_native_context_
void AttachLocalIsolate(OptimizedCompilationInfo *info, LocalIsolate *local_isolate)
ZoneUnorderedSet< IndirectHandle< JSObject >, IndirectHandle< JSObject >::hash, IndirectHandle< JSObject >::equal_to > array_and_object_prototypes_
StringRef GetTypedArrayStringTag(ElementsKind kind)
ProcessedFeedback const & GetFeedbackForRegExpLiteral(FeedbackSource const &source)
ProcessedFeedback const & ReadFeedbackForTypeOf(FeedbackSource const &source) const
CompareOperationHint GetFeedbackForCompareOperation(FeedbackSource const &source)
ProcessedFeedback const & ReadFeedbackForBinaryOperation(FeedbackSource const &source) const
ProcessedFeedback const & ReadFeedbackForGlobalAccess(JSHeapBroker *broker, FeedbackSource const &source)
KeyedAccessMode(AccessMode access_mode, KeyedAccessLoadMode load_mode)
KeyedAccessStoreMode store_mode() const
static KeyedAccessMode FromNexus(FeedbackNexus const &nexus)
union v8::internal::compiler::KeyedAccessMode::LoadStoreMode load_store_mode_
KeyedAccessLoadMode load_mode() const
MegaDOMPropertyAccessFeedback(FunctionTemplateInfoRef info_ref, FeedbackSlotKind slot_kind)
NamedAccessFeedback(NameRef name, ZoneVector< MapRef > const &maps, FeedbackSlotKind slot_kind, bool has_deprecated_map_without_migration_target=false)
ElementAccessFeedback const & AsElementAccess() const
ForInFeedback const & AsForIn() const
GlobalAccessFeedback const & AsGlobalAccess() const
InstanceOfFeedback const & AsInstanceOf() const
TypeOfOpFeedback const & AsTypeOf() const
RegExpLiteralFeedback const & AsRegExpLiteral() const
TemplateObjectFeedback const & AsTemplateObject() const
MegaDOMPropertyAccessFeedback const & AsMegaDOMPropertyAccess() const
BinaryOperationFeedback const & AsBinaryOperation() const
NamedAccessFeedback const & AsNamedAccess() const
ProcessedFeedback(Kind kind, FeedbackSlotKind slot_kind)
LiteralFeedback const & AsLiteral() const
CompareOperationFeedback const & AsCompareOperation() const
V8_WARN_UNUSED_RESULT bool Cache(JSHeapBroker *broker) const
ObjectRef value(JSHeapBroker *broker) const
Zone * zone_
const PropertyKind kind_
Handle< SharedFunctionInfo > info
#define TYPED_ARRAYS(V)
#define RAB_GSAB_TYPED_ARRAYS_WITH_TYPED_ARRAY_TYPE(V)
JSHeapBroker * broker
TNode< Context > context
TNode< Object > target
std::map< const std::string, const std::string > map
#define TYPED_ARRAY_STRING_TAG(Type, type, TYPE, ctype)
ZoneVector< RpoNumber > & result
#define TRACE(...)
const char * name_
InstructionOperand source
ref_traits< T >::ref_type MakeRefAssumeMemoryFence(JSHeapBroker *broker, Tagged< T > object)
OptionalRef< typename ref_traits< T >::ref_type > TryMakeRef(JSHeapBroker *broker, ObjectData *data)
ref_traits< T >::ref_type MakeRef(JSHeapBroker *broker, Tagged< T > object)
bool IsKeyedHasICKind(FeedbackSlotKind kind)
bool IsDefineNamedOwnICKind(FeedbackSlotKind kind)
bool IsSetNamedICKind(FeedbackSlotKind kind)
v8::MemorySpan< DirectHandle< Map > > MapHandlesSpan
Definition map.h:148
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
bool IsLoadICKind(FeedbackSlotKind kind)
too high values may cause the compiler to set high thresholds for inlining to as much as possible avoid inlined allocation of objects that cannot escape trace load stores from virtual maglev objects use TurboFan fast string builder analyze liveness of environment slots and zap dead values trace TurboFan load elimination emit data about basic block usage in builtins to this enable builtin reordering when run mksnapshot flag for emit warnings when applying builtin profile data verify register allocation in TurboFan randomly schedule instructions to stress dependency tracking enable store store elimination in TurboFan rewrite far to near simulate GC compiler thread race related to allow float parameters to be passed in simulator mode JS Wasm Run additional turbo_optimize_inlined_js_wasm_wrappers enable experimental feedback collection in generic lowering enable Turboshaft s WasmLoadElimination enable Turboshaft s low level load elimination for JS enable Turboshaft s escape analysis for string concatenation use enable Turbolev features that we want to ship in the not too far future trace individual Turboshaft reduction steps trace intermediate Turboshaft reduction steps invocation count threshold for early optimization Enables optimizations which favor memory size over execution speed Enables sampling allocation profiler with X as a sample interval min size of a semi the new space consists of two semi spaces max size of the Collect garbage after Collect garbage after keeps maps alive for< n > old space garbage collections print one detailed trace line in name
Definition flags.cc:2086
bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind)
bool IsFastElementsKind(ElementsKind kind)
V8_INLINE constexpr bool IsHeapObject(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:669
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsKeyedLoadICKind(FeedbackSlotKind kind)
bool IsDefineKeyedOwnICKind(FeedbackSlotKind kind)
bool IsTypedArrayOrRabGsabTypedArrayElementsKind(ElementsKind kind)
bool IsDefineKeyedOwnPropertyInLiteralKind(FeedbackSlotKind kind)
ElementsKind GetInitialFastElementsKind()
bool IsGlobalICKind(FeedbackSlotKind kind)
bool IsKeyedStoreICKind(FeedbackSlotKind kind)
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
OptimizedCompilationInfo * info_
Definition pipeline.cc:305
#define READ_ONLY_ROOT_LIST(V)
Definition roots.h:468
base::Vector< const char > contents
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485