blob: c06e5b9124a3e387e2c160846ed370f22637fbc0 [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 =
211 Handle<TypeFeedbackVector>(f->shared()->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
236
237TEST(VectorLoadICStates) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 if (i::FLAG_always_opt) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 CcTest::InitializeVM();
240 LocalContext context;
241 v8::HandleScope scope(context->GetIsolate());
242 Isolate* isolate = CcTest::i_isolate();
243 Heap* heap = isolate->heap();
244
245 // Make sure function f has a call that uses a type feedback slot.
246 CompileRun(
247 "var o = { foo: 3 };"
248 "function f(a) { return a.foo; } f(o);");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 Handle<JSFunction> f = GetFunction("f");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400250 // There should be one IC.
251 Handle<TypeFeedbackVector> feedback_vector =
252 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253 FeedbackVectorSlot slot(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400254 LoadICNexus nexus(feedback_vector, slot);
255 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
256
257 CompileRun("f(o)");
258 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
259 // Verify that the monomorphic map is the one we expect.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000260 v8::MaybeLocal<v8::Value> v8_o =
261 CcTest::global()->Get(context.local(), v8_str("o"));
262 Handle<JSObject> o =
263 Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 CHECK_EQ(o->map(), nexus.FindFirstMap());
265
266 // Now go polymorphic.
267 CompileRun("f({ blarg: 3, foo: 2 })");
268 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
269
270 CompileRun(
271 "delete o.foo;"
272 "f(o)");
273 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
274
275 CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
276 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
277 MapHandleList maps;
278 nexus.FindAllMaps(&maps);
279 CHECK_EQ(4, maps.length());
280
281 // Finally driven megamorphic.
282 CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
283 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284 CHECK(!nexus.FindFirstMap());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400285
286 // After a collection, state should not be reset to PREMONOMORPHIC.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 heap->CollectAllGarbage();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400288 CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
289}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290
291
292TEST(VectorLoadICSlotSharing) {
293 if (i::FLAG_always_opt) return;
294 CcTest::InitializeVM();
295 LocalContext context;
296 v8::HandleScope scope(context->GetIsolate());
297 Isolate* isolate = CcTest::i_isolate();
298
299 // Function f has 3 LoadICs, one for each o, but the ICs share the same
300 // feedback vector IC slot.
301 CompileRun(
302 "o = 10;"
303 "function f() {"
304 " var x = o + 10;"
305 " return o + x + o;"
306 "}"
307 "f();");
308 Handle<JSFunction> f = GetFunction("f");
309 // There should be one IC slot.
310 Handle<TypeFeedbackVector> feedback_vector =
311 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
312 FeedbackVectorHelper helper(feedback_vector);
313 CHECK_EQ(1, helper.slot_count());
314 FeedbackVectorSlot slot(0);
315 LoadICNexus nexus(feedback_vector, slot);
316 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400317}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318
319
320TEST(VectorLoadICOnSmi) {
321 if (i::FLAG_always_opt) return;
322 CcTest::InitializeVM();
323 LocalContext context;
324 v8::HandleScope scope(context->GetIsolate());
325 Isolate* isolate = CcTest::i_isolate();
326 Heap* heap = isolate->heap();
327
328 // Make sure function f has a call that uses a type feedback slot.
329 CompileRun(
330 "var o = { foo: 3 };"
331 "function f(a) { return a.foo; } f(o);");
332 Handle<JSFunction> f = GetFunction("f");
333 // There should be one IC.
334 Handle<TypeFeedbackVector> feedback_vector =
335 Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
336 FeedbackVectorSlot slot(0);
337 LoadICNexus nexus(feedback_vector, slot);
338 CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
339
340 CompileRun("f(34)");
341 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
342 // Verify that the monomorphic map is the one we expect.
343 Map* number_map = heap->heap_number_map();
344 CHECK_EQ(number_map, nexus.FindFirstMap());
345
346 // Now go polymorphic on o.
347 CompileRun("f(o)");
348 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
349
350 MapHandleList maps;
351 nexus.FindAllMaps(&maps);
352 CHECK_EQ(2, maps.length());
353
354 // One of the maps should be the o map.
355 v8::MaybeLocal<v8::Value> v8_o =
356 CcTest::global()->Get(context.local(), v8_str("o"));
357 Handle<JSObject> o =
358 Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
359 bool number_map_found = false;
360 bool o_map_found = false;
361 for (int i = 0; i < maps.length(); i++) {
362 Handle<Map> current = maps[i];
363 if (*current == number_map)
364 number_map_found = true;
365 else if (*current == o->map())
366 o_map_found = true;
367 }
368 CHECK(number_map_found && o_map_found);
369
370 // The degree of polymorphism doesn't change.
371 CompileRun("f(100)");
372 CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
373 MapHandleList maps2;
374 nexus.FindAllMaps(&maps2);
375 CHECK_EQ(2, maps2.length());
376}
377
378
379TEST(ReferenceContextAllocatesNoSlots) {
380 if (i::FLAG_always_opt) return;
381 CcTest::InitializeVM();
382 LocalContext context;
383 v8::HandleScope scope(context->GetIsolate());
384 Isolate* isolate = CcTest::i_isolate();
385
386 {
387 CompileRun(
388 "function testvar(x) {"
389 " y = x;"
390 " y = a;"
391 " return y;"
392 "}"
393 "a = 3;"
394 "testvar({});");
395
396 Handle<JSFunction> f = GetFunction("testvar");
397
398 // There should be two LOAD_ICs, one for a and one for y at the end.
399 Handle<TypeFeedbackVector> feedback_vector =
400 handle(f->shared()->feedback_vector(), isolate);
401 FeedbackVectorHelper helper(feedback_vector);
402 CHECK_EQ(4, helper.slot_count());
403 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::STORE_IC);
404 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_IC);
405 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
406 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::LOAD_IC);
407 }
408
409 {
410 CompileRun(
411 "function testprop(x) {"
412 " x.blue = a;"
413 "}"
414 "testprop({ blue: 3 });");
415
416 Handle<JSFunction> f = GetFunction("testprop");
417
418 // There should be one LOAD_IC, for the load of a.
419 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
420 FeedbackVectorHelper helper(feedback_vector);
421 CHECK_EQ(2, helper.slot_count());
422 }
423
424 {
425 CompileRun(
426 "function testpropfunc(x) {"
427 " x().blue = a;"
428 " return x().blue;"
429 "}"
430 "function makeresult() { return { blue: 3 }; }"
431 "testpropfunc(makeresult);");
432
433 Handle<JSFunction> f = GetFunction("testpropfunc");
434
435 // There should be 2 LOAD_ICs and 2 CALL_ICs.
436 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
437 FeedbackVectorHelper helper(feedback_vector);
438 CHECK_EQ(5, helper.slot_count());
439 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::CALL_IC);
440 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_IC);
441 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
442 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::CALL_IC);
443 CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC);
444 }
445
446 {
447 CompileRun(
448 "function testkeyedprop(x) {"
449 " x[0] = a;"
450 " return x[0];"
451 "}"
452 "testkeyedprop([0, 1, 2]);");
453
454 Handle<JSFunction> f = GetFunction("testkeyedprop");
455
456 // There should be 1 LOAD_ICs for the load of a, and one KEYED_LOAD_IC for
457 // the load of x[0] in the return statement.
458 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
459 FeedbackVectorHelper helper(feedback_vector);
460 CHECK_EQ(3, helper.slot_count());
461 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_IC);
462 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::KEYED_STORE_IC);
463 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::KEYED_LOAD_IC);
464 }
465
466 {
467 CompileRun(
468 "function testcompound(x) {"
469 " x.old = x.young = x.in_between = a;"
470 " return x.old + x.young;"
471 "}"
472 "testcompound({ old: 3, young: 3, in_between: 3 });");
473
474 Handle<JSFunction> f = GetFunction("testcompound");
475
476 // There should be 3 LOAD_ICs, for load of a and load of x.old and x.young.
477 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
478 FeedbackVectorHelper helper(feedback_vector);
479 CHECK_EQ(6, helper.slot_count());
480 CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_IC);
481 CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::STORE_IC);
482 CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC);
483 CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::STORE_IC);
484 CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC);
485 CHECK_SLOT_KIND(helper, 5, FeedbackVectorSlotKind::LOAD_IC);
486 }
487}
488
489
490TEST(VectorStoreICBasic) {
491 if (i::FLAG_always_opt) return;
492
493 CcTest::InitializeVM();
494 LocalContext context;
495 v8::HandleScope scope(context->GetIsolate());
496
497 CompileRun(
498 "function f(a) {"
499 " a.foo = 5;"
500 "}"
501 "var a = { foo: 3 };"
502 "f(a);"
503 "f(a);"
504 "f(a);");
505 Handle<JSFunction> f = GetFunction("f");
506 // There should be one IC slot.
507 Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
508 FeedbackVectorHelper helper(feedback_vector);
509 CHECK_EQ(1, helper.slot_count());
510 FeedbackVectorSlot slot(0);
511 StoreICNexus nexus(feedback_vector, slot);
512 CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
513}
514
515} // namespace