Line data Source code
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-inl.h"
9 : #include "src/debug/debug.h"
10 : #include "src/execution.h"
11 : #include "src/global-handles.h"
12 : #include "src/heap/factory.h"
13 : #include "src/macro-assembler.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/feedback-cell-inl.h"
16 : #include "test/cctest/test-feedback-vector.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 : namespace {
22 :
23 : #define CHECK_SLOT_KIND(helper, index, expected_kind) \
24 : CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index)));
25 :
26 :
27 72 : static Handle<JSFunction> GetFunction(const char* name) {
28 144 : v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get(
29 288 : v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name));
30 : Handle<JSFunction> f =
31 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked()));
32 72 : return f;
33 : }
34 :
35 :
36 26068 : TEST(VectorStructure) {
37 5 : LocalContext context;
38 10 : v8::HandleScope scope(context->GetIsolate());
39 : Isolate* isolate = CcTest::i_isolate();
40 : Factory* factory = isolate->factory();
41 10 : Zone zone(isolate->allocator(), ZONE_NAME);
42 :
43 : Handle<FeedbackVector> vector;
44 :
45 : {
46 : FeedbackVectorSpec one_slot(&zone);
47 : one_slot.AddForInSlot();
48 5 : vector = NewFeedbackVector(isolate, &one_slot);
49 5 : FeedbackVectorHelper helper(vector);
50 5 : CHECK_EQ(1, helper.slot_count());
51 : }
52 :
53 : {
54 : FeedbackVectorSpec one_icslot(&zone);
55 : one_icslot.AddCallICSlot();
56 5 : vector = NewFeedbackVector(isolate, &one_icslot);
57 5 : FeedbackVectorHelper helper(vector);
58 5 : CHECK_EQ(1, helper.slot_count());
59 : }
60 :
61 : {
62 : FeedbackVectorSpec spec(&zone);
63 35 : for (int i = 0; i < 3; i++) {
64 : spec.AddForInSlot();
65 : }
66 55 : for (int i = 0; i < 5; i++) {
67 : spec.AddCallICSlot();
68 : }
69 5 : vector = NewFeedbackVector(isolate, &spec);
70 5 : FeedbackVectorHelper helper(vector);
71 5 : CHECK_EQ(8, helper.slot_count());
72 :
73 : int index = vector->GetIndex(helper.slot(0));
74 :
75 : CHECK_EQ(helper.slot(0), vector->ToSlot(index));
76 :
77 : index = vector->GetIndex(helper.slot(3));
78 : CHECK_EQ(helper.slot(3), vector->ToSlot(index));
79 :
80 : index = vector->GetIndex(helper.slot(7));
81 5 : CHECK_EQ(3 + 4 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
82 : index);
83 : CHECK_EQ(helper.slot(7), vector->ToSlot(index));
84 :
85 5 : CHECK_EQ(3 + 5 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
86 : vector->length());
87 : }
88 :
89 : {
90 : FeedbackVectorSpec spec(&zone);
91 : spec.AddForInSlot();
92 : spec.AddFeedbackCellForCreateClosure();
93 : spec.AddForInSlot();
94 5 : vector = NewFeedbackVector(isolate, &spec);
95 5 : FeedbackVectorHelper helper(vector);
96 10 : FeedbackCell cell = *vector->GetClosureFeedbackCell(0);
97 5 : CHECK_EQ(cell->value(), *factory->undefined_value());
98 : }
99 5 : }
100 :
101 :
102 : // IC slots need an encoding to recognize what is in there.
103 26068 : TEST(VectorICMetadata) {
104 5 : LocalContext context;
105 10 : v8::HandleScope scope(context->GetIsolate());
106 : Isolate* isolate = CcTest::i_isolate();
107 10 : Zone zone(isolate->allocator(), ZONE_NAME);
108 :
109 : FeedbackVectorSpec spec(&zone);
110 : // Set metadata.
111 405 : for (int i = 0; i < 40; i++) {
112 200 : switch (i % 4) {
113 : case 0:
114 : spec.AddForInSlot();
115 : break;
116 : case 1:
117 : spec.AddCallICSlot();
118 : break;
119 : case 2:
120 : spec.AddLoadICSlot();
121 : break;
122 : case 3:
123 : spec.AddKeyedLoadICSlot();
124 : break;
125 : }
126 : }
127 :
128 5 : Handle<FeedbackVector> vector = NewFeedbackVector(isolate, &spec);
129 5 : FeedbackVectorHelper helper(vector);
130 5 : CHECK_EQ(40, helper.slot_count());
131 :
132 : // Meanwhile set some feedback values and type feedback values to
133 : // verify the data structure remains intact.
134 10 : vector->Set(FeedbackSlot(0), MaybeObject::FromObject(*vector));
135 :
136 : // Verify the metadata is correctly set up from the spec.
137 405 : for (int i = 0; i < 40; i++) {
138 200 : FeedbackSlotKind kind = vector->GetKind(helper.slot(i));
139 200 : switch (i % 4) {
140 : case 0:
141 50 : CHECK_EQ(FeedbackSlotKind::kForIn, kind);
142 : break;
143 : case 1:
144 50 : CHECK_EQ(FeedbackSlotKind::kCall, kind);
145 : break;
146 : case 2:
147 50 : CHECK_EQ(FeedbackSlotKind::kLoadProperty, kind);
148 : break;
149 : case 3:
150 50 : CHECK_EQ(FeedbackSlotKind::kLoadKeyed, kind);
151 : break;
152 : }
153 : }
154 5 : }
155 :
156 :
157 26068 : TEST(VectorCallICStates) {
158 6 : if (!i::FLAG_use_ic) return;
159 5 : if (i::FLAG_always_opt) return;
160 :
161 4 : CcTest::InitializeVM();
162 4 : LocalContext context;
163 8 : v8::HandleScope scope(context->GetIsolate());
164 : Isolate* isolate = CcTest::i_isolate();
165 : // Make sure function f has a call that uses a type feedback slot.
166 : CompileRun(
167 : "function foo() { return 17; }"
168 : "function f(a) { a(); } f(foo);");
169 4 : Handle<JSFunction> f = GetFunction("f");
170 : // There should be one IC.
171 : Handle<FeedbackVector> feedback_vector =
172 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
173 : FeedbackSlot slot(0);
174 : FeedbackNexus nexus(feedback_vector, slot);
175 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
176 :
177 : CompileRun("f(function() { return 16; })");
178 4 : CHECK_EQ(GENERIC, nexus.ic_state());
179 :
180 : // After a collection, state should remain GENERIC.
181 4 : CcTest::CollectAllGarbage();
182 4 : CHECK_EQ(GENERIC, nexus.ic_state());
183 : }
184 :
185 26068 : TEST(VectorCallFeedback) {
186 6 : if (!i::FLAG_use_ic) return;
187 5 : if (i::FLAG_always_opt) return;
188 :
189 4 : CcTest::InitializeVM();
190 4 : LocalContext context;
191 8 : v8::HandleScope scope(context->GetIsolate());
192 : Isolate* isolate = CcTest::i_isolate();
193 : // Make sure function f has a call that uses a type feedback slot.
194 : CompileRun(
195 : "function foo() { return 17; }"
196 : "function f(a) { a(); } f(foo);");
197 4 : Handle<JSFunction> f = GetFunction("f");
198 4 : Handle<JSFunction> foo = GetFunction("foo");
199 : // There should be one IC.
200 : Handle<FeedbackVector> feedback_vector =
201 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
202 : FeedbackSlot slot(0);
203 : FeedbackNexus nexus(feedback_vector, slot);
204 :
205 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
206 : HeapObject heap_object;
207 8 : CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
208 4 : CHECK_EQ(*foo, heap_object);
209 :
210 4 : CcTest::CollectAllGarbage();
211 : // It should stay monomorphic even after a GC.
212 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
213 : }
214 :
215 26068 : TEST(VectorCallFeedbackForArray) {
216 6 : if (!i::FLAG_use_ic) return;
217 5 : if (i::FLAG_always_opt) return;
218 :
219 4 : CcTest::InitializeVM();
220 4 : LocalContext context;
221 8 : v8::HandleScope scope(context->GetIsolate());
222 : Isolate* isolate = CcTest::i_isolate();
223 : // Make sure function f has a call that uses a type feedback slot.
224 : CompileRun("function f(a) { a(); } f(Array);");
225 4 : Handle<JSFunction> f = GetFunction("f");
226 : // There should be one IC.
227 : Handle<FeedbackVector> feedback_vector =
228 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
229 : FeedbackSlot slot(0);
230 : FeedbackNexus nexus(feedback_vector, slot);
231 :
232 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
233 : HeapObject heap_object;
234 8 : CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
235 8 : CHECK_EQ(*isolate->array_function(), heap_object);
236 :
237 4 : CcTest::CollectAllGarbage();
238 : // It should stay monomorphic even after a GC.
239 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
240 : }
241 :
242 24 : size_t GetFeedbackVectorLength(Isolate* isolate, const char* src,
243 : bool with_oneshot_opt) {
244 24 : i::FLAG_enable_one_shot_optimization = with_oneshot_opt;
245 : i::Handle<i::Object> i_object = v8::Utils::OpenHandle(*CompileRun(src));
246 : i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(i_object);
247 : Handle<FeedbackVector> feedback_vector =
248 48 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
249 24 : return feedback_vector->length();
250 : }
251 :
252 26068 : TEST(OneShotCallICSlotCount) {
253 6 : if (!i::FLAG_use_ic) return;
254 5 : if (i::FLAG_always_opt) return;
255 :
256 4 : CcTest::InitializeVM();
257 4 : LocalContext context;
258 8 : v8::HandleScope scope(context->GetIsolate());
259 : Isolate* isolate = CcTest::i_isolate();
260 4 : i::FLAG_compilation_cache = false;
261 :
262 : const char* no_call = R"(
263 : function f1() {};
264 : function f2() {};
265 : (function() {
266 : return arguments.callee;
267 : })();
268 : )";
269 : // len = 2 * 1 ldaNamed property
270 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, false), 2);
271 : // no slots of named property loads/stores in one shot
272 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, true), 0);
273 :
274 : const char* single_call = R"(
275 : function f1() {};
276 : function f2() {};
277 : (function() {
278 : f1();
279 : return arguments.callee;
280 : })();
281 : )";
282 : // len = 2 * 1 ldaNamed Slot + 2 * 1 CachedGlobalSlot + 2 * 1 CallICSlot
283 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, false), 6);
284 : // len = 2 * 1 CachedGlobalSlot
285 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, true), 2);
286 :
287 : const char* multiple_calls = R"(
288 : function f1() {};
289 : function f2() {};
290 : (function() {
291 : f1();
292 : f2();
293 : f1();
294 : f2();
295 : return arguments.callee;
296 : })();
297 : )";
298 : // len = 2 * 1 ldaNamedSlot + 2 * 2 CachedGlobalSlot (one for each unique
299 : // function) + 2 * 4 CallICSlot (one for each function call)
300 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, false), 14);
301 : // CachedGlobalSlot (one for each unique function)
302 : // len = 2 * 2 CachedGlobalSlot (one for each unique function)
303 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, true), 4);
304 : }
305 :
306 26068 : TEST(VectorCallCounts) {
307 6 : if (!i::FLAG_use_ic) return;
308 5 : if (i::FLAG_always_opt) return;
309 :
310 4 : CcTest::InitializeVM();
311 4 : LocalContext context;
312 8 : v8::HandleScope scope(context->GetIsolate());
313 : Isolate* isolate = CcTest::i_isolate();
314 :
315 : // Make sure function f has a call that uses a type feedback slot.
316 : CompileRun(
317 : "function foo() { return 17; }"
318 : "function f(a) { a(); } f(foo);");
319 4 : Handle<JSFunction> f = GetFunction("f");
320 : // There should be one IC.
321 : Handle<FeedbackVector> feedback_vector =
322 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
323 : FeedbackSlot slot(0);
324 : FeedbackNexus nexus(feedback_vector, slot);
325 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
326 :
327 : CompileRun("f(foo); f(foo);");
328 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
329 4 : CHECK_EQ(3, nexus.GetCallCount());
330 :
331 : // Send the IC megamorphic, but we should still have incrementing counts.
332 : CompileRun("f(function() { return 12; });");
333 4 : CHECK_EQ(GENERIC, nexus.ic_state());
334 4 : CHECK_EQ(4, nexus.GetCallCount());
335 : }
336 :
337 26068 : TEST(VectorConstructCounts) {
338 6 : if (!i::FLAG_use_ic) return;
339 5 : if (i::FLAG_always_opt) return;
340 :
341 4 : CcTest::InitializeVM();
342 4 : LocalContext context;
343 8 : v8::HandleScope scope(context->GetIsolate());
344 : Isolate* isolate = CcTest::i_isolate();
345 :
346 : // Make sure function f has a call that uses a type feedback slot.
347 : CompileRun(
348 : "function Foo() {}"
349 : "function f(a) { new a(); } f(Foo);");
350 4 : Handle<JSFunction> f = GetFunction("f");
351 : Handle<FeedbackVector> feedback_vector =
352 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
353 :
354 : FeedbackSlot slot(0);
355 : FeedbackNexus nexus(feedback_vector, slot);
356 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
357 :
358 4 : CHECK(feedback_vector->Get(slot)->IsWeak());
359 :
360 : CompileRun("f(Foo); f(Foo);");
361 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
362 4 : CHECK_EQ(3, nexus.GetCallCount());
363 :
364 : // Send the IC megamorphic, but we should still have incrementing counts.
365 : CompileRun("f(function() {});");
366 4 : CHECK_EQ(GENERIC, nexus.ic_state());
367 4 : CHECK_EQ(4, nexus.GetCallCount());
368 : }
369 :
370 26068 : TEST(VectorSpeculationMode) {
371 6 : if (!i::FLAG_use_ic) return;
372 5 : if (i::FLAG_always_opt) return;
373 :
374 4 : CcTest::InitializeVM();
375 4 : LocalContext context;
376 8 : v8::HandleScope scope(context->GetIsolate());
377 : Isolate* isolate = CcTest::i_isolate();
378 :
379 : // Make sure function f has a call that uses a type feedback slot.
380 : CompileRun(
381 : "function Foo() {}"
382 : "function f(a) { new a(); } f(Foo);");
383 4 : Handle<JSFunction> f = GetFunction("f");
384 : Handle<FeedbackVector> feedback_vector =
385 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
386 :
387 : FeedbackSlot slot(0);
388 : FeedbackNexus nexus(feedback_vector, slot);
389 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
390 :
391 : CompileRun("f(Foo); f(Foo);");
392 4 : CHECK_EQ(3, nexus.GetCallCount());
393 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
394 :
395 4 : nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
396 4 : CHECK_EQ(SpeculationMode::kDisallowSpeculation, nexus.GetSpeculationMode());
397 4 : CHECK_EQ(3, nexus.GetCallCount());
398 :
399 4 : nexus.SetSpeculationMode(SpeculationMode::kAllowSpeculation);
400 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
401 4 : CHECK_EQ(3, nexus.GetCallCount());
402 : }
403 :
404 26068 : TEST(VectorLoadICStates) {
405 6 : if (!i::FLAG_use_ic) return;
406 5 : if (i::FLAG_always_opt) return;
407 :
408 4 : CcTest::InitializeVM();
409 4 : LocalContext context;
410 8 : v8::HandleScope scope(context->GetIsolate());
411 : Isolate* isolate = CcTest::i_isolate();
412 :
413 : // Make sure function f has a call that uses a type feedback slot.
414 : CompileRun(
415 : "var o = { foo: 3 };"
416 : "function f(a) { return a.foo; } f(o);");
417 4 : Handle<JSFunction> f = GetFunction("f");
418 : // There should be one IC.
419 : Handle<FeedbackVector> feedback_vector =
420 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
421 : FeedbackSlot slot(0);
422 : FeedbackNexus nexus(feedback_vector, slot);
423 4 : CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
424 :
425 : CompileRun("f(o)");
426 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
427 : // Verify that the monomorphic map is the one we expect.
428 : v8::MaybeLocal<v8::Value> v8_o =
429 12 : CcTest::global()->Get(context.local(), v8_str("o"));
430 : Handle<JSObject> o =
431 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
432 8 : CHECK_EQ(o->map(), nexus.GetFirstMap());
433 :
434 : // Now go polymorphic.
435 : CompileRun("f({ blarg: 3, foo: 2 })");
436 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
437 :
438 : CompileRun(
439 : "delete o.foo;"
440 : "f(o)");
441 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
442 :
443 : CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
444 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
445 : MapHandles maps;
446 4 : nexus.ExtractMaps(&maps);
447 4 : CHECK_EQ(4, maps.size());
448 :
449 : // Finally driven megamorphic.
450 : CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
451 4 : CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
452 8 : CHECK(nexus.GetFirstMap().is_null());
453 :
454 : // After a collection, state should not be reset to PREMONOMORPHIC.
455 4 : CcTest::CollectAllGarbage();
456 4 : CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
457 : }
458 :
459 26068 : TEST(VectorLoadGlobalICSlotSharing) {
460 6 : if (!i::FLAG_use_ic) return;
461 5 : if (i::FLAG_always_opt) return;
462 :
463 4 : CcTest::InitializeVM();
464 4 : LocalContext context;
465 8 : v8::HandleScope scope(context->GetIsolate());
466 : Isolate* isolate = CcTest::i_isolate();
467 :
468 : // Function f has 5 LoadGlobalICs: 3 for {o} references outside of "typeof"
469 : // operator and 2 for {o} references inside "typeof" operator.
470 : CompileRun(
471 : "o = 10;"
472 : "function f() {"
473 : " var x = o || 10;"
474 : " var y = typeof o;"
475 : " return o , typeof o, x , y, o;"
476 : "}"
477 : "f();");
478 4 : Handle<JSFunction> f = GetFunction("f");
479 : // There should be two IC slots for {o} references outside and inside
480 : // typeof operator respectively.
481 : Handle<FeedbackVector> feedback_vector =
482 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
483 4 : FeedbackVectorHelper helper(feedback_vector);
484 4 : CHECK_EQ(2, helper.slot_count());
485 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
486 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalInsideTypeof);
487 : FeedbackSlot slot1 = helper.slot(0);
488 : FeedbackSlot slot2 = helper.slot(1);
489 4 : CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot1).ic_state());
490 4 : CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot2).ic_state());
491 : }
492 :
493 :
494 26068 : TEST(VectorLoadICOnSmi) {
495 6 : if (!i::FLAG_use_ic) return;
496 5 : if (i::FLAG_always_opt) return;
497 :
498 4 : CcTest::InitializeVM();
499 4 : LocalContext context;
500 8 : v8::HandleScope scope(context->GetIsolate());
501 : Isolate* isolate = CcTest::i_isolate();
502 : Heap* heap = isolate->heap();
503 :
504 : // Make sure function f has a call that uses a type feedback slot.
505 : CompileRun(
506 : "var o = { foo: 3 };"
507 : "function f(a) { return a.foo; } f(o);");
508 4 : Handle<JSFunction> f = GetFunction("f");
509 : // There should be one IC.
510 : Handle<FeedbackVector> feedback_vector =
511 8 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
512 : FeedbackSlot slot(0);
513 : FeedbackNexus nexus(feedback_vector, slot);
514 4 : CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
515 :
516 : CompileRun("f(34)");
517 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
518 : // Verify that the monomorphic map is the one we expect.
519 : Map number_map = ReadOnlyRoots(heap).heap_number_map();
520 4 : CHECK_EQ(number_map, nexus.GetFirstMap());
521 :
522 : // Now go polymorphic on o.
523 : CompileRun("f(o)");
524 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
525 :
526 : MapHandles maps;
527 4 : nexus.ExtractMaps(&maps);
528 4 : CHECK_EQ(2, maps.size());
529 :
530 : // One of the maps should be the o map.
531 : v8::MaybeLocal<v8::Value> v8_o =
532 12 : CcTest::global()->Get(context.local(), v8_str("o"));
533 : Handle<JSObject> o =
534 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
535 : bool number_map_found = false;
536 : bool o_map_found = false;
537 12 : for (Handle<Map> current : maps) {
538 8 : if (*current == number_map)
539 : number_map_found = true;
540 4 : else if (*current == o->map())
541 : o_map_found = true;
542 : }
543 4 : CHECK(number_map_found && o_map_found);
544 :
545 : // The degree of polymorphism doesn't change.
546 : CompileRun("f(100)");
547 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
548 : MapHandles maps2;
549 4 : nexus.ExtractMaps(&maps2);
550 4 : CHECK_EQ(2, maps2.size());
551 : }
552 :
553 :
554 26068 : TEST(ReferenceContextAllocatesNoSlots) {
555 6 : if (!i::FLAG_use_ic) return;
556 5 : if (i::FLAG_always_opt) return;
557 :
558 4 : CcTest::InitializeVM();
559 4 : LocalContext context;
560 8 : v8::HandleScope scope(context->GetIsolate());
561 : Isolate* isolate = CcTest::i_isolate();
562 :
563 : {
564 : CompileRun(
565 : "function testvar(x) {"
566 : " y = x;"
567 : " y = a;"
568 : " return y;"
569 : "}"
570 : "a = 3;"
571 : "testvar({});");
572 :
573 4 : Handle<JSFunction> f = GetFunction("testvar");
574 :
575 : // There should be two LOAD_ICs, one for a and one for y at the end.
576 : Handle<FeedbackVector> feedback_vector =
577 8 : handle(f->feedback_vector(), isolate);
578 4 : FeedbackVectorHelper helper(feedback_vector);
579 4 : CHECK_EQ(3, helper.slot_count());
580 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy);
581 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
582 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
583 : }
584 :
585 : {
586 : CompileRun(
587 : "function testprop(x) {"
588 : " 'use strict';"
589 : " x.blue = a;"
590 : "}"
591 : "testprop({ blue: 3 });");
592 :
593 4 : Handle<JSFunction> f = GetFunction("testprop");
594 :
595 : // There should be one LOAD_IC, for the load of a.
596 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
597 4 : FeedbackVectorHelper helper(feedback_vector);
598 4 : CHECK_EQ(2, helper.slot_count());
599 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
600 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
601 : }
602 :
603 : {
604 : CompileRun(
605 : "function testpropfunc(x) {"
606 : " x().blue = a;"
607 : " return x().blue;"
608 : "}"
609 : "function makeresult() { return { blue: 3 }; }"
610 : "testpropfunc(makeresult);");
611 :
612 4 : Handle<JSFunction> f = GetFunction("testpropfunc");
613 :
614 : // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
615 : // to call x and a LOAD_IC to load blue.
616 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
617 4 : FeedbackVectorHelper helper(feedback_vector);
618 4 : CHECK_EQ(5, helper.slot_count());
619 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kCall);
620 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
621 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy);
622 4 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kCall);
623 4 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
624 : }
625 :
626 : {
627 : CompileRun(
628 : "function testkeyedprop(x) {"
629 : " x[0] = a;"
630 : " return x[0];"
631 : "}"
632 : "testkeyedprop([0, 1, 2]);");
633 :
634 4 : Handle<JSFunction> f = GetFunction("testkeyedprop");
635 :
636 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
637 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
638 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
639 4 : FeedbackVectorHelper helper(feedback_vector);
640 4 : CHECK_EQ(3, helper.slot_count());
641 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
642 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedSloppy);
643 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
644 : }
645 :
646 : {
647 : CompileRun(
648 : "function testkeyedprop(x) {"
649 : " 'use strict';"
650 : " x[0] = a;"
651 : " return x[0];"
652 : "}"
653 : "testkeyedprop([0, 1, 2]);");
654 :
655 4 : Handle<JSFunction> f = GetFunction("testkeyedprop");
656 :
657 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
658 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
659 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
660 4 : FeedbackVectorHelper helper(feedback_vector);
661 4 : CHECK_EQ(3, helper.slot_count());
662 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
663 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedStrict);
664 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
665 : }
666 :
667 : {
668 : CompileRun(
669 : "function testcompound(x) {"
670 : " 'use strict';"
671 : " x.old = x.young = x.in_between = a;"
672 : " return x.old + x.young;"
673 : "}"
674 : "testcompound({ old: 3, young: 3, in_between: 3 });");
675 :
676 4 : Handle<JSFunction> f = GetFunction("testcompound");
677 :
678 : // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
679 : // of x.old and x.young.
680 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
681 4 : FeedbackVectorHelper helper(feedback_vector);
682 4 : CHECK_EQ(7, helper.slot_count());
683 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
684 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
685 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedStrict);
686 4 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kStoreNamedStrict);
687 4 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kBinaryOp);
688 4 : CHECK_SLOT_KIND(helper, 5, FeedbackSlotKind::kLoadProperty);
689 4 : CHECK_SLOT_KIND(helper, 6, FeedbackSlotKind::kLoadProperty);
690 : }
691 : }
692 :
693 :
694 26068 : TEST(VectorStoreICBasic) {
695 6 : if (!i::FLAG_use_ic) return;
696 5 : if (i::FLAG_always_opt) return;
697 :
698 4 : CcTest::InitializeVM();
699 4 : LocalContext context;
700 8 : v8::HandleScope scope(context->GetIsolate());
701 :
702 : CompileRun(
703 : "function f(a) {"
704 : " a.foo = 5;"
705 : "}"
706 : "var a = { foo: 3 };"
707 : "f(a);"
708 : "f(a);"
709 : "f(a);");
710 4 : Handle<JSFunction> f = GetFunction("f");
711 : // There should be one IC slot.
712 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
713 4 : FeedbackVectorHelper helper(feedback_vector);
714 4 : CHECK_EQ(1, helper.slot_count());
715 : FeedbackSlot slot(0);
716 : FeedbackNexus nexus(feedback_vector, slot);
717 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
718 : }
719 :
720 26068 : TEST(StoreOwnIC) {
721 6 : if (!i::FLAG_use_ic) return;
722 5 : if (i::FLAG_always_opt) return;
723 :
724 4 : CcTest::InitializeVM();
725 4 : LocalContext context;
726 8 : v8::HandleScope scope(context->GetIsolate());
727 :
728 : CompileRun(
729 : "function f(v) {"
730 : " return {a: 0, b: v, c: 0};"
731 : "}"
732 : "f(1);"
733 : "f(2);"
734 : "f(3);");
735 4 : Handle<JSFunction> f = GetFunction("f");
736 : // There should be one IC slot.
737 8 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
738 4 : FeedbackVectorHelper helper(feedback_vector);
739 4 : CHECK_EQ(2, helper.slot_count());
740 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLiteral);
741 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreOwnNamed);
742 : FeedbackNexus nexus(feedback_vector, helper.slot(1));
743 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
744 : }
745 :
746 : } // namespace
747 :
748 : } // namespace internal
749 78189 : } // namespace v8
|