Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 38a5f8fa663120cfdba412972728751d50310423..d7f7f53759eab83566b7a60657fc8bf2796dfce3 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -3733,6 +3733,8 @@ Maybe<bool> JSObject::SetPropertyWithInterceptor(LookupIterator* it, |
result_internal->VerifyApiCallResultType(); |
#endif |
return Just(true); |
+ // TODO(neis): In the future, we may want to actually return the interceptor's |
+ // result, which then should be a boolean. |
} |
@@ -3774,21 +3776,8 @@ Maybe<bool> Object::SetPropertyInternal(LookupIterator* it, |
should_throw); |
case LookupIterator::JSPROXY: |
- if (it->HolderIsReceiverOrHiddenPrototype()) { |
- return JSProxy::SetPropertyWithHandler( |
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(), value, |
- should_throw); |
- } else { |
- // TODO(verwaest): Use the MaybeHandle to indicate result. |
- bool has_result = false; |
- Maybe<bool> maybe_result = |
- JSProxy::SetPropertyViaPrototypesWithHandler( |
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName(), |
- value, should_throw, &has_result); |
- if (has_result) return maybe_result; |
- done = true; |
- } |
- break; |
+ return JSProxy::SetProperty(it->GetHolder<JSProxy>(), it->GetName(), |
+ value, it->GetReceiver(), language_mode); |
case LookupIterator::INTERCEPTOR: |
if (it->HolderIsReceiverOrHiddenPrototype()) { |
@@ -3872,6 +3861,7 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, |
StoreFromKeyed store_mode) { |
ShouldThrow should_throw = |
is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; |
+ Isolate* isolate = it->isolate(); |
bool found = false; |
Maybe<bool> result = |
@@ -3884,12 +3874,12 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, |
if (!it->GetReceiver()->IsJSReceiver()) { |
return WriteToReadOnlyProperty(it, value, should_throw); |
} |
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); |
LookupIterator::Configuration c = LookupIterator::OWN; |
LookupIterator own_lookup = |
- it->IsElement() |
- ? LookupIterator(it->isolate(), it->GetReceiver(), it->index(), c) |
- : LookupIterator(it->GetReceiver(), it->name(), c); |
+ it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) |
+ : LookupIterator(receiver, it->name(), c); |
for (; own_lookup.IsFound(); own_lookup.Next()) { |
switch (own_lookup.state()) { |
@@ -3901,7 +3891,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, |
break; |
case LookupIterator::INTEGER_INDEXED_EXOTIC: |
- return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, |
+ case LookupIterator::ACCESSOR: |
+ return RedefineIncompatibleProperty(isolate, it->GetName(), value, |
should_throw); |
case LookupIterator::DATA: { |
@@ -3912,18 +3903,27 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value, |
return SetDataProperty(&own_lookup, value); |
} |
- case LookupIterator::ACCESSOR: { |
- return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, |
- should_throw); |
- } |
- |
case LookupIterator::INTERCEPTOR: |
case LookupIterator::JSPROXY: { |
- bool found = false; |
- Maybe<bool> result = SetPropertyInternal( |
- &own_lookup, value, language_mode, store_mode, &found); |
- if (found) return result; |
- break; |
+ PropertyDescriptor desc; |
+ bool owned = JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc); |
+ if (isolate->has_pending_exception()) return Nothing<bool>(); |
+ if (!owned) { |
+ return JSReceiver::CreateDataProperty(&own_lookup, value, |
+ should_throw); |
+ } |
+ if (PropertyDescriptor::IsAccessorDescriptor(&desc) || |
+ !desc.writable()) { |
+ return RedefineIncompatibleProperty(isolate, it->GetName(), value, |
+ should_throw); |
+ } |
+ |
+ PropertyDescriptor value_desc; |
+ value_desc.set_value(value); |
+ bool result = JSReceiver::DefineOwnProperty( |
+ isolate, receiver, it->GetName(), &value_desc, should_throw); |
+ if (isolate->has_pending_exception()) return Nothing<bool>(); |
+ return Just(result); |
} |
case LookupIterator::NOT_FOUND: |
@@ -4589,110 +4589,65 @@ Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy, |
} |
-Maybe<bool> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy, |
- Handle<Object> receiver, |
- Handle<Name> name, |
- Handle<Object> value, |
- ShouldThrow should_throw) { |
- Isolate* isolate = proxy->GetIsolate(); |
- |
- // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
- if (name->IsSymbol()) return Just(true); |
- |
- Handle<Object> args[] = { receiver, name, value }; |
- RETURN_ON_EXCEPTION_VALUE(isolate, |
- CallTrap(proxy, "set", isolate->derived_set_trap(), |
- arraysize(args), args), |
- Nothing<bool>()); |
- |
- return Just(true); |
- // TODO(neis): This needs to be made spec-conformant by looking at the |
- // trap's result. |
-} |
- |
- |
-Maybe<bool> JSProxy::SetPropertyViaPrototypesWithHandler( |
- Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name, |
- Handle<Object> value, ShouldThrow should_throw, bool* done) { |
+Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name, |
+ Handle<Object> value, Handle<Object> receiver, |
+ LanguageMode language_mode) { |
Isolate* isolate = proxy->GetIsolate(); |
- Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy. |
+ Factory* factory = isolate->factory(); |
+ Handle<String> trap_name = factory->set_string(); |
+ ShouldThrow should_throw = |
+ is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; |
- // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
- if (name->IsSymbol()) { |
- *done = false; // Return value will be ignored. |
+ if (proxy->IsRevoked()) { |
+ isolate->Throw( |
+ *factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name)); |
return Nothing<bool>(); |
} |
- *done = true; // except where redefined... |
- Handle<Object> args[] = { name }; |
- Handle<Object> result; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, result, CallTrap(proxy, "getPropertyDescriptor", |
- Handle<Object>(), arraysize(args), args), |
- Nothing<bool>()); |
+ Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate); |
+ Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate); |
- if (result->IsUndefined()) { |
- *done = false; // Return value will be ignored. |
- return Nothing<bool>(); |
+ Handle<Object> trap; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, trap, GetTrap(proxy, trap_name), |
+ Nothing<bool>()); |
+ if (trap->IsUndefined()) { |
+ LookupIterator it = |
+ LookupIterator::PropertyOrElement(isolate, receiver, name, target); |
+ return Object::SetSuperProperty(&it, value, language_mode, |
+ Object::MAY_BE_STORE_FROM_KEYED); |
} |
- // Emulate [[GetProperty]] semantics for proxies. |
- Handle<Object> argv[] = { result }; |
- Handle<Object> desc; |
+ Handle<Object> trap_result; |
+ Handle<Object> args[] = {target, name, value, receiver}; |
ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, desc, |
- Execution::Call(isolate, isolate->to_complete_property_descriptor(), |
- result, arraysize(argv), argv), |
+ isolate, trap_result, |
+ Execution::Call(isolate, trap, handler, arraysize(args), args), |
Nothing<bool>()); |
- |
- // [[GetProperty]] requires to check that all properties are configurable. |
- Handle<String> configurable_name = |
- isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("configurable_")); |
- Handle<Object> configurable = |
- Object::GetProperty(desc, configurable_name).ToHandleChecked(); |
- DCHECK(configurable->IsBoolean()); |
- if (configurable->IsFalse()) { |
- isolate->Throw(*isolate->factory()->NewTypeError( |
- MessageTemplate::kProxyPropNotConfigurable, handler, name, |
- isolate->factory()->NewStringFromAsciiChecked( |
- "getPropertyDescriptor"))); |
- return Nothing<bool>(); |
+ if (!trap_result->BooleanValue()) { |
+ RETURN_FAILURE(isolate, should_throw, |
+ NewTypeError(MessageTemplate::kProxyHandlerReturned, handler, |
+ factory->false_string(), trap_name)); |
} |
- DCHECK(configurable->IsTrue()); |
- // Check for DataDescriptor. |
- Handle<String> hasWritable_name = |
- isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("hasWritable_")); |
- Handle<Object> hasWritable = |
- Object::GetProperty(desc, hasWritable_name).ToHandleChecked(); |
- DCHECK(hasWritable->IsBoolean()); |
- if (hasWritable->IsTrue()) { |
- Handle<String> writable_name = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("writable_")); |
- Handle<Object> writable = |
- Object::GetProperty(desc, writable_name).ToHandleChecked(); |
- DCHECK(writable->IsBoolean()); |
- *done = writable->IsFalse(); |
- if (!*done) return Nothing<bool>(); // Return value will be ignored. |
- return WriteToReadOnlyProperty(isolate, receiver, name, value, |
- should_throw); |
- } |
- |
- // We have an AccessorDescriptor. |
- Handle<String> set_name = |
- isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("set_")); |
- Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked(); |
- if (!setter->IsUndefined()) { |
- // TODO(rossberg): nicer would be to cast to some JSCallable here... |
- return SetPropertyWithDefinedSetter( |
- receiver, Handle<JSReceiver>::cast(setter), value, should_throw); |
+ // Enforce the invariant. |
+ PropertyDescriptor target_desc; |
+ bool owned = |
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, name, &target_desc); |
+ if (isolate->has_pending_exception()) return Nothing<bool>(); |
+ if (owned) { |
+ bool inconsistent = |
+ (PropertyDescriptor::IsDataDescriptor(&target_desc) && |
+ !target_desc.configurable() && !target_desc.writable() && |
+ !value->SameValue(*target_desc.value())) || |
+ (PropertyDescriptor::IsAccessorDescriptor(&target_desc) && |
+ !target_desc.configurable() && target_desc.set()->IsUndefined()); |
+ if (inconsistent) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyTrapViolatesInvariant, trap_name)); |
+ return Nothing<bool>(); |
+ } |
} |
- |
- RETURN_FAILURE( |
- isolate, should_throw, |
- NewTypeError(MessageTemplate::kNoSetterInCallback, name, proxy)); |
+ return Just(true); |
} |
@@ -5089,28 +5044,6 @@ MaybeHandle<Object> JSObject::DefinePropertyOrElementIgnoreAttributes( |
} |
-Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, |
- Handle<Object> value) { |
- DCHECK(it->GetReceiver()->IsJSObject()); |
- Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(it); |
- if (maybe.IsNothing()) return Nothing<bool>(); |
- |
- if (it->IsFound()) { |
- if (!it->IsConfigurable()) return Just(false); |
- } else { |
- if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) |
- return Just(false); |
- } |
- |
- RETURN_ON_EXCEPTION_VALUE( |
- it->isolate(), |
- DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD), |
- Nothing<bool>()); |
- |
- return Just(true); |
-} |
- |
- |
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor( |
LookupIterator* it) { |
Isolate* isolate = it->isolate(); |
@@ -6567,10 +6500,48 @@ bool JSReceiver::ValidateAndApplyPropertyDescriptor( |
// static |
Maybe<bool> JSReceiver::CreateDataProperty(LookupIterator* it, |
- Handle<Object> value) { |
- // TODO(rossberg): Support proxies. |
- if (!it->GetReceiver()->IsJSObject()) return Nothing<bool>(); |
- return JSObject::CreateDataProperty(it, value); |
+ Handle<Object> value, |
+ ShouldThrow should_throw) { |
+ DCHECK(!it->check_prototype_chain()); |
+ Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver()); |
+ Isolate* isolate = receiver->GetIsolate(); |
+ |
+ if (receiver->IsJSObject()) { |
+ return JSObject::CreateDataProperty(it, value); // Shortcut. |
+ } |
+ |
+ PropertyDescriptor new_desc; |
+ new_desc.set_value(value); |
+ new_desc.set_writable(true); |
+ new_desc.set_enumerable(true); |
+ new_desc.set_configurable(true); |
+ |
+ bool result = JSReceiver::DefineOwnProperty(isolate, receiver, it->GetName(), |
+ &new_desc, should_throw); |
+ if (isolate->has_pending_exception()) return Nothing<bool>(); |
+ return Just(result); |
+} |
+ |
+ |
+Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it, |
+ Handle<Object> value) { |
+ DCHECK(it->GetReceiver()->IsJSObject()); |
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(it); |
+ if (maybe.IsNothing()) return Nothing<bool>(); |
+ |
+ if (it->IsFound()) { |
+ if (!it->IsConfigurable()) return Just(false); |
+ } else { |
+ if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) |
+ return Just(false); |
+ } |
+ |
+ RETURN_ON_EXCEPTION_VALUE( |
+ it->isolate(), |
+ DefineOwnPropertyIgnoreAttributes(it, value, NONE, DONT_FORCE_FIELD), |
+ Nothing<bool>()); |
+ |
+ return Just(true); |
} |
@@ -7369,7 +7340,7 @@ Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) { |
MAYBE_RETURN(target_result, Nothing<bool>()); |
if (target_result.FromJust() != trap_result->BooleanValue()) { |
isolate->Throw(*factory->NewTypeError( |
- MessageTemplate::kProxyIsExtensibleViolatesInvariant)); |
+ MessageTemplate::kProxyTrapViolatesInvariant, trap_name)); |
return Nothing<bool>(); |
} |
return target_result; |