v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
feedback-vector.h
Go to the documentation of this file.
1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_OBJECTS_FEEDBACK_VECTOR_H_
6#define V8_OBJECTS_FEEDBACK_VECTOR_H_
7
8#include <optional>
9#include <vector>
10
11#include "src/base/bit-field.h"
12#include "src/base/logging.h"
13#include "src/base/macros.h"
15#include "src/common/globals.h"
18#include "src/objects/map.h"
20#include "src/objects/name.h"
23
24// Has to be the last include (doesn't have include guards):
26
27namespace v8::internal {
28
29class IsCompiledScope;
30class FeedbackVectorSpec;
31
37
38// Which feedback slots to clear in Clear().
39enum class ClearBehavior {
41 kClearAll, // .. also ForIn, CompareOp, BinaryOp.
42};
43
44enum class FeedbackSlotKind : uint8_t {
45 // This kind means that the slot points to the middle of other slot
46 // which occupies more than one feedback vector element.
47 // There must be no such slots in the system.
49
50 // Sloppy kinds come first, for easy language mode testing.
55
56 // Strict and language mode unaware kinds.
57 kCall,
73 kForIn,
75 kTypeOf,
78
79 kLast = kJumpLoop // Always update this if the list above changes.
80};
81
82static constexpr int kFeedbackSlotKindCount =
83 static_cast<int>(FeedbackSlotKind::kLast) + 1;
84
85using MapAndHandler = std::pair<DirectHandle<Map>, MaybeObjectDirectHandle>;
86
88 public:
89 explicit MapsAndHandlers(Isolate* isolate)
90 : maps_(isolate), handlers_(isolate) {}
91
92 bool empty() const { return maps_.empty(); }
93 size_t size() const { return maps_.size(); }
94 void reserve(size_t capacity) {
95 maps_.reserve(capacity);
96 handlers_.reserve(capacity);
97 }
98
99 MapAndHandler operator[](size_t i) const {
100 DCHECK_LT(i, size());
102 switch (handlers_reference_types_[i]) {
103 case HeapObjectReferenceType::STRONG:
105 break;
106 case HeapObjectReferenceType::WEAK:
108 break;
109 }
110 return MapAndHandler(maps_[i], handler);
111 }
112
113 void set_map(size_t i, DirectHandle<Map> map) {
114 DCHECK_LT(i, size());
115 maps_[i] = map;
116 }
117
118 void set_handler(size_t i, MaybeObjectDirectHandle handler) {
119 DCHECK_LT(i, size());
120 handlers_[i] =
121 handler.is_null() ? DirectHandle<Object>() : handler.object();
122 handlers_reference_types_[i] = handler.reference_type();
123 }
124
125 class Iterator final
126 : public base::iterator<std::input_iterator_tag, MapAndHandler> {
127 public:
128 constexpr Iterator() = default;
129
130 constexpr bool operator==(const Iterator& other) {
131 return index_ == other.index_;
132 }
133 constexpr bool operator!=(const Iterator& other) {
134 return index_ != other.index_;
135 }
136
137 constexpr Iterator& operator++() {
138 ++index_;
139 return *this;
140 }
141
142 constexpr Iterator operator++(int) {
143 Iterator temp = *this;
144 ++*this;
145 return temp;
146 }
147
150 return (*container_)[index_];
151 }
152
153 private:
154 friend class MapsAndHandlers;
155
156 constexpr Iterator(const MapsAndHandlers* container, size_t i)
157 : container_(container), index_(i) {}
158
159 const MapsAndHandlers* container_ = nullptr;
160 size_t index_ = 0;
161 };
162
164 maps_.push_back(map);
165 handlers_.push_back(handler.is_null() ? DirectHandle<Object>()
166 : handler.object());
167 handlers_reference_types_.push_back(handler.reference_type());
168 }
169
170 Iterator begin() const { return Iterator(this, 0); }
171 Iterator end() const { return Iterator(this, size()); }
172
174
175 private:
180};
181
185
189
194
198
202
207
212
216
220
224
229
233
237
241
248
262
263V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
265
266using MaybeObjectHandles = std::vector<MaybeObjectHandle>;
267
268class FeedbackMetadata;
269
270#include "torque-generated/src/objects/feedback-vector-tq.inc"
271
273 public:
276 static constexpr RootIndex kMapRootIndex =
277 RootIndex::kClosureFeedbackCellArrayMap;
278 static constexpr bool kLengthEqualsCapacity = true;
279};
280
281// ClosureFeedbackCellArray contains feedback cells used when creating closures
282// from a function. This is created once the function is compiled and is either
283// held by the feedback vector (if allocated) or by the FeedbackCell of the
284// closure.
304
305class NexusConfig;
306
307// A FeedbackVector has a fixed header followed by an array of feedback slots,
308// of length determined by the feedback metadata.
310 : public TorqueGeneratedFeedbackVector<FeedbackVector, HeapObject> {
311 public:
313 DEFINE_TORQUE_GENERATED_OSR_STATE()
314 DEFINE_TORQUE_GENERATED_FEEDBACK_VECTOR_FLAGS()
315
316#ifndef V8_ENABLE_LEAPTIERING
317 static_assert(TieringStateBits::is_valid(TieringState::kLastTieringState));
318
319 static constexpr uint32_t kFlagsMaybeHasTurbofanCode =
320 FeedbackVector::MaybeHasTurbofanCodeBit::kMask;
321 static constexpr uint32_t kFlagsMaybeHasMaglevCode =
322 FeedbackVector::MaybeHasMaglevCodeBit::kMask;
323 static constexpr uint32_t kFlagsHasAnyOptimizedCode =
324 FeedbackVector::MaybeHasMaglevCodeBit::kMask |
325 FeedbackVector::MaybeHasTurbofanCodeBit::kMask;
326 static constexpr uint32_t kFlagsTieringStateIsAnyRequested =
327 kNoneOrInProgressMask << FeedbackVector::TieringStateBits::kShift;
328 static constexpr uint32_t kFlagsLogNextExecution =
329 FeedbackVector::LogNextExecutionBit::kMask;
330
331 static constexpr inline uint32_t FlagMaskForNeedsProcessingCheckFrom(
332 CodeKind code_kind);
333#endif // !V8_ENABLE_LEAPTIERING
334
335 inline bool is_empty() const;
336
339
340 // Forward declare the non-atomic accessors.
341 using TorqueGeneratedFeedbackVector::invocation_count;
342 using TorqueGeneratedFeedbackVector::set_invocation_count;
343 DECL_RELAXED_INT32_ACCESSORS(invocation_count)
345 using TorqueGeneratedFeedbackVector::invocation_count_before_stable;
346 using TorqueGeneratedFeedbackVector::set_invocation_count_before_stable;
347 DECL_RELAXED_UINT8_ACCESSORS(invocation_count_before_stable)
348
349 // In case a function deoptimizes we set invocation_count_before_stable to
350 // this sentinel.
351 static constexpr uint8_t kInvocationCountBeforeStableDeoptSentinel = 0xff;
352
353 // The [osr_urgency] controls when OSR is attempted, and is incremented as
354 // the function becomes hotter. When the current loop depth is less than the
355 // osr_urgency, JumpLoop calls into runtime to attempt OSR optimization.
356 static constexpr int kMaxOsrUrgency = 6;
357 static_assert(OsrUrgencyBits::is_valid(kMaxOsrUrgency));
358 inline int osr_urgency() const;
359 inline void set_osr_urgency(int urgency);
360 inline void reset_osr_urgency();
361 inline void RequestOsrAtNextOpportunity();
362
363 // Whether this vector may contain cached optimized osr code for *any* slot.
364 // May diverge from the state of the world; the invariant is that if
365 // `maybe_has_(maglev|turbofan)_osr_code` is false, no optimized osr code
366 // exists.
367 inline bool maybe_has_maglev_osr_code() const;
368 inline bool maybe_has_turbofan_osr_code() const;
369 inline bool maybe_has_optimized_osr_code() const;
370 inline void set_maybe_has_optimized_osr_code(bool value, CodeKind code_kind);
371
372 // The `osr_state` contains the osr_urgency and maybe_has_optimized_osr_code.
373 inline void reset_osr_state();
374
375#ifndef V8_ENABLE_LEAPTIERING
376 inline bool log_next_execution() const;
377 inline void set_log_next_execution(bool value = true);
378
379 inline Tagged<Code> optimized_code(IsolateForSandbox isolate) const;
380 // Whether maybe_optimized_code contains a cached Code object.
381 inline bool has_optimized_code() const;
382
383 // Similar to above, but represented internally as a bit that can be
384 // efficiently checked by generated code. May lag behind the actual state of
385 // the world, thus 'maybe'.
386 inline bool maybe_has_maglev_code() const;
387 inline void set_maybe_has_maglev_code(bool value);
388 inline bool maybe_has_turbofan_code() const;
389 inline void set_maybe_has_turbofan_code(bool value);
390
393 Isolate* isolate, Tagged<SharedFunctionInfo> shared, const char* reason);
394 void ClearOptimizedCode();
395#endif // !V8_ENABLE_LEAPTIERING
396
397 // Optimized OSR'd code is cached in JumpLoop feedback vector slots. The
398 // slots either contain a Code object or the ClearedValue.
399 inline std::optional<Tagged<Code>> GetOptimizedOsrCode(Isolate* isolate,
400 FeedbackSlot slot);
401 void SetOptimizedOsrCode(Isolate* isolate, FeedbackSlot slot,
402 Tagged<Code> code);
403
404#ifdef V8_ENABLE_LEAPTIERING
405 inline bool tiering_in_progress() const;
406 void set_tiering_in_progress(bool);
407#else
408 inline TieringState tiering_state() const;
410 inline void reset_tiering_state();
411#endif // !V8_ENABLE_LEAPTIERING
412
414 void set_osr_tiering_in_progress(bool osr_in_progress);
415
416 inline bool interrupt_budget_reset_by_ic_change() const;
417 inline void set_interrupt_budget_reset_by_ic_change(bool value);
418
419 // Check if this function was ever deoptimized. This flag can be used as a
420 // blanked bailout for optimizations which are not guaranteed to be deopt-loop
421 // free (such as hoisting checks out of loops).
422 // TODO(olivf): Have a more granular (e.g., per loop) mechanism.
423 inline bool was_once_deoptimized() const;
424 inline void set_was_once_deoptimized();
425
426 void reset_flags();
427
428 // Conversion from a slot to an integer index to the underlying array.
429 static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); }
430
431 // Conversion from an integer index to the underlying array to a slot.
432 static inline FeedbackSlot ToSlot(intptr_t index);
433
435 inline void SynchronizedSet(FeedbackSlot slot, Tagged<MaybeObject> value,
437
438 inline Tagged<MaybeObject> Get(FeedbackSlot slot) const;
440 FeedbackSlot slot) const;
441
442 // Returns the feedback cell at |index| that is used to create the
443 // closure.
445 int index) const;
446 inline Tagged<FeedbackCell> closure_feedback_cell(int index) const;
447
448 // Gives access to raw memory which stores the array's data.
450
451 // Returns slot kind for given slot.
454 AcquireLoadTag tag) const;
455
458 DirectHandle<ClosureFeedbackCellArray> closure_feedback_cell_array,
459 DirectHandle<FeedbackCell> parent_feedback_cell,
460 IsCompiledScope* is_compiled_scope);
461
463 Isolate* isolate, const FeedbackVectorSpec* spec);
468
469#define DEFINE_SLOT_KIND_PREDICATE(Name) \
470 bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); }
471
475 DEFINE_SLOT_KIND_PREDICATE(IsLoadGlobalIC)
476 DEFINE_SLOT_KIND_PREDICATE(IsKeyedLoadIC)
477 DEFINE_SLOT_KIND_PREDICATE(IsSetNamedIC)
478 DEFINE_SLOT_KIND_PREDICATE(IsDefineNamedOwnIC)
479 DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC)
480 DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
481#undef DEFINE_SLOT_KIND_PREDICATE
482
483 // Returns typeof mode encoded into kind of given slot.
486 }
487
488 // Returns language mode encoded into kind of given slot.
491 }
492
494
495 void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot);
496
497#ifdef V8_TRACE_FEEDBACK_UPDATES
498 static void TraceFeedbackChange(Isolate* isolate,
500 FeedbackSlot slot, const char* reason);
501#endif
502
503 // Clears the vector slots. Return true if feedback has changed.
504 bool ClearSlots(Isolate* isolate) {
505 return ClearSlots(isolate, ClearBehavior::kDefault);
506 }
507 // As above, but clears *all* slots - even those that we usually keep (e.g.:
508 // BinaryOp feedback).
510 return ClearSlots(isolate, ClearBehavior::kClearAll);
511 }
512
513 // The object that indicates an uninitialized cache.
514 static inline DirectHandle<Symbol> UninitializedSentinel(Isolate* isolate);
515
516 // The object that indicates a megamorphic state.
517 static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
518
519 // The object that indicates a MegaDOM state.
520 static inline DirectHandle<Symbol> MegaDOMSentinel(Isolate* isolate);
521
522 // A raw version of the uninitialized sentinel that's safe to read during
523 // garbage collection (e.g., for patching the cache).
524 static inline Tagged<Symbol> RawUninitializedSentinel(Isolate* isolate);
525
526 static_assert(kHeaderSize % kObjectAlignment == 0,
527 "Header must be padded for alignment");
528
529 class BodyDescriptor;
530
531 static constexpr int OffsetOfElementAt(int index) {
532 return kRawFeedbackSlotsOffset + index * kTaggedSize;
533 }
534
536
537 private:
538 bool ClearSlots(Isolate* isolate, ClearBehavior behavior);
539
541 Isolate* isolate, DirectHandle<FeedbackVector> vector);
542
543 // Private for initializing stores in FeedbackVector::New().
544 inline void Set(FeedbackSlot slot, Tagged<MaybeObject> value,
546
547#ifdef DEBUG
548 // Returns true if value is a non-HashTable FixedArray. We want to
549 // make sure not to store such objects in the vector.
550 inline static bool IsOfLegacyType(Tagged<MaybeObject> value);
551#endif // DEBUG
552
553 // NexusConfig controls setting slots in the vector.
555
556 // Don't expose the raw feedback slot getter/setter.
557 using TorqueGeneratedFeedbackVector::raw_feedback_slots;
558};
559
561 public:
562 explicit FeedbackVectorSpec(Zone* zone)
563 : slot_kinds_(zone), create_closure_parameter_counts_(zone) {
564 slot_kinds_.reserve(16);
565 }
566
567 int slot_count() const { return static_cast<int>(slot_kinds_.size()); }
569 return static_cast<int>(create_closure_parameter_counts_.size());
570 }
571
573 create_closure_parameter_counts_.push_back(parameter_count);
574 return create_closure_slot_count() - 1;
575 }
576
577 uint16_t GetCreateClosureParameterCount(int index) const {
578 return create_closure_parameter_counts_.at(index);
579 }
580
582 return slot_kinds_.at(slot.ToInt());
583 }
584
585 FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
586
588 return AddSlot(FeedbackSlotKind::kLoadProperty);
589 }
590
592 return AddSlot(typeof_mode == TypeofMode::kInside
593 ? FeedbackSlotKind::kLoadGlobalInsideTypeof
594 : FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
595 }
596
598 return AddSlot(FeedbackSlotKind::kLoadKeyed);
599 }
600
602 return AddSlot(FeedbackSlotKind::kHasKeyed);
603 }
604
606 static_assert(LanguageModeSize == 2);
607 return is_strict(language_mode) ? FeedbackSlotKind::kSetNamedStrict
608 : FeedbackSlotKind::kSetNamedSloppy;
609 }
610
612 return AddSlot(GetStoreICSlot(language_mode));
613 }
614
616 return AddSlot(FeedbackSlotKind::kDefineNamedOwn);
617 }
618
619 // Similar to DefinedNamedOwn, but will throw if a private field already
620 // exists.
622 return AddSlot(FeedbackSlotKind::kDefineKeyedOwn);
623 }
624
626 static_assert(LanguageModeSize == 2);
627 return AddSlot(is_strict(language_mode)
628 ? FeedbackSlotKind::kStoreGlobalStrict
629 : FeedbackSlotKind::kStoreGlobalSloppy);
630 }
631
633 static_assert(LanguageModeSize == 2);
634 return is_strict(language_mode) ? FeedbackSlotKind::kSetKeyedStrict
635 : FeedbackSlotKind::kSetKeyedSloppy;
636 }
637
639 return AddSlot(GetKeyedStoreICSlotKind(language_mode));
640 }
641
643 return AddSlot(FeedbackSlotKind::kStoreInArrayLiteral);
644 }
645
647 return AddSlot(FeedbackSlotKind::kBinaryOp);
648 }
649
651 return AddSlot(FeedbackSlotKind::kCompareOp);
652 }
653
654 FeedbackSlot AddForInSlot() { return AddSlot(FeedbackSlotKind::kForIn); }
655
657 return AddSlot(FeedbackSlotKind::kInstanceOf);
658 }
659
660 FeedbackSlot AddTypeOfSlot() { return AddSlot(FeedbackSlotKind::kTypeOf); }
661
662 FeedbackSlot AddLiteralSlot() { return AddSlot(FeedbackSlotKind::kLiteral); }
663
665 return AddSlot(FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral);
666 }
667
669 return AddSlot(FeedbackSlotKind::kCloneObject);
670 }
671
673 return AddSlot(FeedbackSlotKind::kJumpLoop);
674 }
675
676#ifdef OBJECT_PRINT
677 // For gdb debugging.
678 void Print();
679#endif // OBJECT_PRINT
680
682
683 private:
685
686 void append(FeedbackSlotKind kind) { slot_kinds_.push_back(kind); }
687
688 static_assert(sizeof(FeedbackSlotKind) == sizeof(uint8_t));
690 // A vector containing the parameter count for every create closure slot.
692
693 friend class SharedFeedbackSlot;
694};
695
696// Helper class that creates a feedback slot on-demand.
698 public:
699 // FeedbackSlot default constructor constructs an invalid slot.
702
705 return slot_;
706 }
707
708 private:
712};
713
714// FeedbackMetadata is an array-like object with a slot count (indicating how
715// many slots are stored). We save space by packing several slots into an array
716// of int32 data. The length is never stored - it is always calculated from
717// slot_count. All instances are created through the static New function, and
718// the number of slots is static once an instance is created.
719//
720// Besides the feedback slots, the FeedbackMetadata also stores the parameter
721// count for every CreateClosure slot as that is required for allocating the
722// FeedbackCells for the closres. This data doesn't necessarily need to live in
723// this object (it could, for example, also be stored on the Bytecode), but
724// keeping it here is somewhat efficient as the uint16s can just be stored
725// after the int32s of the slots.
727 public:
728 // The number of slots that this metadata contains. Stored as an int32.
730
731 // The number of feedback cells required for create closures. Stored as an
732 // int32.
733 // TODO(mythria): Consider using 16 bits for this and slot_count so that we
734 // can save 4 bytes.
736
737 // Get slot_count using an acquire load.
738 inline int32_t slot_count(AcquireLoadTag) const;
739
740 // Get create_closure_slot_count using an acquire load.
742
743 // Returns number of feedback vector elements used by given slot kind.
744 static inline int GetSlotSize(FeedbackSlotKind kind);
745
746 bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
747
748 inline bool is_empty() const;
749
750 // Returns slot kind for given slot.
752
753 // Returns the parameter count for the create closure slot with the given
754 // index.
755 V8_EXPORT_PRIVATE uint16_t GetCreateClosureParameterCount(int index) const;
756
757 // If {spec} is null, then it is considered empty.
758 template <typename IsolateT>
760 IsolateT* isolate, const FeedbackVectorSpec* spec);
761
764
765 static const char* Kind2String(FeedbackSlotKind kind);
766
767 // Garbage collection support.
768 // This includes any necessary padding at the end of the object for pointer
769 // size alignment.
770 inline int AllocatedSize();
771
777
778#define FIELDS(V) \
779 V(kSlotCountOffset, kInt32Size) \
780 V(kCreateClosureSlotCountOffset, kInt32Size) \
781 V(kHeaderSize, 0)
782
784#undef FIELDS
785
786 class BodyDescriptor;
787
788 private:
789 friend class AccessorAssembler;
790
791 // Raw accessors to the encoded slot data.
792 inline int32_t get(int index) const;
793 inline void set(int index, int32_t value);
794
795 // The number of int32 data fields needed to store {slot_count} slots.
796 // Does not include any extra padding for pointer size alignment.
797 static int word_count(int slot_count) {
799 }
800 inline int word_count() const;
801
802 static const int kFeedbackSlotKindBits = 5;
803 static_assert(kFeedbackSlotKindCount <= (1 << kFeedbackSlotKindBits));
804
806
807 void SetCreateClosureParameterCount(int index, uint16_t parameter_count);
808
811 kInt32Size * kBitsPerByte, uint32_t>;
812
814};
815
816// Verify that an empty hash field looks like a tagged object, but can't
817// possibly be confused with a pointer.
819static_assert(Name::kEmptyHashField == 0x3);
820// Verify that a set hash field will not look like a tagged object.
822
824 public:
829
834
835 inline bool HasNext() const;
836
837 inline FeedbackSlot Next();
838
839 // Returns slot kind of the last slot returned by Next().
844
845 // Returns entry size of the last slot returned by Next().
846 inline int entry_size() const;
847
848 private:
852
853 // The reason for having a handle and a raw pointer to the meta data is
854 // to have a single iterator implementation for both "handlified" and raw
855 // pointer use cases.
861};
862
863// NexusConfig adapts the FeedbackNexus to be used on the main thread
864// or a background thread. It controls the actual read and writes of
865// the underlying feedback vector, manages the creation of handles, and
866// expresses capabilities available in the very different contexts of
867// main and background thread. Here are the differences:
868//
869// Capability: MainThread BackgroundThread
870// Write to vector Allowed Not allowed
871// Handle creation Via Isolate Via LocalHeap
872// Reads of vector "Live" Cached after initial read
873// Thread safety Exclusive write, Shared read only
874// shared read
876 public:
878 DCHECK_NOT_NULL(isolate);
879 return NexusConfig(isolate);
880 }
881
883 LocalHeap* local_heap) {
884 DCHECK_NOT_NULL(isolate);
885 return NexusConfig(isolate, local_heap);
886 }
887
888 enum Mode { MainThread, BackgroundThread };
889
890 Mode mode() const {
891 return local_heap_ == nullptr ? MainThread : BackgroundThread;
892 }
893
894 Isolate* isolate() const { return isolate_; }
895
896 MaybeObjectHandle NewHandle(Tagged<MaybeObject> object) const;
897 template <typename T>
898 Handle<T> NewHandle(Tagged<T> object) const;
899
900 bool can_write() const { return mode() == MainThread; }
901
902 inline Tagged<MaybeObject> GetFeedback(Tagged<FeedbackVector> vector,
903 FeedbackSlot slot) const;
904 inline void SetFeedback(Tagged<FeedbackVector> vector, FeedbackSlot slot,
905 Tagged<MaybeObject> object,
906 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) const;
907
908 std::pair<Tagged<MaybeObject>, Tagged<MaybeObject>> GetFeedbackPair(
909 Tagged<FeedbackVector> vector, FeedbackSlot slot) const;
910 void SetFeedbackPair(Tagged<FeedbackVector> vector, FeedbackSlot start_slot,
912 Tagged<MaybeObject> feedback_extra,
913 WriteBarrierMode mode_extra) const;
914
915 private:
916 explicit NexusConfig(Isolate* isolate)
917 : isolate_(isolate), local_heap_(nullptr) {}
918 NexusConfig(Isolate* isolate, LocalHeap* local_heap)
919 : isolate_(isolate), local_heap_(local_heap) {}
920
923};
924
925// A FeedbackNexus is the combination of a FeedbackVector and a slot.
927 public:
928 // For use on the main thread. A null {vector} is accepted as well.
930 FeedbackSlot slot);
932
933 // For use on the main or background thread as configured by {config}.
934 // {vector} must be valid.
936 const NexusConfig& config);
937
938 const NexusConfig* config() const { return &config_; }
940 DCHECK(vector_.is_null());
941 return vector_handle_;
942 }
944 return vector_handle_.is_null() ? vector_ : *vector_handle_;
945 }
946
947 FeedbackSlot slot() const { return slot_; }
948 FeedbackSlotKind kind() const { return kind_; }
949
951 return vector()->GetLanguageMode(slot());
952 }
953
954 InlineCacheState ic_state() const;
955 bool IsUninitialized() const {
956 return ic_state() == InlineCacheState::UNINITIALIZED;
957 }
958 bool IsMegamorphic() const {
959 return ic_state() == InlineCacheState::MEGAMORPHIC;
960 }
961 bool IsGeneric() const { return ic_state() == InlineCacheState::GENERIC; }
962
963 void Print(std::ostream& os);
964
965 // For map-based ICs (load, keyed-load, store, keyed-store).
966 Tagged<Map> GetFirstMap() const;
967 int ExtractMaps(MapHandles* maps) const;
968 // Used to obtain maps and the associated handlers stored in the feedback
969 // vector. This should be called when we expect only a handler to be stored in
970 // the extra feedback. This is used by ICs when updating the handlers.
971 using TryUpdateHandler = std::function<MaybeHandle<Map>(Handle<Map>)>;
972 int ExtractMapsAndHandlers(
973 MapsAndHandlers* maps_and_handlers,
974 TryUpdateHandler map_handler = TryUpdateHandler()) const;
975 MaybeObjectDirectHandle FindHandlerForMap(DirectHandle<Map> map) const;
976 // Used to obtain maps. This is used by compilers to get all the feedback
977 // stored in the vector.
978 template <typename F>
979 void IterateMapsWithUnclearedHandler(F) const;
980
981 bool IsCleared() const {
982 InlineCacheState state = ic_state();
983 return !v8_flags.use_ic || state == InlineCacheState::UNINITIALIZED;
984 }
985
986 // Clear() returns true if the state of the underlying vector was changed.
987 bool Clear(ClearBehavior behavior);
988 void ConfigureUninitialized();
989 // ConfigureMegamorphic() returns true if the state of the underlying vector
990 // was changed. Extra feedback is cleared if the 0 parameter version is used.
991 bool ConfigureMegamorphic();
992 bool ConfigureMegamorphic(IcCheckType property_type);
993
994 inline Tagged<MaybeObject> GetFeedback() const;
995 inline Tagged<MaybeObject> GetFeedbackExtra() const;
996 inline std::pair<Tagged<MaybeObject>, Tagged<MaybeObject>> GetFeedbackPair()
997 const;
998
999 void ConfigureMonomorphic(DirectHandle<Name> name,
1000 DirectHandle<Map> receiver_map,
1001 const MaybeObjectDirectHandle& handler);
1002
1003 void ConfigurePolymorphic(DirectHandle<Name> name,
1004 MapsAndHandlers const& maps_and_handlers);
1005
1006 void ConfigureMegaDOM(const MaybeObjectDirectHandle& handler);
1007 MaybeObjectHandle ExtractMegaDOMHandler();
1008
1009 BinaryOperationHint GetBinaryOperationFeedback() const;
1010 CompareOperationHint GetCompareOperationFeedback() const;
1011 TypeOfFeedback::Result GetTypeOfFeedback() const;
1012 ForInHint GetForInFeedback() const;
1013
1014 // For KeyedLoad ICs.
1015 KeyedAccessLoadMode GetKeyedAccessLoadMode() const;
1016
1017 // For KeyedStore ICs.
1018 KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
1019
1020 // For KeyedLoad and KeyedStore ICs.
1021 IcCheckType GetKeyType() const;
1022 Tagged<Name> GetName() const;
1023
1024 // For Call ICs.
1025 int GetCallCount();
1026 void SetSpeculationMode(SpeculationMode mode);
1027 SpeculationMode GetSpeculationMode();
1028 CallFeedbackContent GetCallFeedbackContent();
1029
1030 // Compute the call frequency based on the call count and the invocation
1031 // count (taken from the type feedback vector).
1032 float ComputeCallFrequency();
1033
1037
1038 // For InstanceOf ICs.
1039 MaybeDirectHandle<JSObject> GetConstructorFeedback() const;
1040
1041 // For Global Load and Store ICs.
1042 void ConfigurePropertyCellMode(DirectHandle<PropertyCell> cell);
1043 // Returns false if given combination of indices is not allowed.
1044 bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index,
1045 bool immutable);
1046 void ConfigureHandlerMode(const MaybeObjectDirectHandle& handler);
1047
1048 // For CloneObject ICs
1049 static constexpr int kCloneObjectPolymorphicEntrySize = 2;
1050 void ConfigureCloneObject(DirectHandle<Map> source_map,
1051 const MaybeObjectHandle& handler);
1052
1053// Bit positions in a smi that encodes lexical environment variable access.
1054#define LEXICAL_MODE_BIT_FIELDS(V, _) \
1055 V(ContextIndexBits, unsigned, 12, _) \
1056 V(SlotIndexBits, unsigned, 18, _) \
1057 V(ImmutabilityBit, bool, 1, _)
1058
1060#undef LEXICAL_MODE_BIT_FIELDS
1061
1062 // Make sure we don't overflow the smi.
1063 static_assert(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize);
1064
1065 private:
1066 template <typename FeedbackType>
1067 inline void SetFeedback(Tagged<FeedbackType> feedback,
1068 WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
1069 template <typename FeedbackType, typename FeedbackExtraType>
1070 inline void SetFeedback(Tagged<FeedbackType> feedback, WriteBarrierMode mode,
1071 Tagged<FeedbackExtraType> feedback_extra,
1072 WriteBarrierMode mode_extra = UPDATE_WRITE_BARRIER);
1073
1074 inline Tagged<MaybeObject> UninitializedSentinel() const;
1075 inline Tagged<MaybeObject> MegamorphicSentinel() const;
1076 inline Tagged<MaybeObject> MegaDOMSentinel() const;
1077
1078 // Create an array. The caller must install it in a feedback vector slot.
1079 DirectHandle<WeakFixedArray> CreateArrayOfSize(int length);
1080
1081 // Helpers to maintain feedback_cache_.
1082 inline Tagged<MaybeObject> FromHandle(MaybeObjectDirectHandle slot) const;
1083 inline MaybeObjectHandle ToHandle(Tagged<MaybeObject> value) const;
1084
1085 // The reason for having a vector handle and a raw pointer is that we can and
1086 // should use handles during IC miss, but not during GC when we clear ICs. If
1087 // you have a handle to the vector that is better because more operations can
1088 // be done, like allocation.
1093 // When using the background-thread configuration, a cache is used to
1094 // guarantee a consistent view of the feedback to FeedbackNexus methods.
1095 mutable std::optional<std::pair<MaybeObjectHandle, MaybeObjectHandle>>
1099};
1100
1102 public:
1103 explicit FeedbackIterator(const FeedbackNexus* nexus);
1104 void Advance();
1105 bool done() { return done_; }
1106 Tagged<Map> map() { return map_; }
1108
1109 static int SizeFor(int number_of_entries) {
1110 CHECK_GT(number_of_entries, 0);
1111 return number_of_entries * kEntrySize;
1112 }
1113
1114 static int MapIndexForEntry(int entry) {
1115 CHECK_GE(entry, 0);
1116 return entry * kEntrySize;
1117 }
1118
1119 static int HandlerIndexForEntry(int entry) {
1120 CHECK_GE(entry, 0);
1121 return (entry * kEntrySize) + kHandlerOffset;
1122 }
1123
1124 static constexpr int kEntrySize = 2;
1125 static constexpr int kHandlerOffset = 1;
1126
1127 private:
1128 void AdvancePolymorphic();
1129 enum State { kMonomorphic, kPolymorphic, kOther };
1130
1134 bool done_;
1137};
1138
1141inline ForInHint ForInHintFromFeedback(ForInFeedback type_feedback);
1142
1143} // namespace v8::internal
1144
1146
1147#endif // V8_OBJECTS_FEEDBACK_VECTOR_H_
Isolate * isolate_
#define F(name, str)
#define DEFINE_BIT_FIELDS(LIST_MACRO)
Definition bit-field.h:126
int16_t parameter_count
Definition builtins.cc:67
Builtins::Kind kind
Definition builtins.cc:40
static int word_count(int items)
Definition bit-field.h:148
static V8_EXPORT_PRIVATE DirectHandle< ClosureFeedbackCellArray > New(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared, AllocationType allocation=AllocationType::kYoung)
void push_back(const_reference x)
Definition handles.h:1092
size_t size() const noexcept
Definition handles.h:1072
static int HandlerIndexForEntry(int entry)
DirectHandle< WeakFixedArray > polymorphic_feedback_
static int MapIndexForEntry(int entry)
static int SizeFor(int number_of_entries)
Tagged< MaybeObject > handler()
FeedbackMetadataIterator(Handle< FeedbackMetadata > metadata)
Tagged< FeedbackMetadata > metadata_
FeedbackMetadataIterator(Tagged< FeedbackMetadata > metadata)
Handle< FeedbackMetadata > metadata_handle_
Tagged< FeedbackMetadata > metadata() const
int32_t slot_count(AcquireLoadTag) const
void SetCreateClosureParameterCount(int index, uint16_t parameter_count)
static int SizeFor(int slot_count, int create_closure_slot_count)
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const
static V8_EXPORT_PRIVATE Handle< FeedbackMetadata > New(IsolateT *isolate, const FeedbackVectorSpec *spec)
OBJECT_CONSTRUCTORS(FeedbackMetadata, HeapObject)
V8_EXPORT_PRIVATE uint16_t GetCreateClosureParameterCount(int index) const
void SetKind(FeedbackSlot slot, FeedbackSlotKind kind)
static int word_count(int slot_count)
static const char * Kind2String(FeedbackSlotKind kind)
int32_t create_closure_slot_count(AcquireLoadTag) const
int32_t get(int index) const
void set(int index, int32_t value)
static int GetSlotSize(FeedbackSlotKind kind)
bool SpecDiffersFrom(const FeedbackVectorSpec *other_spec) const
std::function< MaybeHandle< Map >(Handle< Map >)> TryUpdateHandler
const NexusConfig * config() const
Tagged< FeedbackVector > vector() const
DirectHandle< FeedbackVector > vector_handle() const
FeedbackSlotKind kind() const
Handle< FeedbackVector > vector_handle_
LanguageMode GetLanguageMode() const
Tagged< FeedbackVector > vector_
void Print(std::ostream &os)
FeedbackSlot slot() const
std::optional< std::pair< MaybeObjectHandle, MaybeObjectHandle > > feedback_cache_
bool IsInvalid() const
Definition utils.h:649
FeedbackSlot AddDefineKeyedOwnPropertyInLiteralICSlot()
FeedbackSlotKind GetKind(FeedbackSlot slot) const
void append(FeedbackSlotKind kind)
FeedbackSlot AddKeyedStoreICSlot(LanguageMode language_mode)
FeedbackSlotKind GetKeyedStoreICSlotKind(LanguageMode language_mode)
FeedbackSlot AddSlot(FeedbackSlotKind kind)
FeedbackSlot AddStoreICSlot(LanguageMode language_mode)
ZoneVector< uint16_t > create_closure_parameter_counts_
uint16_t GetCreateClosureParameterCount(int index) const
FeedbackSlot AddLoadGlobalICSlot(TypeofMode typeof_mode)
int AddCreateClosureParameterCount(uint16_t parameter_count)
ZoneVector< FeedbackSlotKind > slot_kinds_
FeedbackSlotKind GetStoreICSlot(LanguageMode language_mode)
FeedbackSlot AddStoreGlobalICSlot(LanguageMode language_mode)
V8_EXPORT_PRIVATE void set_tiering_state(TieringState state)
LanguageMode GetLanguageMode(FeedbackSlot slot) const
static DirectHandle< Symbol > MegaDOMSentinel(Isolate *isolate)
Tagged< MaybeObject > Get(FeedbackSlot slot) const
static FeedbackSlot ToSlot(intptr_t index)
static DirectHandle< Symbol > UninitializedSentinel(Isolate *isolate)
Tagged< Code > optimized_code(IsolateForSandbox isolate) const
void set_maybe_has_turbofan_code(bool value)
TypeofMode GetTypeofMode(FeedbackSlot slot) const
static V8_EXPORT_PRIVATE Handle< FeedbackVector > NewWithOneBinarySlotForTesting(Zone *zone, Isolate *isolate)
static V8_EXPORT_PRIVATE Handle< FeedbackVector > NewForTesting(Isolate *isolate, const FeedbackVectorSpec *spec)
void set_maybe_has_optimized_osr_code(bool value, CodeKind code_kind)
void SetOptimizedOsrCode(Isolate *isolate, FeedbackSlot slot, Tagged< Code > code)
Tagged< FeedbackCell > closure_feedback_cell(int index) const
void Set(FeedbackSlot slot, Tagged< MaybeObject > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
static Tagged< Symbol > RawUninitializedSentinel(Isolate *isolate)
static V8_EXPORT_PRIVATE Handle< FeedbackVector > New(Isolate *isolate, DirectHandle< SharedFunctionInfo > shared, DirectHandle< ClosureFeedbackCellArray > closure_feedback_cell_array, DirectHandle< FeedbackCell > parent_feedback_cell, IsCompiledScope *is_compiled_scope)
static constexpr uint32_t kFlagsHasAnyOptimizedCode
static constexpr uint8_t kInvocationCountBeforeStableDeoptSentinel
static constexpr uint32_t kFlagsMaybeHasMaglevCode
std::optional< Tagged< Code > > GetOptimizedOsrCode(Isolate *isolate, FeedbackSlot slot)
void set_log_next_execution(bool value=true)
Tagged< MaybeObject > SynchronizedGet(FeedbackSlot slot) const
DirectHandle< FeedbackCell > GetClosureFeedbackCell(Isolate *isolate, int index) const
static int GetIndex(FeedbackSlot slot)
bool ClearSlots(Isolate *isolate)
static void AddToVectorsForProfilingTools(Isolate *isolate, DirectHandle< FeedbackVector > vector)
void FeedbackSlotPrint(std::ostream &os, FeedbackSlot slot)
void SynchronizedSet(FeedbackSlot slot, Tagged< MaybeObject > value, WriteBarrierMode mode=UPDATE_WRITE_BARRIER)
static constexpr uint32_t kFlagsTieringStateIsAnyRequested
bool ClearAllSlotsForTesting(Isolate *isolate)
void EvictOptimizedCodeMarkedForDeoptimization(Isolate *isolate, Tagged< SharedFunctionInfo > shared, const char *reason)
void clear_invocation_count(RelaxedStoreTag tag)
void SetOptimizedCode(IsolateForSandbox isolate, Tagged< Code > code)
static constexpr uint32_t kFlagsLogNextExecution
static Handle< Symbol > MegamorphicSentinel(Isolate *isolate)
void set_interrupt_budget_reset_by_ic_change(bool value)
void set_osr_urgency(int urgency)
static constexpr uint32_t kFlagsMaybeHasTurbofanCode
static constexpr int kMaxOsrUrgency
static constexpr uint32_t FlagMaskForNeedsProcessingCheckFrom(CodeKind code_kind)
static V8_EXPORT_PRIVATE Handle< FeedbackVector > NewWithOneCompareSlotForTesting(Zone *zone, Isolate *isolate)
void set_osr_tiering_in_progress(bool osr_in_progress)
V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const
static constexpr int OffsetOfElementAt(int index)
static constexpr int kHeaderSize
constexpr Iterator(const MapsAndHandlers *container, size_t i)
constexpr bool operator==(const Iterator &other)
constexpr bool operator!=(const Iterator &other)
DirectHandleSmallVector< Object, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT > handlers_
void emplace_back(DirectHandle< Map > map, MaybeObjectDirectHandle handler)
MapsAndHandlers(Isolate *isolate)
DirectHandleSmallVector< Map, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT > maps_
base::SmallVector< HeapObjectReferenceType, DEFAULT_MAX_POLYMORPHIC_MAP_COUNT > handlers_reference_types_
MapAndHandler operator[](size_t i) const
base::Vector< DirectHandle< Map > > maps()
void set_handler(size_t i, MaybeObjectDirectHandle handler)
void reserve(size_t capacity)
void set_map(size_t i, DirectHandle< Map > map)
static MaybeObjectDirectHandle Weak(Tagged< Object > object, Isolate *isolate)
static constexpr int kEmptyHashField
Definition name.h:133
static constexpr int kHashNotComputedMask
Definition name.h:131
NexusConfig(Isolate *isolate, LocalHeap *local_heap)
NexusConfig(Isolate *isolate)
static NexusConfig FromMainThread(Isolate *isolate)
static NexusConfig FromBackgroundThread(Isolate *isolate, LocalHeap *local_heap)
SharedFeedbackSlot(FeedbackVectorSpec *spec, FeedbackSlotKind kind)
#define OBJECT_POINTER_ALIGN(value)
Definition globals.h:1783
const MapRef map_
const PropertyKind kind_
bool done_
Definition compiler.cc:3788
std::vector< T > vector_
Definition sweeper.cc:212
#define DEFINE_SLOT_KIND_PREDICATE(Name)
#define LEXICAL_MODE_BIT_FIELDS(V, _)
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 allocation gc speed threshold for starting incremental marking via a task in percent of available threshold for starting incremental marking immediately in percent of available Use a single schedule for determining a marking schedule between JS and C objects schedules the minor GC task with kUserVisible priority max worker number of concurrent for NumberOfWorkerThreads start background threads that allocate memory concurrent_array_buffer_sweeping use parallel threads to clear weak refs in the atomic pause trace progress of the incremental marking trace object counts and memory usage report a tick only when allocated zone memory changes by this amount TracingFlags::gc_stats TracingFlags::gc_stats track native contexts that are expected to be garbage collected verify heap pointers before and after GC memory reducer runs GC with ReduceMemoryFootprint flag Maximum number of memory reducer GCs scheduled Old gen GC speed is computed directly from gc tracer counters Perform compaction on full GCs based on V8 s default heuristics Perform compaction on every full GC Perform code space compaction when finalizing a full GC with stack Stress GC compaction to flush out bugs with moving objects flush of baseline code when it has not been executed recently Use time base code flushing instead of age Use a progress bar to scan large objects in increments when incremental marking is active force incremental marking for small heaps and run it more often force marking at random points between and force scavenge at random points between and reclaim otherwise unreachable unmodified wrapper objects when possible less compaction in non memory reducing mode use high priority threads for concurrent Marking Test mode only flag It allows an unit test to select evacuation candidates use incremental marking for CppHeap cppheap_concurrent_marking c value for membalancer A special constant to balance between memory and space tradeoff The smaller the more memory it uses enable use of SSE4 instructions if available enable use of AVX VNNI instructions if available enable use of POPCNT instruction if available force all emitted branches to be in long mode(MIPS/PPC only)") DEFINE_BOOL(partial_constant_pool
#define FIELDS(V)
std::map< const std::string, const std::string > map
MovableLabel handler
STL namespace.
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
bool IsStoreGlobalICKind(FeedbackSlotKind kind)
bool IsKeyedHasICKind(FeedbackSlotKind kind)
constexpr int kTaggedSize
Definition globals.h:542
bool IsDefineNamedOwnICKind(FeedbackSlotKind kind)
constexpr int kBitsPerByte
Definition globals.h:682
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
ForInHint ForInHintFromFeedback(ForInFeedback type_feedback)
constexpr intptr_t kObjectAlignment
Definition globals.h:930
CompareOperationHint CompareOperationHintFromFeedback(int type_feedback)
bool IsSetNamedICKind(FeedbackSlotKind kind)
static constexpr int kFeedbackSlotKindCount
LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind)
bool IsLoadICKind(FeedbackSlotKind kind)
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
bool IsCallICKind(FeedbackSlotKind kind)
bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind)
constexpr int kInt32Size
Definition globals.h:401
bool is_strict(LanguageMode language_mode)
Definition globals.h:777
const int kHeapObjectTag
Definition v8-internal.h:72
TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind)
V8_EXPORT_PRIVATE FlagValues v8_flags
bool IsKeyedLoadICKind(FeedbackSlotKind kind)
bool IsCloneObjectKind(FeedbackSlotKind kind)
bool IsDefineKeyedOwnICKind(FeedbackSlotKind kind)
constexpr int kUInt16Size
Definition globals.h:399
bool IsLoadGlobalICKind(FeedbackSlotKind kind)
static constexpr uint32_t kNoneOrInProgressMask
Definition globals.h:2512
bool IsDefineKeyedOwnPropertyInLiteralKind(FeedbackSlotKind kind)
BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback)
std::vector< MaybeObjectHandle > MaybeObjectHandles
V8HeapCompressionSchemeImpl< MainCage > V8HeapCompressionScheme
Definition globals.h:1137
bool IsGlobalICKind(FeedbackSlotKind kind)
bool IsKeyedStoreICKind(FeedbackSlotKind kind)
std::pair< DirectHandle< Map >, MaybeObjectDirectHandle > MapAndHandler
#define DECL_GETTER(name,...)
#define DECL_ACQUIRE_GETTER(name,...)
#define DECL_VERIFIER(Name)
#define NEVER_READ_ONLY_SPACE
#define DECL_PRINTER(Name)
#define DECL_RELAXED_INT32_ACCESSORS(name)
#define TQ_OBJECT_CONSTRUCTORS(Type)
#define DECL_INT32_ACCESSORS(name)
#define DECL_RELAXED_UINT8_ACCESSORS(name)
#define CHECK_GE(lhs, rhs)
#define CHECK_GT(lhs, rhs)
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define V8_EXPORT_PRIVATE
Definition macros.h:460
EmbedderRootsHandler * handler_
#define DEFINE_FIELD_OFFSET_CONSTANTS(StartOffset, LIST_MACRO)
Definition utils.h:242