OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_TYPE_FEEDBACK_VECTOR_H_ | 5 #ifndef V8_TYPE_FEEDBACK_VECTOR_H_ |
6 #define V8_TYPE_FEEDBACK_VECTOR_H_ | 6 #define V8_TYPE_FEEDBACK_VECTOR_H_ |
7 | 7 |
8 #include "src/checks.h" | 8 #include "src/checks.h" |
9 #include "src/elements-kind.h" | 9 #include "src/elements-kind.h" |
10 #include "src/heap/heap.h" | 10 #include "src/heap/heap.h" |
11 #include "src/isolate.h" | 11 #include "src/isolate.h" |
12 #include "src/objects.h" | 12 #include "src/objects.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 | 16 |
17 // The shape of the TypeFeedbackVector is an array with: | 17 // The shape of the TypeFeedbackVector is an array with: |
18 // 0: first_ic_slot_index (== length() if no ic slots are present) | 18 // 0: first_ic_slot_index (== length() if no ic slots are present) |
19 // 1: ics_with_types | 19 // 1: ics_with_types |
20 // 2: ics_with_generic_info | 20 // 2: ics_with_generic_info |
21 // 3: first feedback slot | 21 // 3: type information for ic slots, if any |
| 22 // ... |
| 23 // N: first feedback slot (N >= 3) |
22 // ... | 24 // ... |
23 // [<first_ic_slot_index>: feedback slot] | 25 // [<first_ic_slot_index>: feedback slot] |
24 // ...to length() - 1 | 26 // ...to length() - 1 |
25 // | 27 // |
26 class TypeFeedbackVector : public FixedArray { | 28 class TypeFeedbackVector : public FixedArray { |
27 public: | 29 public: |
28 // Casting. | 30 // Casting. |
29 static TypeFeedbackVector* cast(Object* obj) { | 31 static TypeFeedbackVector* cast(Object* obj) { |
30 DCHECK(obj->IsTypeFeedbackVector()); | 32 DCHECK(obj->IsTypeFeedbackVector()); |
31 return reinterpret_cast<TypeFeedbackVector*>(obj); | 33 return reinterpret_cast<TypeFeedbackVector*>(obj); |
32 } | 34 } |
33 | 35 |
34 static const int kReservedIndexCount = 3; | 36 static const int kReservedIndexCount = 3; |
35 static const int kFirstICSlotIndex = 0; | 37 static const int kFirstICSlotIndex = 0; |
36 static const int kWithTypesIndex = 1; | 38 static const int kWithTypesIndex = 1; |
37 static const int kGenericCountIndex = 2; | 39 static const int kGenericCountIndex = 2; |
38 | 40 |
39 int first_ic_slot_index() { | 41 int first_ic_slot_index() const { |
40 DCHECK(length() >= kReservedIndexCount); | 42 DCHECK(length() >= kReservedIndexCount); |
41 return Smi::cast(get(kFirstICSlotIndex))->value(); | 43 return Smi::cast(get(kFirstICSlotIndex))->value(); |
42 } | 44 } |
43 | 45 |
44 int ic_with_type_info_count() { | 46 int ic_with_type_info_count() { |
45 return length() > 0 ? Smi::cast(get(kWithTypesIndex))->value() : 0; | 47 return length() > 0 ? Smi::cast(get(kWithTypesIndex))->value() : 0; |
46 } | 48 } |
47 | 49 |
48 void change_ic_with_type_info_count(int delta) { | 50 void change_ic_with_type_info_count(int delta) { |
49 if (delta == 0) return; | 51 if (delta == 0) return; |
50 int value = ic_with_type_info_count() + delta; | 52 int value = ic_with_type_info_count() + delta; |
51 // Could go negative because of the debugger. | 53 // Could go negative because of the debugger. |
52 if (value >= 0) { | 54 if (value >= 0) { |
53 set(kWithTypesIndex, Smi::FromInt(value)); | 55 set(kWithTypesIndex, Smi::FromInt(value)); |
54 } | 56 } |
55 } | 57 } |
56 | 58 |
57 int ic_generic_count() { | 59 int ic_generic_count() { |
58 return length() > 0 ? Smi::cast(get(kGenericCountIndex))->value() : 0; | 60 return length() > 0 ? Smi::cast(get(kGenericCountIndex))->value() : 0; |
59 } | 61 } |
60 | 62 |
61 void change_ic_generic_count(int delta) { | 63 void change_ic_generic_count(int delta) { |
62 if (delta == 0) return; | 64 if (delta == 0) return; |
63 int value = ic_generic_count() + delta; | 65 int value = ic_generic_count() + delta; |
64 if (value >= 0) { | 66 if (value >= 0) { |
65 set(kGenericCountIndex, Smi::FromInt(value)); | 67 set(kGenericCountIndex, Smi::FromInt(value)); |
66 } | 68 } |
67 } | 69 } |
68 | 70 |
69 int Slots() { | 71 inline int ic_metadata_length() const; |
| 72 |
| 73 int Slots() const { |
70 if (length() == 0) return 0; | 74 if (length() == 0) return 0; |
71 return Max(0, first_ic_slot_index() - kReservedIndexCount); | 75 return Max( |
| 76 0, first_ic_slot_index() - ic_metadata_length() - kReservedIndexCount); |
72 } | 77 } |
73 | 78 |
74 int ICSlots() { | 79 int ICSlots() const { |
75 if (length() == 0) return 0; | 80 if (length() == 0) return 0; |
76 return length() - first_ic_slot_index(); | 81 return length() - first_ic_slot_index(); |
77 } | 82 } |
78 | 83 |
79 // Conversion from a slot or ic slot to an integer index to the underlying | 84 // Conversion from a slot or ic slot to an integer index to the underlying |
80 // array. | 85 // array. |
81 int GetIndex(FeedbackVectorSlot slot) { | 86 int GetIndex(FeedbackVectorSlot slot) const { |
82 return kReservedIndexCount + slot.ToInt(); | 87 return kReservedIndexCount + ic_metadata_length() + slot.ToInt(); |
83 } | 88 } |
84 | 89 |
85 int GetIndex(FeedbackVectorICSlot slot) { | 90 int GetIndex(FeedbackVectorICSlot slot) const { |
86 int first_ic_slot = first_ic_slot_index(); | 91 int first_ic_slot = first_ic_slot_index(); |
87 DCHECK(slot.ToInt() < ICSlots()); | 92 DCHECK(slot.ToInt() < ICSlots()); |
88 return first_ic_slot + slot.ToInt(); | 93 return first_ic_slot + slot.ToInt(); |
89 } | 94 } |
90 | 95 |
91 | |
92 // Conversion from an integer index to either a slot or an ic slot. The caller | 96 // Conversion from an integer index to either a slot or an ic slot. The caller |
93 // should know what kind she expects. | 97 // should know what kind she expects. |
94 FeedbackVectorSlot ToSlot(int index) { | 98 FeedbackVectorSlot ToSlot(int index) const { |
95 DCHECK(index >= kReservedIndexCount && index < first_ic_slot_index()); | 99 DCHECK(index >= kReservedIndexCount && index < first_ic_slot_index()); |
96 return FeedbackVectorSlot(index - kReservedIndexCount); | 100 return FeedbackVectorSlot(index - ic_metadata_length() - |
| 101 kReservedIndexCount); |
97 } | 102 } |
98 | 103 |
99 FeedbackVectorICSlot ToICSlot(int index) { | 104 FeedbackVectorICSlot ToICSlot(int index) const { |
100 DCHECK(index >= first_ic_slot_index() && index < length()); | 105 DCHECK(index >= first_ic_slot_index() && index < length()); |
101 return FeedbackVectorICSlot(index - first_ic_slot_index()); | 106 return FeedbackVectorICSlot(index - first_ic_slot_index()); |
102 } | 107 } |
103 | 108 |
104 Object* Get(FeedbackVectorSlot slot) { return get(GetIndex(slot)); } | 109 Object* Get(FeedbackVectorSlot slot) const { return get(GetIndex(slot)); } |
105 void Set(FeedbackVectorSlot slot, Object* value, | 110 void Set(FeedbackVectorSlot slot, Object* value, |
106 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) { | 111 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) { |
107 set(GetIndex(slot), value, mode); | 112 set(GetIndex(slot), value, mode); |
108 } | 113 } |
109 | 114 |
110 Object* Get(FeedbackVectorICSlot slot) { return get(GetIndex(slot)); } | 115 Object* Get(FeedbackVectorICSlot slot) const { return get(GetIndex(slot)); } |
111 void Set(FeedbackVectorICSlot slot, Object* value, | 116 void Set(FeedbackVectorICSlot slot, Object* value, |
112 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) { | 117 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) { |
113 set(GetIndex(slot), value, mode); | 118 set(GetIndex(slot), value, mode); |
114 } | 119 } |
115 | 120 |
| 121 // IC slots need metadata to recognize the type of IC. Set a Kind for every |
| 122 // slot. If GetKind() returns Code::NUMBER_OF_KINDS, then there is |
| 123 // no kind associated with this slot. This may happen in the current design |
| 124 // if a decision is made at compile time not to emit an IC that was planned |
| 125 // for at parse time. This can be eliminated if we encode kind at parse |
| 126 // time. |
| 127 Code::Kind GetKind(FeedbackVectorICSlot slot) const; |
| 128 void SetKind(FeedbackVectorICSlot slot, Code::Kind kind); |
116 | 129 |
117 static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count, | 130 static Handle<TypeFeedbackVector> Allocate(Isolate* isolate, int slot_count, |
118 int ic_slot_count); | 131 int ic_slot_count); |
119 | 132 |
120 static Handle<TypeFeedbackVector> Copy(Isolate* isolate, | 133 static Handle<TypeFeedbackVector> Copy(Isolate* isolate, |
121 Handle<TypeFeedbackVector> vector); | 134 Handle<TypeFeedbackVector> vector); |
122 | 135 |
123 // Clears the vector slots and the vector ic slots. | 136 // Clears the vector slots and the vector ic slots. |
124 void ClearSlots(SharedFunctionInfo* shared); | 137 void ClearSlots(SharedFunctionInfo* shared); |
125 | 138 |
(...skipping 12 matching lines...) Expand all Loading... |
138 // The object that indicates a monomorphic state of Array with | 151 // The object that indicates a monomorphic state of Array with |
139 // ElementsKind | 152 // ElementsKind |
140 static inline Handle<Object> MonomorphicArraySentinel( | 153 static inline Handle<Object> MonomorphicArraySentinel( |
141 Isolate* isolate, ElementsKind elements_kind); | 154 Isolate* isolate, ElementsKind elements_kind); |
142 | 155 |
143 // A raw version of the uninitialized sentinel that's safe to read during | 156 // A raw version of the uninitialized sentinel that's safe to read during |
144 // garbage collection (e.g., for patching the cache). | 157 // garbage collection (e.g., for patching the cache). |
145 static inline Object* RawUninitializedSentinel(Heap* heap); | 158 static inline Object* RawUninitializedSentinel(Heap* heap); |
146 | 159 |
147 private: | 160 private: |
| 161 enum VectorICKind { |
| 162 KindUnused = 0x0, |
| 163 KindCallIC = 0x1, |
| 164 KindLoadIC = 0x2, |
| 165 KindKeyedLoadIC = 0x3 |
| 166 }; |
| 167 |
| 168 static const int kVectorICKindBits = 2; |
| 169 static VectorICKind FromCodeKind(Code::Kind kind); |
| 170 static Code::Kind FromVectorICKind(VectorICKind kind); |
| 171 typedef BitSetComputer<VectorICKind, kVectorICKindBits, kSmiValueSize, |
| 172 uint32_t> VectorICComputer; |
| 173 |
148 DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector); | 174 DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector); |
149 }; | 175 }; |
| 176 |
| 177 |
| 178 // A FeedbackNexus is the combination of a TypeFeedbackVector and a slot. |
| 179 // Derived classes customize the update and retrieval of feedback. |
| 180 class FeedbackNexus { |
| 181 public: |
| 182 FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot) |
| 183 : vector_handle_(vector), use_handle_(true), slot_(slot) {} |
| 184 FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot) |
| 185 : vector_(vector), use_handle_(false), slot_(slot) {} |
| 186 virtual ~FeedbackNexus() {} |
| 187 |
| 188 Handle<TypeFeedbackVector> vector_handle() const { |
| 189 DCHECK(use_handle_); |
| 190 return vector_handle_; |
| 191 } |
| 192 TypeFeedbackVector* vector() const { |
| 193 return use_handle_ ? *vector_handle_ : vector_; |
| 194 } |
| 195 FeedbackVectorICSlot slot() const { return slot_; } |
| 196 |
| 197 InlineCacheState ic_state() const { return StateFromFeedback(); } |
| 198 Map* FindFirstMap() const { |
| 199 MapHandleList maps; |
| 200 ExtractMaps(&maps); |
| 201 if (maps.length() > 0) return *maps.at(0); |
| 202 return NULL; |
| 203 } |
| 204 |
| 205 virtual InlineCacheState StateFromFeedback() const = 0; |
| 206 virtual int ExtractMaps(MapHandleList* maps) const = 0; |
| 207 virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const = 0; |
| 208 virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const { |
| 209 return length == 0; |
| 210 } |
| 211 virtual Name* FindFirstName() const { return NULL; } |
| 212 |
| 213 Object* GetFeedback() const { return vector()->Get(slot()); } |
| 214 |
| 215 protected: |
| 216 Isolate* GetIsolate() const { return vector()->GetIsolate(); } |
| 217 |
| 218 void SetFeedback(Object* feedback, |
| 219 WriteBarrierMode mode = UPDATE_WRITE_BARRIER) { |
| 220 vector()->Set(slot(), feedback, mode); |
| 221 } |
| 222 |
| 223 Handle<FixedArray> EnsureArrayOfSize(int length); |
| 224 void InstallHandlers(int start_index, TypeHandleList* types, |
| 225 CodeHandleList* handlers); |
| 226 int ExtractMaps(int start_index, MapHandleList* maps) const; |
| 227 MaybeHandle<Code> FindHandlerForMap(int start_index, Handle<Map> map) const; |
| 228 bool FindHandlers(int start_index, CodeHandleList* code_list, |
| 229 int length) const; |
| 230 |
| 231 private: |
| 232 // The reason for the union is that we can use handles during IC miss, |
| 233 // but not during GC when we clear ICs. If you have a handle to the |
| 234 // vector that is better because more operations can be done, like |
| 235 // allocation. |
| 236 union { |
| 237 Handle<TypeFeedbackVector> vector_handle_; |
| 238 TypeFeedbackVector* vector_; |
| 239 }; |
| 240 bool use_handle_; |
| 241 FeedbackVectorICSlot slot_; |
| 242 }; |
| 243 |
| 244 |
| 245 class CallICNexus : public FeedbackNexus { |
| 246 public: |
| 247 CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorICSlot slot) |
| 248 : FeedbackNexus(vector, slot) { |
| 249 DCHECK(vector->GetKind(slot) == Code::CALL_IC); |
| 250 } |
| 251 CallICNexus(TypeFeedbackVector* vector, FeedbackVectorICSlot slot) |
| 252 : FeedbackNexus(vector, slot) { |
| 253 DCHECK(vector->GetKind(slot) == Code::CALL_IC); |
| 254 } |
| 255 |
| 256 void ConfigureUninitialized(); |
| 257 void ConfigureGeneric(); |
| 258 void ConfigureMonomorphicArray(); |
| 259 void ConfigureMonomorphic(Handle<JSFunction> function); |
| 260 |
| 261 virtual InlineCacheState StateFromFeedback() const OVERRIDE; |
| 262 |
| 263 virtual int ExtractMaps(MapHandleList* maps) const OVERRIDE { |
| 264 // CallICs don't record map feedback. |
| 265 return 0; |
| 266 } |
| 267 virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const OVERRIDE { |
| 268 return MaybeHandle<Code>(); |
| 269 } |
| 270 virtual bool FindHandlers(CodeHandleList* code_list, |
| 271 int length = -1) const OVERRIDE { |
| 272 return length == 0; |
| 273 } |
| 274 }; |
150 } | 275 } |
151 } // namespace v8::internal | 276 } // namespace v8::internal |
152 | 277 |
153 #endif // V8_TRANSITIONS_H_ | 278 #endif // V8_TRANSITIONS_H_ |
OLD | NEW |