LCOV - code coverage report
Current view: top level - test/cctest - test-feedback-vector.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 279 279 100.0 %
Date: 2019-03-21 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         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

Generated by: LCOV version 1.10