01c82f9cab
This is a reland of decf5750c6
This patch fixes the hash code migration in the backing store
transition case from Smi to PropertyArray in the IC system and
Turbofan. Also, adds tests.
Bug: v8:6413, v8:6404
Original change's description:
> [runtime] Store hash code in length field
>
> Store the hash code in 21 bits of the length field.
>
> Change the GetIdentityHash API to be unhandlified, since there's no
> property lookup anymore.
>
> Update js/ and test/ to match new API and expections.
>
> Bug:
> Change-Id: I8dc75de4021f59e79b45f3f38ec997c3b3687b24
> Reviewed-on: https://chromium-review.googlesource.com/589688
> Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#47259}
Change-Id: I69289113c4b7978c46f6f9373cc972086ecb6822
Bug:
Reviewed-on: https://chromium-review.googlesource.com/614903
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47459}
901 lines
29 KiB
C++
901 lines
29 KiB
C++
// Copyright 2017 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 <utility>
|
|
#include "src/v8.h"
|
|
|
|
#include "src/objects-inl.h"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
static Isolate* GetIsolateFrom(LocalContext* context) {
|
|
return reinterpret_cast<Isolate*>((*context)->GetIsolate());
|
|
}
|
|
|
|
void CopyHashCode(Handle<JSReceiver> from, Handle<JSReceiver> to) {
|
|
int hash = Smi::ToInt(from->GetHash());
|
|
to->SetIdentityHash(hash);
|
|
}
|
|
|
|
void Verify(Handle<HeapObject> obj) {
|
|
#if VERIFY_HEAP
|
|
obj->ObjectVerify();
|
|
#endif
|
|
}
|
|
|
|
TEST(SmallOrderedHashSetInsertion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashSet> set = factory->NewSmallOrderedHashSet();
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
|
|
// Add a new key.
|
|
Handle<Smi> key1(Smi::FromInt(1), isolate);
|
|
CHECK(!set->HasKey(isolate, key1));
|
|
set = SmallOrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
|
|
// Add existing key.
|
|
set = SmallOrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
|
|
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
|
|
CHECK(!set->HasKey(isolate, key2));
|
|
set = SmallOrderedHashSet::Add(set, key2);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(2, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
|
|
set = SmallOrderedHashSet::Add(set, key2);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(2, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
|
|
Handle<Symbol> key3 = factory->NewSymbol();
|
|
CHECK(!set->HasKey(isolate, key3));
|
|
set = SmallOrderedHashSet::Add(set, key3);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(3, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
CHECK(set->HasKey(isolate, key3));
|
|
|
|
set = SmallOrderedHashSet::Add(set, key3);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(3, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
CHECK(set->HasKey(isolate, key3));
|
|
|
|
Handle<Object> key4 = factory->NewHeapNumber(42.0);
|
|
CHECK(!set->HasKey(isolate, key4));
|
|
set = SmallOrderedHashSet::Add(set, key4);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(4, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
CHECK(set->HasKey(isolate, key3));
|
|
CHECK(set->HasKey(isolate, key4));
|
|
|
|
set = SmallOrderedHashSet::Add(set, key4);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(4, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
CHECK(set->HasKey(isolate, key3));
|
|
CHECK(set->HasKey(isolate, key4));
|
|
}
|
|
|
|
TEST(SmallOrderedHashMapInsertion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashMap> map = factory->NewSmallOrderedHashMap();
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
|
|
// Add a new key.
|
|
Handle<Smi> key1(Smi::FromInt(1), isolate);
|
|
Handle<Smi> value1(Smi::FromInt(1), isolate);
|
|
CHECK(!map->HasKey(isolate, key1));
|
|
map = SmallOrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
|
|
// Add existing key.
|
|
map = SmallOrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
|
|
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
|
|
Handle<String> value = factory->NewStringFromAsciiChecked("foo");
|
|
CHECK(!map->HasKey(isolate, key2));
|
|
map = SmallOrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
|
|
map = SmallOrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
|
|
Handle<Symbol> key3 = factory->NewSymbol();
|
|
CHECK(!map->HasKey(isolate, key3));
|
|
map = SmallOrderedHashMap::Add(map, key3, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(3, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
CHECK(map->HasKey(isolate, key3));
|
|
|
|
map = SmallOrderedHashMap::Add(map, key3, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(3, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
CHECK(map->HasKey(isolate, key3));
|
|
|
|
Handle<Object> key4 = factory->NewHeapNumber(42.0);
|
|
CHECK(!map->HasKey(isolate, key4));
|
|
map = SmallOrderedHashMap::Add(map, key4, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(4, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
CHECK(map->HasKey(isolate, key3));
|
|
CHECK(map->HasKey(isolate, key4));
|
|
|
|
map = SmallOrderedHashMap::Add(map, key4, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(4, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
CHECK(map->HasKey(isolate, key3));
|
|
CHECK(map->HasKey(isolate, key4));
|
|
}
|
|
|
|
TEST(SmallOrderedHashSetDuplicateHashCode) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashSet> set = factory->NewSmallOrderedHashSet();
|
|
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
|
|
set = SmallOrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
|
|
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
|
CopyHashCode(key1, key2);
|
|
|
|
set = SmallOrderedHashSet::Add(set, key2);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(2, set->NumberOfElements());
|
|
CHECK(set->HasKey(isolate, key1));
|
|
CHECK(set->HasKey(isolate, key2));
|
|
}
|
|
|
|
TEST(SmallOrderedHashMapDuplicateHashCode) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashMap> map = factory->NewSmallOrderedHashMap();
|
|
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
|
|
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
|
|
map = SmallOrderedHashMap::Add(map, key1, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
|
|
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
|
CopyHashCode(key1, key2);
|
|
|
|
CHECK(!key1->SameValue(*key2));
|
|
Object* hash1 = key1->GetHash();
|
|
Object* hash2 = key2->GetHash();
|
|
CHECK_EQ(hash1, hash2);
|
|
|
|
map = SmallOrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(map->HasKey(isolate, key1));
|
|
CHECK(map->HasKey(isolate, key2));
|
|
}
|
|
|
|
TEST(SmallOrderedHashSetGrow) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashSet> set = factory->NewSmallOrderedHashSet();
|
|
std::vector<Handle<Object>> keys;
|
|
for (int i = 0; i < 254; i++) {
|
|
Handle<Smi> key(Smi::FromInt(i), isolate);
|
|
keys.push_back(key);
|
|
}
|
|
|
|
for (size_t i = 0; i < 4; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 4; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(4, set->NumberOfElements());
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 4; i < 8; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 8; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(8, set->NumberOfElements());
|
|
CHECK_EQ(4, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 8; i < 16; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 16; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(16, set->NumberOfElements());
|
|
CHECK_EQ(8, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 16; i < 32; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 32; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(32, set->NumberOfElements());
|
|
CHECK_EQ(16, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 32; i < 64; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 64; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(64, set->NumberOfElements());
|
|
CHECK_EQ(32, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 64; i < 128; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 128; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(128, set->NumberOfElements());
|
|
CHECK_EQ(64, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
|
|
for (size_t i = 128; i < 254; i++) {
|
|
set = SmallOrderedHashSet::Add(set, keys[i]);
|
|
Verify(set);
|
|
}
|
|
|
|
for (size_t i = 0; i < 254; i++) {
|
|
CHECK(set->HasKey(isolate, keys[i]));
|
|
Verify(set);
|
|
}
|
|
|
|
CHECK_EQ(254, set->NumberOfElements());
|
|
CHECK_EQ(127, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
Verify(set);
|
|
}
|
|
|
|
TEST(SmallOrderedHashMapGrow) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<SmallOrderedHashMap> map = factory->NewSmallOrderedHashMap();
|
|
std::vector<Handle<Object>> keys;
|
|
for (int i = 0; i < 254; i++) {
|
|
Handle<Smi> key(Smi::FromInt(i), isolate);
|
|
keys.push_back(key);
|
|
}
|
|
|
|
for (size_t i = 0; i < 4; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 4; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(4, map->NumberOfElements());
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 4; i < 8; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 8; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(8, map->NumberOfElements());
|
|
CHECK_EQ(4, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 8; i < 16; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 16; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(16, map->NumberOfElements());
|
|
CHECK_EQ(8, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 16; i < 32; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 32; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(32, map->NumberOfElements());
|
|
CHECK_EQ(16, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 32; i < 64; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 64; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(64, map->NumberOfElements());
|
|
CHECK_EQ(32, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 64; i < 128; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 128; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(128, map->NumberOfElements());
|
|
CHECK_EQ(64, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
|
|
for (size_t i = 128; i < 254; i++) {
|
|
map = SmallOrderedHashMap::Add(map, keys[i], keys[i]);
|
|
Verify(map);
|
|
}
|
|
|
|
for (size_t i = 0; i < 254; i++) {
|
|
CHECK(map->HasKey(isolate, keys[i]));
|
|
Verify(map);
|
|
}
|
|
|
|
CHECK_EQ(254, map->NumberOfElements());
|
|
CHECK_EQ(127, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
Verify(map);
|
|
}
|
|
|
|
TEST(OrderedHashTableInsertion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
|
|
// Add a new key.
|
|
Handle<Smi> key1(Smi::FromInt(1), isolate);
|
|
Handle<Smi> value1(Smi::FromInt(1), isolate);
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
map = OrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
// Add existing key.
|
|
map = OrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
|
|
Handle<String> value = factory->NewStringFromAsciiChecked("bar");
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
map = OrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
|
|
map = OrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
|
|
Handle<Symbol> key3 = factory->NewSymbol();
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
map = OrderedHashMap::Add(map, key3, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(3, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
map = OrderedHashMap::Add(map, key3, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(3, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
Handle<Object> key4 = factory->NewHeapNumber(42.0);
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key4));
|
|
map = OrderedHashMap::Add(map, key4, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(4, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key4));
|
|
|
|
map = OrderedHashMap::Add(map, key4, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(4, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key4));
|
|
}
|
|
|
|
TEST(OrderedHashMapDuplicateHashCode) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
|
|
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
|
|
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
|
|
map = OrderedHashMap::Add(map, key1, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
|
CopyHashCode(key1, key2);
|
|
|
|
map = OrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
}
|
|
|
|
TEST(OrderedHashMapDeletion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
Handle<Smi> value1(Smi::FromInt(1), isolate);
|
|
Handle<String> value = factory->NewStringFromAsciiChecked("bar");
|
|
|
|
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
|
|
// Delete from an empty hash table
|
|
Handle<Smi> key1(Smi::FromInt(1), isolate);
|
|
CHECK(!OrderedHashMap::Delete(isolate, *map, *key1));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
map = OrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
// Delete single existing key
|
|
CHECK(OrderedHashMap::Delete(isolate, *map, *key1));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
CHECK_EQ(1, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
map = OrderedHashMap::Add(map, key1, value1);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(1, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
map = OrderedHashMap::Add(map, key2, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK_EQ(1, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
|
|
Handle<Symbol> key3 = factory->NewSymbol();
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
map = OrderedHashMap::Add(map, key3, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(3, map->NumberOfElements());
|
|
CHECK_EQ(1, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
// Delete multiple existing keys
|
|
CHECK(OrderedHashMap::Delete(isolate, *map, *key1));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(2, map->NumberOfElements());
|
|
CHECK_EQ(2, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
CHECK(OrderedHashMap::Delete(isolate, *map, *key2));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(3, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
CHECK(OrderedHashMap::Delete(isolate, *map, *key3));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
CHECK_EQ(4, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
// Delete non existent key from non new hash table
|
|
CHECK(!OrderedHashMap::Delete(isolate, *map, *key3));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(0, map->NumberOfElements());
|
|
CHECK_EQ(4, map->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
|
|
// Delete non existent key from non empty hash table
|
|
map = OrderedHashMap::Shrink(map);
|
|
map = OrderedHashMap::Add(map, key1, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
CHECK(!OrderedHashMap::Delete(isolate, *map, *key2));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key3));
|
|
}
|
|
|
|
TEST(OrderedHashMapDuplicateHashCodeDeletion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<OrderedHashMap> map = factory->NewOrderedHashMap();
|
|
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
|
|
Handle<JSObject> value = factory->NewJSObjectWithNullProto();
|
|
map = OrderedHashMap::Add(map, key1, value);
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
|
|
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
|
CopyHashCode(key1, key2);
|
|
|
|
// We shouldn't be able to delete the key!
|
|
CHECK(!OrderedHashMap::Delete(isolate, *map, *key2));
|
|
Verify(map);
|
|
CHECK_EQ(2, map->NumberOfBuckets());
|
|
CHECK_EQ(1, map->NumberOfElements());
|
|
CHECK_EQ(0, map->NumberOfDeletedElements());
|
|
CHECK(OrderedHashMap::HasKey(isolate, *map, *key1));
|
|
CHECK(!OrderedHashMap::HasKey(isolate, *map, *key2));
|
|
}
|
|
|
|
TEST(OrderedHashSetDeletion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<OrderedHashSet> set = factory->NewOrderedHashSet();
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
|
|
// Delete from an empty hash table
|
|
Handle<Smi> key1(Smi::FromInt(1), isolate);
|
|
CHECK(!OrderedHashSet::Delete(isolate, *set, *key1));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
|
|
set = OrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
|
|
// Delete single existing key
|
|
CHECK(OrderedHashSet::Delete(isolate, *set, *key1));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
CHECK_EQ(1, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
|
|
set = OrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(1, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
|
|
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
set = OrderedHashSet::Add(set, key2);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(2, set->NumberOfElements());
|
|
CHECK_EQ(1, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
|
|
Handle<Symbol> key3 = factory->NewSymbol();
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
set = OrderedHashSet::Add(set, key3);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(3, set->NumberOfElements());
|
|
CHECK_EQ(1, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
|
|
// Delete multiple existing keys
|
|
CHECK(OrderedHashSet::Delete(isolate, *set, *key1));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(2, set->NumberOfElements());
|
|
CHECK_EQ(2, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
|
|
CHECK(OrderedHashSet::Delete(isolate, *set, *key2));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(3, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
|
|
CHECK(OrderedHashSet::Delete(isolate, *set, *key3));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
CHECK_EQ(4, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
|
|
// Delete non existent key from non new hash table
|
|
CHECK(!OrderedHashSet::Delete(isolate, *set, *key3));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(0, set->NumberOfElements());
|
|
CHECK_EQ(4, set->NumberOfDeletedElements());
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
|
|
// Delete non existent key from non empty hash table
|
|
set = OrderedHashSet::Shrink(set);
|
|
set = OrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key3));
|
|
}
|
|
|
|
TEST(OrderedHashSetDuplicateHashCodeDeletion) {
|
|
LocalContext context;
|
|
Isolate* isolate = GetIsolateFrom(&context);
|
|
Factory* factory = isolate->factory();
|
|
HandleScope scope(isolate);
|
|
|
|
Handle<OrderedHashSet> set = factory->NewOrderedHashSet();
|
|
Handle<JSObject> key1 = factory->NewJSObjectWithNullProto();
|
|
set = OrderedHashSet::Add(set, key1);
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
|
|
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
|
|
CopyHashCode(key1, key2);
|
|
|
|
// We shouldn't be able to delete the key!
|
|
CHECK(!OrderedHashSet::Delete(isolate, *set, *key2));
|
|
Verify(set);
|
|
CHECK_EQ(2, set->NumberOfBuckets());
|
|
CHECK_EQ(1, set->NumberOfElements());
|
|
CHECK_EQ(0, set->NumberOfDeletedElements());
|
|
CHECK(OrderedHashSet::HasKey(isolate, *set, *key1));
|
|
CHECK(!OrderedHashSet::HasKey(isolate, *set, *key2));
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|