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