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
3 // found in the LICENSE file.
6 #include "test/cctest/cctest.h"
10 #include "src/execution.h"
11 #include "src/factory.h"
12 #include "src/global-handles.h"
13 #include "src/macro-assembler.h"
14 #include "src/objects.h"
16 using namespace v8::internal;
20 TEST(VectorStructure) {
22 v8::HandleScope scope(context->GetIsolate());
23 Isolate* isolate = CcTest::i_isolate();
24 Factory* factory = isolate->factory();
26 // Empty vectors are the empty fixed array.
27 FeedbackVectorSpec empty;
28 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
29 CHECK(Handle<FixedArray>::cast(vector)
30 .is_identical_to(factory->empty_fixed_array()));
31 // Which can nonetheless be queried.
32 CHECK_EQ(0, vector->ic_with_type_info_count());
33 CHECK_EQ(0, vector->ic_generic_count());
34 CHECK_EQ(0, vector->Slots());
35 CHECK_EQ(0, vector->ICSlots());
37 FeedbackVectorSpec one_slot(1, 0);
38 vector = factory->NewTypeFeedbackVector(one_slot);
39 CHECK_EQ(1, vector->Slots());
40 CHECK_EQ(0, vector->ICSlots());
42 FeedbackVectorSpec one_icslot(0, 1);
43 if (FLAG_vector_ics) {
44 one_icslot.SetKind(0, Code::CALL_IC);
46 vector = factory->NewTypeFeedbackVector(one_icslot);
47 CHECK_EQ(0, vector->Slots());
48 CHECK_EQ(1, vector->ICSlots());
50 FeedbackVectorSpec spec(3, 5);
51 if (FLAG_vector_ics) {
52 for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
54 vector = factory->NewTypeFeedbackVector(spec);
55 CHECK_EQ(3, vector->Slots());
56 CHECK_EQ(5, vector->ICSlots());
58 int metadata_length = vector->ic_metadata_length();
59 if (!FLAG_vector_ics) {
60 CHECK_EQ(0, metadata_length);
62 CHECK(metadata_length > 0);
65 int index = vector->GetIndex(FeedbackVectorSlot(0));
67 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
68 CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
70 index = vector->GetIndex(FeedbackVectorICSlot(0));
72 TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
73 CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
74 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 +
75 5 * TypeFeedbackVector::elements_per_ic_slot(),
80 // IC slots need an encoding to recognize what is in there.
81 TEST(VectorICMetadata) {
83 v8::HandleScope scope(context->GetIsolate());
84 if (!FLAG_vector_ics) {
85 // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
86 // there is no need for metadata to describe the slots.
89 Isolate* isolate = CcTest::i_isolate();
90 Factory* factory = isolate->factory();
92 FeedbackVectorSpec spec(10, 3 * 10);
94 for (int i = 0; i < 30; i++) {
98 } else if (i % 3 == 1) {
101 kind = Code::KEYED_LOAD_IC;
103 spec.SetKind(i, kind);
106 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
107 CHECK_EQ(10, vector->Slots());
108 CHECK_EQ(3 * 10, vector->ICSlots());
110 // Meanwhile set some feedback values and type feedback values to
111 // verify the data structure remains intact.
112 vector->change_ic_with_type_info_count(100);
113 vector->change_ic_generic_count(3333);
114 vector->Set(FeedbackVectorSlot(0), *vector);
116 // Verify the metadata is correctly set up from the spec.
117 for (int i = 0; i < 30; i++) {
118 Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
120 CHECK_EQ(Code::CALL_IC, kind);
121 } else if (i % 3 == 1) {
122 CHECK_EQ(Code::LOAD_IC, kind);
124 CHECK_EQ(Code::KEYED_LOAD_IC, kind);
130 TEST(VectorSlotClearing) {
131 LocalContext context;
132 v8::HandleScope scope(context->GetIsolate());
133 Isolate* isolate = CcTest::i_isolate();
134 Factory* factory = isolate->factory();
136 // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
137 // The reason is that FeedbackVectorICSlots need a full code environment
138 // to fully test (See VectorICProfilerStatistics test below).
139 FeedbackVectorSpec spec(5, 0);
140 Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
142 // Fill with information
143 vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
144 vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
145 Handle<AllocationSite> site = factory->NewAllocationSite();
146 vector->Set(FeedbackVectorSlot(2), *site);
148 vector->ClearSlots(NULL);
150 // The feedback vector slots are cleared. AllocationSites are granted
151 // an exemption from clearing, as are smis.
152 CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
153 CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
154 vector->Get(FeedbackVectorSlot(1)));
155 CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
159 TEST(VectorICProfilerStatistics) {
160 if (i::FLAG_always_opt) return;
161 CcTest::InitializeVM();
162 LocalContext context;
163 v8::HandleScope scope(context->GetIsolate());
164 Isolate* isolate = CcTest::i_isolate();
165 Heap* heap = isolate->heap();
167 // Make sure function f has a call that uses a type feedback slot.
170 "function f(a) { a(); } f(fun);");
171 Handle<JSFunction> f = v8::Utils::OpenHandle(
172 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
173 // There should be one IC.
174 Handle<Code> code = handle(f->shared()->code(), isolate);
175 TypeFeedbackInfo* feedback_info =
176 TypeFeedbackInfo::cast(code->type_feedback_info());
177 CHECK_EQ(1, feedback_info->ic_total_count());
178 CHECK_EQ(0, feedback_info->ic_with_type_info_count());
179 CHECK_EQ(0, feedback_info->ic_generic_count());
180 Handle<TypeFeedbackVector> feedback_vector =
181 handle(f->shared()->feedback_vector(), isolate);
183 CallICNexus nexus(feedback_vector, FeedbackVectorICSlot(ic_slot));
184 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
185 CHECK_EQ(0, feedback_vector->ic_generic_count());
187 // Now send the information generic.
188 CompileRun("f(Object);");
189 CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
190 CHECK_EQ(1, feedback_vector->ic_generic_count());
192 // A collection will not affect the site.
193 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
194 CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
195 CHECK_EQ(1, feedback_vector->ic_generic_count());
197 // The Array function is special. A call to array remains monomorphic
198 // and isn't cleared by gc because an AllocationSite is being held.
199 // Clear the IC manually in order to test this case.
201 CompileRun("f(Array);");
202 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
203 CHECK_EQ(0, feedback_vector->ic_generic_count());
206 CHECK(nexus.GetFeedback()->IsAllocationSite());
207 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
208 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
209 CHECK_EQ(0, feedback_vector->ic_generic_count());
210 CHECK(nexus.GetFeedback()->IsAllocationSite());
214 TEST(VectorCallICStates) {
215 if (i::FLAG_always_opt) return;
216 CcTest::InitializeVM();
217 LocalContext context;
218 v8::HandleScope scope(context->GetIsolate());
219 Isolate* isolate = CcTest::i_isolate();
220 Heap* heap = isolate->heap();
222 // Make sure function f has a call that uses a type feedback slot.
224 "function foo() { return 17; }"
225 "function f(a) { a(); } f(foo);");
226 Handle<JSFunction> f = v8::Utils::OpenHandle(
227 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
228 // There should be one IC.
229 Handle<TypeFeedbackVector> feedback_vector =
230 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
231 FeedbackVectorICSlot slot(0);
232 CallICNexus nexus(feedback_vector, slot);
233 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
234 // CallIC doesn't return map feedback.
235 CHECK(!nexus.FindFirstMap());
237 CompileRun("f(function() { return 16; })");
238 CHECK_EQ(GENERIC, nexus.StateFromFeedback());
240 // After a collection, state should remain GENERIC.
241 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
242 CHECK_EQ(GENERIC, nexus.StateFromFeedback());
244 // A call to Array is special, it contains an AllocationSite as feedback.
245 // Clear the IC manually in order to test this case.
246 nexus.Clear(f->shared()->code());
247 CompileRun("f(Array)");
248 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
249 CHECK(nexus.GetFeedback()->IsAllocationSite());
251 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
252 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
256 TEST(VectorLoadICStates) {
257 if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
258 CcTest::InitializeVM();
259 LocalContext context;
260 v8::HandleScope scope(context->GetIsolate());
261 Isolate* isolate = CcTest::i_isolate();
262 Heap* heap = isolate->heap();
264 // Make sure function f has a call that uses a type feedback slot.
266 "var o = { foo: 3 };"
267 "function f(a) { return a.foo; } f(o);");
268 Handle<JSFunction> f = v8::Utils::OpenHandle(
269 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
270 // There should be one IC.
271 Handle<TypeFeedbackVector> feedback_vector =
272 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
273 FeedbackVectorICSlot slot(0);
274 LoadICNexus nexus(feedback_vector, slot);
275 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
278 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
279 // Verify that the monomorphic map is the one we expect.
280 Handle<JSObject> o = v8::Utils::OpenHandle(
281 *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
282 CHECK_EQ(o->map(), nexus.FindFirstMap());
284 // Now go polymorphic.
285 CompileRun("f({ blarg: 3, foo: 2 })");
286 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
291 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
293 CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
294 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
296 nexus.FindAllMaps(&maps);
297 CHECK_EQ(4, maps.length());
299 // Finally driven megamorphic.
300 CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
301 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
302 CHECK(!nexus.FindFirstMap());
304 // After a collection, state should not be reset to PREMONOMORPHIC.
305 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
306 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
310 TEST(VectorLoadICSlotSharing) {
311 if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
312 CcTest::InitializeVM();
313 LocalContext context;
314 v8::HandleScope scope(context->GetIsolate());
315 Isolate* isolate = CcTest::i_isolate();
317 // Function f has 3 LoadICs, one for each o, but the ICs share the same
318 // feedback vector IC slot.
326 Handle<JSFunction> f = v8::Utils::OpenHandle(
327 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
328 // There should be one IC slot.
329 Handle<TypeFeedbackVector> feedback_vector =
330 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
331 CHECK_EQ(1, feedback_vector->ICSlots());
332 FeedbackVectorICSlot slot(0);
333 LoadICNexus nexus(feedback_vector, slot);
334 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
338 TEST(VectorLoadICOnSmi) {
339 if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
340 CcTest::InitializeVM();
341 LocalContext context;
342 v8::HandleScope scope(context->GetIsolate());
343 Isolate* isolate = CcTest::i_isolate();
344 Heap* heap = isolate->heap();
346 // Make sure function f has a call that uses a type feedback slot.
348 "var o = { foo: 3 };"
349 "function f(a) { return a.foo; } f(o);");
350 Handle<JSFunction> f = v8::Utils::OpenHandle(
351 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
352 // There should be one IC.
353 Handle<TypeFeedbackVector> feedback_vector =
354 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
355 FeedbackVectorICSlot slot(0);
356 LoadICNexus nexus(feedback_vector, slot);
357 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
360 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
361 // Verify that the monomorphic map is the one we expect.
362 Map* number_map = heap->heap_number_map();
363 CHECK_EQ(number_map, nexus.FindFirstMap());
365 // Now go polymorphic on o.
367 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
370 nexus.FindAllMaps(&maps);
371 CHECK_EQ(2, maps.length());
373 // One of the maps should be the o map.
374 Handle<JSObject> o = v8::Utils::OpenHandle(
375 *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
376 bool number_map_found = false;
377 bool o_map_found = false;
378 for (int i = 0; i < maps.length(); i++) {
379 Handle<Map> current = maps[i];
380 if (*current == number_map)
381 number_map_found = true;
382 else if (*current == o->map())
385 CHECK(number_map_found && o_map_found);
387 // The degree of polymorphism doesn't change.
388 CompileRun("f(100)");
389 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
391 nexus.FindAllMaps(&maps2);
392 CHECK_EQ(2, maps2.length());