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_FEEDBACK_VECTOR_INL_H_
6 #define V8_FEEDBACK_VECTOR_INL_H_
7
8 #include "src/feedback-vector.h"
9 #include "src/globals.h"
10 #include "src/heap/factory-inl.h"
11 #include "src/heap/heap-inl.h"
12 #include "src/objects/maybe-object-inl.h"
13 #include "src/objects/shared-function-info.h"
14
15 // Has to be the last include (doesn't have include guards):
16 #include "src/objects/object-macros.h"
17
18 namespace v8 {
19 namespace internal {
20
INT32_ACCESSORS(FeedbackMetadata,slot_count,kSlotCountOffset)21 INT32_ACCESSORS(FeedbackMetadata, slot_count, kSlotCountOffset)
22
23 int32_t FeedbackMetadata::synchronized_slot_count() const {
24 return base::Acquire_Load(reinterpret_cast<const base::Atomic32*>(
25 FIELD_ADDR(this, kSlotCountOffset)));
26 }
27
28 // static
cast(Object * obj)29 FeedbackMetadata* FeedbackMetadata::cast(Object* obj) {
30 DCHECK(obj->IsFeedbackMetadata());
31 return reinterpret_cast<FeedbackMetadata*>(obj);
32 }
33
get(int index)34 int32_t FeedbackMetadata::get(int index) const {
35 DCHECK(index >= 0 && index < length());
36 int offset = kHeaderSize + index * kInt32Size;
37 return READ_INT32_FIELD(this, offset);
38 }
39
set(int index,int32_t value)40 void FeedbackMetadata::set(int index, int32_t value) {
41 DCHECK(index >= 0 && index < length());
42 int offset = kHeaderSize + index * kInt32Size;
43 WRITE_INT32_FIELD(this, offset, value);
44 }
45
is_empty()46 bool FeedbackMetadata::is_empty() const { return slot_count() == 0; }
47
length()48 int FeedbackMetadata::length() const {
49 return FeedbackMetadata::length(slot_count());
50 }
51
52 // static
cast(Object * obj)53 FeedbackVector* FeedbackVector::cast(Object* obj) {
54 DCHECK(obj->IsFeedbackVector());
55 return reinterpret_cast<FeedbackVector*>(obj);
56 }
57
GetSlotSize(FeedbackSlotKind kind)58 int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
59 switch (kind) {
60 case FeedbackSlotKind::kForIn:
61 case FeedbackSlotKind::kInstanceOf:
62 case FeedbackSlotKind::kCompareOp:
63 case FeedbackSlotKind::kBinaryOp:
64 case FeedbackSlotKind::kLiteral:
65 case FeedbackSlotKind::kCreateClosure:
66 case FeedbackSlotKind::kTypeProfile:
67 return 1;
68
69 case FeedbackSlotKind::kCall:
70 case FeedbackSlotKind::kCloneObject:
71 case FeedbackSlotKind::kLoadProperty:
72 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
73 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
74 case FeedbackSlotKind::kLoadKeyed:
75 case FeedbackSlotKind::kStoreNamedSloppy:
76 case FeedbackSlotKind::kStoreNamedStrict:
77 case FeedbackSlotKind::kStoreOwnNamed:
78 case FeedbackSlotKind::kStoreGlobalSloppy:
79 case FeedbackSlotKind::kStoreGlobalStrict:
80 case FeedbackSlotKind::kStoreKeyedSloppy:
81 case FeedbackSlotKind::kStoreKeyedStrict:
82 case FeedbackSlotKind::kStoreInArrayLiteral:
83 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
84 return 2;
85
86 case FeedbackSlotKind::kInvalid:
87 case FeedbackSlotKind::kKindsNumber:
88 UNREACHABLE();
89 break;
90 }
91 return 1;
92 }
93
ACCESSORS(FeedbackVector,shared_function_info,SharedFunctionInfo,kSharedFunctionInfoOffset)94 ACCESSORS(FeedbackVector, shared_function_info, SharedFunctionInfo,
95 kSharedFunctionInfoOffset)
96 WEAK_ACCESSORS(FeedbackVector, optimized_code_weak_or_smi, kOptimizedCodeOffset)
97 INT32_ACCESSORS(FeedbackVector, length, kLengthOffset)
98 INT32_ACCESSORS(FeedbackVector, invocation_count, kInvocationCountOffset)
99 INT32_ACCESSORS(FeedbackVector, profiler_ticks, kProfilerTicksOffset)
100 INT32_ACCESSORS(FeedbackVector, deopt_count, kDeoptCountOffset)
101
102 bool FeedbackVector::is_empty() const { return length() == 0; }
103
metadata()104 FeedbackMetadata* FeedbackVector::metadata() const {
105 return shared_function_info()->feedback_metadata();
106 }
107
clear_invocation_count()108 void FeedbackVector::clear_invocation_count() { set_invocation_count(0); }
109
increment_deopt_count()110 void FeedbackVector::increment_deopt_count() {
111 int count = deopt_count();
112 if (count < std::numeric_limits<int32_t>::max()) {
113 set_deopt_count(count + 1);
114 }
115 }
116
optimized_code()117 Code* FeedbackVector::optimized_code() const {
118 MaybeObject* slot = optimized_code_weak_or_smi();
119 DCHECK(slot->IsSmi() || slot->IsClearedWeakHeapObject() ||
120 slot->IsWeakHeapObject());
121 HeapObject* heap_object;
122 return slot->ToStrongOrWeakHeapObject(&heap_object) ? Code::cast(heap_object)
123 : nullptr;
124 }
125
optimization_marker()126 OptimizationMarker FeedbackVector::optimization_marker() const {
127 MaybeObject* slot = optimized_code_weak_or_smi();
128 Smi* value;
129 if (!slot->ToSmi(&value)) return OptimizationMarker::kNone;
130 return static_cast<OptimizationMarker>(value->value());
131 }
132
has_optimized_code()133 bool FeedbackVector::has_optimized_code() const {
134 return optimized_code() != nullptr;
135 }
136
has_optimization_marker()137 bool FeedbackVector::has_optimization_marker() const {
138 return optimization_marker() != OptimizationMarker::kLogFirstExecution &&
139 optimization_marker() != OptimizationMarker::kNone;
140 }
141
142 // Conversion from an integer index to either a slot or an ic slot.
143 // static
ToSlot(int index)144 FeedbackSlot FeedbackVector::ToSlot(int index) {
145 DCHECK_GE(index, 0);
146 return FeedbackSlot(index);
147 }
148
Get(FeedbackSlot slot)149 MaybeObject* FeedbackVector::Get(FeedbackSlot slot) const {
150 return get(GetIndex(slot));
151 }
152
get(int index)153 MaybeObject* FeedbackVector::get(int index) const {
154 DCHECK_GE(index, 0);
155 DCHECK_LT(index, this->length());
156 int offset = kFeedbackSlotsOffset + index * kPointerSize;
157 return RELAXED_READ_WEAK_FIELD(this, offset);
158 }
159
Set(FeedbackSlot slot,MaybeObject * value,WriteBarrierMode mode)160 void FeedbackVector::Set(FeedbackSlot slot, MaybeObject* value,
161 WriteBarrierMode mode) {
162 set(GetIndex(slot), value, mode);
163 }
164
set(int index,MaybeObject * value,WriteBarrierMode mode)165 void FeedbackVector::set(int index, MaybeObject* value, WriteBarrierMode mode) {
166 DCHECK_GE(index, 0);
167 DCHECK_LT(index, this->length());
168 int offset = kFeedbackSlotsOffset + index * kPointerSize;
169 RELAXED_WRITE_FIELD(this, offset, value);
170 CONDITIONAL_WEAK_WRITE_BARRIER(this, offset, value, mode);
171 }
172
Set(FeedbackSlot slot,Object * value,WriteBarrierMode mode)173 void FeedbackVector::Set(FeedbackSlot slot, Object* value,
174 WriteBarrierMode mode) {
175 set(GetIndex(slot), MaybeObject::FromObject(value), mode);
176 }
177
set(int index,Object * value,WriteBarrierMode mode)178 void FeedbackVector::set(int index, Object* value, WriteBarrierMode mode) {
179 set(index, MaybeObject::FromObject(value), mode);
180 }
181
slots_start()182 inline MaybeObject** FeedbackVector::slots_start() {
183 return HeapObject::RawMaybeWeakField(this, kFeedbackSlotsOffset);
184 }
185
186 // Helper function to transform the feedback to BinaryOperationHint.
BinaryOperationHintFromFeedback(int type_feedback)187 BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
188 switch (type_feedback) {
189 case BinaryOperationFeedback::kNone:
190 return BinaryOperationHint::kNone;
191 case BinaryOperationFeedback::kSignedSmall:
192 return BinaryOperationHint::kSignedSmall;
193 case BinaryOperationFeedback::kSignedSmallInputs:
194 return BinaryOperationHint::kSignedSmallInputs;
195 case BinaryOperationFeedback::kNumber:
196 return BinaryOperationHint::kNumber;
197 case BinaryOperationFeedback::kNumberOrOddball:
198 return BinaryOperationHint::kNumberOrOddball;
199 case BinaryOperationFeedback::kString:
200 return BinaryOperationHint::kString;
201 case BinaryOperationFeedback::kBigInt:
202 return BinaryOperationHint::kBigInt;
203 default:
204 return BinaryOperationHint::kAny;
205 }
206 UNREACHABLE();
207 }
208
209 // Helper function to transform the feedback to CompareOperationHint.
CompareOperationHintFromFeedback(int type_feedback)210 CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) {
211 switch (type_feedback) {
212 case CompareOperationFeedback::kNone:
213 return CompareOperationHint::kNone;
214 case CompareOperationFeedback::kSignedSmall:
215 return CompareOperationHint::kSignedSmall;
216 case CompareOperationFeedback::kNumber:
217 return CompareOperationHint::kNumber;
218 case CompareOperationFeedback::kNumberOrOddball:
219 return CompareOperationHint::kNumberOrOddball;
220 case CompareOperationFeedback::kInternalizedString:
221 return CompareOperationHint::kInternalizedString;
222 case CompareOperationFeedback::kString:
223 return CompareOperationHint::kString;
224 case CompareOperationFeedback::kSymbol:
225 return CompareOperationHint::kSymbol;
226 case CompareOperationFeedback::kBigInt:
227 return CompareOperationHint::kBigInt;
228 case CompareOperationFeedback::kReceiver:
229 return CompareOperationHint::kReceiver;
230 default:
231 return CompareOperationHint::kAny;
232 }
233 UNREACHABLE();
234 }
235
236 // Helper function to transform the feedback to ForInHint.
ForInHintFromFeedback(int type_feedback)237 ForInHint ForInHintFromFeedback(int type_feedback) {
238 switch (type_feedback) {
239 case ForInFeedback::kNone:
240 return ForInHint::kNone;
241 case ForInFeedback::kEnumCacheKeys:
242 return ForInHint::kEnumCacheKeys;
243 case ForInFeedback::kEnumCacheKeysAndIndices:
244 return ForInHint::kEnumCacheKeysAndIndices;
245 default:
246 return ForInHint::kAny;
247 }
248 UNREACHABLE();
249 }
250
ComputeCounts(int * with_type_info,int * generic,int * vector_ic_count)251 void FeedbackVector::ComputeCounts(int* with_type_info, int* generic,
252 int* vector_ic_count) {
253 MaybeObject* megamorphic_sentinel = MaybeObject::FromObject(
254 *FeedbackVector::MegamorphicSentinel(GetIsolate()));
255 int with = 0;
256 int gen = 0;
257 int total = 0;
258 FeedbackMetadataIterator iter(metadata());
259 while (iter.HasNext()) {
260 FeedbackSlot slot = iter.Next();
261 FeedbackSlotKind kind = iter.kind();
262
263 MaybeObject* const obj = Get(slot);
264 AssertNoLegacyTypes(obj);
265 switch (kind) {
266 case FeedbackSlotKind::kCall:
267 case FeedbackSlotKind::kLoadProperty:
268 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
269 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
270 case FeedbackSlotKind::kLoadKeyed:
271 case FeedbackSlotKind::kStoreNamedSloppy:
272 case FeedbackSlotKind::kStoreNamedStrict:
273 case FeedbackSlotKind::kStoreOwnNamed:
274 case FeedbackSlotKind::kStoreGlobalSloppy:
275 case FeedbackSlotKind::kStoreGlobalStrict:
276 case FeedbackSlotKind::kStoreKeyedSloppy:
277 case FeedbackSlotKind::kStoreKeyedStrict:
278 case FeedbackSlotKind::kStoreInArrayLiteral:
279 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
280 case FeedbackSlotKind::kTypeProfile: {
281 HeapObject* heap_object;
282 if (obj->IsWeakOrClearedHeapObject() ||
283 (obj->ToStrongHeapObject(&heap_object) &&
284 (heap_object->IsWeakFixedArray() || heap_object->IsString()))) {
285 with++;
286 } else if (obj == megamorphic_sentinel) {
287 gen++;
288 with++;
289 }
290 total++;
291 break;
292 }
293 case FeedbackSlotKind::kBinaryOp: {
294 int const feedback = Smi::ToInt(obj->ToSmi());
295 BinaryOperationHint hint = BinaryOperationHintFromFeedback(feedback);
296 if (hint == BinaryOperationHint::kAny) {
297 gen++;
298 }
299 if (hint != BinaryOperationHint::kNone) {
300 with++;
301 }
302 total++;
303 break;
304 }
305 case FeedbackSlotKind::kCompareOp: {
306 int const feedback = Smi::ToInt(obj->ToSmi());
307 CompareOperationHint hint = CompareOperationHintFromFeedback(feedback);
308 if (hint == CompareOperationHint::kAny) {
309 gen++;
310 }
311 if (hint != CompareOperationHint::kNone) {
312 with++;
313 }
314 total++;
315 break;
316 }
317 case FeedbackSlotKind::kForIn: {
318 int const feedback = Smi::ToInt(obj->ToSmi());
319 ForInHint hint = ForInHintFromFeedback(feedback);
320 if (hint == ForInHint::kAny) {
321 gen++;
322 }
323 if (hint != ForInHint::kNone) {
324 with++;
325 }
326 total++;
327 break;
328 }
329 case FeedbackSlotKind::kInstanceOf: {
330 if (obj->IsWeakOrClearedHeapObject()) {
331 with++;
332 } else if (obj == megamorphic_sentinel) {
333 gen++;
334 with++;
335 }
336 total++;
337 break;
338 }
339 case FeedbackSlotKind::kCreateClosure:
340 case FeedbackSlotKind::kLiteral:
341 case FeedbackSlotKind::kCloneObject:
342 break;
343 case FeedbackSlotKind::kInvalid:
344 case FeedbackSlotKind::kKindsNumber:
345 UNREACHABLE();
346 break;
347 }
348 }
349
350 *with_type_info = with;
351 *generic = gen;
352 *vector_ic_count = total;
353 }
354
UninitializedSentinel(Isolate * isolate)355 Handle<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) {
356 return isolate->factory()->uninitialized_symbol();
357 }
358
GenericSentinel(Isolate * isolate)359 Handle<Symbol> FeedbackVector::GenericSentinel(Isolate* isolate) {
360 return isolate->factory()->generic_symbol();
361 }
362
MegamorphicSentinel(Isolate * isolate)363 Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
364 return isolate->factory()->megamorphic_symbol();
365 }
366
PremonomorphicSentinel(Isolate * isolate)367 Handle<Symbol> FeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
368 return isolate->factory()->premonomorphic_symbol();
369 }
370
RawUninitializedSentinel(Isolate * isolate)371 Symbol* FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
372 return ReadOnlyRoots(isolate).uninitialized_symbol();
373 }
374
HasNext()375 bool FeedbackMetadataIterator::HasNext() const {
376 return next_slot_.ToInt() < metadata()->slot_count();
377 }
378
Next()379 FeedbackSlot FeedbackMetadataIterator::Next() {
380 DCHECK(HasNext());
381 cur_slot_ = next_slot_;
382 slot_kind_ = metadata()->GetKind(cur_slot_);
383 next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size());
384 return cur_slot_;
385 }
386
entry_size()387 int FeedbackMetadataIterator::entry_size() const {
388 return FeedbackMetadata::GetSlotSize(kind());
389 }
390
GetFeedback()391 MaybeObject* FeedbackNexus::GetFeedback() const {
392 MaybeObject* feedback = vector()->Get(slot());
393 FeedbackVector::AssertNoLegacyTypes(feedback);
394 return feedback;
395 }
396
GetFeedbackExtra()397 MaybeObject* FeedbackNexus::GetFeedbackExtra() const {
398 #ifdef DEBUG
399 FeedbackSlotKind kind = vector()->GetKind(slot());
400 DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
401 #endif
402 int extra_index = vector()->GetIndex(slot()) + 1;
403 return vector()->get(extra_index);
404 }
405
SetFeedback(Object * feedback,WriteBarrierMode mode)406 void FeedbackNexus::SetFeedback(Object* feedback, WriteBarrierMode mode) {
407 SetFeedback(MaybeObject::FromObject(feedback));
408 }
409
SetFeedback(MaybeObject * feedback,WriteBarrierMode mode)410 void FeedbackNexus::SetFeedback(MaybeObject* feedback, WriteBarrierMode mode) {
411 FeedbackVector::AssertNoLegacyTypes(feedback);
412 vector()->Set(slot(), feedback, mode);
413 }
414
SetFeedbackExtra(Object * feedback_extra,WriteBarrierMode mode)415 void FeedbackNexus::SetFeedbackExtra(Object* feedback_extra,
416 WriteBarrierMode mode) {
417 #ifdef DEBUG
418 FeedbackSlotKind kind = vector()->GetKind(slot());
419 DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
420 FeedbackVector::AssertNoLegacyTypes(MaybeObject::FromObject(feedback_extra));
421 #endif
422 int index = vector()->GetIndex(slot()) + 1;
423 vector()->set(index, MaybeObject::FromObject(feedback_extra), mode);
424 }
425
SetFeedbackExtra(MaybeObject * feedback_extra,WriteBarrierMode mode)426 void FeedbackNexus::SetFeedbackExtra(MaybeObject* feedback_extra,
427 WriteBarrierMode mode) {
428 #ifdef DEBUG
429 FeedbackVector::AssertNoLegacyTypes(feedback_extra);
430 #endif
431 int index = vector()->GetIndex(slot()) + 1;
432 vector()->set(index, feedback_extra, mode);
433 }
434
GetIsolate()435 Isolate* FeedbackNexus::GetIsolate() const { return vector()->GetIsolate(); }
436 } // namespace internal
437 } // namespace v8
438
439 #include "src/objects/object-macros-undef.h"
440
441 #endif // V8_FEEDBACK_VECTOR_INL_H_
442