Commit 2ba464e1 authored by jkummerow's avatar jkummerow Committed by Commit bot

[proxies] [[HasProperty]]: fix trap call.

BUG=v8:1543
LOG=n

Review URL: https://codereview.chromium.org/1479143002

Cr-Commit-Position: refs/heads/master@{#32391}
parent f7226a79
...@@ -109,7 +109,6 @@ enum BindingFlags { ...@@ -109,7 +109,6 @@ enum BindingFlags {
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \ V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \ V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \
V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \ V(DERIVED_GET_TRAP_INDEX, JSFunction, derived_get_trap) \
V(DERIVED_HAS_TRAP_INDEX, JSFunction, derived_has_trap) \
V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \ V(DERIVED_SET_TRAP_INDEX, JSFunction, derived_set_trap) \
V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \ V(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \ V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
......
...@@ -130,10 +130,6 @@ function DerivedSetTrap(receiver, name, val) { ...@@ -130,10 +130,6 @@ function DerivedSetTrap(receiver, name, val) {
return true; return true;
} }
function DerivedHasTrap(name) {
return !!this.getPropertyDescriptor(name)
}
function DerivedHasOwnTrap(name) { function DerivedHasOwnTrap(name) {
return !!this.getOwnPropertyDescriptor(name) return !!this.getOwnPropertyDescriptor(name)
} }
...@@ -197,7 +193,6 @@ utils.Export(function(to) { ...@@ -197,7 +193,6 @@ utils.Export(function(to) {
%InstallToContext([ %InstallToContext([
"derived_get_trap", DerivedGetTrap, "derived_get_trap", DerivedGetTrap,
"derived_has_trap", DerivedHasTrap,
"derived_set_trap", DerivedSetTrap, "derived_set_trap", DerivedSetTrap,
"proxy_enumerate", ProxyEnumerate, "proxy_enumerate", ProxyEnumerate,
]); ]);
......
...@@ -654,8 +654,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) { ...@@ -654,8 +654,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
UNREACHABLE(); UNREACHABLE();
case LookupIterator::JSPROXY: case LookupIterator::JSPROXY:
// Call the "has" trap on proxies. // Call the "has" trap on proxies.
return JSProxy::HasPropertyWithHandler(it->GetHolder<JSProxy>(), return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
it->GetName()); it->GetName());
case LookupIterator::INTERCEPTOR: { case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result = Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it); JSObject::GetPropertyAttributesWithInterceptor(it);
...@@ -4523,21 +4523,69 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object, ...@@ -4523,21 +4523,69 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
} }
Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Name> name) { Handle<Name> name) {
Isolate* isolate = proxy->GetIsolate(); // 1. (Assert)
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
// TODO(rossberg): adjust once there is a story for symbols vs proxies. Handle<Object> handler(proxy->handler(), isolate);
if (name->IsSymbol()) return Just(false); // 3. If handler is null, throw a TypeError exception.
if (JSProxy::IsRevoked(proxy)) {
Handle<Object> args[] = { name }; isolate->Throw(*isolate->factory()->NewTypeError(
Handle<Object> result; MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
return Nothing<bool>();
}
// 4. Assert: Type(handler) is Object.
DCHECK(handler->IsJSReceiver());
DCHECK(proxy->target()->IsJSReceiver());
// 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
// 6. Let trap be ? GetMethod(handler, "has").
Handle<Object> trap;
ASSIGN_RETURN_ON_EXCEPTION_VALUE( ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(), isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
arraysize(args), args), isolate->factory()->has_string()),
Nothing<bool>()); Nothing<bool>());
// 7. If trap is undefined, then
return Just(result->BooleanValue()); if (trap->IsUndefined()) {
// 7a. Return target.[[HasProperty]](P).
return JSReceiver::HasProperty(target, name);
}
// 8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, «target, P»)).
Handle<Object> trap_result_obj;
Handle<Object> args[] = {target, name};
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, trap_result_obj,
Execution::Call(isolate, trap, handler, arraysize(args), args),
Nothing<bool>());
bool boolean_trap_result = trap_result_obj->BooleanValue();
// 9. If booleanTrapResult is false, then:
if (!boolean_trap_result) {
// 9a. Let targetDesc be ? target.[[GetOwnProperty]](P).
PropertyDescriptor target_desc;
bool target_found = JSReceiver::GetOwnPropertyDescriptor(
isolate, target, name, &target_desc);
// 9b. If targetDesc is not undefined, then:
if (target_found) {
// 9b i. If targetDesc.[[Configurable]] is false, throw a TypeError
// exception.
if (!target_desc.configurable()) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyTargetPropNotConfigurable, name));
return Nothing<bool>();
}
// 9b ii. Let extensibleTarget be ? IsExtensible(target).
Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
if (maybe_extensible.IsNothing()) return maybe_extensible;
bool extensible_target = maybe_extensible.FromJust();
// 9b iii. If extensibleTarget is false, throw a TypeError exception.
if (!extensible_target) {
isolate->Throw(*isolate->factory()->NewTypeError(
MessageTemplate::kProxyTargetNotExtensible));
}
}
}
// 10. Return booleanTrapResult.
return Just(boolean_trap_result);
} }
......
...@@ -9522,6 +9522,11 @@ class JSProxy: public JSReceiver { ...@@ -9522,6 +9522,11 @@ class JSProxy: public JSReceiver {
Handle<Object> key, PropertyDescriptor* desc, Handle<Object> key, PropertyDescriptor* desc,
ShouldThrow should_throw); ShouldThrow should_throw);
// ES6 9.5.7
MUST_USE_RESULT static Maybe<bool> HasProperty(Isolate* isolate,
Handle<JSProxy> proxy,
Handle<Name> name);
// ES6 9.5.10 (when passed SLOPPY) // ES6 9.5.10 (when passed SLOPPY)
MUST_USE_RESULT static Maybe<bool> DeletePropertyOrElement( MUST_USE_RESULT static Maybe<bool> DeletePropertyOrElement(
Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode); Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode);
...@@ -9588,9 +9593,6 @@ class JSProxy: public JSReceiver { ...@@ -9588,9 +9593,6 @@ class JSProxy: public JSReceiver {
Handle<JSProxy> proxy, const char* name, Handle<Object> derived_trap, Handle<JSProxy> proxy, const char* name, Handle<Object> derived_trap,
int argc, Handle<Object> args[]); int argc, Handle<Object> args[]);
MUST_USE_RESULT static Maybe<bool> HasPropertyWithHandler(
Handle<JSProxy> proxy, Handle<Name> name);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy); DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
}; };
......
...@@ -17,6 +17,11 @@ var handler = { ...@@ -17,6 +17,11 @@ var handler = {
yield "bar"; yield "bar";
} }
return keys(); return keys();
},
// For-in calls "has" on every iteration, so for TestForIn() below to
// detect all results of the "enumerate" trap, "has" must return true.
has: function(target, name) {
return true;
} }
} }
...@@ -37,8 +42,7 @@ var receiver = { ...@@ -37,8 +42,7 @@ var receiver = {
"receiver_one": 1 "receiver_one": 1
}; };
receiver.__proto__ = proxy; receiver.__proto__ = proxy;
// TODO(jkummerow): Needs proper 'has' trap; implement that and enable this! TestForIn(receiver, ["receiver_one", "foo", "bar"]);
// TestForIn(receiver, ["receiver_one", "foo", "bar"]);
// Fall through to default behavior when trap is undefined. // Fall through to default behavior when trap is undefined.
handler.enumerate = undefined; handler.enumerate = undefined;
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --harmony-proxies
var target = {
"target_one": 1
};
target.__proto__ = {
"target_two": 2
};
var handler = {
has: function(target, name) {
return name == "present";
}
}
var proxy = new Proxy(target, handler);
// Test simple cases.
assertTrue("present" in proxy);
assertFalse("nonpresent" in proxy);
// Test interesting algorithm steps:
// Step 7: Fall through to target if trap is undefined.
handler.has = undefined;
assertTrue("target_one" in proxy);
assertTrue("target_two" in proxy);
assertFalse("in_your_dreams" in proxy);
// Step 8: Result is converted to boolean.
var result = 1;
handler.has = function(t, n) { return result; }
assertTrue("foo" in proxy);
result = {};
assertTrue("foo" in proxy);
result = undefined;
assertFalse("foo" in proxy);
result = "string";
assertTrue("foo" in proxy);
// Step 9b i. Trap result must confirm presence of non-configurable properties
// of the target.
Object.defineProperty(target, "nonconf", {value: 1, configurable: false});
result = false;
assertThrows("'nonconf' in proxy", TypeError);
// Step 9b iii. Trap result must confirm presence of all own properties of
// non-extensible targets.
Object.freeze(target);
assertThrows("'nonconf' in proxy", TypeError);
assertThrows("'target_one' in proxy", TypeError);
assertFalse("target_two" in proxy);
assertFalse("in_your_dreams" in proxy);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment