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 {
V(ARRAY_VALUES_ITERATOR_INDEX, JSFunction, array_values_iterator) \
V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \
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(ERROR_FUNCTION_INDEX, JSFunction, error_function) \
V(EVAL_ERROR_FUNCTION_INDEX, JSFunction, eval_error_function) \
......
......@@ -130,10 +130,6 @@ function DerivedSetTrap(receiver, name, val) {
return true;
}
function DerivedHasTrap(name) {
return !!this.getPropertyDescriptor(name)
}
function DerivedHasOwnTrap(name) {
return !!this.getOwnPropertyDescriptor(name)
}
......@@ -197,7 +193,6 @@ utils.Export(function(to) {
%InstallToContext([
"derived_get_trap", DerivedGetTrap,
"derived_has_trap", DerivedHasTrap,
"derived_set_trap", DerivedSetTrap,
"proxy_enumerate", ProxyEnumerate,
]);
......
......@@ -654,8 +654,8 @@ Maybe<bool> JSReceiver::HasProperty(LookupIterator* it) {
UNREACHABLE();
case LookupIterator::JSPROXY:
// Call the "has" trap on proxies.
return JSProxy::HasPropertyWithHandler(it->GetHolder<JSProxy>(),
it->GetName());
return JSProxy::HasProperty(it->isolate(), it->GetHolder<JSProxy>(),
it->GetName());
case LookupIterator::INTERCEPTOR: {
Maybe<PropertyAttributes> result =
JSObject::GetPropertyAttributesWithInterceptor(it);
......@@ -4523,21 +4523,69 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
}
Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
Handle<Name> name) {
Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (name->IsSymbol()) return Just(false);
Handle<Object> args[] = { name };
Handle<Object> result;
Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
Handle<Name> name) {
// 1. (Assert)
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
Handle<Object> handler(proxy->handler(), isolate);
// 3. If handler is null, throw a TypeError exception.
if (JSProxy::IsRevoked(proxy)) {
isolate->Throw(*isolate->factory()->NewTypeError(
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(
isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
arraysize(args), args),
isolate, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
isolate->factory()->has_string()),
Nothing<bool>());
return Just(result->BooleanValue());
// 7. If trap is undefined, then
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 {
Handle<Object> key, PropertyDescriptor* desc,
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)
MUST_USE_RESULT static Maybe<bool> DeletePropertyOrElement(
Handle<JSProxy> proxy, Handle<Name> name, LanguageMode language_mode);
......@@ -9588,9 +9593,6 @@ class JSProxy: public JSReceiver {
Handle<JSProxy> proxy, const char* name, Handle<Object> derived_trap,
int argc, Handle<Object> args[]);
MUST_USE_RESULT static Maybe<bool> HasPropertyWithHandler(
Handle<JSProxy> proxy, Handle<Name> name);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSProxy);
};
......
......@@ -17,6 +17,11 @@ var handler = {
yield "bar";
}
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 = {
"receiver_one": 1
};
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.
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