Feedback vector: ASAN found memory leaks during AST Numbering pass.
[platform/upstream/v8.git] / test / cctest / test-feedback-vector.cc
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.
4
5 #include "src/v8.h"
6 #include "test/cctest/cctest.h"
7
8 #include "src/api.h"
9 #include "src/debug.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"
15
16 using namespace v8::internal;
17
18 namespace {
19
20 TEST(VectorStructure) {
21   LocalContext context;
22   v8::HandleScope scope(context->GetIsolate());
23   Isolate* isolate = CcTest::i_isolate();
24   Factory* factory = isolate->factory();
25   Zone* zone = isolate->runtime_zone();
26
27   // Empty vectors are the empty fixed array.
28   FeedbackVectorSpec empty;
29   Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&empty);
30   CHECK(Handle<FixedArray>::cast(vector)
31             .is_identical_to(factory->empty_fixed_array()));
32   // Which can nonetheless be queried.
33   CHECK_EQ(0, vector->ic_with_type_info_count());
34   CHECK_EQ(0, vector->ic_generic_count());
35   CHECK_EQ(0, vector->Slots());
36   CHECK_EQ(0, vector->ICSlots());
37
38   FeedbackVectorSpec one_slot(1);
39   vector = factory->NewTypeFeedbackVector(&one_slot);
40   CHECK_EQ(1, vector->Slots());
41   CHECK_EQ(0, vector->ICSlots());
42
43   FeedbackVectorSpec one_icslot(0, Code::CALL_IC);
44   vector = factory->NewTypeFeedbackVector(&one_icslot);
45   CHECK_EQ(0, vector->Slots());
46   CHECK_EQ(1, vector->ICSlots());
47
48   ZoneFeedbackVectorSpec spec(zone, 3, 5);
49   if (FLAG_vector_ics) {
50     for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
51   }
52   vector = factory->NewTypeFeedbackVector(&spec);
53   CHECK_EQ(3, vector->Slots());
54   CHECK_EQ(5, vector->ICSlots());
55
56   int metadata_length = vector->ic_metadata_length();
57   if (!FLAG_vector_ics) {
58     CHECK_EQ(0, metadata_length);
59   } else {
60     CHECK(metadata_length > 0);
61   }
62
63   int index = vector->GetIndex(FeedbackVectorSlot(0));
64
65   CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
66   CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
67
68   index = vector->GetIndex(FeedbackVectorICSlot(0));
69   CHECK_EQ(index,
70            TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
71   CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
72   CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 +
73                5 * TypeFeedbackVector::elements_per_ic_slot(),
74            vector->length());
75 }
76
77
78 // IC slots need an encoding to recognize what is in there.
79 TEST(VectorICMetadata) {
80   LocalContext context;
81   v8::HandleScope scope(context->GetIsolate());
82   if (!FLAG_vector_ics) {
83     // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
84     // there is no need for metadata to describe the slots.
85     return;
86   }
87   Isolate* isolate = CcTest::i_isolate();
88   Factory* factory = isolate->factory();
89   Zone* zone = isolate->runtime_zone();
90
91   ZoneFeedbackVectorSpec spec(zone, 10, 3 * 10);
92   // Set metadata.
93   for (int i = 0; i < 30; i++) {
94     Code::Kind kind;
95     if (i % 3 == 0) {
96       kind = Code::CALL_IC;
97     } else if (i % 3 == 1) {
98       kind = Code::LOAD_IC;
99     } else {
100       kind = Code::KEYED_LOAD_IC;
101     }
102     spec.SetKind(i, kind);
103   }
104
105   Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec);
106   CHECK_EQ(10, vector->Slots());
107   CHECK_EQ(3 * 10, vector->ICSlots());
108
109   // Meanwhile set some feedback values and type feedback values to
110   // verify the data structure remains intact.
111   vector->change_ic_with_type_info_count(100);
112   vector->change_ic_generic_count(3333);
113   vector->Set(FeedbackVectorSlot(0), *vector);
114
115   // Verify the metadata is correctly set up from the spec.
116   for (int i = 0; i < 30; i++) {
117     Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
118     if (i % 3 == 0) {
119       CHECK_EQ(Code::CALL_IC, kind);
120     } else if (i % 3 == 1) {
121       CHECK_EQ(Code::LOAD_IC, kind);
122     } else {
123       CHECK_EQ(Code::KEYED_LOAD_IC, kind);
124     }
125   }
126 }
127
128
129 TEST(VectorSlotClearing) {
130   LocalContext context;
131   v8::HandleScope scope(context->GetIsolate());
132   Isolate* isolate = CcTest::i_isolate();
133   Factory* factory = isolate->factory();
134
135   // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
136   // The reason is that FeedbackVectorICSlots need a full code environment
137   // to fully test (See VectorICProfilerStatistics test below).
138   FeedbackVectorSpec spec(5);
139   Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(&spec);
140
141   // Fill with information
142   vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
143   vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
144   Handle<AllocationSite> site = factory->NewAllocationSite();
145   vector->Set(FeedbackVectorSlot(2), *site);
146
147   vector->ClearSlots(NULL);
148
149   // The feedback vector slots are cleared. AllocationSites are granted
150   // an exemption from clearing, as are smis.
151   CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
152   CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
153            vector->Get(FeedbackVectorSlot(1)));
154   CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
155 }
156
157
158 TEST(VectorICProfilerStatistics) {
159   if (i::FLAG_always_opt) return;
160   CcTest::InitializeVM();
161   LocalContext context;
162   v8::HandleScope scope(context->GetIsolate());
163   Isolate* isolate = CcTest::i_isolate();
164   Heap* heap = isolate->heap();
165
166   // Make sure function f has a call that uses a type feedback slot.
167   CompileRun(
168       "function fun() {};"
169       "function f(a) { a(); } f(fun);");
170   Handle<JSFunction> f = v8::Utils::OpenHandle(
171       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
172   // There should be one IC.
173   Handle<Code> code = handle(f->shared()->code(), isolate);
174   TypeFeedbackInfo* feedback_info =
175       TypeFeedbackInfo::cast(code->type_feedback_info());
176   CHECK_EQ(1, feedback_info->ic_total_count());
177   CHECK_EQ(0, feedback_info->ic_with_type_info_count());
178   CHECK_EQ(0, feedback_info->ic_generic_count());
179   Handle<TypeFeedbackVector> feedback_vector =
180       handle(f->shared()->feedback_vector(), isolate);
181   int ic_slot = 0;
182   CallICNexus nexus(feedback_vector, FeedbackVectorICSlot(ic_slot));
183   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
184   CHECK_EQ(0, feedback_vector->ic_generic_count());
185
186   // Now send the information generic.
187   CompileRun("f(Object);");
188   CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
189   CHECK_EQ(1, feedback_vector->ic_generic_count());
190
191   // A collection will not affect the site.
192   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
193   CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
194   CHECK_EQ(1, feedback_vector->ic_generic_count());
195
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   // Clear the IC manually in order to test this case.
199   nexus.Clear(*code);
200   CompileRun("f(Array);");
201   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
202   CHECK_EQ(0, feedback_vector->ic_generic_count());
203
204
205   CHECK(nexus.GetFeedback()->IsAllocationSite());
206   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
207   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
208   CHECK_EQ(0, feedback_vector->ic_generic_count());
209   CHECK(nexus.GetFeedback()->IsAllocationSite());
210 }
211
212
213 TEST(VectorCallICStates) {
214   if (i::FLAG_always_opt) return;
215   CcTest::InitializeVM();
216   LocalContext context;
217   v8::HandleScope scope(context->GetIsolate());
218   Isolate* isolate = CcTest::i_isolate();
219   Heap* heap = isolate->heap();
220
221   // Make sure function f has a call that uses a type feedback slot.
222   CompileRun(
223       "function foo() { return 17; }"
224       "function f(a) { a(); } f(foo);");
225   Handle<JSFunction> f = v8::Utils::OpenHandle(
226       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
227   // There should be one IC.
228   Handle<TypeFeedbackVector> feedback_vector =
229       Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
230   FeedbackVectorICSlot slot(0);
231   CallICNexus nexus(feedback_vector, slot);
232   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
233   // CallIC doesn't return map feedback.
234   CHECK(!nexus.FindFirstMap());
235
236   CompileRun("f(function() { return 16; })");
237   CHECK_EQ(GENERIC, nexus.StateFromFeedback());
238
239   // After a collection, state should remain GENERIC.
240   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
241   CHECK_EQ(GENERIC, nexus.StateFromFeedback());
242
243   // A call to Array is special, it contains an AllocationSite as feedback.
244   // Clear the IC manually in order to test this case.
245   nexus.Clear(f->shared()->code());
246   CompileRun("f(Array)");
247   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
248   CHECK(nexus.GetFeedback()->IsAllocationSite());
249
250   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
251   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
252 }
253
254
255 TEST(VectorLoadICStates) {
256   if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
257   CcTest::InitializeVM();
258   LocalContext context;
259   v8::HandleScope scope(context->GetIsolate());
260   Isolate* isolate = CcTest::i_isolate();
261   Heap* heap = isolate->heap();
262
263   // Make sure function f has a call that uses a type feedback slot.
264   CompileRun(
265       "var o = { foo: 3 };"
266       "function f(a) { return a.foo; } f(o);");
267   Handle<JSFunction> f = v8::Utils::OpenHandle(
268       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
269   // There should be one IC.
270   Handle<TypeFeedbackVector> feedback_vector =
271       Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
272   FeedbackVectorICSlot slot(0);
273   LoadICNexus nexus(feedback_vector, slot);
274   CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
275
276   CompileRun("f(o)");
277   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
278   // Verify that the monomorphic map is the one we expect.
279   Handle<JSObject> o = v8::Utils::OpenHandle(
280       *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
281   CHECK_EQ(o->map(), nexus.FindFirstMap());
282
283   // Now go polymorphic.
284   CompileRun("f({ blarg: 3, foo: 2 })");
285   CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
286
287   CompileRun(
288       "delete o.foo;"
289       "f(o)");
290   CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
291
292   CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
293   CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
294   MapHandleList maps;
295   nexus.FindAllMaps(&maps);
296   CHECK_EQ(4, maps.length());
297
298   // Finally driven megamorphic.
299   CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
300   CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
301   CHECK(!nexus.FindFirstMap());
302
303   // After a collection, state should not be reset to PREMONOMORPHIC.
304   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
305   CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
306 }
307
308
309 TEST(VectorLoadICSlotSharing) {
310   if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
311   CcTest::InitializeVM();
312   LocalContext context;
313   v8::HandleScope scope(context->GetIsolate());
314   Isolate* isolate = CcTest::i_isolate();
315
316   // Function f has 3 LoadICs, one for each o, but the ICs share the same
317   // feedback vector IC slot.
318   CompileRun(
319       "var o = 10;"
320       "function f() {"
321       "  var x = o + 10;"
322       "  return o + x + o;"
323       "}"
324       "f();");
325   Handle<JSFunction> f = v8::Utils::OpenHandle(
326       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
327   // There should be one IC slot.
328   Handle<TypeFeedbackVector> feedback_vector =
329       Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
330   CHECK_EQ(1, feedback_vector->ICSlots());
331   FeedbackVectorICSlot slot(0);
332   LoadICNexus nexus(feedback_vector, slot);
333   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
334 }
335
336
337 TEST(VectorLoadICOnSmi) {
338   if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
339   CcTest::InitializeVM();
340   LocalContext context;
341   v8::HandleScope scope(context->GetIsolate());
342   Isolate* isolate = CcTest::i_isolate();
343   Heap* heap = isolate->heap();
344
345   // Make sure function f has a call that uses a type feedback slot.
346   CompileRun(
347       "var o = { foo: 3 };"
348       "function f(a) { return a.foo; } f(o);");
349   Handle<JSFunction> f = v8::Utils::OpenHandle(
350       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
351   // There should be one IC.
352   Handle<TypeFeedbackVector> feedback_vector =
353       Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
354   FeedbackVectorICSlot slot(0);
355   LoadICNexus nexus(feedback_vector, slot);
356   CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
357
358   CompileRun("f(34)");
359   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
360   // Verify that the monomorphic map is the one we expect.
361   Map* number_map = heap->heap_number_map();
362   CHECK_EQ(number_map, nexus.FindFirstMap());
363
364   // Now go polymorphic on o.
365   CompileRun("f(o)");
366   CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
367
368   MapHandleList maps;
369   nexus.FindAllMaps(&maps);
370   CHECK_EQ(2, maps.length());
371
372   // One of the maps should be the o map.
373   Handle<JSObject> o = v8::Utils::OpenHandle(
374       *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
375   bool number_map_found = false;
376   bool o_map_found = false;
377   for (int i = 0; i < maps.length(); i++) {
378     Handle<Map> current = maps[i];
379     if (*current == number_map)
380       number_map_found = true;
381     else if (*current == o->map())
382       o_map_found = true;
383   }
384   CHECK(number_map_found && o_map_found);
385
386   // The degree of polymorphism doesn't change.
387   CompileRun("f(100)");
388   CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
389   MapHandleList maps2;
390   nexus.FindAllMaps(&maps2);
391   CHECK_EQ(2, maps2.length());
392 }
393 }