LCOV - code coverage report
Current view: top level - src/ic - stub-cache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 51 53 96.2 %
Date: 2019-02-19 Functions: 9 11 81.8 %

          Line data    Source code
       1             : // Copyright 2012 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/ic/stub-cache.h"
       6             : 
       7             : #include "src/ast/ast.h"
       8             : #include "src/base/bits.h"
       9             : #include "src/counters.h"
      10             : #include "src/heap/heap-inl.h"  // For InYoungGeneration().
      11             : #include "src/ic/ic-inl.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16      122101 : StubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
      17             :   // Ensure the nullptr (aka Smi::kZero) which StubCache::Get() returns
      18             :   // when the entry is not found is not considered as a handler.
      19             :   DCHECK(!IC::IsHandler(MaybeObject()));
      20      122101 : }
      21             : 
      22      122098 : void StubCache::Initialize() {
      23             :   DCHECK(base::bits::IsPowerOfTwo(kPrimaryTableSize));
      24             :   DCHECK(base::bits::IsPowerOfTwo(kSecondaryTableSize));
      25      122098 :   Clear();
      26      122098 : }
      27             : 
      28             : // Hash algorithm for the primary table.  This algorithm is replicated in
      29             : // assembler for every architecture.  Returns an index into the table that
      30             : // is scaled by 1 << kCacheIndexShift.
      31           0 : int StubCache::PrimaryOffset(Name name, Map map) {
      32             :   STATIC_ASSERT(kCacheIndexShift == Name::kHashShift);
      33             :   // Compute the hash of the name (use entire hash field).
      34             :   DCHECK(name->HasHashCode());
      35             :   uint32_t field = name->hash_field();
      36             :   // Using only the low bits in 64-bit mode is unlikely to increase the
      37             :   // risk of collision even if the heap is spread over an area larger than
      38             :   // 4Gb (and not at all if it isn't).
      39     1175271 :   uint32_t map_low32bits = static_cast<uint32_t>(map.ptr());
      40             :   // Base the offset on a simple combination of name and map.
      41     1175271 :   uint32_t key = map_low32bits + field;
      42     1175271 :   return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
      43             : }
      44             : 
      45             : // Hash algorithm for the secondary table.  This algorithm is replicated in
      46             : // assembler for every architecture.  Returns an index into the table that
      47             : // is scaled by 1 << kCacheIndexShift.
      48           0 : int StubCache::SecondaryOffset(Name name, int seed) {
      49             :   // Use the seed from the primary cache in the secondary cache.
      50      462343 :   uint32_t name_low32bits = static_cast<uint32_t>(name.ptr());
      51      462343 :   uint32_t key = (seed - name_low32bits) + kSecondaryMagic;
      52      462343 :   return key & ((kSecondaryTableSize - 1) << kCacheIndexShift);
      53             : }
      54             : 
      55         880 : int StubCache::PrimaryOffsetForTesting(Name name, Map map) {
      56         880 :   return PrimaryOffset(name, map);
      57             : }
      58             : 
      59         440 : int StubCache::SecondaryOffsetForTesting(Name name, int seed) {
      60         440 :   return SecondaryOffset(name, seed);
      61             : }
      62             : 
      63             : #ifdef DEBUG
      64             : namespace {
      65             : 
      66             : bool CommonStubCacheChecks(StubCache* stub_cache, Name name, Map map,
      67             :                            MaybeObject handler) {
      68             :   // Validate that the name and handler do not move on scavenge, and that we
      69             :   // can use identity checks instead of structural equality checks.
      70             :   DCHECK(!Heap::InYoungGeneration(name));
      71             :   DCHECK(!Heap::InYoungGeneration(handler));
      72             :   DCHECK(name->IsUniqueName());
      73             :   DCHECK(name->HasHashCode());
      74             :   if (handler->ptr() != kNullAddress) DCHECK(IC::IsHandler(handler));
      75             :   return true;
      76             : }
      77             : 
      78             : }  // namespace
      79             : #endif
      80             : 
      81     1423080 : void StubCache::Set(Name name, Map map, MaybeObject handler) {
      82             :   DCHECK(CommonStubCacheChecks(this, name, map, handler));
      83             : 
      84             :   // Compute the primary entry.
      85             :   int primary_offset = PrimaryOffset(name, map);
      86      711540 :   Entry* primary = entry(primary_, primary_offset);
      87      711540 :   MaybeObject old_handler(primary->value);
      88             : 
      89             :   // If the primary entry has useful data in it, we retire it to the
      90             :   // secondary cache before overwriting it.
      91      711540 :   if (old_handler != MaybeObject::FromObject(
      92     1153911 :                          isolate_->builtins()->builtin(Builtins::kIllegal)) &&
      93      442371 :       primary->map != kNullAddress) {
      94      442371 :     Map old_map = Map::cast(Object(primary->map));
      95      442371 :     int seed = PrimaryOffset(Name::cast(Object(primary->key)), old_map);
      96             :     int secondary_offset =
      97      442371 :         SecondaryOffset(Name::cast(Object(primary->key)), seed);
      98      442371 :     Entry* secondary = entry(secondary_, secondary_offset);
      99      442371 :     *secondary = *primary;
     100             :   }
     101             : 
     102             :   // Update primary cache.
     103      711540 :   primary->key = name.ptr();
     104      711540 :   primary->value = handler.ptr();
     105      711540 :   primary->map = map.ptr();
     106      711540 :   isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
     107      711540 : }
     108             : 
     109       20480 : MaybeObject StubCache::Get(Name name, Map map) {
     110             :   DCHECK(CommonStubCacheChecks(this, name, map, MaybeObject()));
     111             :   int primary_offset = PrimaryOffset(name, map);
     112       20480 :   Entry* primary = entry(primary_, primary_offset);
     113       20480 :   if (primary->key == name.ptr() && primary->map == map.ptr()) {
     114         948 :     return MaybeObject(primary->value);
     115             :   }
     116             :   int secondary_offset = SecondaryOffset(name, primary_offset);
     117       19532 :   Entry* secondary = entry(secondary_, secondary_offset);
     118       19532 :   if (secondary->key == name.ptr() && secondary->map == map.ptr()) {
     119         296 :     return MaybeObject(secondary->value);
     120             :   }
     121       19236 :   return MaybeObject();
     122             : }
     123             : 
     124      542244 : void StubCache::Clear() {
     125             :   MaybeObject empty = MaybeObject::FromObject(
     126      271122 :       isolate_->builtins()->builtin(Builtins::kIllegal));
     127             :   Name empty_string = ReadOnlyRoots(isolate()).empty_string();
     128   555526783 :   for (int i = 0; i < kPrimaryTableSize; i++) {
     129   555255661 :     primary_[i].key = empty_string.ptr();
     130   555255661 :     primary_[i].map = kNullAddress;
     131   555255661 :     primary_[i].value = empty.ptr();
     132             :   }
     133   138702848 :   for (int j = 0; j < kSecondaryTableSize; j++) {
     134   138702848 :     secondary_[j].key = empty_string.ptr();
     135   138702848 :     secondary_[j].map = kNullAddress;
     136   138702848 :     secondary_[j].value = empty.ptr();
     137             :   }
     138      271122 : }
     139             : 
     140             : }  // namespace internal
     141      178779 : }  // namespace v8

Generated by: LCOV version 1.10