• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <vector>
9 
10 #include "src/base/bit-field.h"
11 #include "src/base/logging.h"
12 #include "src/base/macros.h"
13 #include "src/common/globals.h"
14 #include "src/objects/elements-kind.h"
15 #include "src/objects/map.h"
16 #include "src/objects/maybe-object.h"
17 #include "src/objects/name.h"
18 #include "src/objects/type-hints.h"
19 #include "src/zone/zone-containers.h"
20 
21 // Has to be the last include (doesn't have include guards):
22 #include "src/objects/object-macros.h"
23 
24 namespace v8 {
25 namespace internal {
26 
27 class IsCompiledScope;
28 
29 enum class FeedbackSlotKind : uint8_t {
30   // This kind means that the slot points to the middle of other slot
31   // which occupies more than one feedback vector element.
32   // There must be no such slots in the system.
33   kInvalid,
34 
35   // Sloppy kinds come first, for easy language mode testing.
36   kStoreGlobalSloppy,
37   kStoreNamedSloppy,
38   kStoreKeyedSloppy,
39   kLastSloppyKind = kStoreKeyedSloppy,
40 
41   // Strict and language mode unaware kinds.
42   kCall,
43   kLoadProperty,
44   kLoadGlobalNotInsideTypeof,
45   kLoadGlobalInsideTypeof,
46   kLoadKeyed,
47   kHasKeyed,
48   kStoreGlobalStrict,
49   kStoreNamedStrict,
50   kStoreOwnNamed,
51   kStoreKeyedStrict,
52   kStoreInArrayLiteral,
53   kBinaryOp,
54   kCompareOp,
55   kStoreDataPropertyInLiteral,
56   kTypeProfile,
57   kLiteral,
58   kForIn,
59   kInstanceOf,
60   kCloneObject,
61 
62   kKindsNumber  // Last value indicating number of kinds.
63 };
64 
65 using MapAndHandler = std::pair<Handle<Map>, MaybeObjectHandle>;
66 using MapAndFeedback = std::pair<Handle<Map>, MaybeObjectHandle>;
67 
IsCallICKind(FeedbackSlotKind kind)68 inline bool IsCallICKind(FeedbackSlotKind kind) {
69   return kind == FeedbackSlotKind::kCall;
70 }
71 
IsLoadICKind(FeedbackSlotKind kind)72 inline bool IsLoadICKind(FeedbackSlotKind kind) {
73   return kind == FeedbackSlotKind::kLoadProperty;
74 }
75 
IsLoadGlobalICKind(FeedbackSlotKind kind)76 inline bool IsLoadGlobalICKind(FeedbackSlotKind kind) {
77   return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof ||
78          kind == FeedbackSlotKind::kLoadGlobalInsideTypeof;
79 }
80 
IsKeyedLoadICKind(FeedbackSlotKind kind)81 inline bool IsKeyedLoadICKind(FeedbackSlotKind kind) {
82   return kind == FeedbackSlotKind::kLoadKeyed;
83 }
84 
IsKeyedHasICKind(FeedbackSlotKind kind)85 inline bool IsKeyedHasICKind(FeedbackSlotKind kind) {
86   return kind == FeedbackSlotKind::kHasKeyed;
87 }
88 
IsStoreGlobalICKind(FeedbackSlotKind kind)89 inline bool IsStoreGlobalICKind(FeedbackSlotKind kind) {
90   return kind == FeedbackSlotKind::kStoreGlobalSloppy ||
91          kind == FeedbackSlotKind::kStoreGlobalStrict;
92 }
93 
IsStoreICKind(FeedbackSlotKind kind)94 inline bool IsStoreICKind(FeedbackSlotKind kind) {
95   return kind == FeedbackSlotKind::kStoreNamedSloppy ||
96          kind == FeedbackSlotKind::kStoreNamedStrict;
97 }
98 
IsStoreOwnICKind(FeedbackSlotKind kind)99 inline bool IsStoreOwnICKind(FeedbackSlotKind kind) {
100   return kind == FeedbackSlotKind::kStoreOwnNamed;
101 }
102 
IsStoreDataPropertyInLiteralKind(FeedbackSlotKind kind)103 inline bool IsStoreDataPropertyInLiteralKind(FeedbackSlotKind kind) {
104   return kind == FeedbackSlotKind::kStoreDataPropertyInLiteral;
105 }
106 
IsKeyedStoreICKind(FeedbackSlotKind kind)107 inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) {
108   return kind == FeedbackSlotKind::kStoreKeyedSloppy ||
109          kind == FeedbackSlotKind::kStoreKeyedStrict;
110 }
111 
IsStoreInArrayLiteralICKind(FeedbackSlotKind kind)112 inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) {
113   return kind == FeedbackSlotKind::kStoreInArrayLiteral;
114 }
115 
IsGlobalICKind(FeedbackSlotKind kind)116 inline bool IsGlobalICKind(FeedbackSlotKind kind) {
117   return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind);
118 }
119 
IsTypeProfileKind(FeedbackSlotKind kind)120 inline bool IsTypeProfileKind(FeedbackSlotKind kind) {
121   return kind == FeedbackSlotKind::kTypeProfile;
122 }
123 
IsCloneObjectKind(FeedbackSlotKind kind)124 inline bool IsCloneObjectKind(FeedbackSlotKind kind) {
125   return kind == FeedbackSlotKind::kCloneObject;
126 }
127 
GetTypeofModeFromSlotKind(FeedbackSlotKind kind)128 inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) {
129   DCHECK(IsLoadGlobalICKind(kind));
130   return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof)
131              ? INSIDE_TYPEOF
132              : NOT_INSIDE_TYPEOF;
133 }
134 
GetLanguageModeFromSlotKind(FeedbackSlotKind kind)135 inline LanguageMode GetLanguageModeFromSlotKind(FeedbackSlotKind kind) {
136   DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind) ||
137          IsStoreGlobalICKind(kind) || IsKeyedStoreICKind(kind));
138   STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
139                 FeedbackSlotKind::kLastSloppyKind);
140   STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
141                 FeedbackSlotKind::kLastSloppyKind);
142   STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
143                 FeedbackSlotKind::kLastSloppyKind);
144   return (kind <= FeedbackSlotKind::kLastSloppyKind) ? LanguageMode::kSloppy
145                                                      : LanguageMode::kStrict;
146 }
147 
148 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
149                                            FeedbackSlotKind kind);
150 
151 using MaybeObjectHandles = std::vector<MaybeObjectHandle>;
152 
153 class FeedbackMetadata;
154 
155 #include "torque-generated/src/objects/feedback-vector-tq.inc"
156 
157 // ClosureFeedbackCellArray is a FixedArray that contains feedback cells used
158 // when creating closures from a function. This is created once the function is
159 // compiled and is either held by the feedback vector (if allocated) or by the
160 // FeedbackCell of the closure.
161 class ClosureFeedbackCellArray : public FixedArray {
162  public:
163   NEVER_READ_ONLY_SPACE
164 
165   DECL_CAST(ClosureFeedbackCellArray)
166 
167   V8_EXPORT_PRIVATE static Handle<ClosureFeedbackCellArray> New(
168       Isolate* isolate, Handle<SharedFunctionInfo> shared);
169   inline Handle<FeedbackCell> GetFeedbackCell(int index);
170 
171   DECL_VERIFIER(ClosureFeedbackCellArray)
172   DECL_PRINTER(ClosureFeedbackCellArray)
173 
174  private:
175   OBJECT_CONSTRUCTORS(ClosureFeedbackCellArray, FixedArray);
176 };
177 
178 class NexusConfig;
179 
180 // A FeedbackVector has a fixed header with:
181 //  - shared function info (which includes feedback metadata)
182 //  - invocation count
183 //  - runtime profiler ticks
184 //  - optimized code cell (weak cell or Smi marker)
185 // followed by an array of feedback slots, of length determined by the feedback
186 // metadata.
187 class FeedbackVector
188     : public TorqueGeneratedFeedbackVector<FeedbackVector, HeapObject> {
189  public:
190   NEVER_READ_ONLY_SPACE
191   DEFINE_TORQUE_GENERATED_FEEDBACK_VECTOR_FLAGS()
192   STATIC_ASSERT(OptimizationMarker::kLastOptimizationMarker <
193                 OptimizationMarkerBits::kMax);
194   STATIC_ASSERT(OptimizationTier::kLastOptimizationTier <
195                 OptimizationTierBits::kMax);
196 
197   static constexpr uint32_t kHasCompileOptimizedOrLogFirstExecutionMarker =
198       kNoneOrInOptimizationQueueMask << OptimizationMarkerBits::kShift;
199   static constexpr uint32_t kHasNoTopTierCodeOrCompileOptimizedMarkerMask =
200       kNoneOrMidTierMask << OptimizationTierBits::kShift |
201       kHasCompileOptimizedOrLogFirstExecutionMarker;
202   static constexpr uint32_t kHasOptimizedCodeOrCompileOptimizedMarkerMask =
203       OptimizationTierBits::kMask |
204       kHasCompileOptimizedOrLogFirstExecutionMarker;
205 
206   inline bool is_empty() const;
207 
208   inline FeedbackMetadata metadata() const;
209 
210   // Increment profiler ticks, saturating at the maximal value.
211   void SaturatingIncrementProfilerTicks();
212 
213   inline void clear_invocation_count();
214 
215   inline Code optimized_code() const;
216   inline bool has_optimized_code() const;
217   inline bool has_optimization_marker() const;
218   inline OptimizationMarker optimization_marker() const;
219   inline OptimizationTier optimization_tier() const;
220   void ClearOptimizedCode();
221   void EvictOptimizedCodeMarkedForDeoptimization(SharedFunctionInfo shared,
222                                                  const char* reason);
223   static void SetOptimizedCode(Handle<FeedbackVector> vector,
224                                Handle<Code> code);
225   void SetOptimizationMarker(OptimizationMarker marker);
226   void ClearOptimizationTier();
227   void InitializeOptimizationState();
228 
229   // Clears the optimization marker in the feedback vector.
230   void ClearOptimizationMarker();
231 
232   // Conversion from a slot to an integer index to the underlying array.
GetIndex(FeedbackSlot slot)233   static int GetIndex(FeedbackSlot slot) { return slot.ToInt(); }
234 
235   // Conversion from an integer index to the underlying array to a slot.
236   static inline FeedbackSlot ToSlot(intptr_t index);
237 
238   inline MaybeObject SynchronizedGet(FeedbackSlot slot) const;
239   inline void SynchronizedSet(FeedbackSlot slot, MaybeObject value,
240                               WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
241   inline void SynchronizedSet(FeedbackSlot slot, Object value,
242                               WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
243 
244   inline MaybeObject Get(FeedbackSlot slot) const;
245   inline MaybeObject Get(IsolateRoot isolate, FeedbackSlot slot) const;
246 
247   // Returns the feedback cell at |index| that is used to create the
248   // closure.
249   inline Handle<FeedbackCell> GetClosureFeedbackCell(int index) const;
250 
251   // Gives access to raw memory which stores the array's data.
252   inline MaybeObjectSlot slots_start();
253 
254   // Returns slot kind for given slot.
255   V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
256 
257   FeedbackSlot GetTypeProfileSlot() const;
258 
259   V8_EXPORT_PRIVATE static Handle<FeedbackVector> New(
260       Isolate* isolate, Handle<SharedFunctionInfo> shared,
261       Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,
262       IsCompiledScope* is_compiled_scope);
263 
264   V8_EXPORT_PRIVATE static Handle<FeedbackVector>
265   NewWithOneBinarySlotForTesting(Zone* zone, Isolate* isolate);
266   V8_EXPORT_PRIVATE static Handle<FeedbackVector>
267   NewWithOneCompareSlotForTesting(Zone* zone, Isolate* isolate);
268 
269 #define DEFINE_SLOT_KIND_PREDICATE(Name) \
270   bool Name(FeedbackSlot slot) const { return Name##Kind(GetKind(slot)); }
271 
272   DEFINE_SLOT_KIND_PREDICATE(IsCallIC)
DEFINE_SLOT_KIND_PREDICATE(IsGlobalIC)273   DEFINE_SLOT_KIND_PREDICATE(IsGlobalIC)
274   DEFINE_SLOT_KIND_PREDICATE(IsLoadIC)
275   DEFINE_SLOT_KIND_PREDICATE(IsLoadGlobalIC)
276   DEFINE_SLOT_KIND_PREDICATE(IsKeyedLoadIC)
277   DEFINE_SLOT_KIND_PREDICATE(IsStoreIC)
278   DEFINE_SLOT_KIND_PREDICATE(IsStoreOwnIC)
279   DEFINE_SLOT_KIND_PREDICATE(IsStoreGlobalIC)
280   DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
281   DEFINE_SLOT_KIND_PREDICATE(IsTypeProfile)
282 #undef DEFINE_SLOT_KIND_PREDICATE
283 
284   // Returns typeof mode encoded into kind of given slot.
285   inline TypeofMode GetTypeofMode(FeedbackSlot slot) const {
286     return GetTypeofModeFromSlotKind(GetKind(slot));
287   }
288 
289   // Returns language mode encoded into kind of given slot.
GetLanguageMode(FeedbackSlot slot)290   inline LanguageMode GetLanguageMode(FeedbackSlot slot) const {
291     return GetLanguageModeFromSlotKind(GetKind(slot));
292   }
293 
294   DECL_PRINTER(FeedbackVector)
295 
296   void FeedbackSlotPrint(std::ostream& os, FeedbackSlot slot);  // NOLINT
297 
298   // Clears the vector slots. Return true if feedback has changed.
299   bool ClearSlots(Isolate* isolate);
300 
301   // The object that indicates an uninitialized cache.
302   static inline Handle<Symbol> UninitializedSentinel(Isolate* isolate);
303 
304   // The object that indicates a megamorphic state.
305   static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
306 
307   // A raw version of the uninitialized sentinel that's safe to read during
308   // garbage collection (e.g., for patching the cache).
309   static inline Symbol RawUninitializedSentinel(Isolate* isolate);
310 
311   static_assert(kHeaderSize % kObjectAlignment == 0,
312                 "Header must be padded for alignment");
313 
314   class BodyDescriptor;
315 
OffsetOfElementAt(int index)316   static constexpr int OffsetOfElementAt(int index) {
317     return kRawFeedbackSlotsOffset + index * kTaggedSize;
318   }
319 
320   TQ_OBJECT_CONSTRUCTORS(FeedbackVector)
321 
322  private:
323   static void AddToVectorsForProfilingTools(Isolate* isolate,
324                                             Handle<FeedbackVector> vector);
325 
326   // Private for initializing stores in FeedbackVector::New().
327   inline void Set(FeedbackSlot slot, MaybeObject value,
328                   WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
329   inline void Set(FeedbackSlot slot, Object value,
330                   WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
331 
332 #ifdef DEBUG
333   // Returns true if value is a non-HashTable FixedArray. We want to
334   // make sure not to store such objects in the vector.
335   inline static bool IsOfLegacyType(MaybeObject value);
336 #endif  // DEBUG
337 
338   // NexusConfig controls setting slots in the vector.
339   friend NexusConfig;
340 
341   // Don't expose the raw feedback slot getter/setter.
342   using TorqueGeneratedFeedbackVector::raw_feedback_slots;
343 };
344 
345 class V8_EXPORT_PRIVATE FeedbackVectorSpec {
346  public:
FeedbackVectorSpec(Zone * zone)347   explicit FeedbackVectorSpec(Zone* zone) : slot_kinds_(zone) {
348     slot_kinds_.reserve(16);
349   }
350 
slot_count()351   int slot_count() const { return static_cast<int>(slot_kinds_.size()); }
create_closure_slot_count()352   int create_closure_slot_count() const { return create_closure_slot_count_; }
353 
AddCreateClosureSlot()354   int AddCreateClosureSlot() { return create_closure_slot_count_++; }
355 
GetKind(FeedbackSlot slot)356   FeedbackSlotKind GetKind(FeedbackSlot slot) const {
357     return slot_kinds_.at(slot.ToInt());
358   }
359 
360   bool HasTypeProfileSlot() const;
361 
362   // If used, the TypeProfileSlot is always added as the first slot and its
363   // index is constant. If other slots are added before the TypeProfileSlot,
364   // this number changes.
365   static const int kTypeProfileSlotIndex = 0;
366 
AddCallICSlot()367   FeedbackSlot AddCallICSlot() { return AddSlot(FeedbackSlotKind::kCall); }
368 
AddLoadICSlot()369   FeedbackSlot AddLoadICSlot() {
370     return AddSlot(FeedbackSlotKind::kLoadProperty);
371   }
372 
AddLoadGlobalICSlot(TypeofMode typeof_mode)373   FeedbackSlot AddLoadGlobalICSlot(TypeofMode typeof_mode) {
374     return AddSlot(typeof_mode == INSIDE_TYPEOF
375                        ? FeedbackSlotKind::kLoadGlobalInsideTypeof
376                        : FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
377   }
378 
AddKeyedLoadICSlot()379   FeedbackSlot AddKeyedLoadICSlot() {
380     return AddSlot(FeedbackSlotKind::kLoadKeyed);
381   }
382 
AddKeyedHasICSlot()383   FeedbackSlot AddKeyedHasICSlot() {
384     return AddSlot(FeedbackSlotKind::kHasKeyed);
385   }
386 
GetStoreICSlot(LanguageMode language_mode)387   FeedbackSlotKind GetStoreICSlot(LanguageMode language_mode) {
388     STATIC_ASSERT(LanguageModeSize == 2);
389     return is_strict(language_mode) ? FeedbackSlotKind::kStoreNamedStrict
390                                     : FeedbackSlotKind::kStoreNamedSloppy;
391   }
392 
AddStoreICSlot(LanguageMode language_mode)393   FeedbackSlot AddStoreICSlot(LanguageMode language_mode) {
394     return AddSlot(GetStoreICSlot(language_mode));
395   }
396 
AddStoreOwnICSlot()397   FeedbackSlot AddStoreOwnICSlot() {
398     return AddSlot(FeedbackSlotKind::kStoreOwnNamed);
399   }
400 
AddStoreGlobalICSlot(LanguageMode language_mode)401   FeedbackSlot AddStoreGlobalICSlot(LanguageMode language_mode) {
402     STATIC_ASSERT(LanguageModeSize == 2);
403     return AddSlot(is_strict(language_mode)
404                        ? FeedbackSlotKind::kStoreGlobalStrict
405                        : FeedbackSlotKind::kStoreGlobalSloppy);
406   }
407 
GetKeyedStoreICSlotKind(LanguageMode language_mode)408   FeedbackSlotKind GetKeyedStoreICSlotKind(LanguageMode language_mode) {
409     STATIC_ASSERT(LanguageModeSize == 2);
410     return is_strict(language_mode) ? FeedbackSlotKind::kStoreKeyedStrict
411                                     : FeedbackSlotKind::kStoreKeyedSloppy;
412   }
413 
AddKeyedStoreICSlot(LanguageMode language_mode)414   FeedbackSlot AddKeyedStoreICSlot(LanguageMode language_mode) {
415     return AddSlot(GetKeyedStoreICSlotKind(language_mode));
416   }
417 
AddStoreInArrayLiteralICSlot()418   FeedbackSlot AddStoreInArrayLiteralICSlot() {
419     return AddSlot(FeedbackSlotKind::kStoreInArrayLiteral);
420   }
421 
AddBinaryOpICSlot()422   FeedbackSlot AddBinaryOpICSlot() {
423     return AddSlot(FeedbackSlotKind::kBinaryOp);
424   }
425 
AddCompareICSlot()426   FeedbackSlot AddCompareICSlot() {
427     return AddSlot(FeedbackSlotKind::kCompareOp);
428   }
429 
AddForInSlot()430   FeedbackSlot AddForInSlot() { return AddSlot(FeedbackSlotKind::kForIn); }
431 
AddInstanceOfSlot()432   FeedbackSlot AddInstanceOfSlot() {
433     return AddSlot(FeedbackSlotKind::kInstanceOf);
434   }
435 
AddLiteralSlot()436   FeedbackSlot AddLiteralSlot() { return AddSlot(FeedbackSlotKind::kLiteral); }
437 
AddStoreDataPropertyInLiteralICSlot()438   FeedbackSlot AddStoreDataPropertyInLiteralICSlot() {
439     return AddSlot(FeedbackSlotKind::kStoreDataPropertyInLiteral);
440   }
441 
442   FeedbackSlot AddTypeProfileSlot();
443 
AddCloneObjectSlot()444   FeedbackSlot AddCloneObjectSlot() {
445     return AddSlot(FeedbackSlotKind::kCloneObject);
446   }
447 
448 #ifdef OBJECT_PRINT
449   // For gdb debugging.
450   void Print();
451 #endif  // OBJECT_PRINT
452 
453   DECL_PRINTER(FeedbackVectorSpec)
454 
455  private:
456   FeedbackSlot AddSlot(FeedbackSlotKind kind);
457 
append(FeedbackSlotKind kind)458   void append(FeedbackSlotKind kind) { slot_kinds_.push_back(kind); }
459 
460   STATIC_ASSERT(sizeof(FeedbackSlotKind) == sizeof(uint8_t));
461   ZoneVector<FeedbackSlotKind> slot_kinds_;
462   int create_closure_slot_count_ = 0;
463 
464   friend class SharedFeedbackSlot;
465 };
466 
467 // Helper class that creates a feedback slot on-demand.
468 class SharedFeedbackSlot {
469  public:
470   // FeedbackSlot default constructor constructs an invalid slot.
SharedFeedbackSlot(FeedbackVectorSpec * spec,FeedbackSlotKind kind)471   SharedFeedbackSlot(FeedbackVectorSpec* spec, FeedbackSlotKind kind)
472       : kind_(kind), spec_(spec) {}
473 
Get()474   FeedbackSlot Get() {
475     if (slot_.IsInvalid()) slot_ = spec_->AddSlot(kind_);
476     return slot_;
477   }
478 
479  private:
480   FeedbackSlotKind kind_;
481   FeedbackSlot slot_;
482   FeedbackVectorSpec* spec_;
483 };
484 
485 // FeedbackMetadata is an array-like object with a slot count (indicating how
486 // many slots are stored). We save space by packing several slots into an array
487 // of int32 data. The length is never stored - it is always calculated from
488 // slot_count. All instances are created through the static New function, and
489 // the number of slots is static once an instance is created.
490 class FeedbackMetadata : public HeapObject {
491  public:
492   DECL_CAST(FeedbackMetadata)
493 
494   // The number of slots that this metadata contains. Stored as an int32.
495   DECL_INT32_ACCESSORS(slot_count)
496 
497   // The number of feedback cells required for create closures. Stored as an
498   // int32.
499   // TODO(mythria): Consider using 16 bits for this and slot_count so that we
500   // can save 4 bytes.
501   DECL_INT32_ACCESSORS(create_closure_slot_count)
502 
503   // Get slot_count using an acquire load.
504   inline int32_t synchronized_slot_count() const;
505 
506   // Returns number of feedback vector elements used by given slot kind.
507   static inline int GetSlotSize(FeedbackSlotKind kind);
508 
509   bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
510 
511   inline bool is_empty() const;
512 
513   // Returns slot kind for given slot.
514   V8_EXPORT_PRIVATE FeedbackSlotKind GetKind(FeedbackSlot slot) const;
515 
516   // If {spec} is null, then it is considered empty.
517   template <typename LocalIsolate>
518   V8_EXPORT_PRIVATE static Handle<FeedbackMetadata> New(
519       LocalIsolate* isolate, const FeedbackVectorSpec* spec = nullptr);
520 
521   DECL_PRINTER(FeedbackMetadata)
522   DECL_VERIFIER(FeedbackMetadata)
523 
524   static const char* Kind2String(FeedbackSlotKind kind);
525   bool HasTypeProfileSlot() const;
526 
527   // Garbage collection support.
528   // This includes any necessary padding at the end of the object for pointer
529   // size alignment.
SizeFor(int slot_count)530   static int SizeFor(int slot_count) {
531     return OBJECT_POINTER_ALIGN(kHeaderSize + length(slot_count) * kInt32Size);
532   }
533 
534 #define FIELDS(V)                              \
535   V(kSlotCountOffset, kInt32Size)              \
536   V(kCreateClosureSlotCountOffset, kInt32Size) \
537   V(kHeaderSize, 0)
538 
539   DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FIELDS)
540 #undef FIELDS
541 
542   class BodyDescriptor;
543 
544  private:
545   friend class AccessorAssembler;
546 
547   // Raw accessors to the encoded slot data.
548   inline int32_t get(int index) const;
549   inline void set(int index, int32_t value);
550 
551   // The number of int32 data fields needed to store {slot_count} slots.
552   // Does not include any extra padding for pointer size alignment.
length(int slot_count)553   static int length(int slot_count) {
554     return VectorICComputer::word_count(slot_count);
555   }
556   inline int length() const;
557 
558   static const int kFeedbackSlotKindBits = 5;
559   STATIC_ASSERT(static_cast<int>(FeedbackSlotKind::kKindsNumber) <
560                 (1 << kFeedbackSlotKindBits));
561 
562   void SetKind(FeedbackSlot slot, FeedbackSlotKind kind);
563 
564   using VectorICComputer =
565       base::BitSetComputer<FeedbackSlotKind, kFeedbackSlotKindBits,
566                            kInt32Size * kBitsPerByte, uint32_t>;
567 
568   OBJECT_CONSTRUCTORS(FeedbackMetadata, HeapObject);
569 };
570 
571 // Verify that an empty hash field looks like a tagged object, but can't
572 // possibly be confused with a pointer.
573 // NOLINTNEXTLINE(runtime/references) (false positive)
574 STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag);
575 STATIC_ASSERT(Name::kEmptyHashField == 0x3);
576 // Verify that a set hash field will not look like a tagged object.
577 STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag);
578 
579 class FeedbackMetadataIterator {
580  public:
FeedbackMetadataIterator(Handle<FeedbackMetadata> metadata)581   explicit FeedbackMetadataIterator(Handle<FeedbackMetadata> metadata)
582       : metadata_handle_(metadata),
583         next_slot_(FeedbackSlot(0)),
584         slot_kind_(FeedbackSlotKind::kInvalid) {}
585 
FeedbackMetadataIterator(FeedbackMetadata metadata)586   explicit FeedbackMetadataIterator(FeedbackMetadata metadata)
587       : metadata_(metadata),
588         next_slot_(FeedbackSlot(0)),
589         slot_kind_(FeedbackSlotKind::kInvalid) {}
590 
591   inline bool HasNext() const;
592 
593   inline FeedbackSlot Next();
594 
595   // Returns slot kind of the last slot returned by Next().
kind()596   FeedbackSlotKind kind() const {
597     DCHECK_NE(FeedbackSlotKind::kInvalid, slot_kind_);
598     DCHECK_NE(FeedbackSlotKind::kKindsNumber, slot_kind_);
599     return slot_kind_;
600   }
601 
602   // Returns entry size of the last slot returned by Next().
603   inline int entry_size() const;
604 
605  private:
metadata()606   FeedbackMetadata metadata() const {
607     return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_;
608   }
609 
610   // The reason for having a handle and a raw pointer to the meta data is
611   // to have a single iterator implementation for both "handlified" and raw
612   // pointer use cases.
613   Handle<FeedbackMetadata> metadata_handle_;
614   FeedbackMetadata metadata_;
615   FeedbackSlot cur_slot_;
616   FeedbackSlot next_slot_;
617   FeedbackSlotKind slot_kind_;
618 };
619 
620 // NexusConfig adapts the FeedbackNexus to be used on the main thread
621 // or a background thread. It controls the actual read and writes of
622 // the underlying feedback vector, manages the creation of handles, and
623 // expresses capabilities available in the very different contexts of
624 // main and background thread. Here are the differences:
625 //
626 // Capability:      MainThread           BackgroundThread
627 // Write to vector  Allowed              Not allowed
628 // Handle creation  Via Isolate          Via LocalHeap
629 // Reads of vector  "Live"               Cached after initial read
630 // Thread safety    Exclusive write,     Shared read only
631 //                  shared read
632 class V8_EXPORT_PRIVATE NexusConfig {
633  public:
FromMainThread(Isolate * isolate)634   static NexusConfig FromMainThread(Isolate* isolate) {
635     return NexusConfig(isolate);
636   }
637 
FromBackgroundThread(Isolate * isolate,LocalHeap * local_heap)638   static NexusConfig FromBackgroundThread(Isolate* isolate,
639                                           LocalHeap* local_heap) {
640     return NexusConfig(isolate, local_heap);
641   }
642 
643   enum Mode { MainThread, BackgroundThread };
644 
mode()645   Mode mode() const {
646     return local_heap_ == nullptr ? MainThread : BackgroundThread;
647   }
648 
isolate()649   Isolate* isolate() const { return isolate_; }
650 
651   MaybeObjectHandle NewHandle(MaybeObject object) const;
652   template <typename T>
653   Handle<T> NewHandle(T object) const;
654 
can_write()655   bool can_write() const { return mode() == MainThread; }
656 
657   inline MaybeObject GetFeedback(FeedbackVector vector,
658                                  FeedbackSlot slot) const;
659   inline void SetFeedback(FeedbackVector vector, FeedbackSlot slot,
660                           MaybeObject object,
661                           WriteBarrierMode mode = UPDATE_WRITE_BARRIER) const;
662 
663   std::pair<MaybeObject, MaybeObject> GetFeedbackPair(FeedbackVector vector,
664                                                       FeedbackSlot slot) const;
665   void SetFeedbackPair(FeedbackVector vector, FeedbackSlot start_slot,
666                        MaybeObject feedback, WriteBarrierMode mode,
667                        MaybeObject feedback_extra,
668                        WriteBarrierMode mode_extra) const;
669 
670  private:
NexusConfig(Isolate * isolate)671   explicit NexusConfig(Isolate* isolate)
672       : isolate_(isolate), local_heap_(nullptr) {}
NexusConfig(Isolate * isolate,LocalHeap * local_heap)673   NexusConfig(Isolate* isolate, LocalHeap* local_heap)
674       : isolate_(isolate), local_heap_(local_heap) {}
675 
676   Isolate* const isolate_;
677   LocalHeap* const local_heap_;
678 };
679 
680 // A FeedbackNexus is the combination of a FeedbackVector and a slot.
681 class V8_EXPORT_PRIVATE FeedbackNexus final {
682  public:
683   // For use on the main thread. A null {vector} is accepted as well.
684   FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot);
685   FeedbackNexus(FeedbackVector vector, FeedbackSlot slot);
686 
687   // For use on the main or background thread as configured by {config}.
688   // {vector} must be valid.
689   FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot,
690                 const NexusConfig& config);
691 
config()692   const NexusConfig* config() const { return &config_; }
vector_handle()693   Handle<FeedbackVector> vector_handle() const {
694     DCHECK(vector_.is_null());
695     return vector_handle_;
696   }
vector()697   FeedbackVector vector() const {
698     return vector_handle_.is_null() ? vector_ : *vector_handle_;
699   }
700 
slot()701   FeedbackSlot slot() const { return slot_; }
kind()702   FeedbackSlotKind kind() const { return kind_; }
703 
GetLanguageMode()704   inline LanguageMode GetLanguageMode() const {
705     return vector().GetLanguageMode(slot());
706   }
707 
708   InlineCacheState ic_state() const;
IsUninitialized()709   bool IsUninitialized() const { return ic_state() == UNINITIALIZED; }
IsMegamorphic()710   bool IsMegamorphic() const { return ic_state() == MEGAMORPHIC; }
IsGeneric()711   bool IsGeneric() const { return ic_state() == GENERIC; }
712 
713   void Print(std::ostream& os);  // NOLINT
714 
715   // For map-based ICs (load, keyed-load, store, keyed-store).
716   Map GetFirstMap() const;
717   int ExtractMaps(MapHandles* maps) const;
718   // Used to obtain maps and the associated handlers stored in the feedback
719   // vector. This should be called when we expect only a handler to be stored in
720   // the extra feedback. This is used by ICs when updating the handlers.
721   using TryUpdateHandler = std::function<MaybeHandle<Map>(Handle<Map>)>;
722   int ExtractMapsAndHandlers(
723       std::vector<MapAndHandler>* maps_and_handlers,
724       TryUpdateHandler map_handler = TryUpdateHandler()) const;
725   MaybeObjectHandle FindHandlerForMap(Handle<Map> map) const;
726   // Used to obtain maps and the associated feedback stored in the feedback
727   // vector. The returned feedback need not be always a handler. It could be a
728   // name in the case of StoreDataInPropertyLiteral. This is used by TurboFan to
729   // get all the feedback stored in the vector.
730   int ExtractMapsAndFeedback(
731       std::vector<MapAndFeedback>* maps_and_feedback) const;
732 
IsCleared()733   bool IsCleared() const {
734     InlineCacheState state = ic_state();
735     return !FLAG_use_ic || state == UNINITIALIZED;
736   }
737 
738   // Clear() returns true if the state of the underlying vector was changed.
739   bool Clear();
740   void ConfigureUninitialized();
741   // ConfigureMegamorphic() returns true if the state of the underlying vector
742   // was changed. Extra feedback is cleared if the 0 parameter version is used.
743   bool ConfigureMegamorphic();
744   bool ConfigureMegamorphic(IcCheckType property_type);
745 
746   inline MaybeObject GetFeedback() const;
747   inline MaybeObject GetFeedbackExtra() const;
748   inline std::pair<MaybeObject, MaybeObject> GetFeedbackPair() const;
749 
750   inline Isolate* GetIsolate() const;
751 
752   void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
753                             const MaybeObjectHandle& handler);
754 
755   void ConfigurePolymorphic(
756       Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
757 
758   BinaryOperationHint GetBinaryOperationFeedback() const;
759   CompareOperationHint GetCompareOperationFeedback() const;
760   ForInHint GetForInFeedback() const;
761 
762   // For KeyedLoad ICs.
763   KeyedAccessLoadMode GetKeyedAccessLoadMode() const;
764 
765   // For KeyedStore ICs.
766   KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
767 
768   // For KeyedLoad and KeyedStore ICs.
769   IcCheckType GetKeyType() const;
770   Name GetName() const;
771 
772   // For Call ICs.
773   int GetCallCount();
774   void SetSpeculationMode(SpeculationMode mode);
775   SpeculationMode GetSpeculationMode();
776 
777   // Compute the call frequency based on the call count and the invocation
778   // count (taken from the type feedback vector).
779   float ComputeCallFrequency();
780 
781   using SpeculationModeField = base::BitField<SpeculationMode, 0, 1>;
782   using CallCountField = base::BitField<uint32_t, 1, 31>;
783 
784   // For InstanceOf ICs.
785   MaybeHandle<JSObject> GetConstructorFeedback() const;
786 
787   // For Global Load and Store ICs.
788   void ConfigurePropertyCellMode(Handle<PropertyCell> cell);
789   // Returns false if given combination of indices is not allowed.
790   bool ConfigureLexicalVarMode(int script_context_index, int context_slot_index,
791                                bool immutable);
792   void ConfigureHandlerMode(const MaybeObjectHandle& handler);
793 
794   // For CloneObject ICs
795   static constexpr int kCloneObjectPolymorphicEntrySize = 2;
796   void ConfigureCloneObject(Handle<Map> source_map, Handle<Map> result_map);
797 
798 // Bit positions in a smi that encodes lexical environment variable access.
799 #define LEXICAL_MODE_BIT_FIELDS(V, _)  \
800   V(ContextIndexBits, unsigned, 12, _) \
801   V(SlotIndexBits, unsigned, 18, _)    \
802   V(ImmutabilityBit, bool, 1, _)
803 
804   DEFINE_BIT_FIELDS(LEXICAL_MODE_BIT_FIELDS)
805 #undef LEXICAL_MODE_BIT_FIELDS
806 
807   // Make sure we don't overflow the smi.
808   STATIC_ASSERT(LEXICAL_MODE_BIT_FIELDS_Ranges::kBitsCount <= kSmiValueSize);
809 
810   // For TypeProfile feedback vector slots.
811   // ResetTypeProfile will always reset type profile information.
812   void ResetTypeProfile();
813 
814   // Add a type to the list of types for source position <position>.
815   void Collect(Handle<String> type, int position);
816   JSObject GetTypeProfile() const;
817 
818   std::vector<int> GetSourcePositions() const;
819   std::vector<Handle<String>> GetTypesForSourcePositions(uint32_t pos) const;
820 
821  private:
822   template <typename FeedbackType>
823   inline void SetFeedback(FeedbackType feedback,
824                           WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
825   template <typename FeedbackType, typename FeedbackExtraType>
826   inline void SetFeedback(FeedbackType feedback, WriteBarrierMode mode,
827                           FeedbackExtraType feedback_extra,
828                           WriteBarrierMode mode_extra = UPDATE_WRITE_BARRIER);
829 
830   inline MaybeObject UninitializedSentinel() const;
831   inline MaybeObject MegamorphicSentinel() const;
832 
833   // Create an array. The caller must install it in a feedback vector slot.
834   Handle<WeakFixedArray> CreateArrayOfSize(int length);
835 
836   // Helpers to maintain feedback_cache_.
837   inline MaybeObject FromHandle(MaybeObjectHandle slot) const;
838   inline MaybeObjectHandle ToHandle(MaybeObject value) const;
839 
840   // The reason for having a vector handle and a raw pointer is that we can and
841   // should use handles during IC miss, but not during GC when we clear ICs. If
842   // you have a handle to the vector that is better because more operations can
843   // be done, like allocation.
844   Handle<FeedbackVector> vector_handle_;
845   FeedbackVector vector_;
846   FeedbackSlot slot_;
847   FeedbackSlotKind kind_;
848   // When using the background-thread configuration, a cache is used to
849   // guarantee a consistent view of the feedback to FeedbackNexus methods.
850   mutable base::Optional<std::pair<MaybeObjectHandle, MaybeObjectHandle>>
851       feedback_cache_;
852   NexusConfig config_;
853 };
854 
855 class V8_EXPORT_PRIVATE FeedbackIterator final {
856  public:
857   explicit FeedbackIterator(const FeedbackNexus* nexus);
858   void Advance();
done()859   bool done() { return done_; }
map()860   Map map() { return map_; }
handler()861   MaybeObject handler() { return handler_; }
862 
SizeFor(int number_of_entries)863   static int SizeFor(int number_of_entries) {
864     CHECK_GT(number_of_entries, 0);
865     return number_of_entries * kEntrySize;
866   }
867 
MapIndexForEntry(int entry)868   static int MapIndexForEntry(int entry) {
869     CHECK_GE(entry, 0);
870     return entry * kEntrySize;
871   }
872 
HandlerIndexForEntry(int entry)873   static int HandlerIndexForEntry(int entry) {
874     CHECK_GE(entry, 0);
875     return (entry * kEntrySize) + kHandlerOffset;
876   }
877 
878  private:
879   void AdvancePolymorphic();
880   enum State { kMonomorphic, kPolymorphic, kOther };
881 
882   static constexpr int kEntrySize = 2;
883   static constexpr int kHandlerOffset = 1;
884   Handle<WeakFixedArray> polymorphic_feedback_;
885   Map map_;
886   MaybeObject handler_;
887   bool done_;
888   int index_;
889   State state_;
890 };
891 
892 inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback);
893 inline CompareOperationHint CompareOperationHintFromFeedback(int type_feedback);
894 inline ForInHint ForInHintFromFeedback(ForInFeedback type_feedback);
895 
896 }  // namespace internal
897 }  // namespace v8
898 
899 #include "src/objects/object-macros-undef.h"
900 
901 #endif  // V8_OBJECTS_FEEDBACK_VECTOR_H_
902