Commit 0831927a authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

[Collections] Implement OrderedHashMap::Add

Bug: v8:5717
Change-Id: I6bed5f36b7d32cd893c4d1cb1bcc9f21b7fac2f1
Reviewed-on: https://chromium-review.googlesource.com/527932
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45986}
parent 86b3b922
...@@ -18506,6 +18506,40 @@ Object* OrderedHashMap::Get(Isolate* isolate, OrderedHashMap* table, ...@@ -18506,6 +18506,40 @@ Object* OrderedHashMap::Get(Isolate* isolate, OrderedHashMap* table,
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
Handle<OrderedHashMap> OrderedHashMap::Add(Handle<OrderedHashMap> table,
Handle<Object> key,
Handle<Object> value) {
int hash = Object::GetOrCreateHash(table->GetIsolate(), key)->value();
int entry = table->HashToEntry(hash);
// Walk the chain of the bucket and try finding the key.
{
DisallowHeapAllocation no_gc;
Object* raw_key = *key;
while (entry != kNotFound) {
Object* candidate_key = table->KeyAt(entry);
// Do not add if we have the key already
if (candidate_key->SameValueZero(raw_key)) return table;
entry = table->NextChainEntry(entry);
}
}
table = OrderedHashMap::EnsureGrowable(table);
// Read the existing bucket values.
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToEntry(hash);
int nof = table->NumberOfElements();
// Insert a new entry at the end,
int new_entry = nof + table->NumberOfDeletedElements();
int new_index = table->EntryToIndex(new_entry);
table->set(new_index, *key);
table->set(new_index + kValueOffset, *value);
table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
// and point the bucket to the new entry.
table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
table->SetNumberOfElements(nof + 1);
return table;
}
template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate( template Handle<OrderedHashSet> OrderedHashTable<OrderedHashSet, 1>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure); Isolate* isolate, int capacity, PretenureFlag pretenure);
......
...@@ -410,7 +410,7 @@ class OrderedHashTable : public FixedArray { ...@@ -410,7 +410,7 @@ class OrderedHashTable : public FixedArray {
// existing iterators can be updated. // existing iterators can be updated.
static Handle<Derived> Clear(Handle<Derived> table); static Handle<Derived> Clear(Handle<Derived> table);
// Returns a true if the OrderedHashTable contains the key // Returns a true value if the OrderedHashTable contains the key
static Object* HasKey(Isolate* isolate, Derived* table, Object* key); static Object* HasKey(Isolate* isolate, Derived* table, Object* key);
int NumberOfElements() { int NumberOfElements() {
...@@ -557,6 +557,8 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> { ...@@ -557,6 +557,8 @@ class OrderedHashMap : public OrderedHashTable<OrderedHashMap, 2> {
// Returns a value if the OrderedHashMap contains the key, otherwise // Returns a value if the OrderedHashMap contains the key, otherwise
// returns undefined. // returns undefined.
static Object* Get(Isolate* isolate, OrderedHashMap* table, Object* key); static Object* Get(Isolate* isolate, OrderedHashMap* table, Object* key);
static Handle<OrderedHashMap> Add(Handle<OrderedHashMap> table,
Handle<Object> key, Handle<Object> value);
Object* ValueAt(int entry); Object* ValueAt(int entry);
static const int kValueOffset = 1; static const int kValueOffset = 1;
......
...@@ -19,6 +19,12 @@ void Verify(Handle<SmallOrderedHashSet> set) { ...@@ -19,6 +19,12 @@ void Verify(Handle<SmallOrderedHashSet> set) {
#endif #endif
} }
void Verify(Handle<OrderedHashMap> map) {
#if VERIFY_HEAP
map->ObjectVerify();
#endif
}
TEST(Insertion) { TEST(Insertion) {
LocalContext context; LocalContext context;
Isolate* isolate = GetIsolateFrom(&context); Isolate* isolate = GetIsolateFrom(&context);
...@@ -282,3 +288,124 @@ TEST(Grow) { ...@@ -282,3 +288,124 @@ TEST(Grow) {
CHECK_EQ(0, set->NumberOfDeletedElements()); CHECK_EQ(0, set->NumberOfDeletedElements());
Verify(set); Verify(set);
} }
TEST(OrderedHashTableInsertion) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<Object> true_val = factory->true_value();
Handle<Object> false_val = factory->false_value();
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_EQ(*false_val, 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(*true_val, 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_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<String> key2 = factory->NewStringFromAsciiChecked("foo");
Handle<String> value = factory->NewStringFromAsciiChecked("bar");
CHECK_EQ(*false_val, 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(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, 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(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
Handle<Symbol> key3 = factory->NewSymbol();
CHECK_EQ(*false_val, 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(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, 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(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
Handle<Object> key4 = factory->NewHeapNumber(42.0);
CHECK_EQ(*false_val, OrderedHashMap::HasKey(isolate, *map, *key4));
map = OrderedHashMap::Add(map, key4, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(4, map->NumberOfElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key4));
map = OrderedHashMap::Add(map, key4, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(4, map->NumberOfElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key3));
CHECK_EQ(*true_val, 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();
Handle<Object> true_val = factory->true_value();
map = OrderedHashMap::Add(map, key1, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(1, map->NumberOfElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
Handle<Name> hash_code_symbol = isolate->factory()->hash_code_symbol();
Handle<Smi> hash =
Handle<Smi>::cast(JSObject::GetDataProperty(key1, hash_code_symbol));
Handle<JSObject> key2 = factory->NewJSObjectWithNullProto();
LookupIterator it(key2, hash_code_symbol, key2, LookupIterator::OWN);
CHECK(key2->AddDataProperty(
&it, hash, NONE, v8::internal::AccessCheckInfo::THROW_ON_ERROR,
v8::internal::AccessCheckInfo::CERTAINLY_NOT_STORE_FROM_KEYED)
.IsJust());
map = OrderedHashMap::Add(map, key2, value);
Verify(map);
CHECK_EQ(2, map->NumberOfBuckets());
CHECK_EQ(2, map->NumberOfElements());
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key1));
CHECK_EQ(*true_val, OrderedHashMap::HasKey(isolate, *map, *key2));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment