v8/test/cctest/test-swiss-name-dictionary-infra.cc
Patrick Thier aa8cf1f0c2 Refactor Name::Hash
We introduce a new information type ForwardingIndex to be stored in
the Name::Hash field (to be used in the future).
To do so we use the 2 least significant bit to distinguish types
of information stored in the hash field (in contrast to only bit 1
to distinguis integer indicies from "real" hashes).
This motivated a refactor to use base::BitField for the hash field.

Bug: v8:12007
Change-Id: I651c86807edfc218792d0db12379374eaa50c930
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3432385
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Patrick Thier <pthier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78975}
2022-02-07 11:30:04 +00:00

134 lines
4.9 KiB
C++

// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "test/cctest/test-swiss-name-dictionary-infra.h"
namespace v8 {
namespace internal {
namespace test_swiss_hash_table {
namespace {
std::vector<PropertyDetails> MakeDistinctDetails() {
std::vector<PropertyDetails> result(32, PropertyDetails::Empty());
int i = 0;
for (PropertyKind kind : {PropertyKind::kAccessor, PropertyKind::kAccessor}) {
for (PropertyConstness constness :
{PropertyConstness::kConst, PropertyConstness::kMutable}) {
for (bool writeable : {true, false}) {
for (bool enumerable : {true, false}) {
for (bool configurable : {true, false}) {
uint8_t attrs = static_cast<uint8_t>(PropertyAttributes::NONE);
if (!writeable) attrs |= PropertyAttributes::READ_ONLY;
if (!enumerable) {
attrs |= PropertyAttributes::DONT_ENUM;
}
if (!configurable) {
attrs |= PropertyAttributes::DONT_DELETE;
}
PropertyAttributes attributes =
static_cast<PropertyAttributes>(attrs);
PropertyDetails details(kind, attributes,
PropertyCellType::kNoCell);
details = details.CopyWithConstness(constness);
result[i++] = details;
}
}
}
}
}
return result;
}
} // namespace
// To enable more specific testing, we allow overriding the H1 and H2 hashes for
// a key before adding it to the SwissNameDictionary. The necessary overriding
// of the stored hash happens here. Symbols are compared by identity, we cache
// the Symbol associcated with each std::string key. This means that using
// "my_key" twice in the same TestSequence will return the same Symbol
// associcated with "my_key" both times. This also means that within a given
// TestSequence, we cannot use the same (std::string) key with different faked
// hashes.
Handle<Name> CreateKeyWithHash(Isolate* isolate, KeyCache& keys,
const Key& key) {
Handle<Symbol> key_symbol;
auto iter = keys.find(key.str);
if (iter == keys.end()) {
// We haven't seen the the given string as a key in the current
// TestSequence. Create it, fake its hash if requested and cache it.
key_symbol = isolate->factory()->NewSymbol();
// We use the description field to store the original string key for
// debugging.
Handle<String> description =
isolate->factory()->NewStringFromAsciiChecked(key.str.c_str());
key_symbol->set_description(*description);
CachedKey new_info = {key_symbol, key.h1_override, key.h2_override};
keys[key.str] = new_info;
if (key.h1_override || key.h2_override) {
uint32_t actual_hash = key_symbol->hash();
int fake_hash = actual_hash;
if (key.h1_override) {
uint32_t override_with = key.h1_override.value().value;
// We cannot override h1 with 0 unless we also override h2 with a
// non-zero value. Otherwise, the overall hash may become 0 (which is
// forbidden) based on the (nondeterminstic) choice of h2.
CHECK_IMPLIES(override_with == 0,
key.h2_override && key.h2_override.value().value != 0);
fake_hash = (override_with << swiss_table::kH2Bits) |
swiss_table::H2(actual_hash);
}
if (key.h2_override) {
// Unset 7 bits belonging to H2:
fake_hash &= ~((1 << swiss_table::kH2Bits) - 1);
uint8_t override_with = key.h2_override.value().value;
// Same as above, but for h2: Prevent accidentally creating 0 fake hash.
CHECK_IMPLIES(override_with == 0,
key.h1_override && key.h1_override.value().value != 0);
CHECK_LT(key.h2_override.value().value, 1 << swiss_table::kH2Bits);
fake_hash |= swiss_table::H2(override_with);
}
// Prepare what to put into the hash field.
uint32_t hash_field =
Name::CreateHashFieldValue(fake_hash, Name::HashFieldType::kHash);
CHECK_NE(hash_field, 0);
key_symbol->set_raw_hash_field(hash_field);
CHECK_EQ(fake_hash, key_symbol->hash());
}
return key_symbol;
} else {
// We've seen this key before. Return the cached version.
CachedKey& cached_info = iter->second;
// Internal consistency check: Make sure that we didn't request something
// else w.r.t. hash faking when using this key before. If so, the test case
// would make inconsistent assumptions about how the hashes should be faked
// and be broken.
CHECK_EQ(cached_info.h1_override, key.h1_override);
CHECK_EQ(cached_info.h2_override, key.h2_override);
return cached_info.key_symbol;
}
}
const std::vector<PropertyDetails> distinct_property_details =
MakeDistinctDetails();
} // namespace test_swiss_hash_table
} // namespace internal
} // namespace v8