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