11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/ic/stub-cache.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
81cb0ef41Sopenharmony_ci#include "src/base/bits.h"
91cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"  // For InYoungGeneration().
101cb0ef41Sopenharmony_ci#include "src/ic/ic-inl.h"
111cb0ef41Sopenharmony_ci#include "src/logging/counters.h"
121cb0ef41Sopenharmony_ci#include "src/objects/tagged-value-inl.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_cinamespace v8 {
151cb0ef41Sopenharmony_cinamespace internal {
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciStubCache::StubCache(Isolate* isolate) : isolate_(isolate) {
181cb0ef41Sopenharmony_ci  // Ensure the nullptr (aka Smi::zero()) which StubCache::Get() returns
191cb0ef41Sopenharmony_ci  // when the entry is not found is not considered as a handler.
201cb0ef41Sopenharmony_ci  DCHECK(!IC::IsHandler(MaybeObject()));
211cb0ef41Sopenharmony_ci}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_civoid StubCache::Initialize() {
241cb0ef41Sopenharmony_ci  DCHECK(base::bits::IsPowerOfTwo(kPrimaryTableSize));
251cb0ef41Sopenharmony_ci  DCHECK(base::bits::IsPowerOfTwo(kSecondaryTableSize));
261cb0ef41Sopenharmony_ci  Clear();
271cb0ef41Sopenharmony_ci}
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci// Hash algorithm for the primary table. This algorithm is replicated in
301cb0ef41Sopenharmony_ci// the AccessorAssembler.  Returns an index into the table that
311cb0ef41Sopenharmony_ci// is scaled by 1 << kCacheIndexShift.
321cb0ef41Sopenharmony_ciint StubCache::PrimaryOffset(Name name, Map map) {
331cb0ef41Sopenharmony_ci  // Compute the hash of the name (use entire hash field).
341cb0ef41Sopenharmony_ci  DCHECK(name.HasHashCode());
351cb0ef41Sopenharmony_ci  uint32_t field = name.raw_hash_field();
361cb0ef41Sopenharmony_ci  // Using only the low bits in 64-bit mode is unlikely to increase the
371cb0ef41Sopenharmony_ci  // risk of collision even if the heap is spread over an area larger than
381cb0ef41Sopenharmony_ci  // 4Gb (and not at all if it isn't).
391cb0ef41Sopenharmony_ci  uint32_t map_low32bits =
401cb0ef41Sopenharmony_ci      static_cast<uint32_t>(map.ptr() ^ (map.ptr() >> kMapKeyShift));
411cb0ef41Sopenharmony_ci  // Base the offset on a simple combination of name and map.
421cb0ef41Sopenharmony_ci  uint32_t key = map_low32bits + field;
431cb0ef41Sopenharmony_ci  return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
441cb0ef41Sopenharmony_ci}
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci// Hash algorithm for the secondary table.  This algorithm is replicated in
471cb0ef41Sopenharmony_ci// assembler. This hash should be sufficiently different from the primary one
481cb0ef41Sopenharmony_ci// in order to avoid collisions for minified code with short names.
491cb0ef41Sopenharmony_ci// Returns an index into the table that is scaled by 1 << kCacheIndexShift.
501cb0ef41Sopenharmony_ciint StubCache::SecondaryOffset(Name name, Map old_map) {
511cb0ef41Sopenharmony_ci  uint32_t name_low32bits = static_cast<uint32_t>(name.ptr());
521cb0ef41Sopenharmony_ci  uint32_t map_low32bits = static_cast<uint32_t>(old_map.ptr());
531cb0ef41Sopenharmony_ci  uint32_t key = (map_low32bits + name_low32bits);
541cb0ef41Sopenharmony_ci  key = key + (key >> kSecondaryKeyShift);
551cb0ef41Sopenharmony_ci  return key & ((kSecondaryTableSize - 1) << kCacheIndexShift);
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ciint StubCache::PrimaryOffsetForTesting(Name name, Map map) {
591cb0ef41Sopenharmony_ci  return PrimaryOffset(name, map);
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciint StubCache::SecondaryOffsetForTesting(Name name, Map map) {
631cb0ef41Sopenharmony_ci  return SecondaryOffset(name, map);
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci#ifdef DEBUG
671cb0ef41Sopenharmony_cinamespace {
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_cibool CommonStubCacheChecks(StubCache* stub_cache, Name name, Map map,
701cb0ef41Sopenharmony_ci                           MaybeObject handler) {
711cb0ef41Sopenharmony_ci  // Validate that the name and handler do not move on scavenge, and that we
721cb0ef41Sopenharmony_ci  // can use identity checks instead of structural equality checks.
731cb0ef41Sopenharmony_ci  DCHECK(!Heap::InYoungGeneration(name));
741cb0ef41Sopenharmony_ci  DCHECK(!Heap::InYoungGeneration(handler));
751cb0ef41Sopenharmony_ci  DCHECK(name.IsUniqueName());
761cb0ef41Sopenharmony_ci  if (handler->ptr() != kNullAddress) DCHECK(IC::IsHandler(handler));
771cb0ef41Sopenharmony_ci  return true;
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci}  // namespace
811cb0ef41Sopenharmony_ci#endif
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_civoid StubCache::Set(Name name, Map map, MaybeObject handler) {
841cb0ef41Sopenharmony_ci  DCHECK(CommonStubCacheChecks(this, name, map, handler));
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci  // Compute the primary entry.
871cb0ef41Sopenharmony_ci  int primary_offset = PrimaryOffset(name, map);
881cb0ef41Sopenharmony_ci  Entry* primary = entry(primary_, primary_offset);
891cb0ef41Sopenharmony_ci  MaybeObject old_handler(
901cb0ef41Sopenharmony_ci      TaggedValue::ToMaybeObject(isolate(), primary->value));
911cb0ef41Sopenharmony_ci  // If the primary entry has useful data in it, we retire it to the
921cb0ef41Sopenharmony_ci  // secondary cache before overwriting it.
931cb0ef41Sopenharmony_ci  if (old_handler != MaybeObject::FromObject(
941cb0ef41Sopenharmony_ci                         isolate()->builtins()->code(Builtin::kIllegal)) &&
951cb0ef41Sopenharmony_ci      !primary->map.IsSmi()) {
961cb0ef41Sopenharmony_ci    Map old_map =
971cb0ef41Sopenharmony_ci        Map::cast(StrongTaggedValue::ToObject(isolate(), primary->map));
981cb0ef41Sopenharmony_ci    Name old_name =
991cb0ef41Sopenharmony_ci        Name::cast(StrongTaggedValue::ToObject(isolate(), primary->key));
1001cb0ef41Sopenharmony_ci    int secondary_offset = SecondaryOffset(old_name, old_map);
1011cb0ef41Sopenharmony_ci    Entry* secondary = entry(secondary_, secondary_offset);
1021cb0ef41Sopenharmony_ci    *secondary = *primary;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  // Update primary cache.
1061cb0ef41Sopenharmony_ci  primary->key = StrongTaggedValue(name);
1071cb0ef41Sopenharmony_ci  primary->value = TaggedValue(handler);
1081cb0ef41Sopenharmony_ci  primary->map = StrongTaggedValue(map);
1091cb0ef41Sopenharmony_ci  isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciMaybeObject StubCache::Get(Name name, Map map) {
1131cb0ef41Sopenharmony_ci  DCHECK(CommonStubCacheChecks(this, name, map, MaybeObject()));
1141cb0ef41Sopenharmony_ci  int primary_offset = PrimaryOffset(name, map);
1151cb0ef41Sopenharmony_ci  Entry* primary = entry(primary_, primary_offset);
1161cb0ef41Sopenharmony_ci  if (primary->key == name && primary->map == map) {
1171cb0ef41Sopenharmony_ci    return TaggedValue::ToMaybeObject(isolate(), primary->value);
1181cb0ef41Sopenharmony_ci  }
1191cb0ef41Sopenharmony_ci  int secondary_offset = SecondaryOffset(name, map);
1201cb0ef41Sopenharmony_ci  Entry* secondary = entry(secondary_, secondary_offset);
1211cb0ef41Sopenharmony_ci  if (secondary->key == name && secondary->map == map) {
1221cb0ef41Sopenharmony_ci    return TaggedValue::ToMaybeObject(isolate(), secondary->value);
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci  return MaybeObject();
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_civoid StubCache::Clear() {
1281cb0ef41Sopenharmony_ci  MaybeObject empty =
1291cb0ef41Sopenharmony_ci      MaybeObject::FromObject(isolate_->builtins()->code(Builtin::kIllegal));
1301cb0ef41Sopenharmony_ci  Name empty_string = ReadOnlyRoots(isolate()).empty_string();
1311cb0ef41Sopenharmony_ci  for (int i = 0; i < kPrimaryTableSize; i++) {
1321cb0ef41Sopenharmony_ci    primary_[i].key = StrongTaggedValue(empty_string);
1331cb0ef41Sopenharmony_ci    primary_[i].map = StrongTaggedValue(Smi::zero());
1341cb0ef41Sopenharmony_ci    primary_[i].value = TaggedValue(empty);
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci  for (int j = 0; j < kSecondaryTableSize; j++) {
1371cb0ef41Sopenharmony_ci    secondary_[j].key = StrongTaggedValue(empty_string);
1381cb0ef41Sopenharmony_ci    secondary_[j].map = StrongTaggedValue(Smi::zero());
1391cb0ef41Sopenharmony_ci    secondary_[j].value = TaggedValue(empty);
1401cb0ef41Sopenharmony_ci  }
1411cb0ef41Sopenharmony_ci}
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci}  // namespace internal
1441cb0ef41Sopenharmony_ci}  // namespace v8
145