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