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));
75 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
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 Code* code = f->shared()->code();
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 TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
181 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
182 CHECK_EQ(0, feedback_vector->ic_generic_count());
184 // Now send the information generic.
185 CompileRun("f(Object);");
186 feedback_vector = f->shared()->feedback_vector();
187 CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
188 CHECK_EQ(1, feedback_vector->ic_generic_count());
190 // A collection will make the site uninitialized again.
191 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
192 feedback_vector = f->shared()->feedback_vector();
193 CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
194 CHECK_EQ(0, feedback_vector->ic_generic_count());
196 // The Array function is special. A call to array remains monomorphic
197 // and isn't cleared by gc because an AllocationSite is being held.
198 CompileRun("f(Array);");
199 feedback_vector = f->shared()->feedback_vector();
200 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
201 CHECK_EQ(0, feedback_vector->ic_generic_count());
205 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
206 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
207 feedback_vector = f->shared()->feedback_vector();
208 CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
209 CHECK_EQ(0, feedback_vector->ic_generic_count());
211 feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
215 TEST(VectorCallICStates) {
216 if (i::FLAG_always_opt) return;
217 CcTest::InitializeVM();
218 LocalContext context;
219 v8::HandleScope scope(context->GetIsolate());
220 Isolate* isolate = CcTest::i_isolate();
221 Heap* heap = isolate->heap();
223 // Make sure function f has a call that uses a type feedback slot.
225 "function foo() { return 17; }"
226 "function f(a) { a(); } f(foo);");
227 Handle<JSFunction> f = v8::Utils::OpenHandle(
228 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
229 // There should be one IC.
230 Handle<TypeFeedbackVector> feedback_vector =
231 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
232 FeedbackVectorICSlot slot(0);
233 CallICNexus nexus(feedback_vector, slot);
234 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
235 // CallIC doesn't return map feedback.
236 CHECK(!nexus.FindFirstMap());
238 CompileRun("f(function() { return 16; })");
239 CHECK_EQ(GENERIC, nexus.StateFromFeedback());
241 // After a collection, state should be reset to UNINITIALIZED.
242 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
243 CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
245 // Array is special. It will remain monomorphic across gcs and it contains an
247 CompileRun("f(Array)");
248 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
249 CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->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(VectorLoadICOnSmi) {
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();
316 Heap* heap = isolate->heap();
318 // Make sure function f has a call that uses a type feedback slot.
320 "var o = { foo: 3 };"
321 "function f(a) { return a.foo; } f(o);");
322 Handle<JSFunction> f = v8::Utils::OpenHandle(
323 *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
324 // There should be one IC.
325 Handle<TypeFeedbackVector> feedback_vector =
326 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
327 FeedbackVectorICSlot slot(0);
328 LoadICNexus nexus(feedback_vector, slot);
329 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
332 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
333 // Verify that the monomorphic map is the one we expect.
334 Map* number_map = heap->heap_number_map();
335 CHECK_EQ(number_map, nexus.FindFirstMap());
337 // Now go polymorphic on o.
339 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
342 nexus.FindAllMaps(&maps);
343 CHECK_EQ(2, maps.length());
345 // One of the maps should be the o map.
346 Handle<JSObject> o = v8::Utils::OpenHandle(
347 *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
348 bool number_map_found = false;
349 bool o_map_found = false;
350 for (int i = 0; i < maps.length(); i++) {
351 Handle<Map> current = maps[i];
352 if (*current == number_map)
353 number_map_found = true;
354 else if (*current == o->map())
357 CHECK(number_map_found && o_map_found);
359 // The degree of polymorphism doesn't change.
360 CompileRun("f(100)");
361 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
363 nexus.FindAllMaps(&maps2);
364 CHECK_EQ(2, maps2.length());