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::kSetNamedSloppy:
84 case FeedbackSlotKind::kSetNamedStrict:
85 case FeedbackSlotKind::kDefineNamedOwn:
86 case FeedbackSlotKind::kDefineKeyedOwn:
87 case FeedbackSlotKind::kStoreGlobalSloppy:
88 case FeedbackSlotKind::kStoreGlobalStrict:
89 case FeedbackSlotKind::kSetKeyedSloppy:
90 case FeedbackSlotKind::kSetKeyedStrict:
91 case FeedbackSlotKind::kStoreInArrayLiteral:
92 case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
93 return 2;
94
95 case FeedbackSlotKind::kInvalid:
96 case FeedbackSlotKind::kKindsNumber:
97 UNREACHABLE();
98 }
99 return 1;
100 }
101
GetFeedbackCell(int index)102 Handle<FeedbackCell> ClosureFeedbackCellArray::GetFeedbackCell(int index) {
103 return handle(FeedbackCell::cast(get(index)), GetIsolate());
104 }
105
cell(int index)106 FeedbackCell ClosureFeedbackCellArray::cell(int index) {
107 return FeedbackCell::cast(get(index));
108 }
109
is_empty()110 bool FeedbackVector::is_empty() const { return length() == 0; }
111
metadata()112 FeedbackMetadata FeedbackVector::metadata() const {
113 return shared_function_info().feedback_metadata();
114 }
115
metadata(AcquireLoadTag tag)116 FeedbackMetadata FeedbackVector::metadata(AcquireLoadTag tag) const {
117 return shared_function_info().feedback_metadata(tag);
118 }
119
RELAXED_INT32_ACCESSORS(FeedbackVector,invocation_count,kInvocationCountOffset)120 RELAXED_INT32_ACCESSORS(FeedbackVector, invocation_count,
121 kInvocationCountOffset)
122
123 void FeedbackVector::clear_invocation_count(RelaxedStoreTag tag) {
124 set_invocation_count(0, tag);
125 }
126
optimized_code()127 CodeT FeedbackVector::optimized_code() const {
128 MaybeObject slot = maybe_optimized_code(kAcquireLoad);
129 DCHECK(slot->IsWeakOrCleared());
130 HeapObject heap_object;
131 CodeT code;
132 if (slot->GetHeapObject(&heap_object)) {
133 code = CodeT::cast(heap_object);
134 }
135 // It is possible that the maybe_optimized_code slot is cleared but the flags
136 // haven't been updated yet. We update them when we execute the function next
137 // time / when we create new closure.
138 DCHECK_IMPLIES(!code.is_null(), maybe_has_optimized_code());
139 return code;
140 }
141
tiering_state()142 TieringState FeedbackVector::tiering_state() const {
143 return TieringStateBits::decode(flags());
144 }
145
has_optimized_code()146 bool FeedbackVector::has_optimized_code() const {
147 DCHECK_IMPLIES(!optimized_code().is_null(), maybe_has_optimized_code());
148 return !optimized_code().is_null();
149 }
150
maybe_has_optimized_code()151 bool FeedbackVector::maybe_has_optimized_code() const {
152 return MaybeHasOptimizedCodeBit::decode(flags());
153 }
154
set_maybe_has_optimized_code(bool value)155 void FeedbackVector::set_maybe_has_optimized_code(bool value) {
156 set_flags(MaybeHasOptimizedCodeBit::update(flags(), value));
157 }
158
159 // Conversion from an integer index to either a slot or an ic slot.
160 // static
ToSlot(intptr_t index)161 FeedbackSlot FeedbackVector::ToSlot(intptr_t index) {
162 DCHECK_LE(static_cast<uintptr_t>(index),
163 static_cast<uintptr_t>(std::numeric_limits<int>::max()));
164 return FeedbackSlot(static_cast<int>(index));
165 }
166
167 #ifdef DEBUG
168 // Instead of FixedArray, the Feedback and the Extra should contain
169 // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
IsOfLegacyType(MaybeObject value)170 bool FeedbackVector::IsOfLegacyType(MaybeObject value) {
171 HeapObject heap_object;
172 if (value->GetHeapObject(&heap_object)) {
173 return heap_object.IsFixedArray() && !heap_object.IsHashTable();
174 }
175 return false;
176 }
177 #endif // DEBUG
178
Get(FeedbackSlot slot)179 MaybeObject FeedbackVector::Get(FeedbackSlot slot) const {
180 MaybeObject value = raw_feedback_slots(GetIndex(slot), kRelaxedLoad);
181 DCHECK(!IsOfLegacyType(value));
182 return value;
183 }
184
Get(PtrComprCageBase cage_base,FeedbackSlot slot)185 MaybeObject FeedbackVector::Get(PtrComprCageBase cage_base,
186 FeedbackSlot slot) const {
187 MaybeObject value =
188 raw_feedback_slots(cage_base, GetIndex(slot), kRelaxedLoad);
189 DCHECK(!IsOfLegacyType(value));
190 return value;
191 }
192
GetClosureFeedbackCell(int index)193 Handle<FeedbackCell> FeedbackVector::GetClosureFeedbackCell(int index) const {
194 DCHECK_GE(index, 0);
195 return closure_feedback_cell_array().GetFeedbackCell(index);
196 }
197
closure_feedback_cell(int index)198 FeedbackCell FeedbackVector::closure_feedback_cell(int index) const {
199 DCHECK_GE(index, 0);
200 return closure_feedback_cell_array().cell(index);
201 }
202
SynchronizedGet(FeedbackSlot slot)203 MaybeObject FeedbackVector::SynchronizedGet(FeedbackSlot slot) const {
204 const int i = slot.ToInt();
205 DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length()));
206 const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize;
207 MaybeObject value = TaggedField<MaybeObject>::Acquire_Load(*this, offset);
208 DCHECK(!IsOfLegacyType(value));
209 return value;
210 }
211
SynchronizedSet(FeedbackSlot slot,MaybeObject value,WriteBarrierMode mode)212 void FeedbackVector::SynchronizedSet(FeedbackSlot slot, MaybeObject value,
213 WriteBarrierMode mode) {
214 DCHECK(!IsOfLegacyType(value));
215 const int i = slot.ToInt();
216 DCHECK_LT(static_cast<unsigned>(i), static_cast<unsigned>(this->length()));
217 const int offset = kRawFeedbackSlotsOffset + i * kTaggedSize;
218 TaggedField<MaybeObject>::Release_Store(*this, offset, value);
219 CONDITIONAL_WEAK_WRITE_BARRIER(*this, offset, value, mode);
220 }
221
SynchronizedSet(FeedbackSlot slot,Object value,WriteBarrierMode mode)222 void FeedbackVector::SynchronizedSet(FeedbackSlot slot, Object value,
223 WriteBarrierMode mode) {
224 SynchronizedSet(slot, MaybeObject::FromObject(value), mode);
225 }
226
Set(FeedbackSlot slot,MaybeObject value,WriteBarrierMode mode)227 void FeedbackVector::Set(FeedbackSlot slot, MaybeObject value,
228 WriteBarrierMode mode) {
229 DCHECK(!IsOfLegacyType(value));
230 set_raw_feedback_slots(GetIndex(slot), value, mode);
231 }
232
Set(FeedbackSlot slot,Object value,WriteBarrierMode mode)233 void FeedbackVector::Set(FeedbackSlot slot, Object value,
234 WriteBarrierMode mode) {
235 MaybeObject maybe_value = MaybeObject::FromObject(value);
236 DCHECK(!IsOfLegacyType(maybe_value));
237 set_raw_feedback_slots(GetIndex(slot), maybe_value, mode);
238 }
239
slots_start()240 inline MaybeObjectSlot FeedbackVector::slots_start() {
241 return RawMaybeWeakField(OffsetOfElementAt(0));
242 }
243
244 // Helper function to transform the feedback to BinaryOperationHint.
BinaryOperationHintFromFeedback(int type_feedback)245 BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
246 switch (type_feedback) {
247 case BinaryOperationFeedback::kNone:
248 return BinaryOperationHint::kNone;
249 case BinaryOperationFeedback::kSignedSmall:
250 return BinaryOperationHint::kSignedSmall;
251 case BinaryOperationFeedback::kSignedSmallInputs:
252 return BinaryOperationHint::kSignedSmallInputs;
253 case BinaryOperationFeedback::kNumber:
254 return BinaryOperationHint::kNumber;
255 case BinaryOperationFeedback::kNumberOrOddball:
256 return BinaryOperationHint::kNumberOrOddball;
257 case BinaryOperationFeedback::kString:
258 return BinaryOperationHint::kString;
259 case BinaryOperationFeedback::kBigInt:
260 return BinaryOperationHint::kBigInt;
261 default:
262 return BinaryOperationHint::kAny;
263 }
264 UNREACHABLE();
265 }
266
267 // Helper function to transform the feedback to CompareOperationHint.
268 template <CompareOperationFeedback::Type Feedback>
Is(int type_feedback)269 bool Is(int type_feedback) {
270 return !(type_feedback & ~Feedback);
271 }
272
CompareOperationHintFromFeedback(int type_feedback)273 CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) {
274 if (Is<CompareOperationFeedback::kNone>(type_feedback)) {
275 return CompareOperationHint::kNone;
276 }
277
278 if (Is<CompareOperationFeedback::kSignedSmall>(type_feedback)) {
279 return CompareOperationHint::kSignedSmall;
280 } else if (Is<CompareOperationFeedback::kNumber>(type_feedback)) {
281 return CompareOperationHint::kNumber;
282 } else if (Is<CompareOperationFeedback::kNumberOrBoolean>(type_feedback)) {
283 return CompareOperationHint::kNumberOrBoolean;
284 }
285
286 if (Is<CompareOperationFeedback::kInternalizedString>(type_feedback)) {
287 return CompareOperationHint::kInternalizedString;
288 } else if (Is<CompareOperationFeedback::kString>(type_feedback)) {
289 return CompareOperationHint::kString;
290 }
291
292 if (Is<CompareOperationFeedback::kReceiver>(type_feedback)) {
293 return CompareOperationHint::kReceiver;
294 } else if (Is<CompareOperationFeedback::kReceiverOrNullOrUndefined>(
295 type_feedback)) {
296 return CompareOperationHint::kReceiverOrNullOrUndefined;
297 }
298
299 if (Is<CompareOperationFeedback::kBigInt>(type_feedback)) {
300 return CompareOperationHint::kBigInt;
301 }
302
303 if (Is<CompareOperationFeedback::kSymbol>(type_feedback)) {
304 return CompareOperationHint::kSymbol;
305 }
306
307 DCHECK(Is<CompareOperationFeedback::kAny>(type_feedback));
308 return CompareOperationHint::kAny;
309 }
310
311 // Helper function to transform the feedback to ForInHint.
ForInHintFromFeedback(ForInFeedback type_feedback)312 ForInHint ForInHintFromFeedback(ForInFeedback type_feedback) {
313 switch (type_feedback) {
314 case ForInFeedback::kNone:
315 return ForInHint::kNone;
316 case ForInFeedback::kEnumCacheKeys:
317 return ForInHint::kEnumCacheKeys;
318 case ForInFeedback::kEnumCacheKeysAndIndices:
319 return ForInHint::kEnumCacheKeysAndIndices;
320 default:
321 return ForInHint::kAny;
322 }
323 UNREACHABLE();
324 }
325
UninitializedSentinel(Isolate * isolate)326 Handle<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) {
327 return ReadOnlyRoots(isolate).uninitialized_symbol_handle();
328 }
329
MegamorphicSentinel(Isolate * isolate)330 Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
331 return ReadOnlyRoots(isolate).megamorphic_symbol_handle();
332 }
333
MegaDOMSentinel(Isolate * isolate)334 Handle<Symbol> FeedbackVector::MegaDOMSentinel(Isolate* isolate) {
335 return ReadOnlyRoots(isolate).mega_dom_symbol_handle();
336 }
337
RawUninitializedSentinel(Isolate * isolate)338 Symbol FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
339 return ReadOnlyRoots(isolate).uninitialized_symbol();
340 }
341
HasNext()342 bool FeedbackMetadataIterator::HasNext() const {
343 return next_slot_.ToInt() < metadata().slot_count();
344 }
345
Next()346 FeedbackSlot FeedbackMetadataIterator::Next() {
347 DCHECK(HasNext());
348 cur_slot_ = next_slot_;
349 slot_kind_ = metadata().GetKind(cur_slot_);
350 next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size());
351 return cur_slot_;
352 }
353
entry_size()354 int FeedbackMetadataIterator::entry_size() const {
355 return FeedbackMetadata::GetSlotSize(kind());
356 }
357
GetFeedback(FeedbackVector vector,FeedbackSlot slot)358 MaybeObject NexusConfig::GetFeedback(FeedbackVector vector,
359 FeedbackSlot slot) const {
360 return vector.SynchronizedGet(slot);
361 }
362
SetFeedback(FeedbackVector vector,FeedbackSlot slot,MaybeObject feedback,WriteBarrierMode mode)363 void NexusConfig::SetFeedback(FeedbackVector vector, FeedbackSlot slot,
364 MaybeObject feedback,
365 WriteBarrierMode mode) const {
366 DCHECK(can_write());
367 vector.SynchronizedSet(slot, feedback, mode);
368 }
369
UninitializedSentinel()370 MaybeObject FeedbackNexus::UninitializedSentinel() const {
371 return MaybeObject::FromObject(
372 *FeedbackVector::UninitializedSentinel(GetIsolate()));
373 }
374
MegamorphicSentinel()375 MaybeObject FeedbackNexus::MegamorphicSentinel() const {
376 return MaybeObject::FromObject(
377 *FeedbackVector::MegamorphicSentinel(GetIsolate()));
378 }
379
MegaDOMSentinel()380 MaybeObject FeedbackNexus::MegaDOMSentinel() const {
381 return MaybeObject::FromObject(
382 *FeedbackVector::MegaDOMSentinel(GetIsolate()));
383 }
384
FromHandle(MaybeObjectHandle slot)385 MaybeObject FeedbackNexus::FromHandle(MaybeObjectHandle slot) const {
386 return slot.is_null() ? HeapObjectReference::ClearedValue(config()->isolate())
387 : *slot;
388 }
389
ToHandle(MaybeObject value)390 MaybeObjectHandle FeedbackNexus::ToHandle(MaybeObject value) const {
391 return value.IsCleared() ? MaybeObjectHandle()
392 : MaybeObjectHandle(config()->NewHandle(value));
393 }
394
GetFeedback()395 MaybeObject FeedbackNexus::GetFeedback() const {
396 auto pair = GetFeedbackPair();
397 return pair.first;
398 }
399
GetFeedbackExtra()400 MaybeObject FeedbackNexus::GetFeedbackExtra() const {
401 auto pair = GetFeedbackPair();
402 return pair.second;
403 }
404
GetFeedbackPair()405 std::pair<MaybeObject, MaybeObject> FeedbackNexus::GetFeedbackPair() const {
406 if (config()->mode() == NexusConfig::BackgroundThread &&
407 feedback_cache_.has_value()) {
408 return std::make_pair(FromHandle(feedback_cache_->first),
409 FromHandle(feedback_cache_->second));
410 }
411 auto pair = FeedbackMetadata::GetSlotSize(kind()) == 2
412 ? config()->GetFeedbackPair(vector(), slot())
413 : std::make_pair(config()->GetFeedback(vector(), slot()),
414 MaybeObject());
415 if (config()->mode() == NexusConfig::BackgroundThread &&
416 !feedback_cache_.has_value()) {
417 feedback_cache_ =
418 std::make_pair(ToHandle(pair.first), ToHandle(pair.second));
419 }
420 return pair;
421 }
422
423 template <typename T>
424 struct IsValidFeedbackType
425 : public std::integral_constant<bool,
426 std::is_base_of<MaybeObject, T>::value ||
427 std::is_base_of<Object, T>::value> {};
428
429 template <typename FeedbackType>
SetFeedback(FeedbackType feedback,WriteBarrierMode mode)430 void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode) {
431 static_assert(IsValidFeedbackType<FeedbackType>(),
432 "feedbacks need to be Smi, Object or MaybeObject");
433 MaybeObject fmo = MaybeObject::Create(feedback);
434 config()->SetFeedback(vector(), slot(), fmo, mode);
435 }
436
437 template <typename FeedbackType, typename FeedbackExtraType>
SetFeedback(FeedbackType feedback,WriteBarrierMode mode,FeedbackExtraType feedback_extra,WriteBarrierMode mode_extra)438 void FeedbackNexus::SetFeedback(FeedbackType feedback, WriteBarrierMode mode,
439 FeedbackExtraType feedback_extra,
440 WriteBarrierMode mode_extra) {
441 static_assert(IsValidFeedbackType<FeedbackType>(),
442 "feedbacks need to be Smi, Object or MaybeObject");
443 static_assert(IsValidFeedbackType<FeedbackExtraType>(),
444 "feedbacks need to be Smi, Object or MaybeObject");
445 MaybeObject fmo = MaybeObject::Create(feedback);
446 MaybeObject fmo_extra = MaybeObject::Create(feedback_extra);
447 config()->SetFeedbackPair(vector(), slot(), fmo, mode, fmo_extra, mode_extra);
448 }
449
GetIsolate()450 Isolate* FeedbackNexus::GetIsolate() const { return vector().GetIsolate(); }
451 } // namespace internal
452 } // namespace v8
453
454 #include "src/objects/object-macros-undef.h"
455
456 #endif // V8_OBJECTS_FEEDBACK_VECTOR_INL_H_
457