LCOV - code coverage report
Current view: top level - test/cctest - test-feedback-vector.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 275 275 100.0 %
Date: 2019-04-17 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       26644 : 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             :     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       26644 : 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       26644 : TEST(VectorCallICStates) {
     158           6 :   if (!i::FLAG_use_ic) return;
     159           5 :   if (i::FLAG_always_opt) return;
     160           4 :   FLAG_allow_natives_syntax = true;
     161             : 
     162           4 :   CcTest::InitializeVM();
     163           4 :   LocalContext context;
     164           8 :   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           4 :   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           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     178             : 
     179             :   CompileRun("f(function() { return 16; })");
     180           4 :   CHECK_EQ(GENERIC, nexus.ic_state());
     181             : 
     182             :   // After a collection, state should remain GENERIC.
     183           4 :   CcTest::CollectAllGarbage();
     184           4 :   CHECK_EQ(GENERIC, nexus.ic_state());
     185             : }
     186             : 
     187       26644 : TEST(VectorCallFeedback) {
     188           6 :   if (!i::FLAG_use_ic) return;
     189           5 :   if (i::FLAG_always_opt) return;
     190           4 :   FLAG_allow_natives_syntax = true;
     191             : 
     192           4 :   CcTest::InitializeVM();
     193           4 :   LocalContext context;
     194           8 :   v8::HandleScope scope(context->GetIsolate());
     195             :   Isolate* isolate = CcTest::i_isolate();
     196             :   // Make sure function f has a call that uses a type feedback slot.
     197             :   CompileRun(
     198             :       "function foo() { return 17; }"
     199             :       "%EnsureFeedbackVectorForFunction(f);"
     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             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     206             :   FeedbackSlot slot(0);
     207             :   FeedbackNexus nexus(feedback_vector, slot);
     208             : 
     209           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     210             :   HeapObject heap_object;
     211           8 :   CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
     212           4 :   CHECK_EQ(*foo, heap_object);
     213             : 
     214           4 :   CcTest::CollectAllGarbage();
     215             :   // It should stay monomorphic even after a GC.
     216           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     217             : }
     218             : 
     219       26644 : TEST(VectorCallFeedbackForArray) {
     220           6 :   if (!i::FLAG_use_ic) return;
     221           5 :   if (i::FLAG_always_opt) return;
     222           4 :   FLAG_allow_natives_syntax = true;
     223             : 
     224           4 :   CcTest::InitializeVM();
     225           4 :   LocalContext context;
     226           8 :   v8::HandleScope scope(context->GetIsolate());
     227             :   Isolate* isolate = CcTest::i_isolate();
     228             :   // Make sure function f has a call that uses a type feedback slot.
     229             :   CompileRun(
     230             :       "function f(a) { a(); };"
     231             :       "%EnsureFeedbackVectorForFunction(f);"
     232             :       "f(Array);");
     233           4 :   Handle<JSFunction> f = GetFunction("f");
     234             :   // There should be one IC.
     235             :   Handle<FeedbackVector> feedback_vector =
     236             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     237             :   FeedbackSlot slot(0);
     238             :   FeedbackNexus nexus(feedback_vector, slot);
     239             : 
     240           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     241             :   HeapObject heap_object;
     242           8 :   CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
     243           8 :   CHECK_EQ(*isolate->array_function(), heap_object);
     244             : 
     245           4 :   CcTest::CollectAllGarbage();
     246             :   // It should stay monomorphic even after a GC.
     247           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     248             : }
     249             : 
     250          24 : size_t GetFeedbackVectorLength(Isolate* isolate, const char* src,
     251             :                                bool with_oneshot_opt) {
     252          24 :   i::FLAG_enable_one_shot_optimization = with_oneshot_opt;
     253             :   i::Handle<i::Object> i_object = v8::Utils::OpenHandle(*CompileRun(src));
     254             :   i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(i_object);
     255             :   Handle<FeedbackVector> feedback_vector =
     256             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     257          24 :   return feedback_vector->length();
     258             : }
     259             : 
     260       26644 : TEST(OneShotCallICSlotCount) {
     261           6 :   if (!i::FLAG_use_ic) return;
     262           5 :   if (i::FLAG_always_opt) return;
     263           4 :   if (i::FLAG_lazy_feedback_allocation) return;
     264           4 :   FLAG_allow_natives_syntax = true;
     265             : 
     266           4 :   CcTest::InitializeVM();
     267           4 :   LocalContext context;
     268           8 :   v8::HandleScope scope(context->GetIsolate());
     269             :   Isolate* isolate = CcTest::i_isolate();
     270           4 :   i::FLAG_compilation_cache = false;
     271             : 
     272             :   const char* no_call = R"(
     273             :     function f1() {};
     274             :     function f2() {};
     275             :     (function() {
     276             :       return arguments.callee;
     277             :     })();
     278             :   )";
     279             :   // len = 2 * 1 ldaNamed property
     280           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, false), 2);
     281             :   // no slots of named property loads/stores in one shot
     282           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, true), 0);
     283             : 
     284             :   const char* single_call = R"(
     285             :     function f1() {};
     286             :     function f2() {};
     287             :     (function() {
     288             :       f1();
     289             :       return arguments.callee;
     290             :     })();
     291             :   )";
     292             :   // len = 2 * 1 ldaNamed Slot + 2 * 1 CachedGlobalSlot + 2 * 1 CallICSlot
     293           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, false), 6);
     294             :   // len = 2 * 1 CachedGlobalSlot
     295           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, true), 2);
     296             : 
     297             :   const char* multiple_calls = R"(
     298             :     function f1() {};
     299             :     function f2() {};
     300             :     (function() {
     301             :       f1();
     302             :       f2();
     303             :       f1();
     304             :       f2();
     305             :       return arguments.callee;
     306             :     })();
     307             :   )";
     308             :   // len = 2 * 1 ldaNamedSlot + 2 *  2 CachedGlobalSlot (one for each unique
     309             :   // function) + 2 * 4 CallICSlot (one for each function call)
     310           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, false), 14);
     311             :   // CachedGlobalSlot (one for each unique function)
     312             :   // len = 2 * 2 CachedGlobalSlot (one for each unique function)
     313           8 :   CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, true), 4);
     314             : }
     315             : 
     316       26644 : TEST(VectorCallCounts) {
     317           6 :   if (!i::FLAG_use_ic) return;
     318           5 :   if (i::FLAG_always_opt) return;
     319           4 :   FLAG_allow_natives_syntax = true;
     320             : 
     321           4 :   CcTest::InitializeVM();
     322           4 :   LocalContext context;
     323           8 :   v8::HandleScope scope(context->GetIsolate());
     324             :   Isolate* isolate = CcTest::i_isolate();
     325             : 
     326             :   // Make sure function f has a call that uses a type feedback slot.
     327             :   CompileRun(
     328             :       "function foo() { return 17; }"
     329             :       "%EnsureFeedbackVectorForFunction(f);"
     330             :       "function f(a) { a(); } f(foo);");
     331           4 :   Handle<JSFunction> f = GetFunction("f");
     332             :   // There should be one IC.
     333             :   Handle<FeedbackVector> feedback_vector =
     334             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     335             :   FeedbackSlot slot(0);
     336             :   FeedbackNexus nexus(feedback_vector, slot);
     337           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     338             : 
     339             :   CompileRun("f(foo); f(foo);");
     340           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     341           4 :   CHECK_EQ(3, nexus.GetCallCount());
     342             : 
     343             :   // Send the IC megamorphic, but we should still have incrementing counts.
     344             :   CompileRun("f(function() { return 12; });");
     345           4 :   CHECK_EQ(GENERIC, nexus.ic_state());
     346           4 :   CHECK_EQ(4, nexus.GetCallCount());
     347             : }
     348             : 
     349       26644 : TEST(VectorConstructCounts) {
     350           6 :   if (!i::FLAG_use_ic) return;
     351           5 :   if (i::FLAG_always_opt) return;
     352           4 :   FLAG_allow_natives_syntax = true;
     353             : 
     354           4 :   CcTest::InitializeVM();
     355           4 :   LocalContext context;
     356           8 :   v8::HandleScope scope(context->GetIsolate());
     357             :   Isolate* isolate = CcTest::i_isolate();
     358             : 
     359             :   // Make sure function f has a call that uses a type feedback slot.
     360             :   CompileRun(
     361             :       "function Foo() {}"
     362             :       "%EnsureFeedbackVectorForFunction(f);"
     363             :       "function f(a) { new a(); } f(Foo);");
     364           4 :   Handle<JSFunction> f = GetFunction("f");
     365             :   Handle<FeedbackVector> feedback_vector =
     366             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     367             : 
     368             :   FeedbackSlot slot(0);
     369             :   FeedbackNexus nexus(feedback_vector, slot);
     370           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     371             : 
     372           4 :   CHECK(feedback_vector->Get(slot)->IsWeak());
     373             : 
     374             :   CompileRun("f(Foo); f(Foo);");
     375           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     376           4 :   CHECK_EQ(3, nexus.GetCallCount());
     377             : 
     378             :   // Send the IC megamorphic, but we should still have incrementing counts.
     379             :   CompileRun("f(function() {});");
     380           4 :   CHECK_EQ(GENERIC, nexus.ic_state());
     381           4 :   CHECK_EQ(4, nexus.GetCallCount());
     382             : }
     383             : 
     384       26644 : TEST(VectorSpeculationMode) {
     385           6 :   if (!i::FLAG_use_ic) return;
     386           5 :   if (i::FLAG_always_opt) return;
     387           4 :   FLAG_allow_natives_syntax = true;
     388             : 
     389           4 :   CcTest::InitializeVM();
     390           4 :   LocalContext context;
     391           8 :   v8::HandleScope scope(context->GetIsolate());
     392             :   Isolate* isolate = CcTest::i_isolate();
     393             : 
     394             :   // Make sure function f has a call that uses a type feedback slot.
     395             :   CompileRun(
     396             :       "function Foo() {}"
     397             :       "%EnsureFeedbackVectorForFunction(f);"
     398             :       "function f(a) { new a(); } f(Foo);");
     399           4 :   Handle<JSFunction> f = GetFunction("f");
     400             :   Handle<FeedbackVector> feedback_vector =
     401             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     402             : 
     403             :   FeedbackSlot slot(0);
     404             :   FeedbackNexus nexus(feedback_vector, slot);
     405           4 :   CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
     406             : 
     407             :   CompileRun("f(Foo); f(Foo);");
     408           4 :   CHECK_EQ(3, nexus.GetCallCount());
     409           4 :   CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
     410             : 
     411           4 :   nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
     412           4 :   CHECK_EQ(SpeculationMode::kDisallowSpeculation, nexus.GetSpeculationMode());
     413           4 :   CHECK_EQ(3, nexus.GetCallCount());
     414             : 
     415           4 :   nexus.SetSpeculationMode(SpeculationMode::kAllowSpeculation);
     416           4 :   CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
     417           4 :   CHECK_EQ(3, nexus.GetCallCount());
     418             : }
     419             : 
     420       26644 : TEST(VectorLoadICStates) {
     421           6 :   if (!i::FLAG_use_ic) return;
     422           5 :   if (i::FLAG_always_opt) return;
     423           4 :   FLAG_allow_natives_syntax = true;
     424             : 
     425           4 :   CcTest::InitializeVM();
     426           4 :   LocalContext context;
     427           8 :   v8::HandleScope scope(context->GetIsolate());
     428             :   Isolate* isolate = CcTest::i_isolate();
     429             : 
     430             :   // Make sure function f has a call that uses a type feedback slot.
     431             :   CompileRun(
     432             :       "var o = { foo: 3 };"
     433             :       "%EnsureFeedbackVectorForFunction(f);"
     434             :       "function f(a) { return a.foo; } f(o);");
     435           4 :   Handle<JSFunction> f = GetFunction("f");
     436             :   // There should be one IC.
     437             :   Handle<FeedbackVector> feedback_vector =
     438             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     439             :   FeedbackSlot slot(0);
     440             :   FeedbackNexus nexus(feedback_vector, slot);
     441           4 :   CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
     442             : 
     443             :   CompileRun("f(o)");
     444           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     445             :   // Verify that the monomorphic map is the one we expect.
     446             :   v8::MaybeLocal<v8::Value> v8_o =
     447          12 :       CcTest::global()->Get(context.local(), v8_str("o"));
     448             :   Handle<JSObject> o =
     449             :       Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
     450           8 :   CHECK_EQ(o->map(), nexus.GetFirstMap());
     451             : 
     452             :   // Now go polymorphic.
     453             :   CompileRun("f({ blarg: 3, foo: 2 })");
     454           4 :   CHECK_EQ(POLYMORPHIC, nexus.ic_state());
     455             : 
     456             :   CompileRun(
     457             :       "delete o.foo;"
     458             :       "f(o)");
     459           4 :   CHECK_EQ(POLYMORPHIC, nexus.ic_state());
     460             : 
     461             :   CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
     462           4 :   CHECK_EQ(POLYMORPHIC, nexus.ic_state());
     463             :   MapHandles maps;
     464           4 :   nexus.ExtractMaps(&maps);
     465           4 :   CHECK_EQ(4, maps.size());
     466             : 
     467             :   // Finally driven megamorphic.
     468             :   CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
     469           4 :   CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
     470           8 :   CHECK(nexus.GetFirstMap().is_null());
     471             : 
     472             :   // After a collection, state should not be reset to PREMONOMORPHIC.
     473           4 :   CcTest::CollectAllGarbage();
     474           4 :   CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
     475             : }
     476             : 
     477       26644 : TEST(VectorLoadGlobalICSlotSharing) {
     478           6 :   if (!i::FLAG_use_ic) return;
     479           5 :   if (i::FLAG_always_opt) return;
     480           4 :   FLAG_allow_natives_syntax = true;
     481             : 
     482           4 :   CcTest::InitializeVM();
     483           4 :   LocalContext context;
     484           8 :   v8::HandleScope scope(context->GetIsolate());
     485             :   Isolate* isolate = CcTest::i_isolate();
     486             : 
     487             :   // Function f has 5 LoadGlobalICs: 3 for {o} references outside of "typeof"
     488             :   // operator and 2 for {o} references inside "typeof" operator.
     489             :   CompileRun(
     490             :       "o = 10;"
     491             :       "function f() {"
     492             :       "  var x = o || 10;"
     493             :       "  var y = typeof o;"
     494             :       "  return o , typeof o, x , y, o;"
     495             :       "}"
     496             :       "%EnsureFeedbackVectorForFunction(f);"
     497             :       "f();");
     498           4 :   Handle<JSFunction> f = GetFunction("f");
     499             :   // There should be two IC slots for {o} references outside and inside
     500             :   // typeof operator respectively.
     501             :   Handle<FeedbackVector> feedback_vector =
     502             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     503           4 :   FeedbackVectorHelper helper(feedback_vector);
     504           4 :   CHECK_EQ(2, helper.slot_count());
     505           4 :   CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     506           4 :   CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalInsideTypeof);
     507             :   FeedbackSlot slot1 = helper.slot(0);
     508             :   FeedbackSlot slot2 = helper.slot(1);
     509           4 :   CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot1).ic_state());
     510           4 :   CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot2).ic_state());
     511             : }
     512             : 
     513             : 
     514       26644 : TEST(VectorLoadICOnSmi) {
     515           6 :   if (!i::FLAG_use_ic) return;
     516           5 :   if (i::FLAG_always_opt) return;
     517           4 :   FLAG_allow_natives_syntax = true;
     518             : 
     519           4 :   CcTest::InitializeVM();
     520           4 :   LocalContext context;
     521           8 :   v8::HandleScope scope(context->GetIsolate());
     522             :   Isolate* isolate = CcTest::i_isolate();
     523             :   Heap* heap = isolate->heap();
     524             : 
     525             :   // Make sure function f has a call that uses a type feedback slot.
     526             :   CompileRun(
     527             :       "var o = { foo: 3 };"
     528             :       "%EnsureFeedbackVectorForFunction(f);"
     529             :       "function f(a) { return a.foo; } f(o);");
     530           4 :   Handle<JSFunction> f = GetFunction("f");
     531             :   // There should be one IC.
     532             :   Handle<FeedbackVector> feedback_vector =
     533             :       Handle<FeedbackVector>(f->feedback_vector(), isolate);
     534             :   FeedbackSlot slot(0);
     535             :   FeedbackNexus nexus(feedback_vector, slot);
     536           4 :   CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
     537             : 
     538             :   CompileRun("f(34)");
     539           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     540             :   // Verify that the monomorphic map is the one we expect.
     541             :   Map number_map = ReadOnlyRoots(heap).heap_number_map();
     542           4 :   CHECK_EQ(number_map, nexus.GetFirstMap());
     543             : 
     544             :   // Now go polymorphic on o.
     545             :   CompileRun("f(o)");
     546           4 :   CHECK_EQ(POLYMORPHIC, nexus.ic_state());
     547             : 
     548             :   MapHandles maps;
     549           4 :   nexus.ExtractMaps(&maps);
     550           4 :   CHECK_EQ(2, maps.size());
     551             : 
     552             :   // One of the maps should be the o map.
     553             :   v8::MaybeLocal<v8::Value> v8_o =
     554          12 :       CcTest::global()->Get(context.local(), v8_str("o"));
     555             :   Handle<JSObject> o =
     556             :       Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
     557             :   bool number_map_found = false;
     558             :   bool o_map_found = false;
     559          12 :   for (Handle<Map> current : maps) {
     560           8 :     if (*current == number_map)
     561             :       number_map_found = true;
     562           4 :     else if (*current == o->map())
     563             :       o_map_found = true;
     564             :   }
     565           4 :   CHECK(number_map_found && o_map_found);
     566             : 
     567             :   // The degree of polymorphism doesn't change.
     568             :   CompileRun("f(100)");
     569           4 :   CHECK_EQ(POLYMORPHIC, nexus.ic_state());
     570             :   MapHandles maps2;
     571           4 :   nexus.ExtractMaps(&maps2);
     572           4 :   CHECK_EQ(2, maps2.size());
     573             : }
     574             : 
     575             : 
     576       26644 : TEST(ReferenceContextAllocatesNoSlots) {
     577           6 :   if (!i::FLAG_use_ic) return;
     578           5 :   if (i::FLAG_always_opt) return;
     579           4 :   FLAG_allow_natives_syntax = true;
     580             : 
     581           4 :   CcTest::InitializeVM();
     582           4 :   LocalContext context;
     583           8 :   v8::HandleScope scope(context->GetIsolate());
     584             :   Isolate* isolate = CcTest::i_isolate();
     585             : 
     586             :   {
     587             :     CompileRun(
     588             :         "function testvar(x) {"
     589             :         "  y = x;"
     590             :         "  y = a;"
     591             :         "  return y;"
     592             :         "}"
     593             :         "%EnsureFeedbackVectorForFunction(testvar);"
     594             :         "a = 3;"
     595             :         "testvar({});");
     596             : 
     597           4 :     Handle<JSFunction> f = GetFunction("testvar");
     598             : 
     599             :     // There should be two LOAD_ICs, one for a and one for y at the end.
     600             :     Handle<FeedbackVector> feedback_vector =
     601           4 :         handle(f->feedback_vector(), isolate);
     602           4 :     FeedbackVectorHelper helper(feedback_vector);
     603           4 :     CHECK_EQ(3, helper.slot_count());
     604           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy);
     605           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     606           4 :     CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     607             :   }
     608             : 
     609             :   {
     610             :     CompileRun(
     611             :         "function testprop(x) {"
     612             :         "  'use strict';"
     613             :         "  x.blue = a;"
     614             :         "}"
     615             :         "%EnsureFeedbackVectorForFunction(testprop);"
     616             :         "testprop({ blue: 3 });");
     617             : 
     618           4 :     Handle<JSFunction> f = GetFunction("testprop");
     619             : 
     620             :     // There should be one LOAD_IC, for the load of a.
     621             :     Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
     622           4 :     FeedbackVectorHelper helper(feedback_vector);
     623           4 :     CHECK_EQ(2, helper.slot_count());
     624           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     625           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
     626             :   }
     627             : 
     628             :   {
     629             :     CompileRun(
     630             :         "function testpropfunc(x) {"
     631             :         "  x().blue = a;"
     632             :         "  return x().blue;"
     633             :         "}"
     634             :         "%EnsureFeedbackVectorForFunction(testpropfunc);"
     635             :         "function makeresult() { return { blue: 3 }; }"
     636             :         "testpropfunc(makeresult);");
     637             : 
     638           4 :     Handle<JSFunction> f = GetFunction("testpropfunc");
     639             : 
     640             :     // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
     641             :     // to call x and a LOAD_IC to load blue.
     642             :     Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
     643           4 :     FeedbackVectorHelper helper(feedback_vector);
     644           4 :     CHECK_EQ(5, helper.slot_count());
     645           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kCall);
     646           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     647           4 :     CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy);
     648           4 :     CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kCall);
     649           4 :     CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
     650             :   }
     651             : 
     652             :   {
     653             :     CompileRun(
     654             :         "function testkeyedprop(x) {"
     655             :         "  x[0] = a;"
     656             :         "  return x[0];"
     657             :         "}"
     658             :         "%EnsureFeedbackVectorForFunction(testkeyedprop);"
     659             :         "testkeyedprop([0, 1, 2]);");
     660             : 
     661           4 :     Handle<JSFunction> f = GetFunction("testkeyedprop");
     662             : 
     663             :     // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
     664             :     // KEYED_LOAD_IC for the load of x[0] in the return statement.
     665             :     Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
     666           4 :     FeedbackVectorHelper helper(feedback_vector);
     667           4 :     CHECK_EQ(3, helper.slot_count());
     668           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     669           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedSloppy);
     670           4 :     CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
     671             :   }
     672             : 
     673             :   {
     674             :     CompileRun(
     675             :         "function testkeyedprop(x) {"
     676             :         "  'use strict';"
     677             :         "  x[0] = a;"
     678             :         "  return x[0];"
     679             :         "}"
     680             :         "%EnsureFeedbackVectorForFunction(testkeyedprop);"
     681             :         "testkeyedprop([0, 1, 2]);");
     682             : 
     683           4 :     Handle<JSFunction> f = GetFunction("testkeyedprop");
     684             : 
     685             :     // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
     686             :     // KEYED_LOAD_IC for the load of x[0] in the return statement.
     687             :     Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
     688           4 :     FeedbackVectorHelper helper(feedback_vector);
     689           4 :     CHECK_EQ(3, helper.slot_count());
     690           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     691           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedStrict);
     692           4 :     CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
     693             :   }
     694             : 
     695             :   {
     696             :     CompileRun(
     697             :         "function testcompound(x) {"
     698             :         "  'use strict';"
     699             :         "  x.old = x.young = x.in_between = a;"
     700             :         "  return x.old + x.young;"
     701             :         "}"
     702             :         "%EnsureFeedbackVectorForFunction(testcompound);"
     703             :         "testcompound({ old: 3, young: 3, in_between: 3 });");
     704             : 
     705           4 :     Handle<JSFunction> f = GetFunction("testcompound");
     706             : 
     707             :     // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
     708             :     // of x.old and x.young.
     709             :     Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
     710           4 :     FeedbackVectorHelper helper(feedback_vector);
     711           4 :     CHECK_EQ(7, helper.slot_count());
     712           4 :     CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
     713           4 :     CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
     714           4 :     CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedStrict);
     715           4 :     CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kStoreNamedStrict);
     716           4 :     CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kBinaryOp);
     717           4 :     CHECK_SLOT_KIND(helper, 5, FeedbackSlotKind::kLoadProperty);
     718           4 :     CHECK_SLOT_KIND(helper, 6, FeedbackSlotKind::kLoadProperty);
     719             :   }
     720             : }
     721             : 
     722             : 
     723       26644 : TEST(VectorStoreICBasic) {
     724           6 :   if (!i::FLAG_use_ic) return;
     725           5 :   if (i::FLAG_always_opt) return;
     726           4 :   FLAG_allow_natives_syntax = true;
     727             : 
     728           4 :   CcTest::InitializeVM();
     729           4 :   LocalContext context;
     730           8 :   v8::HandleScope scope(context->GetIsolate());
     731             : 
     732             :   CompileRun(
     733             :       "function f(a) {"
     734             :       "  a.foo = 5;"
     735             :       "};"
     736             :       "%EnsureFeedbackVectorForFunction(f);"
     737             :       "var a = { foo: 3 };"
     738             :       "f(a);"
     739             :       "f(a);"
     740             :       "f(a);");
     741           4 :   Handle<JSFunction> f = GetFunction("f");
     742             :   // There should be one IC slot.
     743             :   Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
     744           4 :   FeedbackVectorHelper helper(feedback_vector);
     745           4 :   CHECK_EQ(1, helper.slot_count());
     746             :   FeedbackSlot slot(0);
     747             :   FeedbackNexus nexus(feedback_vector, slot);
     748           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     749             : }
     750             : 
     751       26644 : TEST(StoreOwnIC) {
     752           6 :   if (!i::FLAG_use_ic) return;
     753           5 :   if (i::FLAG_always_opt) return;
     754           4 :   FLAG_allow_natives_syntax = true;
     755             : 
     756           4 :   CcTest::InitializeVM();
     757           4 :   LocalContext context;
     758           8 :   v8::HandleScope scope(context->GetIsolate());
     759             : 
     760             :   CompileRun(
     761             :       "function f(v) {"
     762             :       "  return {a: 0, b: v, c: 0};"
     763             :       "}"
     764             :       "%EnsureFeedbackVectorForFunction(f);"
     765             :       "f(1);"
     766             :       "f(2);"
     767             :       "f(3);");
     768           4 :   Handle<JSFunction> f = GetFunction("f");
     769             :   // There should be one IC slot.
     770             :   Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
     771           4 :   FeedbackVectorHelper helper(feedback_vector);
     772           4 :   CHECK_EQ(2, helper.slot_count());
     773           4 :   CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLiteral);
     774           4 :   CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreOwnNamed);
     775             :   FeedbackNexus nexus(feedback_vector, helper.slot(1));
     776           4 :   CHECK_EQ(MONOMORPHIC, nexus.ic_state());
     777             : }
     778             : 
     779             : }  // namespace
     780             : 
     781             : }  // namespace internal
     782       79917 : }  // namespace v8

Generated by: LCOV version 1.10