Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index 9f639c52dc68f88dfc1d296857cf4ae49e018ecb..fea27b7462bdd3137faace208837ea5a297639e3 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -4664,75 +4664,14 @@ MaybeHandle<Object> JSProxy::DeletePropertyWithHandler( |
} |
-Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler( |
- Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name) { |
- Isolate* isolate = proxy->GetIsolate(); |
+Maybe<PropertyAttributes> JSProxy::GetPropertyAttributes(LookupIterator* it) { |
+ Isolate* isolate = it->isolate(); |
HandleScope scope(isolate); |
- |
- // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
- if (name->IsSymbol()) return Just(ABSENT); |
- |
- Handle<Object> args[] = { name }; |
- Handle<Object> result; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, result, proxy->CallTrap(proxy, "getPropertyDescriptor", |
- Handle<Object>(), arraysize(args), args), |
- Nothing<PropertyAttributes>()); |
- |
- if (result->IsUndefined()) return Just(ABSENT); |
- |
- Handle<Object> argv[] = { result }; |
- Handle<Object> desc; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
- isolate, desc, |
- Execution::Call(isolate, isolate->to_complete_property_descriptor(), |
- result, arraysize(argv), argv), |
- Nothing<PropertyAttributes>()); |
- |
- // Convert result to PropertyAttributes. |
- Handle<String> enum_n = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("enumerable_")); |
- Handle<Object> enumerable; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable, |
- Object::GetProperty(desc, enum_n), |
- Nothing<PropertyAttributes>()); |
- Handle<String> conf_n = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("configurable_")); |
- Handle<Object> configurable; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable, |
- Object::GetProperty(desc, conf_n), |
- Nothing<PropertyAttributes>()); |
- Handle<String> writ_n = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("writable_")); |
- Handle<Object> writable; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable, |
- Object::GetProperty(desc, writ_n), |
- Nothing<PropertyAttributes>()); |
- if (!writable->BooleanValue()) { |
- Handle<String> set_n = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("set_")); |
- Handle<Object> setter; |
- ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter, |
- Object::GetProperty(desc, set_n), |
- Nothing<PropertyAttributes>()); |
- writable = isolate->factory()->ToBoolean(!setter->IsUndefined()); |
- } |
- |
- if (configurable->IsFalse()) { |
- Handle<Object> handler(proxy->handler(), isolate); |
- Handle<String> trap = isolate->factory()->InternalizeOneByteString( |
- STATIC_CHAR_VECTOR("getPropertyDescriptor")); |
- Handle<Object> error = isolate->factory()->NewTypeError( |
- MessageTemplate::kProxyPropNotConfigurable, handler, name, trap); |
- isolate->Throw(*error); |
- return Nothing<PropertyAttributes>(); |
- } |
- |
- int attributes = NONE; |
- if (!enumerable->BooleanValue()) attributes |= DONT_ENUM; |
- if (!configurable->BooleanValue()) attributes |= DONT_DELETE; |
- if (!writable->BooleanValue()) attributes |= READ_ONLY; |
- return Just(static_cast<PropertyAttributes>(attributes)); |
+ PropertyDescriptor desc; |
+ bool found = JSProxy::GetOwnPropertyDescriptor(it, &desc); |
+ if (isolate->has_pending_exception()) return Nothing<PropertyAttributes>(); |
+ if (!found) return Just(ABSENT); |
+ return Just(desc.ToAttributes()); |
} |
@@ -5115,8 +5054,7 @@ Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes( |
case LookupIterator::TRANSITION: |
UNREACHABLE(); |
case LookupIterator::JSPROXY: |
- return JSProxy::GetPropertyAttributesWithHandler( |
- it->GetHolder<JSProxy>(), it->GetReceiver(), it->GetName()); |
+ return JSProxy::GetPropertyAttributes(it); |
case LookupIterator::INTERCEPTOR: { |
Maybe<PropertyAttributes> result = |
JSObject::GetPropertyAttributesWithInterceptor(it); |
@@ -6014,8 +5952,7 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, |
Handle<Object> key, |
Handle<Object> attributes) { |
// 1. If Type(O) is not Object, throw a TypeError exception. |
- // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject". |
- if (!object->IsJSObject()) { |
+ if (!object->IsSpecObject()) { |
Handle<String> fun_name = |
isolate->factory()->InternalizeUtf8String("Object.defineProperty"); |
THROW_NEW_ERROR_RETURN_FAILURE( |
@@ -6031,8 +5968,8 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, |
return isolate->heap()->exception(); |
} |
// 6. Let success be DefinePropertyOrThrow(O,key, desc). |
- bool success = DefineOwnProperty(isolate, Handle<JSObject>::cast(object), key, |
- &desc, THROW_ON_ERROR); |
+ bool success = DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), |
+ key, &desc, THROW_ON_ERROR); |
// 7. ReturnIfAbrupt(success). |
if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
CHECK(success == true); |
@@ -6046,8 +5983,7 @@ Object* JSReceiver::DefineProperty(Isolate* isolate, Handle<Object> object, |
Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object, |
Handle<Object> properties) { |
// 1. If Type(O) is not Object, throw a TypeError exception. |
- // TODO(jkummerow): Implement Proxy support, change to "IsSpecObject". |
- if (!object->IsJSObject()) { |
+ if (!object->IsSpecObject()) { |
Handle<String> fun_name = |
isolate->factory()->InternalizeUtf8String("Object.defineProperties"); |
THROW_NEW_ERROR_RETURN_FAILURE( |
@@ -6078,10 +6014,7 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object, |
LookupIterator it = LookupIterator::PropertyOrElement( |
isolate, props, next_key, &success, LookupIterator::HIDDEN); |
DCHECK(success); |
- // TODO(jkummerow): Support JSProxies. Make sure we call the correct |
- // getOwnPropertyDescriptor trap, and convert the result object to a |
- // PropertyDescriptor. |
- Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it); |
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it); |
if (!maybe.IsJust()) return isolate->heap()->exception(); |
PropertyAttributes attrs = maybe.FromJust(); |
// 7c. If propDesc is not undefined and propDesc.[[Enumerable]] is true: |
@@ -6092,7 +6025,7 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object, |
// 7c ii. ReturnIfAbrupt(descObj). |
Handle<Object> desc_obj; |
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, desc_obj, |
- JSObject::GetProperty(&it)); |
+ Object::GetProperty(&it)); |
// 7c iii. Let desc be ToPropertyDescriptor(descObj). |
success = PropertyDescriptor::ToPropertyDescriptor(isolate, desc_obj, |
&descriptors[i]); |
@@ -6108,7 +6041,7 @@ Object* JSReceiver::DefineProperties(Isolate* isolate, Handle<Object> object, |
// 8a. Let P be the first element of pair. |
// 8b. Let desc be the second element of pair. |
// 8c. Let status be DefinePropertyOrThrow(O, P, desc). |
- bool status = DefineOwnProperty(isolate, Handle<JSObject>::cast(object), |
+ bool status = DefineOwnProperty(isolate, Handle<JSReceiver>::cast(object), |
desc->name(), desc, THROW_ON_ERROR); |
// 8d. ReturnIfAbrupt(status). |
if (isolate->has_pending_exception()) return isolate->heap()->exception(); |
@@ -6127,9 +6060,11 @@ bool JSReceiver::DefineOwnProperty(Isolate* isolate, Handle<JSReceiver> object, |
return JSArray::DefineOwnProperty(isolate, Handle<JSArray>::cast(object), |
key, desc, should_throw); |
} |
+ if (object->IsJSProxy()) { |
+ return JSProxy::DefineOwnProperty(isolate, Handle<JSProxy>::cast(object), |
+ key, desc, should_throw); |
+ } |
// TODO(jkummerow): Support Modules (ES6 9.4.6.6) |
- // TODO(jkummerow): Support Proxies (ES6 9.5.6) |
- if (!object->IsJSObject()) return true; |
// OrdinaryDefineOwnProperty, by virtue of calling |
// DefineOwnPropertyIgnoreAttributes, can handle arguments (ES6 9.4.4.2) |
@@ -6710,6 +6645,117 @@ bool JSArray::ArraySetLength(Isolate* isolate, Handle<JSArray> a, |
} |
+// ES6 9.5.6 |
+// static |
+bool JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> object, |
+ Handle<Object> key, PropertyDescriptor* desc, |
+ ShouldThrow should_throw) { |
+ // 1. Assert: IsPropertyKey(P) is true. |
+ DCHECK(key->IsName() || key->IsNumber()); |
+ // 2. Let handler be the value of the [[ProxyHandler]] internal slot of O. |
+ Handle<Object> handler(object->handler(), isolate); |
+ // 3. If handler is null, throw a TypeError exception. |
+ // TODO(jkummerow): Use "IsRevoked()" instead once we have it. |
+ if (handler->IsNull()) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyHandlerNonObject)); |
+ return false; |
+ } |
+ // 4. Assert: Type(handler) is Object. |
+ DCHECK(handler->IsJSReceiver()); |
+ // If the handler is not null, the target can't be null either. |
+ DCHECK(object->target()->IsSpecObject()); |
+ // 5. Let target be the value of the [[ProxyTarget]] internal slot of O. |
+ Handle<JSReceiver> target(JSReceiver::cast(object->target()), isolate); |
+ // 6. Let trap be ? GetMethod(handler, "defineProperty"). |
+ Handle<Object> trap; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, trap, |
+ Object::GetMethod(Handle<JSReceiver>::cast(handler), |
+ isolate->factory()->defineProperty_string()), |
+ false); |
+ // 7. If trap is undefined, then: |
+ if (trap->IsUndefined()) { |
+ // 7a. Return target.[[DefineOwnProperty]](P, Desc). |
+ return JSReceiver::DefineOwnProperty(isolate, target, key, desc, |
+ should_throw); |
+ } |
+ // 8. Let descObj be FromPropertyDescriptor(Desc). |
+ Handle<Object> desc_obj = desc->ToObject(isolate); |
+ // 9. Let booleanTrapResult be |
+ // ToBoolean(? Call(trap, handler, «target, P, descObj»)). |
+ Handle<Name> property_name = |
+ key->IsName() |
+ ? Handle<Name>::cast(key) |
+ : Handle<Name>::cast(isolate->factory()->NumberToString(key)); |
+ Handle<Object> trap_result_obj; |
+ Handle<Object> args[] = {target, property_name, desc_obj}; |
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
+ isolate, trap_result_obj, |
+ Execution::Call(isolate, trap, handler, arraysize(args), args), false); |
+ // 10. If booleanTrapResult is false, return false. |
+ if (!trap_result_obj->BooleanValue()) { |
+ if (should_throw == THROW_ON_ERROR) { |
+ // TODO(jkummerow): Better error message? |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyHandlerReturned, handler, trap_result_obj, |
+ key)); |
+ } |
+ return false; |
+ } |
+ // 11. Let targetDesc be ? target.[[GetOwnProperty]](P). |
+ PropertyDescriptor target_desc; |
+ bool target_found = |
+ JSReceiver::GetOwnPropertyDescriptor(isolate, target, key, &target_desc); |
+ if (isolate->has_pending_exception()) return false; |
+ // 12. Let extensibleTarget be ? IsExtensible(target). |
+ Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target); |
+ if (maybe_extensible.IsNothing()) return false; |
+ bool extensible_target = maybe_extensible.FromJust(); |
+ // 13. If Desc has a [[Configurable]] field and if Desc.[[Configurable]] |
+ // is false, then: |
+ // 13a. Let settingConfigFalse be true. |
+ // 14. Else let settingConfigFalse be false. |
+ bool setting_config_false = desc->has_configurable() && !desc->configurable(); |
+ // 15. If targetDesc is undefined, then |
+ if (!target_found) { |
+ // 15a. If extensibleTarget is false, throw a TypeError exception. |
+ if (!extensible_target) { |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kProxyTargetNotExtensible)); |
+ return false; |
+ } |
+ // 15b. If settingConfigFalse is true, throw a TypeError exception. |
+ if (setting_config_false) { |
+ // TODO(jkummerow): Better error message? |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kRedefineDisallowed, key)); |
+ return false; |
+ } |
+ } else { |
+ // 16. Else targetDesc is not undefined, |
+ // 16a. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, |
+ // targetDesc) is false, throw a TypeError exception. |
+ bool valid = IsCompatiblePropertyDescriptor( |
+ isolate, extensible_target, desc, &target_desc, property_name); |
+ if (!valid) { |
+ DCHECK(isolate->has_pending_exception()); |
+ return false; |
+ } |
+ // 16b. If settingConfigFalse is true and targetDesc.[[Configurable]] is |
+ // true, throw a TypeError exception. |
+ if (setting_config_false && target_desc.configurable()) { |
+ // TODO(jkummerow): Better error message? |
+ isolate->Throw(*isolate->factory()->NewTypeError( |
+ MessageTemplate::kRedefineDisallowed, key)); |
+ return false; |
+ } |
+ } |
+ // 17. Return true. |
+ return true; |
+} |
+ |
+ |
// static |
bool JSReceiver::GetOwnPropertyDescriptor(Isolate* isolate, |
Handle<JSReceiver> object, |