• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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