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