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