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