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