LCOV - code coverage report
Current view: top level - src/ic - stub-cache.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 43 43 100.0 %
Date: 2017-10-20 Functions: 7 7 100.0 %

          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.h"
      11             : #include "src/ic/ic-inl.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16      110004 : 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(nullptr));
      20      110004 : }
      21             : 
      22      109998 : void StubCache::Initialize() {
      23             :   DCHECK(base::bits::IsPowerOfTwo(kPrimaryTableSize));
      24             :   DCHECK(base::bits::IsPowerOfTwo(kSecondaryTableSize));
      25             :   Clear();
      26      109998 : }
      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        1320 : 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             :   uint32_t map_low32bits =
      40     1273675 :       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
      41             :   // Base the offset on a simple combination of name and map.
      42     1273675 :   uint32_t key = (map_low32bits + field) ^ kPrimaryMagic;
      43     1273675 :   return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
      44             : }
      45             : 
      46             : // Hash algorithm for the secondary table.  This algorithm is replicated in
      47             : // assembler for every architecture.  Returns an index into the table that
      48             : // is scaled by 1 << kCacheIndexShift.
      49         660 : int StubCache::SecondaryOffset(Name* name, int seed) {
      50             :   // Use the seed from the primary cache in the secondary cache.
      51             :   uint32_t name_low32bits =
      52      397750 :       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name));
      53      397750 :   uint32_t key = (seed - name_low32bits) + kSecondaryMagic;
      54      397750 :   return key & ((kSecondaryTableSize - 1) << kCacheIndexShift);
      55             : }
      56             : 
      57             : #ifdef DEBUG
      58             : namespace {
      59             : 
      60             : bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map,
      61             :                            Object* handler) {
      62             :   // Validate that the name and handler do not move on scavenge, and that we
      63             :   // can use identity checks instead of structural equality checks.
      64             :   DCHECK(!name->GetHeap()->InNewSpace(name));
      65             :   DCHECK(!name->GetHeap()->InNewSpace(handler));
      66             :   DCHECK(name->IsUniqueName());
      67             :   DCHECK(name->HasHashCode());
      68             :   if (handler) DCHECK(IC::IsHandler(handler));
      69             :   return true;
      70             : }
      71             : 
      72             : }  // namespace
      73             : #endif
      74             : 
      75     1747650 : Object* StubCache::Set(Name* name, Map* map, Object* handler) {
      76             :   DCHECK(CommonStubCacheChecks(this, name, map, handler));
      77             : 
      78             :   // Compute the primary entry.
      79             :   int primary_offset = PrimaryOffset(name, map);
      80      873825 :   Entry* primary = entry(primary_, primary_offset);
      81      873825 :   Object* old_handler = primary->value;
      82             : 
      83             :   // If the primary entry has useful data in it, we retire it to the
      84             :   // secondary cache before overwriting it.
      85     1747650 :   if (old_handler != isolate_->builtins()->builtin(Builtins::kIllegal)) {
      86      367810 :     Map* old_map = primary->map;
      87      367810 :     int seed = PrimaryOffset(primary->key, old_map);
      88             :     int secondary_offset = SecondaryOffset(primary->key, seed);
      89      367810 :     Entry* secondary = entry(secondary_, secondary_offset);
      90      367810 :     *secondary = *primary;
      91             :   }
      92             : 
      93             :   // Update primary cache.
      94      873825 :   primary->key = name;
      95      873825 :   primary->value = handler;
      96      873825 :   primary->map = map;
      97      873825 :   isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
      98      873825 :   return handler;
      99             : }
     100             : 
     101       30720 : Object* StubCache::Get(Name* name, Map* map) {
     102             :   DCHECK(CommonStubCacheChecks(this, name, map, nullptr));
     103             :   int primary_offset = PrimaryOffset(name, map);
     104       30720 :   Entry* primary = entry(primary_, primary_offset);
     105       30720 :   if (primary->key == name && primary->map == map) {
     106        1440 :     return primary->value;
     107             :   }
     108             :   int secondary_offset = SecondaryOffset(name, primary_offset);
     109       29280 :   Entry* secondary = entry(secondary_, secondary_offset);
     110       29280 :   if (secondary->key == name && secondary->map == map) {
     111         360 :     return secondary->value;
     112             :   }
     113             :   return nullptr;
     114             : }
     115             : 
     116             : 
     117      113606 : void StubCache::Clear() {
     118      223604 :   Code* empty = isolate_->builtins()->builtin(Builtins::kIllegal);
     119   458050040 :   for (int i = 0; i < kPrimaryTableSize; i++) {
     120   457936434 :     primary_[i].key = isolate()->heap()->empty_string();
     121   457936434 :     primary_[i].map = nullptr;
     122   457936434 :     primary_[i].value = empty;
     123             :   }
     124   114407424 :   for (int j = 0; j < kSecondaryTableSize; j++) {
     125   114407424 :     secondary_[j].key = isolate()->heap()->empty_string();
     126   114407424 :     secondary_[j].map = nullptr;
     127   114407424 :     secondary_[j].value = empty;
     128             :   }
     129      113606 : }
     130             : 
     131             : }  // namespace internal
     132             : }  // namespace v8

Generated by: LCOV version 1.10