| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index aa0b6f227f25b9a74089097467f4742c26f59854..f7a5c7c767f8f43799c5f2a6783ea650ff976d5e 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -3279,53 +3279,6 @@ MaybeObject* JSObject::NormalizeElements() {
|
| }
|
|
|
|
|
| -MaybeObject* JSObject::GetHiddenProperties(CreationFlag flag) {
|
| - Isolate* isolate = GetIsolate();
|
| - Heap* heap = isolate->heap();
|
| - Object* holder = BypassGlobalProxy();
|
| - if (holder->IsUndefined()) return heap->undefined_value();
|
| - JSObject* obj = JSObject::cast(holder);
|
| - if (obj->HasFastProperties()) {
|
| - // If the object has fast properties, check whether the first slot
|
| - // in the descriptor array matches the hidden symbol. Since the
|
| - // hidden symbols hash code is zero (and no other string has hash
|
| - // code zero) it will always occupy the first entry if present.
|
| - DescriptorArray* descriptors = obj->map()->instance_descriptors();
|
| - if ((descriptors->number_of_descriptors() > 0) &&
|
| - (descriptors->GetKey(0) == heap->hidden_symbol()) &&
|
| - descriptors->IsProperty(0)) {
|
| - ASSERT(descriptors->GetType(0) == FIELD);
|
| - return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
|
| - }
|
| - }
|
| -
|
| - // Only attempt to find the hidden properties in the local object and not
|
| - // in the prototype chain.
|
| - if (!obj->HasHiddenPropertiesObject()) {
|
| - // Hidden properties object not found. Allocate a new hidden properties
|
| - // object if requested. Otherwise return the undefined value.
|
| - if (flag == ALLOW_CREATION) {
|
| - Object* hidden_obj;
|
| - { MaybeObject* maybe_obj = heap->AllocateJSObject(
|
| - isolate->context()->global_context()->object_function());
|
| - if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
|
| - }
|
| - // Don't allow leakage of the hidden object through accessors
|
| - // on Object.prototype.
|
| - {
|
| - MaybeObject* maybe_obj =
|
| - JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false);
|
| - if (maybe_obj->IsFailure()) return maybe_obj;
|
| - }
|
| - return obj->SetHiddenPropertiesObject(hidden_obj);
|
| - } else {
|
| - return heap->undefined_value();
|
| - }
|
| - }
|
| - return obj->GetHiddenPropertiesObject();
|
| -}
|
| -
|
| -
|
| Smi* JSReceiver::GenerateIdentityHash() {
|
| Isolate* isolate = GetIsolate();
|
|
|
| @@ -3344,46 +3297,24 @@ Smi* JSReceiver::GenerateIdentityHash() {
|
|
|
|
|
| MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
|
| - JSObject* hidden_props;
|
| - MaybeObject* maybe = GetHiddenProperties(flag);
|
| - if (!maybe->To<JSObject>(&hidden_props)) return maybe;
|
| - maybe = hidden_props->SetLocalPropertyIgnoreAttributes(
|
| - GetHeap()->identity_hash_symbol(), hash, NONE);
|
| + MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
|
| + hash);
|
| if (maybe->IsFailure()) return maybe;
|
| return this;
|
| }
|
|
|
|
|
| MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
|
| - Isolate* isolate = GetIsolate();
|
| - Object* hidden_props_obj;
|
| - { MaybeObject* maybe_obj = GetHiddenProperties(flag);
|
| - if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
|
| - }
|
| - if (!hidden_props_obj->IsJSObject()) {
|
| - // We failed to create hidden properties. That's a detached
|
| - // global proxy.
|
| - ASSERT(hidden_props_obj->IsUndefined());
|
| - return Smi::FromInt(0);
|
| - }
|
| - JSObject* hidden_props = JSObject::cast(hidden_props_obj);
|
| - String* hash_symbol = isolate->heap()->identity_hash_symbol();
|
| - {
|
| - // Note that HasLocalProperty() can cause a GC in the general case in the
|
| - // presence of interceptors.
|
| - AssertNoAllocation no_alloc;
|
| - if (hidden_props->HasLocalProperty(hash_symbol)) {
|
| - MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
|
| - return Smi::cast(hash->ToObjectChecked());
|
| - }
|
| - }
|
| + Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
|
| + if (stored_value->IsSmi()) return stored_value;
|
|
|
| Smi* hash = GenerateIdentityHash();
|
| - { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
|
| - hash_symbol,
|
| - hash,
|
| - static_cast<PropertyAttributes>(None));
|
| - if (result->IsFailure()) return result;
|
| + MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
|
| + hash);
|
| + if (result->IsFailure()) return result;
|
| + if (result->ToObjectUnchecked()->IsUndefined()) {
|
| + // Trying to get hash of detached proxy.
|
| + return Smi::FromInt(0);
|
| }
|
| return hash;
|
| }
|
| @@ -3399,6 +3330,171 @@ MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
|
| }
|
|
|
|
|
| +Object* JSObject::GetHiddenProperty(String* key) {
|
| + if (IsJSGlobalProxy()) {
|
| + // For a proxy, use the prototype as target object.
|
| + Object* proxy_parent = GetPrototype();
|
| + // If the proxy is detached, return undefined.
|
| + if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
|
| + ASSERT(proxy_parent->IsJSGlobalObject());
|
| + return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
|
| + }
|
| + ASSERT(!IsJSGlobalProxy());
|
| + MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
|
| + ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
|
| + if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
|
| + return GetHeap()->undefined_value();
|
| + }
|
| + StringDictionary* dictionary =
|
| + StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
|
| + int entry = dictionary->FindEntry(key);
|
| + if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
|
| + return dictionary->ValueAt(entry);
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
|
| + if (IsJSGlobalProxy()) {
|
| + // For a proxy, use the prototype as target object.
|
| + Object* proxy_parent = GetPrototype();
|
| + // If the proxy is detached, return undefined.
|
| + if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
|
| + ASSERT(proxy_parent->IsJSGlobalObject());
|
| + return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
|
| + }
|
| + ASSERT(!IsJSGlobalProxy());
|
| + MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
|
| + StringDictionary* dictionary;
|
| + if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
|
| +
|
| + // If it was found, check if the key is already in the dictionary.
|
| + int entry = dictionary->FindEntry(key);
|
| + if (entry != StringDictionary::kNotFound) {
|
| + // If key was found, just update the value.
|
| + dictionary->ValueAtPut(entry, value);
|
| + return this;
|
| + }
|
| + // Key was not already in the dictionary, so add the entry.
|
| + MaybeObject* insert_result = dictionary->Add(key,
|
| + value,
|
| + PropertyDetails(NONE, NORMAL));
|
| + StringDictionary* new_dict;
|
| + if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
|
| + if (new_dict != dictionary) {
|
| + // If adding the key expanded the dictionary (i.e., Add returned a new
|
| + // dictionary), store it back to the object.
|
| + MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
|
| + if (store_result->IsFailure()) return store_result;
|
| + }
|
| + // Return this to mark success.
|
| + return this;
|
| +}
|
| +
|
| +
|
| +void JSObject::DeleteHiddenProperty(String* key) {
|
| + if (IsJSGlobalProxy()) {
|
| + // For a proxy, use the prototype as target object.
|
| + Object* proxy_parent = GetPrototype();
|
| + // If the proxy is detached, return immediately.
|
| + if (proxy_parent->IsNull()) return;
|
| + ASSERT(proxy_parent->IsJSGlobalObject());
|
| + JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
|
| + return;
|
| + }
|
| + MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
|
| + ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
|
| + if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
|
| + StringDictionary* dictionary =
|
| + StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
|
| + int entry = dictionary->FindEntry(key);
|
| + if (entry == StringDictionary::kNotFound) {
|
| + // Key wasn't in dictionary. Deletion is a success.
|
| + return;
|
| + }
|
| + // Key was in the dictionary. Remove it.
|
| + dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
|
| +}
|
| +
|
| +
|
| +bool JSObject::HasHiddenProperties() {
|
| + LookupResult lookup;
|
| + LocalLookupRealNamedProperty(GetHeap()->hidden_symbol(), &lookup);
|
| + return lookup.IsFound();
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
|
| + ASSERT(!IsJSGlobalProxy());
|
| + if (HasFastProperties()) {
|
| + // If the object has fast properties, check whether the first slot
|
| + // in the descriptor array matches the hidden symbol. Since the
|
| + // hidden symbols hash code is zero (and no other string has hash
|
| + // code zero) it will always occupy the first entry if present.
|
| + DescriptorArray* descriptors = this->map()->instance_descriptors();
|
| + if ((descriptors->number_of_descriptors() > 0) &&
|
| + (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
|
| + descriptors->IsProperty(0)) {
|
| + ASSERT(descriptors->GetType(0) == FIELD);
|
| + Object* hidden_store =
|
| + this->FastPropertyAt(descriptors->GetFieldIndex(0));
|
| + return StringDictionary::cast(hidden_store);
|
| + }
|
| + } else {
|
| + PropertyAttributes attributes;
|
| + // You can't install a getter on a property indexed by the hidden symbol,
|
| + // so we can be sure that GetLocalPropertyPostInterceptor returns a real
|
| + // object.
|
| + Object* lookup =
|
| + GetLocalPropertyPostInterceptor(this,
|
| + GetHeap()->hidden_symbol(),
|
| + &attributes)->ToObjectUnchecked();
|
| + if (!lookup->IsUndefined()) {
|
| + return StringDictionary::cast(lookup);
|
| + }
|
| + }
|
| + if (!create_if_absent) return GetHeap()->undefined_value();
|
| + const int kInitialSize = 5;
|
| + MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
|
| + StringDictionary* dictionary;
|
| + if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
|
| + MaybeObject* store_result =
|
| + SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
|
| + dictionary,
|
| + DONT_ENUM,
|
| + kNonStrictMode);
|
| + if (store_result->IsFailure()) return store_result;
|
| + return dictionary;
|
| +}
|
| +
|
| +
|
| +MaybeObject* JSObject::SetHiddenPropertiesDictionary(
|
| + StringDictionary* dictionary) {
|
| + ASSERT(!IsJSGlobalProxy());
|
| + ASSERT(HasHiddenProperties());
|
| + if (HasFastProperties()) {
|
| + // If the object has fast properties, check whether the first slot
|
| + // in the descriptor array matches the hidden symbol. Since the
|
| + // hidden symbols hash code is zero (and no other string has hash
|
| + // code zero) it will always occupy the first entry if present.
|
| + DescriptorArray* descriptors = this->map()->instance_descriptors();
|
| + if ((descriptors->number_of_descriptors() > 0) &&
|
| + (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
|
| + descriptors->IsProperty(0)) {
|
| + ASSERT(descriptors->GetType(0) == FIELD);
|
| + this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
|
| + return this;
|
| + }
|
| + }
|
| + MaybeObject* store_result =
|
| + SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
|
| + dictionary,
|
| + DONT_ENUM,
|
| + kNonStrictMode);
|
| + if (store_result->IsFailure()) return store_result;
|
| + return this;
|
| +}
|
| +
|
| +
|
| MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
|
| DeleteMode mode) {
|
| // Check local property, ignore interceptor.
|
|
|