8d671de18b
This is the second reland of https://chromium-review.googlesource.com/c/v8/v8/+/2744138. It shortens the runtime of further tests. Original description: This CL is part of a series that adds the C++ implementation of SwissNameDictionary, a deterministic property backing store based on Swiss Tables. This CL adds the actual tests for SwissNameDictionary, defined in test-swiss-name-dictionary-shared-tests.h, using the infrastructure in test-swiss-name-dictionary-infra.[h|cc]. Change-Id: I5b8a7cefb4115ade25b4f8ce032fab9aa10a7b04 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2784683 Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Frank Emrich <emrich@google.com> Cr-Commit-Position: refs/heads/master@{#73641}
228 lines
7.2 KiB
C++
228 lines
7.2 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 "src/objects/swiss-name-dictionary-inl.h"
|
|
#include "test/cctest/cctest.h"
|
|
#include "test/cctest/test-swiss-name-dictionary-infra.h"
|
|
#include "test/cctest/test-swiss-name-dictionary-shared-tests.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace test_swiss_hash_table {
|
|
|
|
// Executes tests by executing C++ versions of dictionary operations.
|
|
class RuntimeTestRunner {
|
|
public:
|
|
RuntimeTestRunner(Isolate* isolate, int initial_capacity, KeyCache& keys)
|
|
: isolate_{isolate}, keys_{keys} {
|
|
table = isolate->factory()->NewSwissNameDictionaryWithCapacity(
|
|
initial_capacity, AllocationType::kYoung);
|
|
}
|
|
|
|
void Add(Handle<Name> key, Handle<Object> value, PropertyDetails details);
|
|
InternalIndex FindEntry(Handle<Name> key);
|
|
// Updates the value and property details of the given entry.
|
|
void Put(InternalIndex entry, Handle<Object> new_value,
|
|
PropertyDetails new_details);
|
|
void Delete(InternalIndex entry);
|
|
void RehashInplace();
|
|
void Shrink();
|
|
|
|
// Retrieves data associated with |entry|, which must be an index pointing to
|
|
// an existing entry. The returned array contains key, value, property details
|
|
// in that order.
|
|
Handle<FixedArray> GetData(InternalIndex entry);
|
|
|
|
// Tests that the current table has the given capacity, and number of
|
|
// (deleted) elements, based on which optional values are present.
|
|
void CheckCounts(base::Optional<int> capacity, base::Optional<int> elements,
|
|
base::Optional<int> deleted);
|
|
// Checks that |expected_keys| contains exactly the keys in the current table,
|
|
// in the given order.
|
|
void CheckEnumerationOrder(const std::vector<std::string>& expected_keys);
|
|
void CheckCopy();
|
|
void VerifyHeap();
|
|
|
|
// Just for debugging.
|
|
void PrintTable();
|
|
|
|
Handle<SwissNameDictionary> table;
|
|
|
|
private:
|
|
Isolate* isolate_;
|
|
KeyCache& keys_;
|
|
};
|
|
|
|
void RuntimeTestRunner::Add(Handle<Name> key, Handle<Object> value,
|
|
PropertyDetails details) {
|
|
Handle<SwissNameDictionary> updated_table =
|
|
SwissNameDictionary::Add(isolate_, this->table, key, value, details);
|
|
this->table = updated_table;
|
|
}
|
|
|
|
InternalIndex RuntimeTestRunner::FindEntry(Handle<Name> key) {
|
|
return table->FindEntry(isolate_, key);
|
|
}
|
|
|
|
Handle<FixedArray> RuntimeTestRunner::GetData(InternalIndex entry) {
|
|
if (entry.is_found()) {
|
|
Handle<FixedArray> data = isolate_->factory()->NewFixedArray(3);
|
|
data->set(0, table->KeyAt(entry));
|
|
data->set(1, table->ValueAt(entry));
|
|
data->set(2, table->DetailsAt(entry).AsSmi());
|
|
return data;
|
|
} else {
|
|
return handle(ReadOnlyRoots(isolate_).empty_fixed_array(), isolate_);
|
|
}
|
|
}
|
|
|
|
void RuntimeTestRunner::Put(InternalIndex entry, Handle<Object> new_value,
|
|
PropertyDetails new_details) {
|
|
CHECK(entry.is_found());
|
|
|
|
table->ValueAtPut(entry, *new_value);
|
|
table->DetailsAtPut(entry, new_details);
|
|
}
|
|
|
|
void RuntimeTestRunner::Delete(InternalIndex entry) {
|
|
CHECK(entry.is_found());
|
|
table = table->DeleteEntry(isolate_, table, entry);
|
|
}
|
|
|
|
void RuntimeTestRunner::CheckCounts(base::Optional<int> capacity,
|
|
base::Optional<int> elements,
|
|
base::Optional<int> deleted) {
|
|
if (capacity.has_value()) {
|
|
CHECK_EQ(capacity.value(), table->Capacity());
|
|
}
|
|
if (elements.has_value()) {
|
|
CHECK_EQ(elements.value(), table->NumberOfElements());
|
|
}
|
|
if (deleted.has_value()) {
|
|
CHECK_EQ(deleted.value(), table->NumberOfDeletedElements());
|
|
}
|
|
}
|
|
|
|
void RuntimeTestRunner::CheckEnumerationOrder(
|
|
const std::vector<std::string>& expected_keys) {
|
|
ReadOnlyRoots roots(isolate_);
|
|
int i = 0;
|
|
for (InternalIndex index : table->IterateEntriesOrdered()) {
|
|
Object key;
|
|
if (table->ToKey(roots, index, &key)) {
|
|
CHECK_LT(i, expected_keys.size());
|
|
Handle<Name> expected_key =
|
|
CreateKeyWithHash(isolate_, this->keys_, Key{expected_keys[i]});
|
|
|
|
CHECK_EQ(key, *expected_key);
|
|
++i;
|
|
}
|
|
}
|
|
CHECK_EQ(i, expected_keys.size());
|
|
}
|
|
|
|
void RuntimeTestRunner::RehashInplace() { table->Rehash(isolate_); }
|
|
|
|
void RuntimeTestRunner::Shrink() {
|
|
table = SwissNameDictionary::Shrink(isolate_, table);
|
|
}
|
|
|
|
void RuntimeTestRunner::CheckCopy() {
|
|
Handle<SwissNameDictionary> copy =
|
|
SwissNameDictionary::ShallowCopy(isolate_, table);
|
|
|
|
CHECK(table->EqualsForTesting(*copy));
|
|
}
|
|
|
|
void RuntimeTestRunner::VerifyHeap() {
|
|
#if VERIFY_HEAP
|
|
table->SwissNameDictionaryVerify(isolate_, true);
|
|
#endif
|
|
}
|
|
|
|
void RuntimeTestRunner::PrintTable() {
|
|
#ifdef OBJECT_PRINT
|
|
table->SwissNameDictionaryPrint(std::cout);
|
|
#endif
|
|
}
|
|
|
|
TEST(CapacityFor) {
|
|
for (int elements = 0; elements <= 32; elements++) {
|
|
int capacity = SwissNameDictionary::CapacityFor(elements);
|
|
if (elements == 0) {
|
|
CHECK_EQ(0, capacity);
|
|
} else if (elements <= 3) {
|
|
CHECK_EQ(4, capacity);
|
|
} else if (elements == 4) {
|
|
CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 8, capacity == 8);
|
|
CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 16, capacity == 4);
|
|
} else if (elements <= 7) {
|
|
CHECK_EQ(8, capacity);
|
|
} else if (elements <= 14) {
|
|
CHECK_EQ(16, capacity);
|
|
} else if (elements <= 28) {
|
|
CHECK_EQ(32, capacity);
|
|
} else if (elements <= 32) {
|
|
CHECK_EQ(64, capacity);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(MaxUsableCapacity) {
|
|
CHECK_EQ(0, SwissNameDictionary::MaxUsableCapacity(0));
|
|
CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 8,
|
|
SwissNameDictionary::MaxUsableCapacity(4) == 3);
|
|
CHECK_IMPLIES(SwissNameDictionary::kGroupWidth == 16,
|
|
SwissNameDictionary::MaxUsableCapacity(4) == 4);
|
|
CHECK_EQ(7, SwissNameDictionary::MaxUsableCapacity(8));
|
|
CHECK_EQ(14, SwissNameDictionary::MaxUsableCapacity(16));
|
|
CHECK_EQ(28, SwissNameDictionary::MaxUsableCapacity(32));
|
|
}
|
|
|
|
TEST(SizeFor) {
|
|
int baseline = HeapObject::kHeaderSize +
|
|
// prefix:
|
|
4 +
|
|
// capacity:
|
|
4 +
|
|
// meta table:
|
|
kTaggedSize;
|
|
|
|
int size_0 = baseline +
|
|
// ctrl table:
|
|
SwissNameDictionary::kGroupWidth;
|
|
|
|
int size_4 = baseline +
|
|
// data table:
|
|
4 * 2 * kTaggedSize +
|
|
// ctrl table:
|
|
4 + SwissNameDictionary::kGroupWidth +
|
|
// property details table:
|
|
4;
|
|
|
|
int size_8 = baseline +
|
|
// data table:
|
|
8 * 2 * kTaggedSize +
|
|
// ctrl table:
|
|
8 + SwissNameDictionary::kGroupWidth +
|
|
// property details table:
|
|
8;
|
|
|
|
CHECK_EQ(SwissNameDictionary::SizeFor(0), size_0);
|
|
CHECK_EQ(SwissNameDictionary::SizeFor(4), size_4);
|
|
CHECK_EQ(SwissNameDictionary::SizeFor(8), size_8);
|
|
}
|
|
|
|
// Executes the tests defined in test-swiss-name-dictionary-shared-tests.h as if
|
|
// they were defined in this file, using the RuntimeTestRunner. See comments in
|
|
// test-swiss-name-dictionary-shared-tests.h and in
|
|
// swiss-name-dictionary-infra.h for details.
|
|
const char kRuntimeTestFileName[] = __FILE__;
|
|
SharedSwissTableTests<RuntimeTestRunner, kRuntimeTestFileName>
|
|
execute_shared_tests_runtime;
|
|
|
|
} // namespace test_swiss_hash_table
|
|
} // namespace internal
|
|
} // namespace v8
|