From: rafaelw@chromium.org Date: Tue, 5 Nov 2013 11:47:11 +0000 (+0000) Subject: Remove calls to JSObject::SetLocalPropertyIgnoreAttributesTrampoline within objects.cc X-Git-Tag: upstream/4.7.83~11900 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ada13dfc3f29a8af28e6001f909aa050df64c415;p=platform%2Fupstream%2Fv8.git Remove calls to JSObject::SetLocalPropertyIgnoreAttributesTrampoline within objects.cc This includes handlifing: -SetHiddenPropertiesHashTable -ObjectHashSet::Add/Remove -ObjectHashTable::Put And splitting the following methods which previously took "allow creation" enum arguments to into side-effect-free getters and GetOrCreate*-handlfied getters. -GetHash (now GetHash & handlified GetOrCreateHash) -GetIdentityHash (now GetIdentityHash & handlified GetOrCreateIdentityHash) -GetHiddenPropertiesHashTable (now GetHiddenPropertiesHashTable & handlified GetOrCreateaHiddenPropertiesHashTable) BUG=v8:2877 R=mstarzinger@chromium.org Review URL: https://codereview.chromium.org/48913008 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17477 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/api.cc b/src/api.cc index 8a73877..50cd68a 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3689,7 +3689,8 @@ int v8::Object::GetIdentityHash() { ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle self = Utils::OpenHandle(this); - return i::JSObject::GetIdentityHash(self); + return i::Handle::cast( + i::JSReceiver::GetOrCreateIdentityHash(self))->value(); } diff --git a/src/factory.cc b/src/factory.cc index 1dd246f..c0b4f53 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -132,11 +132,14 @@ Handle Factory::NewObjectHashSet(int at_least_space_for) { } -Handle Factory::NewObjectHashTable(int at_least_space_for) { +Handle Factory::NewObjectHashTable( + int at_least_space_for, + MinimumCapacity capacity_option) { ASSERT(0 <= at_least_space_for); CALL_HEAP_FUNCTION(isolate(), ObjectHashTable::Allocate(isolate()->heap(), - at_least_space_for), + at_least_space_for, + capacity_option), ObjectHashTable); } @@ -147,7 +150,7 @@ Handle Factory::NewWeakHashTable(int at_least_space_for) { isolate(), WeakHashTable::Allocate(isolate()->heap(), at_least_space_for, - WeakHashTable::USE_DEFAULT_MINIMUM_CAPACITY, + USE_DEFAULT_MINIMUM_CAPACITY, TENURED), WeakHashTable); } diff --git a/src/factory.h b/src/factory.h index ee25bf2..47a8f43 100644 --- a/src/factory.h +++ b/src/factory.h @@ -74,7 +74,9 @@ class Factory { Handle NewObjectHashSet(int at_least_space_for); - Handle NewObjectHashTable(int at_least_space_for); + Handle NewObjectHashTable( + int at_least_space_for, + MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY); Handle NewWeakHashTable(int at_least_space_for); diff --git a/src/handles.cc b/src/handles.cc index 4cb1827..f3928eb 100644 --- a/src/handles.cc +++ b/src/handles.cc @@ -767,31 +767,6 @@ Handle GetEnumPropertyKeys(Handle object, } -Handle ObjectHashSetAdd(Handle table, - Handle key) { - CALL_HEAP_FUNCTION(table->GetIsolate(), - table->Add(*key), - ObjectHashSet); -} - - -Handle ObjectHashSetRemove(Handle table, - Handle key) { - CALL_HEAP_FUNCTION(table->GetIsolate(), - table->Remove(*key), - ObjectHashSet); -} - - -Handle PutIntoObjectHashTable(Handle table, - Handle key, - Handle value) { - CALL_HEAP_FUNCTION(table->GetIsolate(), - table->Put(*key, *value), - ObjectHashTable); -} - - DeferredHandleScope::DeferredHandleScope(Isolate* isolate) : impl_(isolate->handle_scope_implementer()) { impl_->BeginDeferredScope(); diff --git a/src/handles.h b/src/handles.h index cfdecac..890f4f5 100644 --- a/src/handles.h +++ b/src/handles.h @@ -303,16 +303,6 @@ Handle ReinitializeJSGlobalProxy( Handle constructor, Handle global); -Handle ObjectHashSetAdd(Handle table, - Handle key); - -Handle ObjectHashSetRemove(Handle table, - Handle key); - -Handle PutIntoObjectHashTable(Handle table, - Handle key, - Handle value); - void AddWeakObjectToCodeDependency(Heap* heap, Handle object, Handle code); diff --git a/src/objects-inl.h b/src/objects-inl.h index 87ad8ec..bef807e 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -5851,10 +5851,17 @@ Object* JSObject::BypassGlobalProxy() { } -MaybeObject* JSReceiver::GetIdentityHash(CreationFlag flag) { +Handle JSReceiver::GetOrCreateIdentityHash(Handle object) { + return object->IsJSProxy() + ? JSProxy::GetOrCreateIdentityHash(Handle::cast(object)) + : JSObject::GetOrCreateIdentityHash(Handle::cast(object)); +} + + +Object* JSReceiver::GetIdentityHash() { return IsJSProxy() - ? JSProxy::cast(this)->GetIdentityHash(flag) - : JSObject::cast(this)->GetIdentityHash(flag); + ? JSProxy::cast(this)->GetIdentityHash() + : JSObject::cast(this)->GetIdentityHash(); } @@ -6054,16 +6061,14 @@ bool ObjectHashTableShape::IsMatch(Object* key, Object* other) { template uint32_t ObjectHashTableShape::Hash(Object* key) { - MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); - return Smi::cast(maybe_hash->ToObjectChecked())->value(); + return Smi::cast(key->GetHash())->value(); } template uint32_t ObjectHashTableShape::HashForObject(Object* key, Object* other) { - MaybeObject* maybe_hash = other->GetHash(OMIT_CREATION); - return Smi::cast(maybe_hash->ToObjectChecked())->value(); + return Smi::cast(other->GetHash())->value(); } diff --git a/src/objects.cc b/src/objects.cc index 4cc0346..57adb19 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1028,7 +1028,7 @@ Object* Object::GetPrototype(Isolate* isolate) { } -MaybeObject* Object::GetHash(CreationFlag flag) { +Object* Object::GetHash() { // The object is either a number, a name, an odd-ball, // a real JS object, or a Harmony proxy. if (IsNumber()) { @@ -1043,12 +1043,20 @@ MaybeObject* Object::GetHash(CreationFlag flag) { uint32_t hash = Oddball::cast(this)->to_string()->Hash(); return Smi::FromInt(hash); } - if (IsJSReceiver()) { - return JSReceiver::cast(this)->GetIdentityHash(flag); - } - UNREACHABLE(); - return Smi::FromInt(0); + ASSERT(IsJSReceiver()); + return JSReceiver::cast(this)->GetIdentityHash(); +} + + +Handle Object::GetOrCreateHash(Handle object, + Isolate* isolate) { + Handle hash(object->GetHash(), isolate); + if (hash->IsSmi()) + return hash; + + ASSERT(object->IsJSReceiver()); + return JSReceiver::GetOrCreateIdentityHash(Handle::cast(object)); } @@ -3755,7 +3763,7 @@ void JSProxy::Fix(Handle proxy) { Isolate* isolate = proxy->GetIsolate(); // Save identity hash. - Handle hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION); + Handle hash(proxy->GetIdentityHash(), isolate); if (proxy->IsJSFunctionProxy()) { isolate->factory()->BecomeJSFunction(proxy); @@ -3767,7 +3775,8 @@ void JSProxy::Fix(Handle proxy) { // Inherit identity, if it was present. if (hash->IsSmi()) { - JSObject::SetIdentityHash(Handle::cast(proxy), Smi::cast(*hash)); + JSObject::SetIdentityHash(Handle::cast(proxy), + Handle::cast(hash)); } } @@ -4788,52 +4797,52 @@ Smi* JSReceiver::GenerateIdentityHash() { } -void JSObject::SetIdentityHash(Handle object, Smi* hash) { - CALL_HEAP_FUNCTION_VOID(object->GetIsolate(), - object->SetHiddenProperty( - object->GetHeap()->identity_hash_string(), hash)); +void JSObject::SetIdentityHash(Handle object, Handle hash) { + Isolate* isolate = object->GetIsolate(); + SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash); } -int JSObject::GetIdentityHash(Handle object) { - CALL_AND_RETRY_OR_DIE(object->GetIsolate(), - object->GetIdentityHash(ALLOW_CREATION), - return Smi::cast(__object__)->value(), - return 0); +Object* JSObject::GetIdentityHash() { + Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string()); + return stored_value->IsSmi() ? stored_value : GetHeap()->undefined_value(); } -MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { - Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string()); - if (stored_value->IsSmi()) return stored_value; +Handle JSObject::GetOrCreateIdentityHash(Handle object) { + Handle hash(object->GetIdentityHash(), object->GetIsolate()); + if (hash->IsSmi()) + return hash; - // Do not generate permanent identity hash code if not requested. - if (flag == OMIT_CREATION) return GetHeap()->undefined_value(); + Isolate* isolate = object->GetIsolate(); - Smi* hash = GenerateIdentityHash(); - MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_string(), - hash); - if (result->IsFailure()) return result; - if (result->ToObjectUnchecked()->IsUndefined()) { + hash = handle(object->GenerateIdentityHash(), isolate); + Handle result = SetHiddenProperty(object, + isolate->factory()->identity_hash_string(), hash); + + if (result->IsUndefined()) { // Trying to get hash of detached proxy. - return Smi::FromInt(0); + return handle(Smi::FromInt(0), isolate); } + return hash; } -Handle JSProxy::GetIdentityHash(Handle proxy, - CreationFlag flag) { - CALL_HEAP_FUNCTION(proxy->GetIsolate(), proxy->GetIdentityHash(flag), Object); +Object* JSProxy::GetIdentityHash() { + return this->hash(); } -MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { - Object* hash = this->hash(); - if (!hash->IsSmi() && flag == ALLOW_CREATION) { - hash = GenerateIdentityHash(); - set_hash(hash); - } +Handle JSProxy::GetOrCreateIdentityHash(Handle proxy) { + Isolate* isolate = proxy->GetIsolate(); + + Handle hash(proxy->GetIdentityHash(), isolate); + if (hash->IsSmi()) + return hash; + + hash = handle(proxy->GenerateIdentityHash(), isolate); + proxy->set_hash(*hash); return hash; } @@ -4849,9 +4858,7 @@ Object* JSObject::GetHiddenProperty(Name* key) { return JSObject::cast(proxy_parent)->GetHiddenProperty(key); } ASSERT(!IsJSGlobalProxy()); - MaybeObject* hidden_lookup = - GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - Object* inline_value = hidden_lookup->ToObjectUnchecked(); + Object* inline_value = GetHiddenPropertiesHashTable(); if (inline_value->IsSmi()) { // Handle inline-stored identity hash. @@ -4870,53 +4877,45 @@ Object* JSObject::GetHiddenProperty(Name* key) { } -Handle JSObject::SetHiddenProperty(Handle obj, +Handle JSObject::SetHiddenProperty(Handle object, Handle key, Handle value) { - CALL_HEAP_FUNCTION(obj->GetIsolate(), - obj->SetHiddenProperty(*key, *value), - Object); -} - + Isolate* isolate = object->GetIsolate(); -MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) { ASSERT(key->IsUniqueName()); - if (IsJSGlobalProxy()) { + if (object->IsJSGlobalProxy()) { // For a proxy, use the prototype as target object. - Object* proxy_parent = GetPrototype(); + Handle proxy_parent(object->GetPrototype(), isolate); // If the proxy is detached, return undefined. - if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); + if (proxy_parent->IsNull()) return isolate->factory()->undefined_value(); ASSERT(proxy_parent->IsJSGlobalObject()); - return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); + return SetHiddenProperty(Handle::cast(proxy_parent), key, value); } - ASSERT(!IsJSGlobalProxy()); - MaybeObject* hidden_lookup = - GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - Object* inline_value = hidden_lookup->ToObjectUnchecked(); + ASSERT(!object->IsJSGlobalProxy()); + + Handle inline_value(object->GetHiddenPropertiesHashTable(), isolate); // If there is no backing store yet, store the identity hash inline. if (value->IsSmi() && - key == GetHeap()->identity_hash_string() && + *key == *isolate->factory()->identity_hash_string() && (inline_value->IsUndefined() || inline_value->IsSmi())) { - return SetHiddenPropertiesHashTable(value); + return JSObject::SetHiddenPropertiesHashTable(object, value); } - hidden_lookup = GetHiddenPropertiesHashTable(CREATE_NEW_IF_ABSENT); - ObjectHashTable* hashtable; - if (!hidden_lookup->To(&hashtable)) return hidden_lookup; + Handle hashtable = + GetOrCreateHiddenPropertiesHashtable(object); // If it was found, check if the key is already in the dictionary. - MaybeObject* insert_result = hashtable->Put(key, value); - ObjectHashTable* new_table; - if (!insert_result->To(&new_table)) return insert_result; - if (new_table != hashtable) { + Handle new_table = ObjectHashTable::Put(hashtable, key, + value); + if (*new_table != *hashtable) { // If adding the key expanded the dictionary (i.e., Add returned a new // dictionary), store it back to the object. - MaybeObject* store_result = SetHiddenPropertiesHashTable(new_table); - if (store_result->IsFailure()) return store_result; + SetHiddenPropertiesHashTable(object, new_table); } + // Return this to mark success. - return this; + return object; } @@ -4931,16 +4930,14 @@ void JSObject::DeleteHiddenProperty(Handle object, Handle key) { return DeleteHiddenProperty(Handle::cast(proto), key); } - MaybeObject* hidden_lookup = - object->GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE); - Object* inline_value = hidden_lookup->ToObjectUnchecked(); + Object* inline_value = object->GetHiddenPropertiesHashTable(); // We never delete (inline-stored) identity hashes. - ASSERT(*key != isolate->heap()->identity_hash_string()); + ASSERT(*key != *isolate->factory()->identity_hash_string()); if (inline_value->IsUndefined() || inline_value->IsSmi()) return; Handle hashtable(ObjectHashTable::cast(inline_value)); - PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value()); + ObjectHashTable::Put(hashtable, key, isolate->factory()->the_hole_value()); } @@ -4951,10 +4948,8 @@ bool JSObject::HasHiddenProperties() { } -MaybeObject* JSObject::GetHiddenPropertiesHashTable( - InitializeHiddenProperties init_option) { +Object* JSObject::GetHiddenPropertiesHashTable() { ASSERT(!IsJSGlobalProxy()); - Object* inline_value; if (HasFastProperties()) { // If the object has fast properties, check whether the first slot // in the descriptor array matches the hidden string. Since the @@ -4968,91 +4963,95 @@ MaybeObject* JSObject::GetHiddenPropertiesHashTable( ASSERT(descriptors->GetType(sorted_index) == FIELD); ASSERT(descriptors->GetDetails(sorted_index).representation(). IsCompatibleForLoad(Representation::Tagged())); - inline_value = this->RawFastPropertyAt( + return this->RawFastPropertyAt( descriptors->GetFieldIndex(sorted_index)); } else { - inline_value = GetHeap()->undefined_value(); + return GetHeap()->undefined_value(); } } else { - inline_value = GetHeap()->undefined_value(); + return GetHeap()->undefined_value(); } } else { PropertyAttributes attributes; // You can't install a getter on a property indexed by the hidden string, // so we can be sure that GetLocalPropertyPostInterceptor returns a real // object. - inline_value = - GetLocalPropertyPostInterceptor(this, - GetHeap()->hidden_string(), - &attributes)->ToObjectUnchecked(); + return GetLocalPropertyPostInterceptor(this, + GetHeap()->hidden_string(), + &attributes)->ToObjectUnchecked(); } +} - if (init_option == ONLY_RETURN_INLINE_VALUE || - inline_value->IsHashTable()) { - return inline_value; - } +Handle JSObject::GetOrCreateHiddenPropertiesHashtable( + Handle object) { + Isolate* isolate = object->GetIsolate(); - ObjectHashTable* hashtable; static const int kInitialCapacity = 4; - MaybeObject* maybe_obj = - ObjectHashTable::Allocate(GetHeap(), - kInitialCapacity, - ObjectHashTable::USE_CUSTOM_MINIMUM_CAPACITY); - if (!maybe_obj->To(&hashtable)) return maybe_obj; + Handle inline_value(object->GetHiddenPropertiesHashTable(), isolate); + if (inline_value->IsHashTable()) { + return Handle::cast(inline_value); + } + + Handle hashtable = isolate->factory()->NewObjectHashTable( + kInitialCapacity, + USE_CUSTOM_MINIMUM_CAPACITY); if (inline_value->IsSmi()) { // We were storing the identity hash inline and now allocated an actual // dictionary. Put the identity hash into the new dictionary. - MaybeObject* insert_result = - hashtable->Put(GetHeap()->identity_hash_string(), inline_value); - ObjectHashTable* new_table; - if (!insert_result->To(&new_table)) return insert_result; - // We expect no resizing for the first insert. - ASSERT_EQ(hashtable, new_table); + hashtable = ObjectHashTable::Put(hashtable, + isolate->factory()->identity_hash_string(), + inline_value); } - MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( - GetHeap()->hidden_string(), + JSObject::SetLocalPropertyIgnoreAttributes( + object, + isolate->factory()->hidden_string(), hashtable, DONT_ENUM, OPTIMAL_REPRESENTATION, ALLOW_AS_CONSTANT, OMIT_EXTENSIBILITY_CHECK); - if (store_result->IsFailure()) return store_result; + return hashtable; } -MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) { - ASSERT(!IsJSGlobalProxy()); +Handle JSObject::SetHiddenPropertiesHashTable(Handle object, + Handle value) { + ASSERT(!object->IsJSGlobalProxy()); + + Isolate* isolate = object->GetIsolate(); + // We can store the identity hash inline iff there is no backing store // for hidden properties yet. - ASSERT(HasHiddenProperties() != value->IsSmi()); - if (HasFastProperties()) { + ASSERT(object->HasHiddenProperties() != value->IsSmi()); + if (object->HasFastProperties()) { // If the object has fast properties, check whether the first slot // in the descriptor array matches the hidden string. Since the // hidden strings hash code is zero (and no other name has hash // code zero) it will always occupy the first entry if present. - DescriptorArray* descriptors = this->map()->instance_descriptors(); + DescriptorArray* descriptors = object->map()->instance_descriptors(); if (descriptors->number_of_descriptors() > 0) { int sorted_index = descriptors->GetSortedKeyIndex(0); - if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() && - sorted_index < map()->NumberOfOwnDescriptors()) { + if (descriptors->GetKey(sorted_index) == isolate->heap()->hidden_string() + && sorted_index < object->map()->NumberOfOwnDescriptors()) { ASSERT(descriptors->GetType(sorted_index) == FIELD); - FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value); - return this; + object->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), + *value); + return object; } } } - MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline( - GetHeap()->hidden_string(), - value, - DONT_ENUM, - OPTIMAL_REPRESENTATION, - ALLOW_AS_CONSTANT, - OMIT_EXTENSIBILITY_CHECK); - if (store_result->IsFailure()) return store_result; - return this; + + SetLocalPropertyIgnoreAttributes(object, + isolate->factory()->hidden_string(), + value, + DONT_ENUM, + OPTIMAL_REPRESENTATION, + ALLOW_AS_CONSTANT, + OMIT_EXTENSIBILITY_CHECK); + return object; } @@ -15141,7 +15140,7 @@ MaybeObject* Dictionary::Allocate(Heap* heap, HashTable::Allocate( heap, at_least_space_for, - HashTable::USE_DEFAULT_MINIMUM_CAPACITY, + USE_DEFAULT_MINIMUM_CAPACITY, pretenure); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } @@ -15707,61 +15706,99 @@ MaybeObject* NameDictionary::TransformPropertiesToFastFor( } +Handle ObjectHashSet::EnsureCapacity( + Handle table, + int n, + Handle key, + PretenureFlag pretenure) { + Handle, Object*> > table_base = table; + CALL_HEAP_FUNCTION(table_base->GetIsolate(), + table_base->EnsureCapacity(n, *key, pretenure), + ObjectHashSet); +} + + +Handle ObjectHashSet::Shrink(Handle table, + Handle key) { + Handle, Object*> > table_base = table; + CALL_HEAP_FUNCTION(table_base->GetIsolate(), + table_base->Shrink(*key), + ObjectHashSet); +} + + bool ObjectHashSet::Contains(Object* key) { ASSERT(IsKey(key)); // If the object does not have an identity hash, it was never used as a key. - { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); - if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false; - } + Object* hash = key->GetHash(); + if (hash->IsUndefined()) return false; + return (FindEntry(key) != kNotFound); } -MaybeObject* ObjectHashSet::Add(Object* key) { - ASSERT(IsKey(key)); +Handle ObjectHashSet::Add(Handle table, + Handle key) { + ASSERT(table->IsKey(*key)); // Make sure the key object has an identity hash code. - int hash; - { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); - if (maybe_hash->IsFailure()) return maybe_hash; - ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); - hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); - } - int entry = FindEntry(key); + Handle object_hash = Object::GetOrCreateHash(key, + table->GetIsolate()); + + int entry = table->FindEntry(*key); // Check whether key is already present. - if (entry != kNotFound) return this; + if (entry != kNotFound) return table; // Check whether the hash set should be extended and add entry. - Object* obj; - { MaybeObject* maybe_obj = EnsureCapacity(1, key); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - ObjectHashSet* table = ObjectHashSet::cast(obj); - entry = table->FindInsertionEntry(hash); - table->set(EntryToIndex(entry), key); - table->ElementAdded(); - return table; + Handle new_table = + ObjectHashSet::EnsureCapacity(table, 1, key); + entry = new_table->FindInsertionEntry(Smi::cast(*object_hash)->value()); + new_table->set(EntryToIndex(entry), *key); + new_table->ElementAdded(); + return new_table; } -MaybeObject* ObjectHashSet::Remove(Object* key) { - ASSERT(IsKey(key)); +Handle ObjectHashSet::Remove(Handle table, + Handle key) { + ASSERT(table->IsKey(*key)); // If the object does not have an identity hash, it was never used as a key. - { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); - if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this; - } - int entry = FindEntry(key); + if (key->GetHash()->IsUndefined()) return table; + + int entry = table->FindEntry(*key); // Check whether key is actually present. - if (entry == kNotFound) return this; + if (entry == kNotFound) return table; // Remove entry and try to shrink this hash set. - set_the_hole(EntryToIndex(entry)); - ElementRemoved(); - return Shrink(key); + table->set_the_hole(EntryToIndex(entry)); + table->ElementRemoved(); + + return ObjectHashSet::Shrink(table, key); +} + + +Handle ObjectHashTable::EnsureCapacity( + Handle table, + int n, + Handle key, + PretenureFlag pretenure) { + Handle, Object*> > table_base = table; + CALL_HEAP_FUNCTION(table_base->GetIsolate(), + table_base->EnsureCapacity(n, *key, pretenure), + ObjectHashTable); +} + + +Handle ObjectHashTable::Shrink( + Handle table, Handle key) { + Handle, Object*> > table_base = table; + CALL_HEAP_FUNCTION(table_base->GetIsolate(), + table_base->Shrink(*key), + ObjectHashTable); } @@ -15769,10 +15806,9 @@ Object* ObjectHashTable::Lookup(Object* key) { ASSERT(IsKey(key)); // If the object does not have an identity hash, it was never used as a key. - { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION); - if (maybe_hash->ToObjectUnchecked()->IsUndefined()) { - return GetHeap()->the_hole_value(); - } + Object* hash = key->GetHash(); + if (hash->IsUndefined()) { + return GetHeap()->the_hole_value(); } int entry = FindEntry(key); if (entry == kNotFound) return GetHeap()->the_hole_value(); @@ -15780,38 +15816,36 @@ Object* ObjectHashTable::Lookup(Object* key) { } -MaybeObject* ObjectHashTable::Put(Object* key, Object* value) { - ASSERT(IsKey(key)); +Handle ObjectHashTable::Put(Handle table, + Handle key, + Handle value) { + ASSERT(table->IsKey(*key)); + + Isolate* isolate = table->GetIsolate(); // Make sure the key object has an identity hash code. - int hash; - { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION); - if (maybe_hash->IsFailure()) return maybe_hash; - ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash); - hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value(); - } - int entry = FindEntry(key); + Handle hash = Object::GetOrCreateHash(key, isolate); + + int entry = table->FindEntry(*key); // Check whether to perform removal operation. if (value->IsTheHole()) { - if (entry == kNotFound) return this; - RemoveEntry(entry); - return Shrink(key); + if (entry == kNotFound) return table; + table->RemoveEntry(entry); + return Shrink(table, key); } // Key is already in table, just overwrite value. if (entry != kNotFound) { - set(EntryToIndex(entry) + 1, value); - return this; + table->set(EntryToIndex(entry) + 1, *value); + return table; } // Check whether the hash table should be extended. - Object* obj; - { MaybeObject* maybe_obj = EnsureCapacity(1, key); - if (!maybe_obj->ToObject(&obj)) return maybe_obj; - } - ObjectHashTable* table = ObjectHashTable::cast(obj); - table->AddEntry(table->FindInsertionEntry(hash), key, value); + table = EnsureCapacity(table, 1, key); + table->AddEntry(table->FindInsertionEntry(Handle::cast(hash)->value()), + *key, + *value); return table; } diff --git a/src/objects.h b/src/objects.h index e2f4350..64f6a4f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -255,13 +255,6 @@ enum NormalizedMapSharingMode { }; -// Indicates whether a get method should implicitly create the object looked up. -enum CreationFlag { - ALLOW_CREATION, - OMIT_CREATION -}; - - // Indicates whether transitions can be added to a source map or not. enum TransitionFlag { INSERT_TRANSITION, @@ -1509,10 +1502,17 @@ class Object : public MaybeObject { // Return the object's prototype (might be Heap::null_value()). Object* GetPrototype(Isolate* isolate); + // Returns the permanent hash code associated with this object. May return + // undefined if not yet created. + Object* GetHash(); + // Returns the permanent hash code associated with this object depending on - // the actual object type. Might return a failure in case no hash was - // created yet or GC was caused by creation. - MUST_USE_RESULT MaybeObject* GetHash(CreationFlag flag); + // the actual object type. May create and store a hash code if needed and none + // exists. + // TODO(rafaelw): Remove isolate parameter when objects.cc is fully + // handlified. + static Handle GetOrCreateHash(Handle object, + Isolate* isolate); // Checks whether this object has the same value as the given one. This // function is implemented according to ES5, section 9.12 and can be used @@ -2003,8 +2003,13 @@ class JSReceiver: public HeapObject { inline Object* GetConstructor(); // Retrieves a permanent object identity hash code. The undefined value might - // be returned in case no hash was created yet and OMIT_CREATION was used. - inline MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); + // be returned in case no hash was created yet. + inline Object* GetIdentityHash(); + + // Retrieves a permanent object identity hash code. May create and store a + // hash code if needed and none exists. + inline static Handle GetOrCreateIdentityHash( + Handle object); // Lookup a property. If found, the result is valid and has // detailed information. @@ -2036,6 +2041,9 @@ class JSReceiver: public HeapObject { DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver); }; +// Forward declaration for JSObject::GetOrCreateHiddenPropertiesHashTable. +class ObjectHashTable; + // The JSObject describes real heap allocated JavaScript objects with // properties. // Note that the map of JSObject changes during execution to enable inline @@ -2287,11 +2295,9 @@ class JSObject: public JSReceiver { // Sets a hidden property on this object. Returns this object if successful, // undefined if called on a detached proxy. - static Handle SetHiddenProperty(Handle obj, + static Handle SetHiddenProperty(Handle object, Handle key, Handle value); - // Returns a failure if a GC is required. - MUST_USE_RESULT MaybeObject* SetHiddenProperty(Name* key, Object* value); // Gets the value of a hidden property with the given key. Returns the hole // if the property doesn't exist (or if called on a detached proxy), // otherwise returns the value set for the key. @@ -2303,8 +2309,7 @@ class JSObject: public JSReceiver { // Returns true if the object has a property with the hidden string as name. bool HasHiddenProperties(); - static int GetIdentityHash(Handle object); - static void SetIdentityHash(Handle object, Smi* hash); + static void SetIdentityHash(Handle object, Handle hash); inline void ValidateElements(); @@ -2858,23 +2863,25 @@ class JSObject: public JSReceiver { Handle accessor, PropertyAttributes attributes); - enum InitializeHiddenProperties { - CREATE_NEW_IF_ABSENT, - ONLY_RETURN_INLINE_VALUE - }; - // If create_if_absent is true, return the hash table backing store - // for hidden properties. If there is no backing store, allocate one. - // If create_if_absent is false, return the hash table backing store - // or the inline stored identity hash, whatever is found. - MUST_USE_RESULT MaybeObject* GetHiddenPropertiesHashTable( - InitializeHiddenProperties init_option); + // Return the hash table backing store or the inline stored identity hash, + // whatever is found. + MUST_USE_RESULT Object* GetHiddenPropertiesHashTable(); + + // Return the hash table backing store for hidden properties. If there is no + // backing store, allocate one. + static Handle GetOrCreateHiddenPropertiesHashtable( + Handle object); + // Set the hidden property backing store to either a hash table or // the inline-stored identity hash. - MUST_USE_RESULT MaybeObject* SetHiddenPropertiesHashTable( - Object* value); + static Handle SetHiddenPropertiesHashTable( + Handle object, + Handle value); + + MUST_USE_RESULT Object* GetIdentityHash(); - MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); + static Handle GetOrCreateIdentityHash(Handle object); DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject); }; @@ -3484,11 +3491,6 @@ class BaseShape { template class HashTable: public FixedArray { public: - enum MinimumCapacity { - USE_DEFAULT_MINIMUM_CAPACITY, - USE_CUSTOM_MINIMUM_CAPACITY - }; - // Wrapper methods inline uint32_t Hash(Key key) { if (Shape::UsesSeed) { @@ -3599,6 +3601,9 @@ class HashTable: public FixedArray { void Rehash(Key key); protected: + friend class ObjectHashSet; + friend class ObjectHashTable; + // Find the entry at which to insert element with the given key that // has the given hash value. uint32_t FindInsertionEntry(uint32_t hash); @@ -4062,11 +4067,23 @@ class ObjectHashSet: public HashTable, Object*> { // Looks up whether the given key is part of this hash set. bool Contains(Object* key); + static Handle EnsureCapacity( + Handle table, + int n, + Handle key, + PretenureFlag pretenure = NOT_TENURED); + + // Attempt to shrink hash table after removal of key. + static Handle Shrink(Handle table, + Handle key); + // Adds the given key to this hash set. - MUST_USE_RESULT MaybeObject* Add(Object* key); + static Handle Add(Handle table, + Handle key); // Removes the given key from this hash set. - MUST_USE_RESULT MaybeObject* Remove(Object* key); + static Handle Remove(Handle table, + Handle key); }; @@ -4079,13 +4096,25 @@ class ObjectHashTable: public HashTable, Object*> { return reinterpret_cast(obj); } + static Handle EnsureCapacity( + Handle table, + int n, + Handle key, + PretenureFlag pretenure = NOT_TENURED); + + // Attempt to shrink hash table after removal of key. + static Handle Shrink(Handle table, + Handle key); + // Looks up the value associated with the given key. The hole value is // returned in case the key is not present. Object* Lookup(Object* key); // Adds (or overwrites) the value associated with the given key. Mapping a // key to the hole value causes removal of the whole entry. - MUST_USE_RESULT MaybeObject* Put(Object* key, Object* value); + static Handle Put(Handle table, + Handle key, + Handle value); private: friend class MarkCompactCollector; @@ -9368,9 +9397,9 @@ class JSProxy: public JSReceiver { uint32_t index, DeleteMode mode); - MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag); - static Handle GetIdentityHash(Handle proxy, - CreationFlag flag); + MUST_USE_RESULT Object* GetIdentityHash(); + + static Handle GetOrCreateIdentityHash(Handle proxy); DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy); }; diff --git a/src/runtime.cc b/src/runtime.cc index e3749af..51a27ab 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1387,7 +1387,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) { CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); Handle key(args[1], isolate); Handle table(ObjectHashSet::cast(holder->table())); - table = ObjectHashSetAdd(table, key); + table = ObjectHashSet::Add(table, key); holder->set_table(*table); return isolate->heap()->undefined_value(); } @@ -1409,7 +1409,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) { CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0); Handle key(args[1], isolate); Handle table(ObjectHashSet::cast(holder->table())); - table = ObjectHashSetRemove(table, key); + table = ObjectHashSet::Remove(table, key); holder->set_table(*table); return isolate->heap()->undefined_value(); } @@ -1464,7 +1464,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MapDelete) { Handle table(ObjectHashTable::cast(holder->table())); Handle lookup(table->Lookup(*key), isolate); Handle new_table = - PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value()); + ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); holder->set_table(*new_table); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } @@ -1477,7 +1477,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) { CONVERT_ARG_HANDLE_CHECKED(Object, key, 1); CONVERT_ARG_HANDLE_CHECKED(Object, value, 2); Handle table(ObjectHashTable::cast(holder->table())); - Handle new_table = PutIntoObjectHashTable(table, key, value); + Handle new_table = ObjectHashTable::Put(table, key, value); holder->set_table(*new_table); return isolate->heap()->undefined_value(); } @@ -1543,7 +1543,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionDelete) { weak_collection->table())); Handle lookup(table->Lookup(*key), isolate); Handle new_table = - PutIntoObjectHashTable(table, key, isolate->factory()->the_hole_value()); + ObjectHashTable::Put(table, key, isolate->factory()->the_hole_value()); weak_collection->set_table(*new_table); return isolate->heap()->ToBoolean(!lookup->IsTheHole()); } @@ -1557,7 +1557,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakCollectionSet) { Handle value(args[2], isolate); Handle table( ObjectHashTable::cast(weak_collection->table())); - Handle new_table = PutIntoObjectHashTable(table, key, value); + Handle new_table = ObjectHashTable::Put(table, key, value); weak_collection->set_table(*new_table); return isolate->heap()->undefined_value(); } diff --git a/src/v8globals.h b/src/v8globals.h index 7fa2fd6..4910cb7 100644 --- a/src/v8globals.h +++ b/src/v8globals.h @@ -199,6 +199,11 @@ const int kSpaceTagMask = (1 << kSpaceTagSize) - 1; // allows). enum PretenureFlag { NOT_TENURED, TENURED }; +enum MinimumCapacity { + USE_DEFAULT_MINIMUM_CAPACITY, + USE_CUSTOM_MINIMUM_CAPACITY +}; + enum GarbageCollector { SCAVENGER, MARK_COMPACTOR }; enum Executability { NOT_EXECUTABLE, EXECUTABLE }; diff --git a/test/cctest/test-dictionary.cc b/test/cctest/test-dictionary.cc index 44f64f7..6e62a22 100644 --- a/test/cctest/test-dictionary.cc +++ b/test/cctest/test-dictionary.cc @@ -47,7 +47,7 @@ TEST(ObjectHashTable) { Handle table = factory->NewObjectHashTable(23); Handle a = factory->NewJSArray(7); Handle b = factory->NewJSArray(11); - table = PutIntoObjectHashTable(table, a, b); + table = ObjectHashTable::Put(table, a, b); CHECK_EQ(table->NumberOfElements(), 1); CHECK_EQ(table->Lookup(*a), *b); CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); @@ -59,12 +59,12 @@ TEST(ObjectHashTable) { CHECK_EQ(table->Lookup(*b), CcTest::heap()->the_hole_value()); // Keys that are overwritten should not change number of elements. - table = PutIntoObjectHashTable(table, a, factory->NewJSArray(13)); + table = ObjectHashTable::Put(table, a, factory->NewJSArray(13)); CHECK_EQ(table->NumberOfElements(), 1); CHECK_NE(table->Lookup(*a), *b); // Keys mapped to the hole should be removed permanently. - table = PutIntoObjectHashTable(table, a, factory->the_hole_value()); + table = ObjectHashTable::Put(table, a, factory->the_hole_value()); CHECK_EQ(table->NumberOfElements(), 0); CHECK_EQ(table->NumberOfDeletedElements(), 1); CHECK_EQ(table->Lookup(*a), CcTest::heap()->the_hole_value()); @@ -74,21 +74,21 @@ TEST(ObjectHashTable) { for (int i = 0; i < 100; i++) { Handle key = factory->NewJSArray(7); Handle value = factory->NewJSArray(11); - table = PutIntoObjectHashTable(table, key, value); + table = ObjectHashTable::Put(table, key, value); CHECK_EQ(table->NumberOfElements(), i + 1); CHECK_NE(table->FindEntry(*key), ObjectHashTable::kNotFound); CHECK_EQ(table->Lookup(*key), *value); - CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi()); + CHECK(key->GetIdentityHash()->IsSmi()); } // Keys never added to the map which already have an identity hash // code should not be found. for (int i = 0; i < 100; i++) { Handle key = factory->NewJSArray(7); - CHECK(key->GetIdentityHash(ALLOW_CREATION)->ToObjectChecked()->IsSmi()); + CHECK(JSReceiver::GetOrCreateIdentityHash(key)->IsSmi()); CHECK_EQ(table->FindEntry(*key), ObjectHashTable::kNotFound); CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); - CHECK(key->GetIdentityHash(OMIT_CREATION)->ToObjectChecked()->IsSmi()); + CHECK(key->GetIdentityHash()->IsSmi()); } // Keys that don't have an identity hash should not be found and also @@ -96,7 +96,7 @@ TEST(ObjectHashTable) { for (int i = 0; i < 100; i++) { Handle key = factory->NewJSArray(7); CHECK_EQ(table->Lookup(*key), CcTest::heap()->the_hole_value()); - CHECK_EQ(key->GetIdentityHash(OMIT_CREATION), + CHECK_EQ(key->GetIdentityHash(), CcTest::heap()->undefined_value()); } } @@ -175,13 +175,17 @@ TEST(ObjectHashSetCausesGC) { SimulateFullSpace(CcTest::heap()->old_pointer_space()); // Calling Contains() should not cause GC ever. + int gc_count = isolate->heap()->gc_count(); CHECK(!table->Contains(*key)); + CHECK(gc_count == isolate->heap()->gc_count()); - // Calling Remove() should not cause GC ever. - CHECK(!table->Remove(*key)->IsFailure()); + // Calling Remove() will not cause GC in this case. + table = ObjectHashSet::Remove(table, key); + CHECK(gc_count == isolate->heap()->gc_count()); - // Calling Add() should request GC by returning a failure. - CHECK(table->Add(*key)->IsRetryAfterGC()); + // Calling Add() should cause GC. + table = ObjectHashSet::Add(table, key); + CHECK(gc_count < isolate->heap()->gc_count()); } #endif @@ -211,6 +215,8 @@ TEST(ObjectHashTableCausesGC) { CHECK(table->Lookup(*key)->IsTheHole()); // Calling Put() should request GC by returning a failure. - CHECK(table->Put(*key, *key)->IsRetryAfterGC()); + int gc_count = isolate->heap()->gc_count(); + ObjectHashTable::Put(table, key, key); + CHECK(gc_count < isolate->heap()->gc_count()); } #endif diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 74c2b75..3426cdb 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -2759,7 +2759,7 @@ TEST(Regress2211) { // In the first iteration, set hidden value first and identity hash second. // In the second iteration, reverse the order. if (i == 0) obj->SetHiddenValue(v8_str("key string"), value); - JSObject::SetIdentityHash(internal_obj, hash); + JSObject::SetIdentityHash(internal_obj, handle(hash, CcTest::i_isolate())); if (i == 1) obj->SetHiddenValue(v8_str("key string"), value); // Check values. diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc index 932b06b..175ca28 100644 --- a/test/cctest/test-weakmaps.cc +++ b/test/cctest/test-weakmaps.cc @@ -56,7 +56,7 @@ static Handle AllocateJSWeakMap(Isolate* isolate) { static void PutIntoWeakMap(Handle weakmap, Handle key, Handle value) { - Handle table = PutIntoObjectHashTable( + Handle table = ObjectHashTable::Put( Handle(ObjectHashTable::cast(weakmap->table())), Handle(JSObject::cast(*key)), value); diff --git a/test/cctest/test-weaksets.cc b/test/cctest/test-weaksets.cc index aff4c7f..f7cc73c 100644 --- a/test/cctest/test-weaksets.cc +++ b/test/cctest/test-weaksets.cc @@ -56,7 +56,7 @@ static Handle AllocateJSWeakSet(Isolate* isolate) { static void PutIntoWeakSet(Handle weakset, Handle key, Handle value) { - Handle table = PutIntoObjectHashTable( + Handle table = ObjectHashTable::Put( Handle(ObjectHashTable::cast(weakset->table())), Handle(JSObject::cast(*key)), value);