LCOV - code coverage report
Current view: top level - test/cctest - test-feedback-vector.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 308 308 100.0 %
Date: 2019-02-19 Functions: 19 19 100.0 %

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

Generated by: LCOV version 1.10