}
-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()) {
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> Object::GetOrCreateHash(Handle<Object> object,
+ Isolate* isolate) {
+ Handle<Object> hash(object->GetHash(), isolate);
+ if (hash->IsSmi())
+ return hash;
+
+ ASSERT(object->IsJSReceiver());
+ return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
}
Isolate* isolate = proxy->GetIsolate();
// Save identity hash.
- Handle<Object> hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION);
+ Handle<Object> hash(proxy->GetIdentityHash(), isolate);
if (proxy->IsJSFunctionProxy()) {
isolate->factory()->BecomeJSFunction(proxy);
// Inherit identity, if it was present.
if (hash->IsSmi()) {
- JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), Smi::cast(*hash));
+ JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
+ Handle<Smi>::cast(hash));
}
}
}
-void JSObject::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
- CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
- object->SetHiddenProperty(
- object->GetHeap()->identity_hash_string(), hash));
+void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
+ Isolate* isolate = object->GetIsolate();
+ SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
}
-int JSObject::GetIdentityHash(Handle<JSObject> 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<Object> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
+ Handle<Object> 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<Object> 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<Object> JSProxy::GetIdentityHash(Handle<JSProxy> 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<Object> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
+ Isolate* isolate = proxy->GetIsolate();
+
+ Handle<Object> hash(proxy->GetIdentityHash(), isolate);
+ if (hash->IsSmi())
+ return hash;
+
+ hash = handle(proxy->GenerateIdentityHash(), isolate);
+ proxy->set_hash(*hash);
return hash;
}
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.
}
-Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
+Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
Handle<Name> key,
Handle<Object> 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<Object> 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<JSObject>::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<Object> 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<ObjectHashTable> 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<ObjectHashTable> 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;
}
return DeleteHiddenProperty(Handle<JSObject>::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<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
- PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value());
+ ObjectHashTable::Put(hashtable, key, isolate->factory()->the_hole_value());
}
}
-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
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<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
+ Handle<JSObject> 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<ObjectHashTable>(&hashtable)) return maybe_obj;
+ Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
+ if (inline_value->IsHashTable()) {
+ return Handle<ObjectHashTable>::cast(inline_value);
+ }
+
+ Handle<ObjectHashTable> 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<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
+ Handle<Object> 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;
}
HashTable<Shape, Key>::Allocate(
heap,
at_least_space_for,
- HashTable<Shape, Key>::USE_DEFAULT_MINIMUM_CAPACITY,
+ USE_DEFAULT_MINIMUM_CAPACITY,
pretenure);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
}
+Handle<ObjectHashSet> ObjectHashSet::EnsureCapacity(
+ Handle<ObjectHashSet> table,
+ int n,
+ Handle<Object> key,
+ PretenureFlag pretenure) {
+ Handle<HashTable<ObjectHashTableShape<1>, Object*> > table_base = table;
+ CALL_HEAP_FUNCTION(table_base->GetIsolate(),
+ table_base->EnsureCapacity(n, *key, pretenure),
+ ObjectHashSet);
+}
+
+
+Handle<ObjectHashSet> ObjectHashSet::Shrink(Handle<ObjectHashSet> table,
+ Handle<Object> key) {
+ Handle<HashTable<ObjectHashTableShape<1>, 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> ObjectHashSet::Add(Handle<ObjectHashSet> table,
+ Handle<Object> 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> 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<ObjectHashSet> 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> ObjectHashSet::Remove(Handle<ObjectHashSet> table,
+ Handle<Object> 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> ObjectHashTable::EnsureCapacity(
+ Handle<ObjectHashTable> table,
+ int n,
+ Handle<Object> key,
+ PretenureFlag pretenure) {
+ Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table;
+ CALL_HEAP_FUNCTION(table_base->GetIsolate(),
+ table_base->EnsureCapacity(n, *key, pretenure),
+ ObjectHashTable);
+}
+
+
+Handle<ObjectHashTable> ObjectHashTable::Shrink(
+ Handle<ObjectHashTable> table, Handle<Object> key) {
+ Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table;
+ CALL_HEAP_FUNCTION(table_base->GetIsolate(),
+ table_base->Shrink(*key),
+ ObjectHashTable);
}
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();
}
-MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
- ASSERT(IsKey(key));
+Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ Handle<Object> 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<Object> 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<Smi>::cast(hash)->value()),
+ *key,
+ *value);
return table;
}
};
-// 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,
// 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<Object> GetOrCreateHash(Handle<Object> 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
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<Object> GetOrCreateIdentityHash(
+ Handle<JSReceiver> object);
// Lookup a property. If found, the result is valid and has
// detailed information.
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
// Sets a hidden property on this object. Returns this object if successful,
// undefined if called on a detached proxy.
- static Handle<Object> SetHiddenProperty(Handle<JSObject> obj,
+ static Handle<Object> SetHiddenProperty(Handle<JSObject> object,
Handle<Name> key,
Handle<Object> 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.
// Returns true if the object has a property with the hidden string as name.
bool HasHiddenProperties();
- static int GetIdentityHash(Handle<JSObject> object);
- static void SetIdentityHash(Handle<JSObject> object, Smi* hash);
+ static void SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash);
inline void ValidateElements();
Handle<Object> 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<ObjectHashTable> GetOrCreateHiddenPropertiesHashtable(
+ Handle<JSObject> 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<Object> SetHiddenPropertiesHashTable(
+ Handle<JSObject> object,
+ Handle<Object> value);
+
+ MUST_USE_RESULT Object* GetIdentityHash();
- MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
+ static Handle<Object> GetOrCreateIdentityHash(Handle<JSObject> object);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSObject);
};
template<typename Shape, typename Key>
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) {
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);
// Looks up whether the given key is part of this hash set.
bool Contains(Object* key);
+ static Handle<ObjectHashSet> EnsureCapacity(
+ Handle<ObjectHashSet> table,
+ int n,
+ Handle<Object> key,
+ PretenureFlag pretenure = NOT_TENURED);
+
+ // Attempt to shrink hash table after removal of key.
+ static Handle<ObjectHashSet> Shrink(Handle<ObjectHashSet> table,
+ Handle<Object> key);
+
// Adds the given key to this hash set.
- MUST_USE_RESULT MaybeObject* Add(Object* key);
+ static Handle<ObjectHashSet> Add(Handle<ObjectHashSet> table,
+ Handle<Object> key);
// Removes the given key from this hash set.
- MUST_USE_RESULT MaybeObject* Remove(Object* key);
+ static Handle<ObjectHashSet> Remove(Handle<ObjectHashSet> table,
+ Handle<Object> key);
};
return reinterpret_cast<ObjectHashTable*>(obj);
}
+ static Handle<ObjectHashTable> EnsureCapacity(
+ Handle<ObjectHashTable> table,
+ int n,
+ Handle<Object> key,
+ PretenureFlag pretenure = NOT_TENURED);
+
+ // Attempt to shrink hash table after removal of key.
+ static Handle<ObjectHashTable> Shrink(Handle<ObjectHashTable> table,
+ Handle<Object> 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<ObjectHashTable> Put(Handle<ObjectHashTable> table,
+ Handle<Object> key,
+ Handle<Object> value);
private:
friend class MarkCompactCollector;
uint32_t index,
DeleteMode mode);
- MUST_USE_RESULT MaybeObject* GetIdentityHash(CreationFlag flag);
- static Handle<Object> GetIdentityHash(Handle<JSProxy> proxy,
- CreationFlag flag);
+ MUST_USE_RESULT Object* GetIdentityHash();
+
+ static Handle<Object> GetOrCreateIdentityHash(Handle<JSProxy> proxy);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
};
Handle<ObjectHashTable> table = factory->NewObjectHashTable(23);
Handle<JSObject> a = factory->NewJSArray(7);
Handle<JSObject> 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());
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());
for (int i = 0; i < 100; i++) {
Handle<JSReceiver> key = factory->NewJSArray(7);
Handle<JSObject> 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<JSReceiver> 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
for (int i = 0; i < 100; i++) {
Handle<JSReceiver> 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());
}
}
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
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