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

Generated by: LCOV version 1.10