blob: 69c60ca96ba7a5650dd48f4aa0e6175501c6249d [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/debug/debug.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010#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"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "test/cctest/test-feedback-vector.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016
17using namespace v8::internal;
18
19namespace {
20
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021#define CHECK_SLOT_KIND(helper, index, expected_kind) \
22 CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index)));
23
24
25static Handle<JSFunction> GetFunction(const char* name) {
26 v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get(
27 v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name));
28 Handle<JSFunction> f =
29 Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked()));
30 return f;
31}
32
33
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034TEST(VectorStructure) {
35 LocalContext context;
36 v8::HandleScope scope(context->GetIsolate());
37 Isolate* isolate = CcTest::i_isolate();
38 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039 Zone* zone = isolate->runtime_zone();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040040
41 // Empty vectors are the empty fixed array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 StaticFeedbackVectorSpec empty;
43 Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &empty);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044 CHECK(Handle<FixedArray>::cast(vector)
45 .is_identical_to(factory->empty_fixed_array()));
46 // Which can nonetheless be queried.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047 CHECK(vector->is_empty());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 {
50 FeedbackVectorSpec one_slot(zone);
51 one_slot.AddGeneralSlot();
52 vector = NewTypeFeedbackVector(isolate, &one_slot);
53 FeedbackVectorHelper helper(vector);
54 CHECK_EQ(1, helper.slot_count());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055 }
56
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 {
58 FeedbackVectorSpec one_icslot(zone);
59 one_icslot.AddCallICSlot();
60 vector = NewTypeFeedbackVector(isolate, &one_icslot);
61 FeedbackVectorHelper helper(vector);
62 CHECK_EQ(1, helper.slot_count());
63 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 {
66 FeedbackVectorSpec spec(zone);
67 for (int i = 0; i < 3; i++) {
68 spec.AddGeneralSlot();
69 }
70 for (int i = 0; i < 5; i++) {
71 spec.AddCallICSlot();
72 }
73 vector = NewTypeFeedbackVector(isolate, &spec);
74 FeedbackVectorHelper helper(vector);
75 CHECK_EQ(8, helper.slot_count());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000077 int index = vector->GetIndex(helper.slot(0));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040078
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount, index);
80 CHECK_EQ(helper.slot(0), vector->ToSlot(index));
81
82 index = vector->GetIndex(helper.slot(3));
83 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3, index);
84 CHECK_EQ(helper.slot(3), vector->ToSlot(index));
85
86 index = vector->GetIndex(helper.slot(7));
87 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 +
88 4 * TypeFeedbackMetadata::GetSlotSize(
89 FeedbackVectorSlotKind::CALL_IC),
90 index);
91 CHECK_EQ(helper.slot(7), vector->ToSlot(index));
92
93 CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 +
94 5 * TypeFeedbackMetadata::GetSlotSize(
95 FeedbackVectorSlotKind::CALL_IC),
96 vector->length());
97 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098}
99
100
101// IC slots need an encoding to recognize what is in there.
102TEST(VectorICMetadata) {
103 LocalContext context;
104 v8::HandleScope scope(context->GetIsolate());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105 Isolate* isolate = CcTest::i_isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 Zone* zone = isolate->runtime_zone();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400107
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 FeedbackVectorSpec spec(zone);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109 // Set metadata.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 for (int i = 0; i < 40; i++) {
111 switch (i % 4) {
112 case 0:
113 spec.AddGeneralSlot();
114 break;
115 case 1:
116 spec.AddCallICSlot();
117 break;
118 case 2:
119 spec.AddLoadICSlot();
120 break;
121 case 3:
122 spec.AddKeyedLoadICSlot();
123 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400124 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125 }
126
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000127 Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &spec);
128 FeedbackVectorHelper helper(vector);
129 CHECK_EQ(40, helper.slot_count());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400130
131 // Meanwhile set some feedback values and type feedback values to
132 // verify the data structure remains intact.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400133 vector->Set(FeedbackVectorSlot(0), *vector);
134
135 // Verify the metadata is correctly set up from the spec.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136 for (int i = 0; i < 40; i++) {
137 FeedbackVectorSlotKind kind = vector->GetKind(helper.slot(i));
138 switch (i % 4) {
139 case 0:
140 CHECK_EQ(FeedbackVectorSlotKind::GENERAL, kind);
141 break;
142 case 1:
143 CHECK_EQ(FeedbackVectorSlotKind::CALL_IC, kind);
144 break;
145 case 2:
146 CHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, kind);
147 break;
148 case 3:
149 CHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind);
150 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400151 }
152 }
153}
154
155
156TEST(VectorSlotClearing) {
157 LocalContext context;
158 v8::HandleScope scope(context->GetIsolate());
159 Isolate* isolate = CcTest::i_isolate();
160 Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 Zone* zone = isolate->runtime_zone();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400162
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 // We only test clearing FeedbackVectorSlots, not FeedbackVectorSlots.
164 // The reason is that FeedbackVectorSlots need a full code environment
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165 // to fully test (See VectorICProfilerStatistics test below).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 FeedbackVectorSpec spec(zone);
167 for (int i = 0; i < 5; i++) {
168 spec.AddGeneralSlot();
169 }
170 Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &spec);
171 FeedbackVectorHelper helper(vector);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172
173 // Fill with information
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000174 vector->Set(helper.slot(0), Smi::FromInt(1));
175 Handle<WeakCell> cell = factory->NewWeakCell(factory->fixed_array_map());
176 vector->Set(helper.slot(1), *cell);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177 Handle<AllocationSite> site = factory->NewAllocationSite();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178 vector->Set(helper.slot(2), *site);
179
180 // GC time clearing leaves slots alone.
181 vector->ClearSlotsAtGCTime(NULL);
182 Object* obj = vector->Get(helper.slot(1));
183 CHECK(obj->IsWeakCell() && !WeakCell::cast(obj)->cleared());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400184
185 vector->ClearSlots(NULL);
186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187 // The feedback vector slots are cleared. AllocationSites are still granted
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400188 // an exemption from clearing, as are smis.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189 CHECK_EQ(Smi::FromInt(1), vector->Get(helper.slot(0)));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 vector->Get(helper.slot(1)));
192 CHECK(vector->Get(helper.slot(2))->IsAllocationSite());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400193}
194
195
196TEST(VectorCallICStates) {
197 if (i::FLAG_always_opt) return;
198 CcTest::InitializeVM();
199 LocalContext context;
200 v8::HandleScope scope(context->GetIsolate());
201 Isolate* isolate = CcTest::i_isolate();
202 Heap* heap = isolate->heap();
203
204 // Make sure function f has a call that uses a type feedback slot.
205 CompileRun(
206 "function foo() { return 17; }"
207 "function f(a) { a(); } f(foo);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000208 Handle<JSFunction> f = GetFunction("f");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400209 // There should be one IC.
210 Handle<TypeFeedbackVector> feedback_vector =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100211 Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 FeedbackVectorSlot slot(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400213 CallICNexus nexus(feedback_vector, slot);
214 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
215 // CallIC doesn't return map feedback.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 CHECK(!nexus.FindFirstMap());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400217
218 CompileRun("f(function() { return 16; })");
219 CHECK_EQ(GENERIC, nexus.StateFromFeedback());
220
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 // After a collection, state should remain GENERIC.
222 heap->CollectAllGarbage();
223 CHECK_EQ(GENERIC, nexus.StateFromFeedback());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 // A call to Array is special, it contains an AllocationSite as feedback.
226 // Clear the IC manually in order to test this case.
227 nexus.Clear(f->shared()->code());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400228 CompileRun("f(Array)");
229 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 CHECK(nexus.GetFeedback()->IsAllocationSite());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 heap->CollectAllGarbage();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
234}
235
Ben Murdoch61f157c2016-09-16 13:49:30 +0100236TEST(VectorCallCounts) {
237 if (i::FLAG_always_opt) return;
238 CcTest::InitializeVM();
239 LocalContext context;
240 v8::HandleScope scope(context->GetIsolate());
241 Isolate* isolate = CcTest::i_isolate();
242
243 // Make sure function f has a call that uses a type feedback slot.
244 CompileRun(
245 "function foo() { return 17; }"
246 "function f(a) { a(); } f(foo);");
247 Handle<JSFunction> f = GetFunction("f");
248 // There should be one IC.
249 Handle<TypeFeedbackVector> feedback_vector =
250 Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
251 FeedbackVectorSlot slot(0);
252 CallICNexus nexus(feedback_vector, slot);
253 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
254
255 CompileRun("f(foo); f(foo);");
256 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
257 CHECK_EQ(3, nexus.ExtractCallCount());
258
259 CompileRun(
260 "function Foo() {}"
261 "function f(a) { new a(); } f(Foo);");
262 f = GetFunction("f");
263 // There should be one IC.
264 feedback_vector = Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
265 FeedbackVectorSlot cslot(1);
266
267 CompileRun("f(Foo); f(Foo);");
268 CHECK(feedback_vector->Get(cslot)->IsSmi());
269 CHECK_EQ(3, Smi::cast(feedback_vector->Get(cslot))->value());
270}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271
272TEST(VectorLoadICStates) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273 if (i::FLAG_always_opt) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400274 CcTest::InitializeVM();
275 LocalContext context;
276 v8::HandleScope scope(context->GetIsolate());
277 Isolate* isolate = CcTest::i_isolate();
278 Heap* heap = isolate->heap();
279
280 // Make sure function f has a call that uses a type feedback slot.
281 CompileRun(
282 "var o = { foo: 3 };"
283 "function f(a) { return a.foo; } f(o);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 Handle<JSFunction> f = GetFunction("f");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400285 // There should be one IC.
286 Handle<TypeFeedbackVector> feedback_vector =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100287 Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 FeedbackVectorSlot slot(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400289 LoadICNexus nexus(feedback_vector, slot);
290 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
291
292 CompileRun("f(o)");
293 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
294 // Verify that the monomorphic map is the one we expect.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 v8::MaybeLocal<v8::Value> v8_o =
296 CcTest::global()->Get(context.local(), v8_str("o"));
297 Handle<JSObject> o =
298 Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400299 CHECK_EQ(o->map(), nexus.FindFirstMap());
300
301 // Now go polymorphic.
302 CompileRun("f({ blarg: 3, foo: 2 })");
303 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
304
305 CompileRun(
306 "delete o.foo;"
307 "f(o)");
308 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
309
310 CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
311 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
312 MapHandleList maps;
313 nexus.FindAllMaps(&maps);
314 CHECK_EQ(4, maps.length());
315
316 // Finally driven megamorphic.
317 CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
318 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 CHECK(!nexus.FindFirstMap());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400320
321 // After a collection, state should not be reset to PREMONOMORPHIC.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 heap->CollectAllGarbage();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400323 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
324}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325
326
327TEST(VectorLoadICSlotSharing) {
328 if (i::FLAG_always_opt) return;
329 CcTest::InitializeVM();
330 LocalContext context;
331 v8::HandleScope scope(context->GetIsolate());
332 Isolate* isolate = CcTest::i_isolate();
333
334 // Function f has 3 LoadICs, one for each o, but the ICs share the same
335 // feedback vector IC slot.
336 CompileRun(
337 "o = 10;"
338 "function f() {"
339 " var x = o + 10;"
340 " return o + x + o;"
341 "}"
342 "f();");
343 Handle<JSFunction> f = GetFunction("f");
344 // There should be one IC slot.
345 Handle<TypeFeedbackVector> feedback_vector =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100346 Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000347 FeedbackVectorHelper helper(feedback_vector);
348 CHECK_EQ(1, helper.slot_count());
349 FeedbackVectorSlot slot(0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100350 LoadGlobalICNexus nexus(feedback_vector, slot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400352}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353
354
355TEST(VectorLoadICOnSmi) {
356 if (i::FLAG_always_opt) return;
357 CcTest::InitializeVM();
358 LocalContext context;
359 v8::HandleScope scope(context->GetIsolate());
360 Isolate* isolate = CcTest::i_isolate();
361 Heap* heap = isolate->heap();
362
363 // Make sure function f has a call that uses a type feedback slot.
364 CompileRun(
365 "var o = { foo: 3 };"
366 "function f(a) { return a.foo; } f(o);");
367 Handle<JSFunction> f = GetFunction("f");
368 // There should be one IC.
369 Handle<TypeFeedbackVector> feedback_vector =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100370 Handle<TypeFeedbackVector>(f->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 FeedbackVectorSlot slot(0);
372 LoadICNexus nexus(feedback_vector, slot);
373 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
374
375 CompileRun("f(34)");
376 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
377 // Verify that the monomorphic map is the one we expect.
378 Map* number_map = heap->heap_number_map();
379 CHECK_EQ(number_map, nexus.FindFirstMap());
380
381 // Now go polymorphic on o.
382 CompileRun("f(o)");
383 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
384
385 MapHandleList maps;
386 nexus.FindAllMaps(&maps);
387 CHECK_EQ(2, maps.length());
388
389 // One of the maps should be the o map.
390 v8::MaybeLocal<v8::Value> v8_o =
391 CcTest::global()->Get(context.local(), v8_str("o"));
392 Handle<JSObject> o =
393 Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
394 bool number_map_found = false;
395 bool o_map_found = false;
396 for (int i = 0; i < maps.length(); i++) {
397 Handle<Map> current = maps[i];
398 if (*current == number_map)
399 number_map_found = true;
400 else if (*current == o->map())
401 o_map_found = true;
402 }
403 CHECK(number_map_found && o_map_found);
404
405 // The degree of polymorphism doesn't change.
406 CompileRun("f(100)");
407 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
408 MapHandleList maps2;
409 nexus.FindAllMaps(&maps2);
410 CHECK_EQ(2, maps2.length());
411}
412
413
414TEST(ReferenceContextAllocatesNoSlots) {
415 if (i::FLAG_always_opt) return;
416 CcTest::InitializeVM();
417 LocalContext context;
418 v8::HandleScope scope(context->GetIsolate());
419 Isolate* isolate = CcTest::i_isolate();
420
421 {
422 CompileRun(
423 "function testvar(x) {"
424 " y = x;"
425 " y = a;"
426 " return y;"
427 "}"
428 "a = 3;"
429 "testvar({});");
430
431 Handle<JSFunction> f = GetFunction("testvar");
432
433 // There should be two LOAD_ICs, one for a and one for y at the end.
434 Handle<TypeFeedbackVector> feedback_vector =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100435 handle(f->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 FeedbackVectorHelper helper(feedback_vector);
437 CHECK_EQ(4, helper.slot_count());
438 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::STORE_IC);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100439 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100441 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000442 }
443
444 {
445 CompileRun(
446 "function testprop(x) {"
447 " x.blue = a;"
448 "}"
449 "testprop({ blue: 3 });");
450
451 Handle<JSFunction> f = GetFunction("testprop");
452
453 // There should be one LOAD_IC, for the load of a.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100454 Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455 FeedbackVectorHelper helper(feedback_vector);
456 CHECK_EQ(2, helper.slot_count());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100457 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
458 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::STORE_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 }
460
461 {
462 CompileRun(
463 "function testpropfunc(x) {"
464 " x().blue = a;"
465 " return x().blue;"
466 "}"
467 "function makeresult() { return { blue: 3 }; }"
468 "testpropfunc(makeresult);");
469
470 Handle<JSFunction> f = GetFunction("testpropfunc");
471
Ben Murdoch61f157c2016-09-16 13:49:30 +0100472 // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
473 // to call x and a LOAD_IC to load blue.
474 Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 FeedbackVectorHelper helper(feedback_vector);
476 CHECK_EQ(5, helper.slot_count());
477 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::CALL_IC);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100478 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
480 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::CALL_IC);
481 CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC);
482 }
483
484 {
485 CompileRun(
486 "function testkeyedprop(x) {"
487 " x[0] = a;"
488 " return x[0];"
489 "}"
490 "testkeyedprop([0, 1, 2]);");
491
492 Handle<JSFunction> f = GetFunction("testkeyedprop");
493
Ben Murdoch61f157c2016-09-16 13:49:30 +0100494 // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
495 // KEYED_LOAD_IC for the load of x[0] in the return statement.
496 Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000497 FeedbackVectorHelper helper(feedback_vector);
498 CHECK_EQ(3, helper.slot_count());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100499 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::KEYED_STORE_IC);
501 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::KEYED_LOAD_IC);
502 }
503
504 {
505 CompileRun(
506 "function testcompound(x) {"
507 " x.old = x.young = x.in_between = a;"
508 " return x.old + x.young;"
509 "}"
510 "testcompound({ old: 3, young: 3, in_between: 3 });");
511
512 Handle<JSFunction> f = GetFunction("testcompound");
513
Ben Murdoch61f157c2016-09-16 13:49:30 +0100514 // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
515 // of x.old and x.young.
516 Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 FeedbackVectorHelper helper(feedback_vector);
518 CHECK_EQ(6, helper.slot_count());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100519 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000520 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::STORE_IC);
521 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
522 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::STORE_IC);
523 CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC);
524 CHECK_SLOT_KIND(helper, 5, FeedbackVectorSlotKind::LOAD_IC);
525 }
526}
527
528
529TEST(VectorStoreICBasic) {
530 if (i::FLAG_always_opt) return;
531
532 CcTest::InitializeVM();
533 LocalContext context;
534 v8::HandleScope scope(context->GetIsolate());
535
536 CompileRun(
537 "function f(a) {"
538 " a.foo = 5;"
539 "}"
540 "var a = { foo: 3 };"
541 "f(a);"
542 "f(a);"
543 "f(a);");
544 Handle<JSFunction> f = GetFunction("f");
545 // There should be one IC slot.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100546 Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 FeedbackVectorHelper helper(feedback_vector);
548 CHECK_EQ(1, helper.slot_count());
549 FeedbackVectorSlot slot(0);
550 StoreICNexus nexus(feedback_vector, slot);
551 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
552}
553
554} // namespace