LCOV - code coverage report
Current view: top level - test/cctest - test-accessor-assembler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 93 94 98.9 %
Date: 2019-04-17 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright 2016 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 "test/cctest/cctest.h"
       6             : 
       7             : #include "src/base/utils/random-number-generator.h"
       8             : #include "src/ic/accessor-assembler.h"
       9             : #include "src/ic/stub-cache.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects/smi.h"
      12             : #include "test/cctest/compiler/code-assembler-tester.h"
      13             : #include "test/cctest/compiler/function-tester.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : using compiler::CodeAssemblerTester;
      19             : using compiler::FunctionTester;
      20             : using compiler::Node;
      21             : 
      22             : namespace {
      23             : 
      24           8 : void TestStubCacheOffsetCalculation(StubCache::Table table) {
      25             :   Isolate* isolate(CcTest::InitIsolateOnce());
      26             :   const int kNumParams = 2;
      27          16 :   CodeAssemblerTester data(isolate, kNumParams);
      28             :   AccessorAssembler m(data.state());
      29             : 
      30             :   {
      31           8 :     Node* name = m.Parameter(0);
      32           8 :     Node* map = m.Parameter(1);
      33             :     Node* primary_offset = m.StubCachePrimaryOffsetForTesting(name, map);
      34             :     Node* result;
      35           8 :     if (table == StubCache::kPrimary) {
      36             :       result = primary_offset;
      37             :     } else {
      38           4 :       CHECK_EQ(StubCache::kSecondary, table);
      39             :       result = m.StubCacheSecondaryOffsetForTesting(name, primary_offset);
      40             :     }
      41          16 :     m.Return(m.SmiTag(result));
      42             :   }
      43             : 
      44           8 :   Handle<Code> code = data.GenerateCode();
      45           8 :   FunctionTester ft(code, kNumParams);
      46             : 
      47             :   Factory* factory = isolate->factory();
      48             :   Handle<Name> names[] = {
      49             :       factory->NewSymbol(),
      50             :       factory->InternalizeUtf8String("a"),
      51             :       factory->InternalizeUtf8String("bb"),
      52             :       factory->InternalizeUtf8String("ccc"),
      53             :       factory->NewPrivateSymbol(),
      54             :       factory->InternalizeUtf8String("dddd"),
      55             :       factory->InternalizeUtf8String("eeeee"),
      56             :       factory->InternalizeUtf8String("name"),
      57             :       factory->NewSymbol(),
      58             :       factory->NewPrivateSymbol(),
      59          80 :   };
      60             : 
      61             :   Handle<Map> maps[] = {
      62             :       Handle<Map>(Map(), isolate),
      63             :       factory->cell_map(),
      64             :       Map::Create(isolate, 0),
      65             :       factory->meta_map(),
      66             :       factory->code_map(),
      67             :       Map::Create(isolate, 0),
      68             :       factory->hash_table_map(),
      69             :       factory->symbol_map(),
      70             :       factory->string_map(),
      71             :       Map::Create(isolate, 0),
      72             :       factory->sloppy_arguments_elements_map(),
      73          56 :   };
      74             : 
      75         168 :   for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
      76          80 :     Handle<Name> name = names[name_index];
      77        1840 :     for (size_t map_index = 0; map_index < arraysize(maps); map_index++) {
      78         880 :       Handle<Map> map = maps[map_index];
      79             : 
      80             :       int expected_result;
      81             :       {
      82         880 :         int primary_offset = StubCache::PrimaryOffsetForTesting(*name, *map);
      83         880 :         if (table == StubCache::kPrimary) {
      84             :           expected_result = primary_offset;
      85             :         } else {
      86             :           expected_result =
      87         440 :               StubCache::SecondaryOffsetForTesting(*name, primary_offset);
      88             :         }
      89             :       }
      90        1760 :       Handle<Object> result = ft.Call(name, map).ToHandleChecked();
      91             : 
      92         880 :       Smi expected = Smi::FromInt(expected_result & Smi::kMaxValue);
      93         880 :       CHECK_EQ(expected, Smi::cast(*result));
      94             :     }
      95             :   }
      96           8 : }
      97             : 
      98             : }  // namespace
      99             : 
     100       26643 : TEST(StubCachePrimaryOffset) {
     101           4 :   TestStubCacheOffsetCalculation(StubCache::kPrimary);
     102           4 : }
     103             : 
     104       26643 : TEST(StubCacheSecondaryOffset) {
     105           4 :   TestStubCacheOffsetCalculation(StubCache::kSecondary);
     106           4 : }
     107             : 
     108             : namespace {
     109             : 
     110         120 : Handle<Code> CreateCodeOfKind(Code::Kind kind) {
     111             :   Isolate* isolate(CcTest::InitIsolateOnce());
     112         240 :   CodeAssemblerTester data(isolate, kind);
     113         120 :   CodeStubAssembler m(data.state());
     114         240 :   m.Return(m.UndefinedConstant());
     115         120 :   return data.GenerateCodeCloseAndEscape();
     116             : }
     117             : 
     118             : }  // namespace
     119             : 
     120       26643 : TEST(TryProbeStubCache) {
     121             :   typedef CodeStubAssembler::Label Label;
     122             :   Isolate* isolate(CcTest::InitIsolateOnce());
     123             :   const int kNumParams = 3;
     124           8 :   CodeAssemblerTester data(isolate, kNumParams);
     125             :   AccessorAssembler m(data.state());
     126             : 
     127           4 :   StubCache stub_cache(isolate);
     128           4 :   stub_cache.Clear();
     129             : 
     130             :   {
     131           4 :     Node* receiver = m.Parameter(0);
     132           4 :     Node* name = m.Parameter(1);
     133           4 :     Node* expected_handler = m.Parameter(2);
     134             : 
     135           4 :     Label passed(&m), failed(&m);
     136             : 
     137             :     CodeStubAssembler::TVariable<MaybeObject> var_handler(&m);
     138           4 :     Label if_handler(&m), if_miss(&m);
     139             : 
     140             :     m.TryProbeStubCache(&stub_cache, receiver, name, &if_handler, &var_handler,
     141           4 :                         &if_miss);
     142           4 :     m.BIND(&if_handler);
     143           8 :     m.Branch(m.WordEqual(expected_handler,
     144           8 :                          m.BitcastMaybeObjectToWord(var_handler.value())),
     145           4 :              &passed, &failed);
     146             : 
     147           4 :     m.BIND(&if_miss);
     148          12 :     m.Branch(m.WordEqual(expected_handler, m.IntPtrConstant(0)), &passed,
     149           4 :              &failed);
     150             : 
     151           4 :     m.BIND(&passed);
     152           8 :     m.Return(m.BooleanConstant(true));
     153             : 
     154           4 :     m.BIND(&failed);
     155           8 :     m.Return(m.BooleanConstant(false));
     156             :   }
     157             : 
     158           4 :   Handle<Code> code = data.GenerateCode();
     159           4 :   FunctionTester ft(code, kNumParams);
     160             : 
     161             :   std::vector<Handle<Name>> names;
     162             :   std::vector<Handle<JSObject>> receivers;
     163             :   std::vector<Handle<Code>> handlers;
     164             : 
     165           4 :   base::RandomNumberGenerator rand_gen(FLAG_random_seed);
     166             : 
     167             :   Factory* factory = isolate->factory();
     168             : 
     169             :   // Generate some number of names.
     170        2340 :   for (int i = 0; i < StubCache::kPrimaryTableSize / 7; i++) {
     171             :     Handle<Name> name;
     172        1168 :     switch (rand_gen.NextInt(3)) {
     173             :       case 0: {
     174             :         // Generate string.
     175         728 :         std::stringstream ss;
     176             :         ss << "s" << std::hex
     177         728 :            << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
     178         728 :         name = factory->InternalizeUtf8String(ss.str().c_str());
     179             :         break;
     180             :       }
     181             :       case 1: {
     182             :         // Generate number string.
     183         808 :         std::stringstream ss;
     184         404 :         ss << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
     185         808 :         name = factory->InternalizeUtf8String(ss.str().c_str());
     186             :         break;
     187             :       }
     188             :       case 2: {
     189             :         // Generate symbol.
     190         400 :         name = factory->NewSymbol();
     191         400 :         break;
     192             :       }
     193             :       default:
     194           0 :         UNREACHABLE();
     195             :     }
     196        1168 :     names.push_back(name);
     197             :   }
     198             : 
     199             :   // Generate some number of receiver maps and receivers.
     200        2052 :   for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) {
     201        1024 :     Handle<Map> map = Map::Create(isolate, 0);
     202        2048 :     receivers.push_back(factory->NewJSObjectFromMap(map));
     203             :   }
     204             : 
     205             :   // Generate some number of handlers.
     206         244 :   for (int i = 0; i < 30; i++) {
     207         240 :     handlers.push_back(CreateCodeOfKind(Code::STUB));
     208             :   }
     209             : 
     210             :   // Ensure that GC does happen because from now on we are going to fill our
     211             :   // own stub cache instance with raw values.
     212             :   DisallowHeapAllocation no_gc;
     213             : 
     214             :   // Populate {stub_cache}.
     215             :   const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize;
     216       20484 :   for (int i = 0; i < N; i++) {
     217             :     int index = rand_gen.NextInt();
     218       30720 :     Handle<Name> name = names[index % names.size()];
     219       20480 :     Handle<JSObject> receiver = receivers[index % receivers.size()];
     220       20480 :     Handle<Code> handler = handlers[index % handlers.size()];
     221       10240 :     stub_cache.Set(*name, receiver->map(), MaybeObject::FromObject(*handler));
     222             :   }
     223             : 
     224             :   // Perform some queries.
     225             :   bool queried_existing = false;
     226             :   bool queried_non_existing = false;
     227       20484 :   for (int i = 0; i < N; i++) {
     228             :     int index = rand_gen.NextInt();
     229       30720 :     Handle<Name> name = names[index % names.size()];
     230       20480 :     Handle<JSObject> receiver = receivers[index % receivers.size()];
     231       10240 :     MaybeObject handler = stub_cache.Get(*name, receiver->map());
     232       10240 :     if (handler.ptr() == kNullAddress) {
     233             :       queried_non_existing = true;
     234             :     } else {
     235             :       queried_existing = true;
     236             :     }
     237             : 
     238             :     Handle<Object> expected_handler(handler->GetHeapObjectOrSmi(), isolate);
     239       10240 :     ft.CheckTrue(receiver, name, expected_handler);
     240             :   }
     241             : 
     242       20484 :   for (int i = 0; i < N; i++) {
     243             :     int index1 = rand_gen.NextInt();
     244             :     int index2 = rand_gen.NextInt();
     245       30720 :     Handle<Name> name = names[index1 % names.size()];
     246       30720 :     Handle<JSObject> receiver = receivers[index2 % receivers.size()];
     247       10240 :     MaybeObject handler = stub_cache.Get(*name, receiver->map());
     248       10240 :     if (handler.ptr() == kNullAddress) {
     249             :       queried_non_existing = true;
     250             :     } else {
     251             :       queried_existing = true;
     252             :     }
     253             : 
     254             :     Handle<Object> expected_handler(handler->GetHeapObjectOrSmi(), isolate);
     255       10240 :     ft.CheckTrue(receiver, name, expected_handler);
     256             :   }
     257             :   // Ensure we performed both kind of queries.
     258           4 :   CHECK(queried_existing && queried_non_existing);
     259           4 : }
     260             : 
     261             : }  // namespace internal
     262       79917 : }  // namespace v8

Generated by: LCOV version 1.10