Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 0f8efcd38b1d68f1037baefd7b4250ae605f5d76..441c13907cb71d769607a3ac9372404810a69bdd 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -4877,34 +4877,31 @@ Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object, |
MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor( |
- Handle<JSObject> object, Handle<Name> name) { |
- Isolate* isolate = object->GetIsolate(); |
+ Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name) { |
+ Isolate* isolate = holder->GetIsolate(); |
// TODO(rossberg): Support symbols in the API. |
- if (name->IsSymbol()) return isolate->factory()->false_value(); |
+ if (name->IsSymbol()) return MaybeHandle<Object>(); |
- Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); |
- if (!interceptor->deleter()->IsUndefined()) { |
- v8::NamedPropertyDeleterCallback deleter = |
- v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter()); |
- LOG(isolate, |
- ApiNamedPropertyAccess("interceptor-named-delete", *object, *name)); |
- PropertyCallbackArguments args( |
- isolate, interceptor->data(), *object, *object); |
- v8::Handle<v8::Boolean> result = |
- args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name))); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- if (!result.IsEmpty()) { |
- DCHECK(result->IsBoolean()); |
- Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
- result_internal->VerifyApiCallResultType(); |
- // Rebox CustomArguments::kReturnValueOffset before returning. |
- return handle(*result_internal, isolate); |
- } |
- } |
- Handle<Object> result = |
- DeletePropertyPostInterceptor(object, name, NORMAL_DELETION); |
- return result; |
+ Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor()); |
+ if (interceptor->deleter()->IsUndefined()) return MaybeHandle<Object>(); |
+ |
+ v8::NamedPropertyDeleterCallback deleter = |
+ v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter()); |
+ LOG(isolate, |
+ ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name)); |
+ PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, |
+ *holder); |
+ v8::Handle<v8::Boolean> result = |
+ args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name))); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
+ if (result.IsEmpty()) return MaybeHandle<Object>(); |
+ |
+ DCHECK(result->IsBoolean()); |
+ Handle<Object> result_internal = v8::Utils::OpenHandle(*result); |
+ result_internal->VerifyApiCallResultType(); |
+ // Rebox CustomArguments::kReturnValueOffset before returning. |
+ return handle(*result_internal, isolate); |
} |
@@ -5020,87 +5017,89 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object, |
MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object, |
Handle<Name> name, |
DeleteMode delete_mode) { |
- Isolate* isolate = object->GetIsolate(); |
// ECMA-262, 3rd, 8.6.2.5 |
DCHECK(name->IsName()); |
- // Check access rights if needed. |
- if (object->IsAccessCheckNeeded() && |
- !isolate->MayNamedAccess(object, name, v8::ACCESS_DELETE)) { |
- isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE); |
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); |
- return isolate->factory()->false_value(); |
- } |
- |
- if (object->IsJSGlobalProxy()) { |
- PrototypeIterator iter(isolate, object); |
- if (iter.IsAtEnd()) return isolate->factory()->false_value(); |
- DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject()); |
- return JSGlobalObject::DeleteProperty( |
- Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter)), name, |
- delete_mode); |
- } |
- |
uint32_t index = 0; |
if (name->AsArrayIndex(&index)) { |
return DeleteElement(object, index, delete_mode); |
} |
- LookupResult lookup(isolate); |
- object->LookupOwn(name, &lookup, true); |
- if (!lookup.IsFound()) return isolate->factory()->true_value(); |
- // Ignore attributes if forcing a deletion. |
- if (lookup.IsDontDelete() && delete_mode != FORCE_DELETION) { |
- if (delete_mode == STRICT_DELETION) { |
- // Deleting a non-configurable property in strict mode. |
- Handle<Object> args[2] = { name, object }; |
- Handle<Object> error = isolate->factory()->NewTypeError( |
- "strict_delete_property", HandleVector(args, ARRAY_SIZE(args))); |
- isolate->Throw(*error); |
- return Handle<Object>(); |
- } |
- return isolate->factory()->false_value(); |
- } |
+ // Skip interceptors on FORCE_DELETION. |
+ LookupIterator::Configuration config = |
+ delete_mode == FORCE_DELETION ? LookupIterator::CHECK_HIDDEN_ACCESS |
+ : LookupIterator::CHECK_OWN; |
+ |
+ LookupIterator it(object, name, config); |
- Handle<Object> old_value = isolate->factory()->the_hole_value(); |
bool is_observed = object->map()->is_observed() && |
- *name != isolate->heap()->hidden_string(); |
- if (is_observed && lookup.IsDataProperty()) { |
- old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked(); |
- } |
- Handle<Object> result; |
+ *name != it.isolate()->heap()->hidden_string(); |
- // Check for interceptor. |
- if (lookup.IsInterceptor()) { |
- // Skip interceptor if forcing a deletion. |
- if (delete_mode == FORCE_DELETION) { |
- result = DeletePropertyPostInterceptor(object, name, delete_mode); |
- } else { |
- ASSIGN_RETURN_ON_EXCEPTION( |
- isolate, result, |
- DeletePropertyWithInterceptor(object, name), |
- Object); |
- } |
- } else { |
- PropertyNormalizationMode mode = object->map()->is_prototype_map() |
- ? KEEP_INOBJECT_PROPERTIES |
- : CLEAR_INOBJECT_PROPERTIES; |
- // Normalize object if needed. |
- NormalizeProperties(object, mode, 0); |
- // Make sure the properties are normalized before removing the entry. |
- result = DeleteNormalizedProperty(object, name, delete_mode); |
- ReoptimizeIfPrototype(object); |
- } |
+ for (; it.IsFound(); it.Next()) { |
+ switch (it.state()) { |
+ case LookupIterator::NOT_FOUND: |
+ case LookupIterator::JSPROXY: |
+ UNREACHABLE(); |
+ case LookupIterator::ACCESS_CHECK: |
+ if (it.HasAccess(v8::ACCESS_DELETE)) break; |
+ it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>(), |
+ v8::ACCESS_DELETE); |
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it.isolate(), Object); |
+ return it.isolate()->factory()->false_value(); |
+ case LookupIterator::INTERCEPTOR: { |
+ MaybeHandle<Object> maybe_result = |
+ JSObject::DeletePropertyWithInterceptor(it.GetHolder<JSObject>(), |
+ object, it.name()); |
+ // Delete with interceptor succeeded. Return result. |
+ if (!maybe_result.is_null()) return maybe_result; |
+ // An exception was thrown in the interceptor. Propagate. |
+ if (it.isolate()->has_pending_exception()) return maybe_result; |
+ break; |
+ } |
+ case LookupIterator::PROPERTY: { |
+ if (!it.HasProperty()) continue; |
+ if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) { |
+ // Fail if the property is not configurable. |
+ if (delete_mode == STRICT_DELETION) { |
+ Handle<Object> args[2] = {name, object}; |
+ Handle<Object> error = it.isolate()->factory()->NewTypeError( |
+ "strict_delete_property", HandleVector(args, ARRAY_SIZE(args))); |
+ it.isolate()->Throw(*error); |
+ return Handle<Object>(); |
+ } |
+ return it.isolate()->factory()->false_value(); |
+ } |
- if (is_observed) { |
- Maybe<bool> maybe = HasOwnProperty(object, name); |
- if (!maybe.has_value) return MaybeHandle<Object>(); |
- if (!maybe.value) { |
- EnqueueChangeRecord(object, "delete", name, old_value); |
+ Handle<Object> old_value; |
+ if (is_observed) { |
+ switch (it.property_kind()) { |
+ case LookupIterator::ACCESSOR: |
+ old_value = it.isolate()->factory()->the_hole_value(); |
+ break; |
+ case LookupIterator::DATA: |
+ old_value = it.GetDataValue(); |
+ } |
+ } |
+ |
+ PropertyNormalizationMode mode = object->map()->is_prototype_map() |
+ ? KEEP_INOBJECT_PROPERTIES |
+ : CLEAR_INOBJECT_PROPERTIES; |
+ Handle<JSObject> holder = it.GetHolder<JSObject>(); |
+ NormalizeProperties(holder, mode, 0); |
+ Handle<Object> result = |
+ DeleteNormalizedProperty(holder, name, delete_mode); |
+ ReoptimizeIfPrototype(holder); |
+ |
+ if (is_observed) { |
+ EnqueueChangeRecord(object, "delete", name, old_value); |
+ } |
+ |
+ return result; |
+ } |
} |
} |
- return result; |
+ return it.isolate()->factory()->true_value(); |
} |