Introduce FeedbackNexus for vector-based ics.
[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
26   // Empty vectors are the empty fixed array.
27   Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(0, 0);
28   CHECK(Handle<FixedArray>::cast(vector)
29             .is_identical_to(factory->empty_fixed_array()));
30   // Which can nonetheless be queried.
31   CHECK_EQ(0, vector->ic_with_type_info_count());
32   CHECK_EQ(0, vector->ic_generic_count());
33   CHECK_EQ(0, vector->Slots());
34   CHECK_EQ(0, vector->ICSlots());
35
36   vector = factory->NewTypeFeedbackVector(1, 0);
37   CHECK_EQ(1, vector->Slots());
38   CHECK_EQ(0, vector->ICSlots());
39
40   vector = factory->NewTypeFeedbackVector(0, 1);
41   CHECK_EQ(0, vector->Slots());
42   CHECK_EQ(1, vector->ICSlots());
43
44   vector = factory->NewTypeFeedbackVector(3, 5);
45   CHECK_EQ(3, vector->Slots());
46   CHECK_EQ(5, vector->ICSlots());
47
48   int metadata_length = vector->ic_metadata_length();
49   if (!FLAG_vector_ics) {
50     CHECK_EQ(0, metadata_length);
51   } else {
52     CHECK(metadata_length > 0);
53   }
54
55   int index = vector->GetIndex(FeedbackVectorSlot(0));
56   CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
57   CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
58
59   index = vector->GetIndex(FeedbackVectorICSlot(0));
60   CHECK_EQ(index,
61            TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
62   CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
63
64   CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
65            vector->length());
66 }
67
68
69 // IC slots need an encoding to recognize what is in there.
70 TEST(VectorICMetadata) {
71   LocalContext context;
72   v8::HandleScope scope(context->GetIsolate());
73   if (!FLAG_vector_ics) {
74     // 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.
76     return;
77   }
78   Isolate* isolate = CcTest::i_isolate();
79   Factory* factory = isolate->factory();
80
81   Handle<TypeFeedbackVector> vector =
82       factory->NewTypeFeedbackVector(10, 3 * 10);
83   CHECK_EQ(10, vector->Slots());
84   CHECK_EQ(3 * 10, vector->ICSlots());
85
86   // Set metadata.
87   for (int i = 0; i < 30; i++) {
88     Code::Kind kind;
89     if (i % 3 == 0) {
90       kind = Code::CALL_IC;
91     } else if (i % 3 == 1) {
92       kind = Code::LOAD_IC;
93     } else {
94       kind = Code::KEYED_LOAD_IC;
95     }
96     vector->SetKind(FeedbackVectorICSlot(i), kind);
97   }
98
99   // Meanwhile set some feedback values and type feedback values to
100   // verify the data structure remains intact.
101   vector->change_ic_with_type_info_count(100);
102   vector->change_ic_generic_count(3333);
103   vector->Set(FeedbackVectorSlot(0), *vector);
104
105   // Verify the metadata remains the same.
106   for (int i = 0; i < 30; i++) {
107     Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
108     if (i % 3 == 0) {
109       CHECK_EQ(Code::CALL_IC, kind);
110     } else if (i % 3 == 1) {
111       CHECK_EQ(Code::LOAD_IC, kind);
112     } else {
113       CHECK_EQ(Code::KEYED_LOAD_IC, kind);
114     }
115   }
116 }
117
118
119 TEST(VectorSlotClearing) {
120   LocalContext context;
121   v8::HandleScope scope(context->GetIsolate());
122   Isolate* isolate = CcTest::i_isolate();
123   Factory* factory = isolate->factory();
124
125   // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
126   // The reason is that FeedbackVectorICSlots need a full code environment
127   // to fully test (See VectorICProfilerStatistics test below).
128   Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(5, 0);
129
130   // Fill with information
131   vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
132   vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
133   Handle<AllocationSite> site = factory->NewAllocationSite();
134   vector->Set(FeedbackVectorSlot(2), *site);
135
136   vector->ClearSlots(NULL);
137
138   // The feedback vector slots are cleared. AllocationSites are granted
139   // an exemption from clearing, as are smis.
140   CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
141   CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
142            vector->Get(FeedbackVectorSlot(1)));
143   CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
144 }
145
146
147 TEST(VectorICProfilerStatistics) {
148   if (i::FLAG_always_opt) return;
149   CcTest::InitializeVM();
150   LocalContext context;
151   v8::HandleScope scope(context->GetIsolate());
152   Isolate* isolate = CcTest::i_isolate();
153   Heap* heap = isolate->heap();
154
155   // Make sure function f has a call that uses a type feedback slot.
156   CompileRun(
157       "function fun() {};"
158       "function f(a) { a(); } f(fun);");
159   Handle<JSFunction> f = v8::Utils::OpenHandle(
160       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
161   // There should be one IC.
162   Code* code = f->shared()->code();
163   TypeFeedbackInfo* feedback_info =
164       TypeFeedbackInfo::cast(code->type_feedback_info());
165   CHECK_EQ(1, feedback_info->ic_total_count());
166   CHECK_EQ(0, feedback_info->ic_with_type_info_count());
167   CHECK_EQ(0, feedback_info->ic_generic_count());
168   TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
169   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
170   CHECK_EQ(0, feedback_vector->ic_generic_count());
171
172   // Now send the information generic.
173   CompileRun("f(Object);");
174   feedback_vector = f->shared()->feedback_vector();
175   CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
176   CHECK_EQ(1, feedback_vector->ic_generic_count());
177
178   // A collection will make the site uninitialized again.
179   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
180   feedback_vector = f->shared()->feedback_vector();
181   CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
182   CHECK_EQ(0, feedback_vector->ic_generic_count());
183
184   // The Array function is special. A call to array remains monomorphic
185   // and isn't cleared by gc because an AllocationSite is being held.
186   CompileRun("f(Array);");
187   feedback_vector = f->shared()->feedback_vector();
188   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
189   CHECK_EQ(0, feedback_vector->ic_generic_count());
190
191   int ic_slot = FLAG_vector_ics ? 1 : 0;
192   CHECK(
193       feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
194   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
195   feedback_vector = f->shared()->feedback_vector();
196   CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
197   CHECK_EQ(0, feedback_vector->ic_generic_count());
198   CHECK(
199       feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
200 }
201
202
203 TEST(VectorCallICStates) {
204   if (i::FLAG_always_opt) return;
205   CcTest::InitializeVM();
206   LocalContext context;
207   v8::HandleScope scope(context->GetIsolate());
208   Isolate* isolate = CcTest::i_isolate();
209   Heap* heap = isolate->heap();
210
211   // Make sure function f has a call that uses a type feedback slot.
212   CompileRun(
213       "function foo() { return 17; }"
214       "function f(a) { a(); } f(foo);");
215   Handle<JSFunction> f = v8::Utils::OpenHandle(
216       *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
217   // There should be one IC.
218   Handle<TypeFeedbackVector> feedback_vector =
219       Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
220   FeedbackVectorICSlot slot(FLAG_vector_ics ? 1 : 0);
221   CallICNexus nexus(feedback_vector, slot);
222   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
223   // CallIC doesn't return map feedback.
224   CHECK_EQ(NULL, nexus.FindFirstMap());
225
226   CompileRun("f(function() { return 16; })");
227   CHECK_EQ(GENERIC, nexus.StateFromFeedback());
228
229   // After a collection, state should be reset to UNINITIALIZED.
230   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
231   CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
232
233   // Array is special. It will remain monomorphic across gcs and it contains an
234   // AllocationSite.
235   CompileRun("f(Array)");
236   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
237   CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite());
238
239   heap->CollectAllGarbage(i::Heap::kNoGCFlags);
240   CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
241 }
242 }