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