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/factory.h"
9 #include "src/feedback-vector.h"
10 #include "src/globals.h"
11
12 namespace v8 {
13 namespace internal {
14
15 template <typename Derived>
AddSlot(FeedbackSlotKind kind)16 FeedbackSlot FeedbackVectorSpecBase<Derived>::AddSlot(FeedbackSlotKind kind) {
17 int slot = This()->slots();
18 int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
19 This()->append(kind);
20 for (int i = 1; i < entries_per_slot; i++) {
21 This()->append(FeedbackSlotKind::kInvalid);
22 }
23 return FeedbackSlot(slot);
24 }
25
26 // static
cast(Object * obj)27 FeedbackMetadata* FeedbackMetadata::cast(Object* obj) {
28 DCHECK(obj->IsFeedbackMetadata());
29 return reinterpret_cast<FeedbackMetadata*>(obj);
30 }
31
is_empty()32 bool FeedbackMetadata::is_empty() const {
33 if (length() == 0) return true;
34 return false;
35 }
36
slot_count()37 int FeedbackMetadata::slot_count() const {
38 if (length() == 0) return 0;
39 DCHECK(length() > kReservedIndexCount);
40 return Smi::cast(get(kSlotsCountIndex))->value();
41 }
42
43 // static
cast(Object * obj)44 FeedbackVector* FeedbackVector::cast(Object* obj) {
45 DCHECK(obj->IsFeedbackVector());
46 return reinterpret_cast<FeedbackVector*>(obj);
47 }
48
GetSlotSize(FeedbackSlotKind kind)49 int FeedbackMetadata::GetSlotSize(FeedbackSlotKind kind) {
50 switch (kind) {
51 case FeedbackSlotKind::kGeneral:
52 case FeedbackSlotKind::kCompareOp:
53 case FeedbackSlotKind::kBinaryOp:
54 case FeedbackSlotKind::kToBoolean:
55 case FeedbackSlotKind::kLiteral:
56 case FeedbackSlotKind::kCreateClosure:
57 return 1;
58
59 case FeedbackSlotKind::kCall:
60 case FeedbackSlotKind::kLoadProperty:
61 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
62 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
63 case FeedbackSlotKind::kLoadKeyed:
64 case FeedbackSlotKind::kStoreNamedSloppy:
65 case FeedbackSlotKind::kStoreNamedStrict:
66 case FeedbackSlotKind::kStoreOwnNamed:
67 case FeedbackSlotKind::kStoreKeyedSloppy:
68 case FeedbackSlotKind::kStoreKeyedStrict:
69 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
70 return 2;
71
72 case FeedbackSlotKind::kInvalid:
73 case FeedbackSlotKind::kKindsNumber:
74 UNREACHABLE();
75 break;
76 }
77 return 1;
78 }
79
is_empty()80 bool FeedbackVector::is_empty() const {
81 return length() == kReservedIndexCount;
82 }
83
slot_count()84 int FeedbackVector::slot_count() const {
85 return length() - kReservedIndexCount;
86 }
87
metadata()88 FeedbackMetadata* FeedbackVector::metadata() const {
89 return shared_function_info()->feedback_metadata();
90 }
91
shared_function_info()92 SharedFunctionInfo* FeedbackVector::shared_function_info() const {
93 return SharedFunctionInfo::cast(get(kSharedFunctionInfoIndex));
94 }
95
invocation_count()96 int FeedbackVector::invocation_count() const {
97 return Smi::cast(get(kInvocationCountIndex))->value();
98 }
99
clear_invocation_count()100 void FeedbackVector::clear_invocation_count() {
101 set(kInvocationCountIndex, Smi::kZero);
102 }
103
104 // Conversion from an integer index to either a slot or an ic slot.
105 // static
ToSlot(int index)106 FeedbackSlot FeedbackVector::ToSlot(int index) {
107 DCHECK_GE(index, kReservedIndexCount);
108 return FeedbackSlot(index - kReservedIndexCount);
109 }
110
Get(FeedbackSlot slot)111 Object* FeedbackVector::Get(FeedbackSlot slot) const {
112 return get(GetIndex(slot));
113 }
114
Set(FeedbackSlot slot,Object * value,WriteBarrierMode mode)115 void FeedbackVector::Set(FeedbackSlot slot, Object* value,
116 WriteBarrierMode mode) {
117 set(GetIndex(slot), value, mode);
118 }
119
120 // Helper function to transform the feedback to BinaryOperationHint.
BinaryOperationHintFromFeedback(int type_feedback)121 BinaryOperationHint BinaryOperationHintFromFeedback(int type_feedback) {
122 switch (type_feedback) {
123 case BinaryOperationFeedback::kNone:
124 return BinaryOperationHint::kNone;
125 case BinaryOperationFeedback::kSignedSmall:
126 return BinaryOperationHint::kSignedSmall;
127 case BinaryOperationFeedback::kNumber:
128 case BinaryOperationFeedback::kNumberOrOddball:
129 return BinaryOperationHint::kNumberOrOddball;
130 case BinaryOperationFeedback::kString:
131 return BinaryOperationHint::kString;
132 case BinaryOperationFeedback::kAny:
133 default:
134 return BinaryOperationHint::kAny;
135 }
136 UNREACHABLE();
137 return BinaryOperationHint::kNone;
138 }
139
140 // Helper function to transform the feedback to CompareOperationHint.
CompareOperationHintFromFeedback(int type_feedback)141 CompareOperationHint CompareOperationHintFromFeedback(int type_feedback) {
142 switch (type_feedback) {
143 case CompareOperationFeedback::kNone:
144 return CompareOperationHint::kNone;
145 case CompareOperationFeedback::kSignedSmall:
146 return CompareOperationHint::kSignedSmall;
147 case CompareOperationFeedback::kNumber:
148 return CompareOperationHint::kNumber;
149 case CompareOperationFeedback::kNumberOrOddball:
150 return CompareOperationHint::kNumberOrOddball;
151 case CompareOperationFeedback::kInternalizedString:
152 return CompareOperationHint::kInternalizedString;
153 case CompareOperationFeedback::kString:
154 return CompareOperationHint::kString;
155 case CompareOperationFeedback::kReceiver:
156 return CompareOperationHint::kReceiver;
157 default:
158 return CompareOperationHint::kAny;
159 }
160 UNREACHABLE();
161 return CompareOperationHint::kNone;
162 }
163
ComputeCounts(int * with_type_info,int * generic,int * vector_ic_count,bool code_is_interpreted)164 void FeedbackVector::ComputeCounts(int* with_type_info, int* generic,
165 int* vector_ic_count,
166 bool code_is_interpreted) {
167 Object* megamorphic_sentinel =
168 *FeedbackVector::MegamorphicSentinel(GetIsolate());
169 int with = 0;
170 int gen = 0;
171 int total = 0;
172 FeedbackMetadataIterator iter(metadata());
173 while (iter.HasNext()) {
174 FeedbackSlot slot = iter.Next();
175 FeedbackSlotKind kind = iter.kind();
176
177 Object* const obj = Get(slot);
178 switch (kind) {
179 case FeedbackSlotKind::kCall:
180 case FeedbackSlotKind::kLoadProperty:
181 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
182 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
183 case FeedbackSlotKind::kLoadKeyed:
184 case FeedbackSlotKind::kStoreNamedSloppy:
185 case FeedbackSlotKind::kStoreNamedStrict:
186 case FeedbackSlotKind::kStoreOwnNamed:
187 case FeedbackSlotKind::kStoreKeyedSloppy:
188 case FeedbackSlotKind::kStoreKeyedStrict:
189 case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
190 if (obj->IsWeakCell() || obj->IsFixedArray() || obj->IsString()) {
191 with++;
192 } else if (obj == megamorphic_sentinel) {
193 gen++;
194 if (code_is_interpreted) with++;
195 }
196 total++;
197 break;
198 }
199 case FeedbackSlotKind::kBinaryOp:
200 // If we are not running interpreted code, we need to ignore the special
201 // IC slots for binaryop/compare used by the interpreter.
202 // TODO(mvstanton): Remove code_is_interpreted when full code is retired
203 // from service.
204 if (code_is_interpreted) {
205 int const feedback = Smi::cast(obj)->value();
206 BinaryOperationHint hint = BinaryOperationHintFromFeedback(feedback);
207 if (hint == BinaryOperationHint::kAny) {
208 gen++;
209 }
210 if (hint != BinaryOperationHint::kNone) {
211 with++;
212 }
213 total++;
214 }
215 break;
216 case FeedbackSlotKind::kCompareOp: {
217 // If we are not running interpreted code, we need to ignore the special
218 // IC slots for binaryop/compare used by the interpreter.
219 // TODO(mvstanton): Remove code_is_interpreted when full code is retired
220 // from service.
221 if (code_is_interpreted) {
222 int const feedback = Smi::cast(obj)->value();
223 CompareOperationHint hint =
224 CompareOperationHintFromFeedback(feedback);
225 if (hint == CompareOperationHint::kAny) {
226 gen++;
227 }
228 if (hint != CompareOperationHint::kNone) {
229 with++;
230 }
231 total++;
232 }
233 break;
234 }
235 case FeedbackSlotKind::kToBoolean:
236 case FeedbackSlotKind::kCreateClosure:
237 case FeedbackSlotKind::kGeneral:
238 case FeedbackSlotKind::kLiteral:
239 break;
240 case FeedbackSlotKind::kInvalid:
241 case FeedbackSlotKind::kKindsNumber:
242 UNREACHABLE();
243 break;
244 }
245 }
246
247 *with_type_info = with;
248 *generic = gen;
249 *vector_ic_count = total;
250 }
251
UninitializedSentinel(Isolate * isolate)252 Handle<Symbol> FeedbackVector::UninitializedSentinel(Isolate* isolate) {
253 return isolate->factory()->uninitialized_symbol();
254 }
255
MegamorphicSentinel(Isolate * isolate)256 Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
257 return isolate->factory()->megamorphic_symbol();
258 }
259
PremonomorphicSentinel(Isolate * isolate)260 Handle<Symbol> FeedbackVector::PremonomorphicSentinel(Isolate* isolate) {
261 return isolate->factory()->premonomorphic_symbol();
262 }
263
RawUninitializedSentinel(Isolate * isolate)264 Symbol* FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
265 return isolate->heap()->uninitialized_symbol();
266 }
267
HasNext()268 bool FeedbackMetadataIterator::HasNext() const {
269 return next_slot_.ToInt() < metadata()->slot_count();
270 }
271
Next()272 FeedbackSlot FeedbackMetadataIterator::Next() {
273 DCHECK(HasNext());
274 cur_slot_ = next_slot_;
275 slot_kind_ = metadata()->GetKind(cur_slot_);
276 next_slot_ = FeedbackSlot(next_slot_.ToInt() + entry_size());
277 return cur_slot_;
278 }
279
entry_size()280 int FeedbackMetadataIterator::entry_size() const {
281 return FeedbackMetadata::GetSlotSize(kind());
282 }
283
GetFeedback()284 Object* FeedbackNexus::GetFeedback() const { return vector()->Get(slot()); }
285
GetFeedbackExtra()286 Object* FeedbackNexus::GetFeedbackExtra() const {
287 #ifdef DEBUG
288 FeedbackSlotKind kind = vector()->GetKind(slot());
289 DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
290 #endif
291 int extra_index = vector()->GetIndex(slot()) + 1;
292 return vector()->get(extra_index);
293 }
294
SetFeedback(Object * feedback,WriteBarrierMode mode)295 void FeedbackNexus::SetFeedback(Object* feedback, WriteBarrierMode mode) {
296 vector()->Set(slot(), feedback, mode);
297 }
298
SetFeedbackExtra(Object * feedback_extra,WriteBarrierMode mode)299 void FeedbackNexus::SetFeedbackExtra(Object* feedback_extra,
300 WriteBarrierMode mode) {
301 #ifdef DEBUG
302 FeedbackSlotKind kind = vector()->GetKind(slot());
303 DCHECK_LT(1, FeedbackMetadata::GetSlotSize(kind));
304 #endif
305 int index = vector()->GetIndex(slot()) + 1;
306 vector()->set(index, feedback_extra, mode);
307 }
308
GetIsolate()309 Isolate* FeedbackNexus::GetIsolate() const { return vector()->GetIsolate(); }
310 } // namespace internal
311 } // namespace v8
312
313 #endif // V8_FEEDBACK_VECTOR_INL_H_
314