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 #include "src/v8.h" | 5 #include "src/v8.h" |
6 #include "test/cctest/cctest.h" | 6 #include "test/cctest/cctest.h" |
7 | 7 |
8 #include "src/api.h" | 8 #include "src/api.h" |
9 #include "src/debug.h" | 9 #include "src/debug.h" |
10 #include "src/execution.h" | 10 #include "src/execution.h" |
11 #include "src/factory.h" | 11 #include "src/factory.h" |
12 #include "src/global-handles.h" | 12 #include "src/global-handles.h" |
13 #include "src/macro-assembler.h" | 13 #include "src/macro-assembler.h" |
14 #include "src/objects.h" | 14 #include "src/objects.h" |
15 | 15 |
16 using namespace v8::internal; | 16 using namespace v8::internal; |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 TEST(VectorStructure) { | 20 TEST(VectorStructure) { |
21 LocalContext context; | 21 LocalContext context; |
22 v8::HandleScope scope(context->GetIsolate()); | 22 v8::HandleScope scope(context->GetIsolate()); |
23 Isolate* isolate = CcTest::i_isolate(); | 23 Isolate* isolate = CcTest::i_isolate(); |
24 Factory* factory = isolate->factory(); | 24 Factory* factory = isolate->factory(); |
25 | 25 |
26 // Empty vectors are the empty fixed array. | 26 // Empty vectors are the empty fixed array. |
27 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(0, 0); | 27 FeedbackVectorSpec empty; |
| 28 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty); |
28 CHECK(Handle<FixedArray>::cast(vector) | 29 CHECK(Handle<FixedArray>::cast(vector) |
29 .is_identical_to(factory->empty_fixed_array())); | 30 .is_identical_to(factory->empty_fixed_array())); |
30 // Which can nonetheless be queried. | 31 // Which can nonetheless be queried. |
31 CHECK_EQ(0, vector->ic_with_type_info_count()); | 32 CHECK_EQ(0, vector->ic_with_type_info_count()); |
32 CHECK_EQ(0, vector->ic_generic_count()); | 33 CHECK_EQ(0, vector->ic_generic_count()); |
33 CHECK_EQ(0, vector->Slots()); | 34 CHECK_EQ(0, vector->Slots()); |
34 CHECK_EQ(0, vector->ICSlots()); | 35 CHECK_EQ(0, vector->ICSlots()); |
35 | 36 |
36 vector = factory->NewTypeFeedbackVector(1, 0); | 37 FeedbackVectorSpec one_slot(1, 0); |
| 38 vector = factory->NewTypeFeedbackVector(one_slot); |
37 CHECK_EQ(1, vector->Slots()); | 39 CHECK_EQ(1, vector->Slots()); |
38 CHECK_EQ(0, vector->ICSlots()); | 40 CHECK_EQ(0, vector->ICSlots()); |
39 | 41 |
40 vector = factory->NewTypeFeedbackVector(0, 1); | 42 FeedbackVectorSpec one_icslot(0, 1); |
| 43 vector = factory->NewTypeFeedbackVector(one_icslot); |
41 CHECK_EQ(0, vector->Slots()); | 44 CHECK_EQ(0, vector->Slots()); |
42 CHECK_EQ(1, vector->ICSlots()); | 45 CHECK_EQ(1, vector->ICSlots()); |
43 | 46 |
44 vector = factory->NewTypeFeedbackVector(3, 5); | 47 FeedbackVectorSpec spec(3, 5); |
| 48 vector = factory->NewTypeFeedbackVector(spec); |
45 CHECK_EQ(3, vector->Slots()); | 49 CHECK_EQ(3, vector->Slots()); |
46 CHECK_EQ(5, vector->ICSlots()); | 50 CHECK_EQ(5, vector->ICSlots()); |
47 | 51 |
48 int metadata_length = vector->ic_metadata_length(); | 52 int metadata_length = vector->ic_metadata_length(); |
49 if (!FLAG_vector_ics) { | 53 if (!FLAG_vector_ics) { |
50 CHECK_EQ(0, metadata_length); | 54 CHECK_EQ(0, metadata_length); |
51 } else { | 55 } else { |
52 CHECK(metadata_length > 0); | 56 CHECK(metadata_length > 0); |
53 } | 57 } |
54 | 58 |
55 int index = vector->GetIndex(FeedbackVectorSlot(0)); | 59 int index = vector->GetIndex(FeedbackVectorSlot(0)); |
| 60 |
56 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index); | 61 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index); |
57 CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index)); | 62 CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index)); |
58 | 63 |
59 index = vector->GetIndex(FeedbackVectorICSlot(0)); | 64 index = vector->GetIndex(FeedbackVectorICSlot(0)); |
60 CHECK_EQ(index, | 65 CHECK_EQ(index, |
61 TypeFeedbackVector::kReservedIndexCount + metadata_length + 3); | 66 TypeFeedbackVector::kReservedIndexCount + metadata_length + 3); |
62 CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index)); | 67 CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index)); |
63 | 68 |
64 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5, | 69 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5, |
65 vector->length()); | 70 vector->length()); |
66 } | 71 } |
67 | 72 |
68 | 73 |
69 // IC slots need an encoding to recognize what is in there. | 74 // IC slots need an encoding to recognize what is in there. |
70 TEST(VectorICMetadata) { | 75 TEST(VectorICMetadata) { |
71 LocalContext context; | 76 LocalContext context; |
72 v8::HandleScope scope(context->GetIsolate()); | 77 v8::HandleScope scope(context->GetIsolate()); |
73 if (!FLAG_vector_ics) { | 78 if (!FLAG_vector_ics) { |
74 // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so | 79 // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so |
75 // there is no need for metadata to describe the slots. | 80 // there is no need for metadata to describe the slots. |
76 return; | 81 return; |
77 } | 82 } |
78 Isolate* isolate = CcTest::i_isolate(); | 83 Isolate* isolate = CcTest::i_isolate(); |
79 Factory* factory = isolate->factory(); | 84 Factory* factory = isolate->factory(); |
80 | 85 |
81 Handle<TypeFeedbackVector> vector = | 86 FeedbackVectorSpec spec(10, 3 * 10); |
82 factory->NewTypeFeedbackVector(10, 3 * 10); | |
83 CHECK_EQ(10, vector->Slots()); | |
84 CHECK_EQ(3 * 10, vector->ICSlots()); | |
85 | |
86 // Set metadata. | 87 // Set metadata. |
87 for (int i = 0; i < 30; i++) { | 88 for (int i = 0; i < 30; i++) { |
88 Code::Kind kind; | 89 Code::Kind kind; |
89 if (i % 3 == 0) { | 90 if (i % 3 == 0) { |
90 kind = Code::CALL_IC; | 91 kind = Code::CALL_IC; |
91 } else if (i % 3 == 1) { | 92 } else if (i % 3 == 1) { |
92 kind = Code::LOAD_IC; | 93 kind = Code::LOAD_IC; |
93 } else { | 94 } else { |
94 kind = Code::KEYED_LOAD_IC; | 95 kind = Code::KEYED_LOAD_IC; |
95 } | 96 } |
96 vector->SetKind(FeedbackVectorICSlot(i), kind); | 97 spec.SetKind(i, kind); |
97 } | 98 } |
98 | 99 |
| 100 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec); |
| 101 CHECK_EQ(10, vector->Slots()); |
| 102 CHECK_EQ(3 * 10, vector->ICSlots()); |
| 103 |
99 // Meanwhile set some feedback values and type feedback values to | 104 // Meanwhile set some feedback values and type feedback values to |
100 // verify the data structure remains intact. | 105 // verify the data structure remains intact. |
101 vector->change_ic_with_type_info_count(100); | 106 vector->change_ic_with_type_info_count(100); |
102 vector->change_ic_generic_count(3333); | 107 vector->change_ic_generic_count(3333); |
103 vector->Set(FeedbackVectorSlot(0), *vector); | 108 vector->Set(FeedbackVectorSlot(0), *vector); |
104 | 109 |
105 // Verify the metadata remains the same. | 110 // Verify the metadata is correctly set up from the spec. |
106 for (int i = 0; i < 30; i++) { | 111 for (int i = 0; i < 30; i++) { |
107 Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i)); | 112 Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i)); |
108 if (i % 3 == 0) { | 113 if (i % 3 == 0) { |
109 CHECK_EQ(Code::CALL_IC, kind); | 114 CHECK_EQ(Code::CALL_IC, kind); |
110 } else if (i % 3 == 1) { | 115 } else if (i % 3 == 1) { |
111 CHECK_EQ(Code::LOAD_IC, kind); | 116 CHECK_EQ(Code::LOAD_IC, kind); |
112 } else { | 117 } else { |
113 CHECK_EQ(Code::KEYED_LOAD_IC, kind); | 118 CHECK_EQ(Code::KEYED_LOAD_IC, kind); |
114 } | 119 } |
115 } | 120 } |
116 } | 121 } |
117 | 122 |
118 | 123 |
119 TEST(VectorSlotClearing) { | 124 TEST(VectorSlotClearing) { |
120 LocalContext context; | 125 LocalContext context; |
121 v8::HandleScope scope(context->GetIsolate()); | 126 v8::HandleScope scope(context->GetIsolate()); |
122 Isolate* isolate = CcTest::i_isolate(); | 127 Isolate* isolate = CcTest::i_isolate(); |
123 Factory* factory = isolate->factory(); | 128 Factory* factory = isolate->factory(); |
124 | 129 |
125 // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots. | 130 // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots. |
126 // The reason is that FeedbackVectorICSlots need a full code environment | 131 // The reason is that FeedbackVectorICSlots need a full code environment |
127 // to fully test (See VectorICProfilerStatistics test below). | 132 // to fully test (See VectorICProfilerStatistics test below). |
128 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(5, 0); | 133 FeedbackVectorSpec spec(5, 0); |
| 134 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec); |
129 | 135 |
130 // Fill with information | 136 // Fill with information |
131 vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1)); | 137 vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1)); |
132 vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map()); | 138 vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map()); |
133 Handle<AllocationSite> site = factory->NewAllocationSite(); | 139 Handle<AllocationSite> site = factory->NewAllocationSite(); |
134 vector->Set(FeedbackVectorSlot(2), *site); | 140 vector->Set(FeedbackVectorSlot(2), *site); |
135 | 141 |
136 vector->ClearSlots(NULL); | 142 vector->ClearSlots(NULL); |
137 | 143 |
138 // The feedback vector slots are cleared. AllocationSites are granted | 144 // The feedback vector slots are cleared. AllocationSites are granted |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 CHECK_EQ(0, feedback_vector->ic_with_type_info_count()); | 187 CHECK_EQ(0, feedback_vector->ic_with_type_info_count()); |
182 CHECK_EQ(0, feedback_vector->ic_generic_count()); | 188 CHECK_EQ(0, feedback_vector->ic_generic_count()); |
183 | 189 |
184 // The Array function is special. A call to array remains monomorphic | 190 // The Array function is special. A call to array remains monomorphic |
185 // and isn't cleared by gc because an AllocationSite is being held. | 191 // and isn't cleared by gc because an AllocationSite is being held. |
186 CompileRun("f(Array);"); | 192 CompileRun("f(Array);"); |
187 feedback_vector = f->shared()->feedback_vector(); | 193 feedback_vector = f->shared()->feedback_vector(); |
188 CHECK_EQ(1, feedback_vector->ic_with_type_info_count()); | 194 CHECK_EQ(1, feedback_vector->ic_with_type_info_count()); |
189 CHECK_EQ(0, feedback_vector->ic_generic_count()); | 195 CHECK_EQ(0, feedback_vector->ic_generic_count()); |
190 | 196 |
191 int ic_slot = FLAG_vector_ics ? 1 : 0; | 197 int ic_slot = 0; |
192 CHECK( | 198 CHECK( |
193 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); | 199 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); |
194 heap->CollectAllGarbage(i::Heap::kNoGCFlags); | 200 heap->CollectAllGarbage(i::Heap::kNoGCFlags); |
195 feedback_vector = f->shared()->feedback_vector(); | 201 feedback_vector = f->shared()->feedback_vector(); |
196 CHECK_EQ(1, feedback_vector->ic_with_type_info_count()); | 202 CHECK_EQ(1, feedback_vector->ic_with_type_info_count()); |
197 CHECK_EQ(0, feedback_vector->ic_generic_count()); | 203 CHECK_EQ(0, feedback_vector->ic_generic_count()); |
198 CHECK( | 204 CHECK( |
199 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); | 205 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite()); |
200 } | 206 } |
201 | 207 |
202 | 208 |
203 TEST(VectorCallICStates) { | 209 TEST(VectorCallICStates) { |
204 if (i::FLAG_always_opt) return; | 210 if (i::FLAG_always_opt) return; |
205 CcTest::InitializeVM(); | 211 CcTest::InitializeVM(); |
206 LocalContext context; | 212 LocalContext context; |
207 v8::HandleScope scope(context->GetIsolate()); | 213 v8::HandleScope scope(context->GetIsolate()); |
208 Isolate* isolate = CcTest::i_isolate(); | 214 Isolate* isolate = CcTest::i_isolate(); |
209 Heap* heap = isolate->heap(); | 215 Heap* heap = isolate->heap(); |
210 | 216 |
211 // Make sure function f has a call that uses a type feedback slot. | 217 // Make sure function f has a call that uses a type feedback slot. |
212 CompileRun( | 218 CompileRun( |
213 "function foo() { return 17; }" | 219 "function foo() { return 17; }" |
214 "function f(a) { a(); } f(foo);"); | 220 "function f(a) { a(); } f(foo);"); |
215 Handle<JSFunction> f = v8::Utils::OpenHandle( | 221 Handle<JSFunction> f = v8::Utils::OpenHandle( |
216 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); | 222 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); |
217 // There should be one IC. | 223 // There should be one IC. |
218 Handle<TypeFeedbackVector> feedback_vector = | 224 Handle<TypeFeedbackVector> feedback_vector = |
219 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate); | 225 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate); |
220 FeedbackVectorICSlot slot(FLAG_vector_ics ? 1 : 0); | 226 FeedbackVectorICSlot slot(0); |
221 CallICNexus nexus(feedback_vector, slot); | 227 CallICNexus nexus(feedback_vector, slot); |
222 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); | 228 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
223 // CallIC doesn't return map feedback. | 229 // CallIC doesn't return map feedback. |
224 CHECK_EQ(NULL, nexus.FindFirstMap()); | 230 CHECK_EQ(NULL, nexus.FindFirstMap()); |
225 | 231 |
226 CompileRun("f(function() { return 16; })"); | 232 CompileRun("f(function() { return 16; })"); |
227 CHECK_EQ(GENERIC, nexus.StateFromFeedback()); | 233 CHECK_EQ(GENERIC, nexus.StateFromFeedback()); |
228 | 234 |
229 // After a collection, state should be reset to UNINITIALIZED. | 235 // After a collection, state should be reset to UNINITIALIZED. |
230 heap->CollectAllGarbage(i::Heap::kNoGCFlags); | 236 heap->CollectAllGarbage(i::Heap::kNoGCFlags); |
231 CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback()); | 237 CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback()); |
232 | 238 |
233 // Array is special. It will remain monomorphic across gcs and it contains an | 239 // Array is special. It will remain monomorphic across gcs and it contains an |
234 // AllocationSite. | 240 // AllocationSite. |
235 CompileRun("f(Array)"); | 241 CompileRun("f(Array)"); |
236 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); | 242 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
237 CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite()); | 243 CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite()); |
238 | 244 |
239 heap->CollectAllGarbage(i::Heap::kNoGCFlags); | 245 heap->CollectAllGarbage(i::Heap::kNoGCFlags); |
240 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); | 246 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
241 } | 247 } |
| 248 |
| 249 |
| 250 TEST(VectorLoadICStates) { |
| 251 if (i::FLAG_always_opt || !i::FLAG_vector_ics) return; |
| 252 CcTest::InitializeVM(); |
| 253 LocalContext context; |
| 254 v8::HandleScope scope(context->GetIsolate()); |
| 255 Isolate* isolate = CcTest::i_isolate(); |
| 256 Heap* heap = isolate->heap(); |
| 257 |
| 258 // Make sure function f has a call that uses a type feedback slot. |
| 259 CompileRun( |
| 260 "var o = { foo: 3 };" |
| 261 "function f(a) { return a.foo; } f(o);"); |
| 262 Handle<JSFunction> f = v8::Utils::OpenHandle( |
| 263 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f")))); |
| 264 // There should be one IC. |
| 265 Handle<TypeFeedbackVector> feedback_vector = |
| 266 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate); |
| 267 FeedbackVectorICSlot slot(0); |
| 268 LoadICNexus nexus(feedback_vector, slot); |
| 269 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback()); |
| 270 |
| 271 CompileRun("f(o)"); |
| 272 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 273 // Verify that the monomorphic map is the one we expect. |
| 274 Handle<JSObject> o = v8::Utils::OpenHandle( |
| 275 *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o")))); |
| 276 CHECK_EQ(o->map(), nexus.FindFirstMap()); |
| 277 |
| 278 // Now go polymorphic. |
| 279 CompileRun("f({ blarg: 3, foo: 2 })"); |
| 280 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 281 |
| 282 CompileRun( |
| 283 "delete o.foo;" |
| 284 "f(o)"); |
| 285 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 286 |
| 287 CompileRun("f({ blarg: 3, torino: 10, foo: 2 })"); |
| 288 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 289 MapHandleList maps; |
| 290 nexus.FindAllMaps(&maps); |
| 291 CHECK_EQ(4, maps.length()); |
| 292 |
| 293 // Finally driven megamorphic. |
| 294 CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })"); |
| 295 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback()); |
| 296 CHECK_EQ(NULL, nexus.FindFirstMap()); |
| 297 |
| 298 // After a collection, state should be reset to PREMONOMORPHIC. |
| 299 heap->CollectAllGarbage(i::Heap::kNoGCFlags); |
| 300 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback()); |
242 } | 301 } |
| 302 } |
OLD | NEW |