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 | |
22 | namespace v8 { |
23 | namespace internal { |
24 | |
25 | enum 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 | |
61 | inline bool IsCallICKind(FeedbackSlotKind kind) { |
62 | return kind == FeedbackSlotKind::kCall; |
63 | } |
64 | |
65 | inline bool IsLoadICKind(FeedbackSlotKind kind) { |
66 | return kind == FeedbackSlotKind::kLoadProperty; |
67 | } |
68 | |
69 | inline bool IsLoadGlobalICKind(FeedbackSlotKind kind) { |
70 | return kind == FeedbackSlotKind::kLoadGlobalNotInsideTypeof || |
71 | kind == FeedbackSlotKind::kLoadGlobalInsideTypeof; |
72 | } |
73 | |
74 | inline bool IsKeyedLoadICKind(FeedbackSlotKind kind) { |
75 | return kind == FeedbackSlotKind::kLoadKeyed; |
76 | } |
77 | |
78 | inline bool IsKeyedHasICKind(FeedbackSlotKind kind) { |
79 | return kind == FeedbackSlotKind::kHasKeyed; |
80 | } |
81 | |
82 | inline bool IsStoreGlobalICKind(FeedbackSlotKind kind) { |
83 | return kind == FeedbackSlotKind::kStoreGlobalSloppy || |
84 | kind == FeedbackSlotKind::kStoreGlobalStrict; |
85 | } |
86 | |
87 | inline bool IsStoreICKind(FeedbackSlotKind kind) { |
88 | return kind == FeedbackSlotKind::kStoreNamedSloppy || |
89 | kind == FeedbackSlotKind::kStoreNamedStrict; |
90 | } |
91 | |
92 | inline bool IsStoreOwnICKind(FeedbackSlotKind kind) { |
93 | return kind == FeedbackSlotKind::kStoreOwnNamed; |
94 | } |
95 | |
96 | inline bool IsStoreDataPropertyInLiteralKind(FeedbackSlotKind kind) { |
97 | return kind == FeedbackSlotKind::kStoreDataPropertyInLiteral; |
98 | } |
99 | |
100 | inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) { |
101 | return kind == FeedbackSlotKind::kStoreKeyedSloppy || |
102 | kind == FeedbackSlotKind::kStoreKeyedStrict; |
103 | } |
104 | |
105 | inline bool IsStoreInArrayLiteralICKind(FeedbackSlotKind kind) { |
106 | return kind == FeedbackSlotKind::kStoreInArrayLiteral; |
107 | } |
108 | |
109 | inline bool IsGlobalICKind(FeedbackSlotKind kind) { |
110 | return IsLoadGlobalICKind(kind) || IsStoreGlobalICKind(kind); |
111 | } |
112 | |
113 | inline bool IsTypeProfileKind(FeedbackSlotKind kind) { |
114 | return kind == FeedbackSlotKind::kTypeProfile; |
115 | } |
116 | |
117 | inline bool IsCloneObjectKind(FeedbackSlotKind kind) { |
118 | return kind == FeedbackSlotKind::kCloneObject; |
119 | } |
120 | |
121 | inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) { |
122 | DCHECK(IsLoadGlobalICKind(kind)); |
123 | return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof) |
124 | ? INSIDE_TYPEOF |
125 | : NOT_INSIDE_TYPEOF; |
126 | } |
127 | |
128 | inline 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 | |
141 | V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, |
142 | FeedbackSlotKind kind); |
143 | |
144 | typedef std::vector<MaybeObjectHandle> MaybeObjectHandles; |
145 | |
146 | class 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. |
154 | class 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. |
178 | class 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(, 0) |
325 | |
326 | DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, FEEDBACK_VECTOR_FIELDS) |
327 | #undef FEEDBACK_VECTOR_FIELDS |
328 | |
329 | static const int = |
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 | |
347 | class 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. |
474 | class 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. |
496 | class 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 = 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. |
574 | STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag); |
575 | STATIC_ASSERT(Name::kEmptyHashField == 0x3); |
576 | // Verify that a set hash field will not look like a tagged object. |
577 | STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag); |
578 | |
579 | class FeedbackMetadataIterator { |
580 | public: |
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. |
621 | class 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 () 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 (Object , |
755 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
756 | inline void (MaybeObject , |
757 | WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
758 | |
759 | Handle<WeakFixedArray> EnsureArrayOfSize(int length); |
760 | Handle<WeakFixedArray> (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 | |
773 | inline BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback); |
774 | inline CompareOperationHint CompareOperationHintFromFeedback(int type_feedback); |
775 | inline 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 | |