[cleanup] Devirtualize HashForObject on StringTableKey and CodeCacheHashTableKey

Only the CompilationCache doesn't actually specialize the table to the point where it knows how to hash stored keys. This moves the virtual HashForObject down from HashTableKey to CompilationCacheKey, and moves previous virtual implementations to the respective shapes.

Bug: v8:6474
Change-Id: I0a1ae26a224d602d16692d2b09c96a2ab193f07f
Reviewed-on: https://chromium-review.googlesource.com/529110
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45842}
This commit is contained in:
Toon Verwaest 2017-06-09 16:49:30 +02:00 committed by Commit Bot
parent ee596af250
commit c31302d031
10 changed files with 84 additions and 110 deletions

View File

@ -69,10 +69,6 @@ class AstRawStringInternalizationKey : public HashTableKey {
uint32_t Hash() override { return string_->hash() >> Name::kHashShift; }
uint32_t HashForObject(Object* key) override {
return String::cast(key)->Hash();
}
Handle<Object> AsHandle(Isolate* isolate) override {
if (string_->is_one_byte())
return isolate->factory()->NewOneByteInternalizedString(

View File

@ -886,10 +886,6 @@ class SequentialStringKey : public HashTableKey {
return result;
}
uint32_t HashForObject(Object* other) override {
return String::cast(other)->Hash();
}
Vector<const Char> string_;
uint32_t hash_field_;
uint32_t seed_;
@ -936,10 +932,6 @@ class SeqOneByteSubStringKey : public HashTableKey {
#pragma warning(pop)
#endif
uint32_t HashForObject(Object* other) override {
return String::cast(other)->Hash();
}
bool IsMatch(Object* string) override;
Handle<Object> AsHandle(Isolate* isolate) override;
@ -980,10 +972,6 @@ class Utf8StringKey : public HashTableKey {
return result;
}
uint32_t HashForObject(Object* other) override {
return String::cast(other)->Hash();
}
Handle<Object> AsHandle(Isolate* isolate) override {
if (hash_field_ == 0) Hash();
return isolate->factory()->NewInternalizedStringFromUtf8(string_, chars_,
@ -3006,6 +2994,10 @@ uint32_t StringSetShape::HashForObject(String* key, Object* object) {
return object->IsString() ? String::cast(object)->Hash() : 0;
}
uint32_t StringTableShape::HashForObject(HashTableKey* key, Object* object) {
return String::cast(object)->Hash();
}
bool SeededNumberDictionary::requires_slow_elements() {
Object* max_index_object = get(kMaxNumberKeyIndex);
if (!max_index_object->IsSmi()) return false;

View File

@ -9751,61 +9751,6 @@ Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
}
// The key in the code cache hash table consists of the property name and the
// code object. The actual match is on the name and the code flags. If a key
// is created using the flags and not a code object it can only be used for
// lookup not to create a new entry.
class CodeCacheHashTableKey : public HashTableKey {
public:
CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
: name_(name), flags_(flags), code_() {
DCHECK(name_->IsUniqueName());
}
CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
: name_(name), flags_(code->flags()), code_(code) {
DCHECK(name_->IsUniqueName());
}
bool IsMatch(Object* other) override {
DCHECK(other->IsFixedArray());
FixedArray* pair = FixedArray::cast(other);
Name* name = Name::cast(pair->get(0));
Code::Flags flags = Code::cast(pair->get(1))->flags();
if (flags != flags_) return false;
DCHECK(name->IsUniqueName());
return *name_ == name;
}
static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
return name->Hash() ^ flags;
}
uint32_t Hash() override { return NameFlagsHashHelper(*name_, flags_); }
uint32_t HashForObject(Object* obj) override {
FixedArray* pair = FixedArray::cast(obj);
Name* name = Name::cast(pair->get(0));
Code* code = Code::cast(pair->get(1));
return NameFlagsHashHelper(name, code->flags());
}
MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
Handle<Code> code = code_.ToHandleChecked();
Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
pair->set(0, *name_);
pair->set(1, *code);
return pair;
}
private:
Handle<Name> name_;
Code::Flags flags_;
// TODO(jkummerow): We should be able to get by without this.
MaybeHandle<Code> code_;
};
Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
CodeCacheHashTableKey key(name, code);
@ -15949,7 +15894,7 @@ void Symbol::SymbolShortPrint(std::ostream& os) {
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
class StringSharedKey : public CompilationCacheKey {
public:
// This tuple unambiguously identifies calls to eval() or
// CreateDynamicFunction() (such as through the Function() constructor).
@ -16247,7 +16192,7 @@ MaybeHandle<JSRegExp> JSRegExp::Initialize(Handle<JSRegExp> regexp,
// RegExpKey carries the source and flags of a regular expression as key.
class RegExpKey : public HashTableKey {
class RegExpKey : public CompilationCacheKey {
public:
RegExpKey(Handle<String> string, JSRegExp::Flags flags)
: string_(string), flags_(Smi::FromInt(flags)) {}
@ -16322,10 +16267,6 @@ class InternalizedStringKey : public HashTableKey {
uint32_t Hash() override { return string_->Hash(); }
uint32_t HashForObject(Object* other) override {
return String::cast(other)->Hash();
}
Handle<Object> AsHandle(Isolate* isolate) override {
// Internalize the string if possible.
MaybeHandle<Map> maybe_map =
@ -17304,10 +17245,6 @@ class TwoCharHashTableKey : public HashTableKey {
}
uint32_t Hash() override { return hash_; }
uint32_t HashForObject(Object* key) override {
if (!key->IsString()) return 0;
return String::cast(key)->Hash();
}
Handle<Object> AsHandle(Isolate* isolate) override {
// The TwoCharHashTableKey is only used for looking in the string
@ -17600,10 +17537,6 @@ class StringTableNoAllocateKey : public HashTableKey {
uint32_t Hash() override { return hash_; }
uint32_t HashForObject(Object* key) override {
return String::cast(key)->Hash();
}
MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
UNREACHABLE();
}

View File

@ -16,7 +16,7 @@ namespace internal {
CAST_ACCESSOR(CodeCacheHashTable)
Handle<Object> CodeCacheHashTableShape::AsHandle(Isolate* isolate,
HashTableKey* key) {
CodeCacheHashTableKey* key) {
return key->AsHandle(isolate);
}

View File

@ -13,19 +13,73 @@
namespace v8 {
namespace internal {
class CodeCacheHashTableShape : public BaseShape<HashTableKey*> {
// The key in the code cache hash table consists of the property name and the
// code object. The actual match is on the name and the code flags. If a key
// is created using the flags and not a code object it can only be used for
// lookup not to create a new entry.
class CodeCacheHashTableKey final {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
: name_(name), flags_(flags), code_() {
DCHECK(name_->IsUniqueName());
}
CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
: name_(name), flags_(code->flags()), code_(code) {
DCHECK(name_->IsUniqueName());
}
bool IsMatch(Object* other) {
DCHECK(other->IsFixedArray());
FixedArray* pair = FixedArray::cast(other);
Name* name = Name::cast(pair->get(0));
Code::Flags flags = Code::cast(pair->get(1))->flags();
if (flags != flags_) return false;
DCHECK(name->IsUniqueName());
return *name_ == name;
}
static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
return name->Hash() ^ flags;
}
uint32_t Hash() { return NameFlagsHashHelper(*name_, flags_); }
MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) {
Handle<Code> code = code_.ToHandleChecked();
Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
pair->set(0, *name_);
pair->set(1, *code);
return pair;
}
private:
Handle<Name> name_;
Code::Flags flags_;
// TODO(jkummerow): We should be able to get by without this.
MaybeHandle<Code> code_;
};
class CodeCacheHashTableShape : public BaseShape<CodeCacheHashTableKey*> {
public:
static inline bool IsMatch(CodeCacheHashTableKey* key, Object* value) {
return key->IsMatch(value);
}
static inline uint32_t Hash(HashTableKey* key) { return key->Hash(); }
static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
static inline uint32_t Hash(CodeCacheHashTableKey* key) {
return key->Hash();
}
static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
static inline uint32_t HashForObject(CodeCacheHashTableKey* key,
Object* object) {
FixedArray* pair = FixedArray::cast(object);
Name* name = Name::cast(pair->get(0));
Code* code = Code::cast(pair->get(1));
return CodeCacheHashTableKey::NameFlagsHashHelper(name, code->flags());
}
static inline Handle<Object> AsHandle(Isolate* isolate,
CodeCacheHashTableKey* key);
static const int kPrefixSize = 0;
// The both the key (name + flags) and value (code object) can be derived from

View File

@ -16,7 +16,7 @@ namespace internal {
CAST_ACCESSOR(CompilationCacheTable)
Handle<Object> CompilationCacheShape::AsHandle(Isolate* isolate,
HashTableKey* key) {
CompilationCacheKey* key) {
return key->AsHandle(isolate);
}

View File

@ -13,19 +13,26 @@
namespace v8 {
namespace internal {
class CompilationCacheShape : public BaseShape<HashTableKey*> {
class CompilationCacheKey : public HashTableKey {
public:
static inline bool IsMatch(HashTableKey* key, Object* value) {
virtual uint32_t HashForObject(Object* object) = 0;
};
class CompilationCacheShape : public BaseShape<CompilationCacheKey*> {
public:
static inline bool IsMatch(CompilationCacheKey* key, Object* value) {
return key->IsMatch(value);
}
static inline uint32_t Hash(HashTableKey* key) { return key->Hash(); }
static inline uint32_t Hash(CompilationCacheKey* key) { return key->Hash(); }
static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
static inline uint32_t HashForObject(CompilationCacheKey* key,
Object* object) {
return key->HashForObject(object);
}
static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);
static inline Handle<Object> AsHandle(Isolate* isolate,
CompilationCacheKey* key);
static const int kPrefixSize = 0;
static const int kEntrySize = 3;

View File

@ -260,8 +260,6 @@ class HashTableKey {
virtual bool IsMatch(Object* other) = 0;
// Returns the hash value for this key.
virtual uint32_t Hash() = 0;
// Returns the hash value for object.
virtual uint32_t HashForObject(Object* key) = 0;
// Returns the key object for storing into the hash table.
MUST_USE_RESULT virtual Handle<Object> AsHandle(Isolate* isolate) = 0;
// Required.

View File

@ -21,9 +21,7 @@ class StringTableShape : public BaseShape<HashTableKey*> {
static inline uint32_t Hash(HashTableKey* key) { return key->Hash(); }
static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
return key->HashForObject(object);
}
static inline uint32_t HashForObject(HashTableKey* key, Object* object);
static inline Handle<Object> AsHandle(Isolate* isolate, HashTableKey* key);

View File

@ -284,24 +284,20 @@ void Deserializer::PrintDisassembledCodeObjects() {
class StringTableInsertionKey : public HashTableKey {
public:
explicit StringTableInsertionKey(String* string)
: string_(string), hash_(HashForObject(string)) {
: string_(string), hash_(string->Hash()) {
DCHECK(string->IsInternalizedString());
}
bool IsMatch(Object* string) override {
// We know that all entries in a hash table had their hash keys created.
// Use that knowledge to have fast failure.
if (hash_ != HashForObject(string)) return false;
if (hash_ != String::cast(string)->Hash()) return false;
// We want to compare the content of two internalized strings here.
return string_->SlowEquals(String::cast(string));
}
uint32_t Hash() override { return hash_; }
uint32_t HashForObject(Object* key) override {
return String::cast(key)->Hash();
}
MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) override {
return handle(string_, isolate);
}