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