1 // Copyright 2012 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_INL_H_
6 #define V8_OBJECTS_FEEDBACK_VECTOR_INL_H_
7
8 #include "src/common/globals.h"
9 #include "src/heap/heap-write-barrier-inl.h"
10 #include "src/objects/code-inl.h"
11 #include "src/objects/feedback-cell-inl.h"
12 #include "src/objects/feedback-vector.h"
13 #include "src/objects/maybe-object-inl.h"
14 #include "src/objects/shared-function-info.h"
15 #include "src/objects/smi.h"
16 #include "src/roots/roots-inl.h"
17
18 // Has to be the last include (doesn't have include guards):
19 #include "src/objects/object-macros.h"
20
21 namespace v8 {
22 namespace internal {
23
24 #include "torque-generated/src/objects/feedback-vector-tq-inl.inc"
25
26 TQ_OBJECT_CONSTRUCTORS_IMPL(FeedbackVector)
OBJECT_CONSTRUCTORS_IMPL(FeedbackMetadata,HeapObject)27 OBJECT_CONSTRUCTORS_IMPL(FeedbackMetadata, HeapObject)
28 OBJECT_CONSTRUCTORS_IMPL(ClosureFeedbackCellArray, FixedArray)
29
30 NEVER_READ_ONLY_SPACE_IMPL(FeedbackVector)
31 NEVER_READ_ONLY_SPACE_IMPL(ClosureFeedbackCellArray)
32
33 CAST_ACCESSOR(FeedbackMetadata)
34 CAST_ACCESSOR(ClosureFeedbackCellArray)
35
36 INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset)
37
38 INT32_ACCESSORS(FeedbackMetadata, create_closure_slot_count,
39 kCreateClosureSlotCountOffset)
40
41 RELEASE_ACQUIRE_WEAK_ACCESSORS(FeedbackVector, maybe_optimized_code,
42 kMaybeOptimizedCodeOffset)
43
44 int32_t FeedbackMetadata::slot_count(AcquireLoadTag) const {
45 return ACQUIRE_READ_INT32_FIELD(*this, kSlotCountOffset);
46 }
47
get(int index)48 int32_t FeedbackMetadata::get(int index) const {
49 DCHECK(index >= 0 && index < length());
50 int offset = kHeaderSize + index * kInt32Size;
51 return ReadField<int32_t>(offset);
52 }
53
set(int index,int32_t value)54 void FeedbackMetadata::set(int index, int32_t value) {
55 DCHECK(index >= 0 && index < length());
56 int offset = kHeaderSize + index * kInt32Size;
57 WriteField<int32_t>(offset, value);
58 }
59
is_empty()60 bool FeedbackMetadata::is_empty() const { return slot_count() == 0; }
61
length()62 int FeedbackMetadata::length() const {
63 return FeedbackMetadata::length(slot_count());
64 }
65
GetSlotSize(FeedbackSlotKind kind)66 int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
67 switch (kind) {
68 case FeedbackSlotKind::kForIn:
69 case FeedbackSlotKind::kInstanceOf:
70 case FeedbackSlotKind::kCompareOp:
71 case FeedbackSlotKind::kBinaryOp:
72 case FeedbackSlotKind::kLiteral:
73 case FeedbackSlotKind::kTypeProfile:
74 return 1;
75
76 case FeedbackSlotKind::kCall:
77 case FeedbackSlotKind::kCloneObject:
78 case FeedbackSlotKind::kLoadProperty:
79 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
80 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
81 case FeedbackSlotKind::kLoadKeyed:
82 case FeedbackSlotKind::kHasKeyed:
83 case FeedbackSlotKind::kStoreNamedSloppy:
84 case FeedbackSlotKind::kStoreNamedStrict:
85 case FeedbackSlotKind::kStoreOwnNamed:
86 case FeedbackSlotKind::kStoreGlobalSloppy:
87 case FeedbackSlotKind::kStoreGlobalStrict:
88 case FeedbackSlotKind::kStoreKeyedSloppy:
89 case FeedbackSlotKind::kStoreKeyedStrict:
90 case FeedbackSlotKind::kStoreInArrayLiteral:
91 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
92 return 2;
93
94 case FeedbackSlotKind::kInvalid:
95 case FeedbackSlotKind::kKindsNumber:
96 UNREACHABLE();
97 }
98 return 1;
99 }
100
GetFeedbackCell(int index)101 Handle<FeedbackCell> ClosureFeedbackCellArray::GetFeedbackCell(int index) {
102 return handle(FeedbackCell::cast(get(index)), GetIsolate());
103 }
104
cell(int index)105 FeedbackCell ClosureFeedbackCellArray::cell(int index) {
106 return FeedbackCell::cast(get(index));
107 }
108
is_empty()109 bool FeedbackVector::is_empty() const { return length() == 0; }
110
metadata()111 FeedbackMetadata FeedbackVector::metadata() const {
112 return shared_function_info().feedback_metadata();
113 }
114
metadata(AcquireLoadTag tag)115 FeedbackMetadata FeedbackVector::metadata(AcquireLoadTag tag) const {
116 return shared_function_info().feedback_metadata(tag);
117 }
118
RELAXED_INT32_ACCESSORS(FeedbackVector,invocation_count,kInvocationCountOffset)119 RELAXED_INT32_ACCESSORS(FeedbackVector, invocation_count,
120 kInvocationCountOffset)
121
122 void FeedbackVector::clear_invocation_count(RelaxedStoreTag tag) {
123 set_invocation_count(0, tag);
124 }
125
optimized_code()126 Code FeedbackVector::optimized_code() const {
127 MaybeObject slot = maybe_optimized_code(kAcquireLoad);
128 DCHECK(slot->IsWeakOrCleared());
129 HeapObject heap_object;
130 Code code;
131 if (slot->GetHeapObject(&heap_object)) {
132 code = FromCodeT(CodeT::cast(heap_object));
133 }
134 // It is possible that the maybe_optimized_code slot is cleared but the
135 // optimization tier hasn't been updated yet. We update the tier when we
136 // execute the function next time / when we create new closure.
137 DCHECK_IMPLIES(!code.is_null(), OptimizationTierBits::decode(flags()) ==
138 GetTierForCodeKind(code.kind()));
139 return code;
140 }
141
optimization_marker()142 OptimizationMarker FeedbackVector::optimization_marker() const {
143 return OptimizationMarkerBits::decode(flags());
144 }
145
optimization_tier()146 OptimizationTier FeedbackVector::optimization_tier() const {
147 OptimizationTier tier = OptimizationTierBits::decode(flags());
148 // It is possible that the optimization tier bits aren't updated when the code
149 // was cleared due to a GC.
150 DCHECK_IMPLIES(tier == OptimizationTier::kNone,
151 maybe_optimized_code(kAcquireLoad)->IsCleared());
152 return tier;
153 }
154
has_optimized_code()155 bool FeedbackVector::has_optimized_code() const {
156 return !optimized_code().is_null();
157 }
158
has_optimization_marker()159 bool FeedbackVector::has_optimization_marker() const {
160 return optimization_marker() != OptimizationMarker::kLogFirstExecution &&
161 optimization_marker() != OptimizationMarker::kNone;
162 }
163
164 // Conversion from an integer index to either a slot or an ic slot.
165 // static
ToSlot(intptr_t index)166 FeedbackSlot FeedbackVector::ToSlot(intptr_t index) {
167 DCHECK_LE(static_cast<uintptr_t>(index),
168 static_cast<uintptr_t>(std::numeric_limits<int>::max()));
169 return FeedbackSlot(static_cast<int>(index));
170 }
171
172 #ifdef DEBUG
173 // Instead of FixedArray, the Feedback and the Extra should contain
174 // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
IsOfLegacyType(MaybeObject value)175 bool FeedbackVector::IsOfLegacyType(MaybeObject value) {
176 HeapObject heap_object;
177 if (value->GetHeapObject(&heap_object)) {
178 return heap_object.IsFixedArray() && !heap_object.IsHashTable();
179 }
180 return false;
181 }
182 #endif // DEBUG
183
Get(FeedbackSlot slot)184 MaybeObject FeedbackVector::Get(FeedbackSlot slot) const {
185 MaybeObject value = raw_feedback_slots(GetIndex(slot), kRelaxedLoad);
186 DCHECK(!IsOfLegacyType(value));
187 return value;
188 }
189
Get(PtrComprCageBase cage_base,FeedbackSlot slot)190 MaybeObject FeedbackVector::Get(PtrComprCageBase cage_base,
191 FeedbackSlot slot) const {
192 MaybeObject value =
193 raw_feedback_slots(cage_base, GetIndex(slot), kRelaxedLoad);
194 DCHECK(!IsOfLegacyType(value));
195 return value;
196 }
197
GetClosureFeedbackCell(int index)198 Handle<FeedbackCell> FeedbackVector::GetClosureFeedbackCell(int index) const {
199 DCHECK_GE(index, 0);
200 return closure_feedback_cell_array().GetFeedbackCell(index);
201 }
202
closure_feedback_cell(int index)203 FeedbackCell FeedbackVector::closure_feedback_cell(int index) const {
204 DCHECK_GE(index, 0);
205 return closure_feedback_cell_array().cell(index);
206 }
207
SynchronizedGet(FeedbackSlot slot)208 MaybeObject FeedbackVector::SynchronizedGet(FeedbackSlot slot) const {
209 const int i = slot.ToInt();
210 DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length()));
211 const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize;
212 MaybeObject value = TaggedField<MaybeObject>::Acquire_Load(*this, offset);
213 DCHECK(!IsOfLegacyType(value));
214 return value;
215 }
216
SynchronizedSet(FeedbackSlot slot,MaybeObject value,WriteBarrierMode mode)217 void FeedbackVector::SynchronizedSet(FeedbackSlot slot, MaybeObject value,
218 WriteBarrierMode mode) {
219 DCHECK(!IsOfLegacyType(value));
220 const int i = slot.ToInt();
221 DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length()));
222 const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize;
223 TaggedField<MaybeObject>::Release_Store(*this, offset, value);
224 CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode);
225 }
226
SynchronizedSet(FeedbackSlot slot,Object value,WriteBarrierMode mode)227 void FeedbackVector::SynchronizedSet(FeedbackSlot slot, Object value,
228 WriteBarrierMode mode) {
229 SynchronizedSet(slot, MaybeObject::FromObject(value), mode);
230 }
231
Set(FeedbackSlot slot,MaybeObject value,WriteBarrierMode mode)232 void FeedbackVector::Set(FeedbackSlot slot, MaybeObject value,
233 WriteBarrierMode mode) {
234 DCHECK(!IsOfLegacyType(value));
235 set_raw_feedback_slots(GetIndex(slot), value, mode);
236 }
237
Set(FeedbackSlot slot,Object value,WriteBarrierMode mode)238 void FeedbackVector::Set(FeedbackSlot slot, Object value,
239 WriteBarrierMode mode) {
240 MaybeObject maybe_value = MaybeObject::FromObject(value);
241 DCHECK(!IsOfLegacyType(maybe_value));
242 set_raw_feedback_slots(GetIndex(slot), maybe_value, mode);
243 }
244
slots_start()245 inline MaybeObjectSlot FeedbackVector::slots_start() {
246 return RawMaybeWeakField(OffsetOfElementAt(0));
247 }
248
249 // Helper function to transform the feedback to BinaryOperationHint.
BinaryOperationHintFromFeedback(int type_feedback)250 BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
251 switch (type_feedback) {
252 case BinaryOperationFeedback::kNone:
253 return BinaryOperationHint::kNone;
254 case BinaryOperationFeedback::kSignedSmall:
255 return BinaryOperationHint::kSignedSmall;
256 case BinaryOperationFeedback::kSignedSmallInputs:
257 return BinaryOperationHint::kSignedSmallInputs;
258 case BinaryOperationFeedback::kNumber:
259 return BinaryOperationHint::kNumber;
260 case BinaryOperationFeedback::kNumberOrOddball:
261 return BinaryOperationHint::kNumberOrOddball;
262 case BinaryOperationFeedback::kString:
263 return BinaryOperationHint::kString;
264 case BinaryOperationFeedback::kBigInt:
265 return BinaryOperationHint::kBigInt;
266 default:
267 return BinaryOperationHint::kAny;
268 }
269 UNREACHABLE();
270 }
271
272 // Helper function to transform the feedback to CompareOperationHint.
273 template <CompareOperationFeedback::Type Feedback>
Is(int type_feedback)274 bool Is(int type_feedback) {
275 return !(type_feedback & ~Feedback);
276 }
277
CompareOperationHintFromFeedback(int type_feedback)278 CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) {
279 if (Is<CompareOperationFeedback::kNone>(type_feedback)) {
280 return CompareOperationHint::kNone;
281 }
282
283 if (Is<CompareOperationFeedback::kSignedSmall>(type_feedback)) {
284 return CompareOperationHint::kSignedSmall;
285 } else if (Is<CompareOperationFeedback::kNumber>(type_feedback)) {
286 return CompareOperationHint::kNumber;
287 } else if (Is<CompareOperationFeedback::kNumberOrBoolean>(type_feedback)) {
288 return CompareOperationHint::kNumberOrBoolean;
289 }
290
291 if (Is<CompareOperationFeedback::kInternalizedString>(type_feedback)) {
292 return CompareOperationHint::kInternalizedString;
293 } else if (Is<CompareOperationFeedback::kString>(type_feedback)) {
294 return CompareOperationHint::kString;
295 }
296
297 if (Is<CompareOperationFeedback::kReceiver>(type_feedback)) {
298 return CompareOperationHint::kReceiver;
299 } else if (Is<CompareOperationFeedback::kReceiverOrNullOrUndefined>(
300 type_feedback)) {
301 return CompareOperationHint::kReceiverOrNullOrUndefined;
302 }
303
304 if (Is<CompareOperationFeedback::kBigInt>(type_feedback)) {
305 return CompareOperationHint::kBigInt;
306 }
307
308 if (Is<CompareOperationFeedback::kSymbol>(type_feedback)) {
309 return CompareOperationHint::kSymbol;
310 }
311
312 DCHECK(Is<CompareOperationFeedback::kAny>(type_feedback));
313 return CompareOperationHint::kAny;
314 }
315
316 // Helper function to transform the feedback to ForInHint.
ForInHintFromFeedback(ForInFeedback type_feedback)317 ForInHint ForInHintFromFeedback(ForInFeedback type_feedback) {
318 switch (type_feedback) {
319 case ForInFeedback::kNone:
320 return ForInHint::kNone;
321 case ForInFeedback::kEnumCacheKeys:
322 return ForInHint::kEnumCacheKeys;
323 case ForInFeedback::kEnumCacheKeysAndIndices:
324 return ForInHint::kEnumCacheKeysAndIndices;
325 default:
326 return ForInHint::kAny;
327 }
328 UNREACHABLE();
329 }
330
UninitializedSentinel(Isolate * isolate)331 Handle<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) {
332 return ReadOnlyRoots(isolate).uninitialized_symbol_handle();
333 }
334
MegamorphicSentinel(Isolate * isolate)335 Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
336 return ReadOnlyRoots(isolate).megamorphic_symbol_handle();
337 }
338
MegaDOMSentinel(Isolate * isolate)339 Handle<Symbol> FeedbackVector::MegaDOMSentinel(Isolate* isolate) {
340 return ReadOnlyRoots(isolate).mega_dom_symbol_handle();
341 }
342
RawUninitializedSentinel(Isolate * isolate)343 Symbol FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
344 return ReadOnlyRoots(isolate).uninitialized_symbol();
345 }
346
HasNext()347 bool FeedbackMetadataIterator::HasNext() const {
348 return next_slot_.ToInt() < metadata().slot_count();
349 }
350
Next()351 FeedbackSlot FeedbackMetadataIterator::Next() {
352 DCHECK(HasNext());
353 cur_slot_ = next_slot_;
354 slot_kind_ = metadata().GetKind(cur_slot_);
355 next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size());
356 return cur_slot_;
357 }
358
entry_size()359 int FeedbackMetadataIterator::entry_size() const {
360 return FeedbackMetadata::GetSlotSize(kind());
361 }
362
GetFeedback(FeedbackVector vector,FeedbackSlot slot)363 MaybeObject NexusConfig::GetFeedback(FeedbackVector vector,
364 FeedbackSlot slot) const {
365 return vector.SynchronizedGet(slot);
366 }
367
SetFeedback(FeedbackVector vector,FeedbackSlot slot,MaybeObject feedback,WriteBarrierMode mode)368 void NexusConfig::SetFeedback(FeedbackVector vector, FeedbackSlot slot,
369 MaybeObject feedback,
370 WriteBarrierMode mode) const {
371 DCHECK(can_write());
372 vector.SynchronizedSet(slot, feedback, mode);
373 }
374
UninitializedSentinel()375 MaybeObject FeedbackNexus::UninitializedSentinel() const {
376 return MaybeObject::FromObject(
377 *FeedbackVector::UninitializedSentinel(GetIsolate()));
378 }
379
MegamorphicSentinel()380 MaybeObject FeedbackNexus::MegamorphicSentinel() const {
381 return MaybeObject::FromObject(
382 *FeedbackVector::MegamorphicSentinel(GetIsolate()));
383 }
384
MegaDOMSentinel()385 MaybeObject FeedbackNexus::MegaDOMSentinel() const {
386 return MaybeObject::FromObject(
387 *FeedbackVector::MegaDOMSentinel(GetIsolate()));
388 }
389
FromHandle(MaybeObjectHandle slot)390 MaybeObject FeedbackNexus::FromHandle(MaybeObjectHandle slot) const {
391 return slot.is_null() ? HeapObjectReference::ClearedValue(config()->isolate())
392 : *slot;
393 }
394
ToHandle(MaybeObject value)395 MaybeObjectHandle FeedbackNexus::ToHandle(MaybeObject value) const {
396 return value.IsCleared() ? MaybeObjectHandle()
397 : MaybeObjectHandle(config()->NewHandle(value));
398 }
399
GetFeedback()400 MaybeObject FeedbackNexus::GetFeedback() const {
401 auto pair = GetFeedbackPair();
402 return pair.first;
403 }
404
GetFeedbackExtra()405 MaybeObject FeedbackNexus::GetFeedbackExtra() const {
406 auto pair = GetFeedbackPair();
407 return pair.second;
408 }
409
GetFeedbackPair()410 std::pair<MaybeObject, MaybeObject> FeedbackNexus::GetFeedbackPair() const {
411 if (config()->mode() == NexusConfig::BackgroundThread &&
412 feedback_cache_.has_value()) {
413 return std::make_pair(FromHandle(feedback_cache_->first),
414 FromHandle(feedback_cache_->second));
415 }
416 auto pair = FeedbackMetadata::GetSlotSize(kind()) == 2
417 ? config()->GetFeedbackPair(vector(), slot())
418 : std::make_pair(config()->GetFeedback(vector(), slot()),
419 MaybeObject());
420 if (config()->mode() == NexusConfig::BackgroundThread &&
421 !feedback_cache_.has_value()) {
422 feedback_cache_ =
423 std::make_pair(ToHandle(pair.first), ToHandle(pair.second));
424 }
425 return pair;
426 }
427
428 template <typename T>
429 struct IsValidFeedbackType
430 : public std::integral_constant<bool,
431 std::is_base_of<MaybeObject, T>::value ||
432 std::is_base_of<Object, T>::value> {};
433
434 template <typename FeedbackType>
SetFeedback(FeedbackType feedback,WriteBarrierMode mode)435 void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode) {
436 static_assert(IsValidFeedbackType<FeedbackType>(),
437 "feedbacks need to be Smi, Object or MaybeObject");
438 MaybeObject fmo = MaybeObject::Create(feedback);
439 config()->SetFeedback(vector(), slot(), fmo, mode);
440 }
441
442 template <typename FeedbackType, typename FeedbackExtraType>
SetFeedback(FeedbackType feedback,WriteBarrierMode mode,FeedbackExtraType feedback_extra,WriteBarrierMode mode_extra)443 void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode,
444 FeedbackExtraType feedback_extra,
445 WriteBarrierMode mode_extra) {
446 static_assert(IsValidFeedbackType<FeedbackType>(),
447 "feedbacks need to be Smi, Object or MaybeObject");
448 static_assert(IsValidFeedbackType<FeedbackExtraType>(),
449 "feedbacks need to be Smi, Object or MaybeObject");
450 MaybeObject fmo = MaybeObject::Create(feedback);
451 MaybeObject fmo_extra = MaybeObject::Create(feedback_extra);
452 config()->SetFeedbackPair(vector(), slot(), fmo, mode, fmo_extra, mode_extra);
453 }
454
GetIsolate()455 Isolate* FeedbackNexus::GetIsolate() const { return vector().GetIsolate(); }
456 } // namespace internal
457 } // namespace v8
458
459 #include "src/objects/object-macros-undef.h"
460
461 #endif // V8_OBJECTS_FEEDBACK_VECTOR_INL_H_
462