Skip to content

Commit 62127d0

Browse files
GeorgNeisCommit bot
authored andcommitted
[proxies] Implement Proxy.revocable.
For now, we revoke a proxy by setting its handler to null (as in the spec). Change the "target" field from Object to JSReceiver as there's no point in allowing more. R=jkummerow@chromium.org, rossberg BUG=v8:1543 LOG=n Review URL: https://codereview.chromium.org/1496243003 Cr-Commit-Position: refs/heads/master@{#32608}
1 parent 6f4d477 commit 62127d0

7 files changed

Lines changed: 90 additions & 64 deletions

File tree

src/js/proxy.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ function ProxyCreateFunction(handler, callTrap, constructTrap) {
4242
{}, handler, callTrap, constructTrap, GlobalFunction.prototype)
4343
}
4444

45+
function ProxyCreateRevocable(target, handler) {
46+
var p = new GlobalProxy(target, handler);
47+
return {proxy: p, revoke: () => %RevokeProxy(p)};
48+
}
49+
4550
// -------------------------------------------------------------------
4651
// Proxy Builtins
4752

@@ -144,6 +149,7 @@ function ProxyEnumerate(trap, handler, target) {
144149

145150
//Set up non-enumerable properties of the Proxy object.
146151
utils.InstallFunctions(GlobalProxy, DONT_ENUM, [
152+
"revocable", ProxyCreateRevocable,
147153
"createFunction", ProxyCreateFunction
148154
]);
149155

src/objects-inl.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6336,10 +6336,12 @@ int JSFunction::NumberOfLiterals() {
63366336
}
63376337

63386338

6339-
ACCESSORS(JSProxy, target, Object, kTargetOffset)
63406339
ACCESSORS(JSProxy, handler, Object, kHandlerOffset)
6340+
ACCESSORS(JSProxy, target, JSReceiver, kTargetOffset)
63416341
ACCESSORS(JSProxy, hash, Object, kHashOffset)
63426342

6343+
bool JSProxy::IsRevoked() const { return !handler()->IsJSReceiver(); }
6344+
63436345
ACCESSORS(JSFunctionProxy, call_trap, JSReceiver, kCallTrapOffset)
63446346
ACCESSORS(JSFunctionProxy, construct_trap, Object, kConstructTrapOffset)
63456347

src/objects.cc

Lines changed: 40 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -758,16 +758,14 @@ MaybeHandle<Object> JSProxy::GetProperty(Isolate* isolate,
758758
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
759759
Handle<Object> handler(proxy->handler(), isolate);
760760
// 3. If handler is null, throw a TypeError exception.
761+
// 4. Assert: Type(handler) is Object.
761762
if (proxy->IsRevoked()) {
762763
THROW_NEW_ERROR(isolate,
763764
NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
764765
Object);
765766
}
766-
// 4. Assert: Type(handler) is Object.
767-
DCHECK(handler->IsJSReceiver());
768-
DCHECK(proxy->target()->IsJSReceiver());
769767
// 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
770-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
768+
Handle<JSReceiver> target(proxy->target(), isolate);
771769
// 6. Let trap be ? GetMethod(handler, "get").
772770
Handle<Object> trap;
773771
ASSIGN_RETURN_ON_EXCEPTION(
@@ -957,22 +955,22 @@ Handle<FixedArray> JSObject::EnsureWritableFastElements(
957955
// static
958956
MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
959957
Isolate* isolate = proxy->GetIsolate();
958+
Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
959+
960960
// 1. Let handler be the value of the [[ProxyHandler]] internal slot.
961-
Handle<Object> raw_handler(proxy->handler(), isolate);
962961
// 2. If handler is null, throw a TypeError exception.
963962
// 3. Assert: Type(handler) is Object.
964-
if (!raw_handler->IsJSReceiver()) {
965-
// TODO(cbruni): Throw correct error message.
966-
THROW_NEW_ERROR(
967-
isolate, NewTypeError(MessageTemplate::kProxyHandlerNonObject), Object);
968-
}
969-
Handle<JSReceiver> handler = Handle<JSReceiver>::cast(raw_handler);
970963
// 4. Let target be the value of the [[ProxyTarget]] internal slot.
971-
// TODO(cbruni): Change target type to JSReceiver by default.
972-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
964+
if (proxy->IsRevoked()) {
965+
THROW_NEW_ERROR(isolate,
966+
NewTypeError(MessageTemplate::kProxyRevoked, trap_name),
967+
Object);
968+
}
969+
Handle<JSReceiver> target(proxy->target(), isolate);
970+
Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
971+
973972
// 5. Let trap be ? GetMethod(handler, "getPrototypeOf").
974973
Handle<Object> trap;
975-
Handle<String> trap_name = isolate->factory()->getPrototypeOf_string();
976974
ASSIGN_RETURN_ON_EXCEPTION(isolate, trap, GetMethod(handler, trap_name),
977975
Object);
978976
// 6. If trap is undefined, then return target.[[GetPrototypeOf]]().
@@ -1013,15 +1011,6 @@ MaybeHandle<Object> JSProxy::GetPrototype(Handle<JSProxy> proxy) {
10131011
}
10141012

10151013

1016-
bool JSProxy::IsRevoked() const {
1017-
// TODO(neis): Decide on how to represent revocation. For now, revocation is
1018-
// unsupported.
1019-
DCHECK(target()->IsJSReceiver());
1020-
DCHECK(handler()->IsJSReceiver());
1021-
return false;
1022-
}
1023-
1024-
10251014
MaybeHandle<Object> Object::GetPropertyWithAccessor(
10261015
LookupIterator* it, LanguageMode language_mode) {
10271016
Isolate* isolate = it->isolate();
@@ -4620,22 +4609,27 @@ Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
46204609
}
46214610

46224611

4612+
void JSProxy::Revoke(Handle<JSProxy> proxy) {
4613+
Isolate* isolate = proxy->GetIsolate();
4614+
if (!proxy->IsRevoked()) proxy->set_handler(isolate->heap()->null_value());
4615+
DCHECK(proxy->IsRevoked());
4616+
}
4617+
4618+
46234619
Maybe<bool> JSProxy::HasProperty(Isolate* isolate, Handle<JSProxy> proxy,
46244620
Handle<Name> name) {
46254621
// 1. (Assert)
46264622
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
46274623
Handle<Object> handler(proxy->handler(), isolate);
46284624
// 3. If handler is null, throw a TypeError exception.
4625+
// 4. Assert: Type(handler) is Object.
46294626
if (proxy->IsRevoked()) {
46304627
isolate->Throw(*isolate->factory()->NewTypeError(
46314628
MessageTemplate::kProxyRevoked, isolate->factory()->has_string()));
46324629
return Nothing<bool>();
46334630
}
4634-
// 4. Assert: Type(handler) is Object.
4635-
DCHECK(handler->IsJSReceiver());
4636-
DCHECK(proxy->target()->IsJSReceiver());
46374631
// 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
4638-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
4632+
Handle<JSReceiver> target(proxy->target(), isolate);
46394633
// 6. Let trap be ? GetMethod(handler, "has").
46404634
Handle<Object> trap;
46414635
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -4700,8 +4694,7 @@ Maybe<bool> JSProxy::SetProperty(Handle<JSProxy> proxy, Handle<Name> name,
47004694
*factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
47014695
return Nothing<bool>();
47024696
}
4703-
4704-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
4697+
Handle<JSReceiver> target(proxy->target(), isolate);
47054698
Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
47064699

47074700
Handle<Object> trap;
@@ -4762,8 +4755,7 @@ Maybe<bool> JSProxy::DeletePropertyOrElement(Handle<JSProxy> proxy,
47624755
*factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
47634756
return Nothing<bool>();
47644757
}
4765-
4766-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
4758+
Handle<JSReceiver> target(proxy->target(), isolate);
47674759
Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
47684760

47694761
Handle<Object> trap;
@@ -6835,17 +6827,14 @@ bool JSProxy::DefineOwnProperty(Isolate* isolate, Handle<JSProxy> proxy,
68356827
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
68366828
Handle<Object> handler(proxy->handler(), isolate);
68376829
// 3. If handler is null, throw a TypeError exception.
6830+
// 4. Assert: Type(handler) is Object.
68386831
if (proxy->IsRevoked()) {
68396832
isolate->Throw(*isolate->factory()->NewTypeError(
68406833
MessageTemplate::kProxyRevoked, trap_name));
68416834
return false;
68426835
}
6843-
// 4. Assert: Type(handler) is Object.
6844-
DCHECK(handler->IsJSReceiver());
6845-
// If the handler is not null, the target can't be null either.
6846-
DCHECK(proxy->target()->IsJSReceiver());
68476836
// 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
6848-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
6837+
Handle<JSReceiver> target(proxy->target(), isolate);
68496838
// 6. Let trap be ? GetMethod(handler, "defineProperty").
68506839
Handle<Object> trap;
68516840
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -7019,17 +7008,14 @@ bool JSProxy::GetOwnPropertyDescriptor(Isolate* isolate, Handle<JSProxy> proxy,
70197008
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
70207009
Handle<Object> handler(proxy->handler(), isolate);
70217010
// 3. If handler is null, throw a TypeError exception.
7011+
// 4. Assert: Type(handler) is Object.
70227012
if (proxy->IsRevoked()) {
70237013
isolate->Throw(*isolate->factory()->NewTypeError(
70247014
MessageTemplate::kProxyRevoked, trap_name));
70257015
return false;
70267016
}
7027-
// 4. Assert: Type(handler) is Object.
7028-
DCHECK(handler->IsJSReceiver());
7029-
// If the handler is not null, the target can't be null either.
7030-
DCHECK(proxy->target()->IsJSReceiver());
70317017
// 5. Let target be the value of the [[ProxyTarget]] internal slot of O.
7032-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7018+
Handle<JSReceiver> target(proxy->target(), isolate);
70337019
// 6. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
70347020
Handle<Object> trap;
70357021
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -7277,8 +7263,7 @@ Maybe<bool> JSProxy::PreventExtensions(Handle<JSProxy> proxy,
72777263
*factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
72787264
return Nothing<bool>();
72797265
}
7280-
7281-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7266+
Handle<JSReceiver> target(proxy->target(), isolate);
72827267
Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
72837268

72847269
Handle<Object> trap;
@@ -7387,8 +7372,7 @@ Maybe<bool> JSProxy::IsExtensible(Handle<JSProxy> proxy) {
73877372
*factory->NewTypeError(MessageTemplate::kProxyRevoked, trap_name));
73887373
return Nothing<bool>();
73897374
}
7390-
7391-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
7375+
Handle<JSReceiver> target(proxy->target(), isolate);
73927376
Handle<JSReceiver> handler(JSReceiver::cast(proxy->handler()), isolate);
73937377

73947378
Handle<Object> trap;
@@ -8296,16 +8280,15 @@ bool JSProxy::Enumerate(Isolate* isolate, Handle<JSReceiver> receiver,
82968280
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
82978281
Handle<Object> handler(proxy->handler(), isolate);
82988282
// 2. If handler is null, throw a TypeError exception.
8283+
// 3. Assert: Type(handler) is Object.
82998284
if (proxy->IsRevoked()) {
83008285
isolate->Throw(*isolate->factory()->NewTypeError(
83018286
MessageTemplate::kProxyRevoked,
83028287
isolate->factory()->enumerate_string()));
83038288
return false;
83048289
}
8305-
// 3. Assert: Type(handler) is Object.
8306-
DCHECK(handler->IsJSReceiver());
83078290
// 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
8308-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8291+
Handle<JSReceiver> target(proxy->target(), isolate);
83098292
// 5. Let trap be ? GetMethod(handler, "enumerate").
83108293
Handle<Object> trap;
83118294
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -8402,15 +8385,14 @@ bool JSProxy::OwnPropertyKeys(Isolate* isolate, Handle<JSReceiver> receiver,
84028385
// 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
84038386
Handle<Object> handler(proxy->handler(), isolate);
84048387
// 2. If handler is null, throw a TypeError exception.
8388+
// 3. Assert: Type(handler) is Object.
84058389
if (proxy->IsRevoked()) {
84068390
isolate->Throw(*isolate->factory()->NewTypeError(
84078391
MessageTemplate::kProxyRevoked, isolate->factory()->ownKeys_string()));
84088392
return false;
84098393
}
8410-
// 3. Assert: Type(handler) is Object.
8411-
DCHECK(handler->IsJSReceiver());
84128394
// 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
8413-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
8395+
Handle<JSReceiver> target(proxy->target(), isolate);
84148396
// 5. Let trap be ? GetMethod(handler, "ownKeys").
84158397
Handle<Object> trap;
84168398
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
@@ -14891,28 +14873,26 @@ Maybe<bool> JSProxy::SetPrototype(Handle<JSProxy> proxy, Handle<Object> value,
1489114873
bool from_javascript,
1489214874
ShouldThrow should_throw) {
1489314875
Isolate* isolate = proxy->GetIsolate();
14894-
Handle<JSReceiver> handle;
1489514876
Handle<Name> trap_name = isolate->factory()->setPrototypeOf_string();
1489614877
// 1. Assert: Either Type(V) is Object or Type(V) is Null.
1489714878
DCHECK(value->IsJSReceiver() || value->IsNull());
1489814879
// 2. Let handler be the value of the [[ProxyHandler]] internal slot of O.
14899-
Handle<Object> raw_handler(proxy->handler(), isolate);
14880+
Handle<Object> handler(proxy->handler(), isolate);
1490014881
// 3. If handler is null, throw a TypeError exception.
1490114882
// 4. Assert: Type(handler) is Object.
1490214883
if (proxy->IsRevoked()) {
14903-
DCHECK(raw_handler->IsNull());
14904-
DCHECK(proxy->target()->IsNull());
14905-
isolate->Throw(
14906-
*isolate->factory()->NewTypeError(MessageTemplate::kProxyRevoked));
14884+
isolate->Throw(*isolate->factory()->NewTypeError(
14885+
MessageTemplate::kProxyRevoked, trap_name));
1490714886
return Nothing<bool>();
1490814887
}
14909-
Handle<JSReceiver> handler = Handle<JSReceiver>::cast(raw_handler);
1491014888
// 5. Let target be the value of the [[ProxyTarget]] internal slot.
14911-
Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate);
14889+
Handle<JSReceiver> target(proxy->target(), isolate);
1491214890
// 6. Let trap be ? GetMethod(handler, "getPrototypeOf").
1491314891
Handle<Object> trap;
1491414892
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
14915-
isolate, trap, Object::GetMethod(handler, trap_name), Nothing<bool>());
14893+
isolate, trap,
14894+
Object::GetMethod(Handle<JSReceiver>::cast(handler), trap_name),
14895+
Nothing<bool>());
1491614896
// 7. If trap is undefined, then return target.[[SetPrototypeOf]]().
1491714897
if (trap->IsUndefined()) {
1491814898
return JSReceiver::SetPrototype(target, value, from_javascript,

src/objects.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9500,15 +9500,16 @@ class JSProxy: public JSReceiver {
95009500
// [handler]: The handler property.
95019501
DECL_ACCESSORS(handler, Object)
95029502
// [target]: The target property.
9503-
DECL_ACCESSORS(target, Object)
9503+
DECL_ACCESSORS(target, JSReceiver)
95049504
// [hash]: The hash code property (undefined if not initialized yet).
95059505
DECL_ACCESSORS(hash, Object)
95069506

95079507
static MaybeHandle<Context> GetFunctionRealm(Handle<JSProxy> proxy);
95089508

95099509
DECLARE_CAST(JSProxy)
95109510

9511-
bool IsRevoked() const;
9511+
INLINE(bool IsRevoked() const);
9512+
static void Revoke(Handle<JSProxy> proxy);
95129513

95139514
// ES6 9.5.1
95149515
static MaybeHandle<Object> GetPrototype(Handle<JSProxy> receiver);

src/runtime/runtime-proxy.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,15 @@ RUNTIME_FUNCTION(Runtime_GetConstructTrap) {
6565
return proxy->construct_trap();
6666
}
6767

68+
69+
RUNTIME_FUNCTION(Runtime_RevokeProxy) {
70+
HandleScope scope(isolate);
71+
DCHECK(args.length() == 1);
72+
CONVERT_ARG_HANDLE_CHECKED(JSProxy, proxy, 0);
73+
JSProxy::Revoke(proxy);
74+
return isolate->heap()->undefined_value();
75+
}
76+
77+
6878
} // namespace internal
6979
} // namespace v8

src/runtime/runtime.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,8 @@ namespace internal {
547547
F(IsJSFunctionProxy, 1, 1) \
548548
F(GetHandler, 1, 1) \
549549
F(GetCallTrap, 1, 1) \
550-
F(GetConstructTrap, 1, 1)
550+
F(GetConstructTrap, 1, 1) \
551+
F(RevokeProxy, 1, 1)
551552

552553

553554
#define FOR_EACH_INTRINSIC_REGEXP(F) \
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2015 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// Flags: --harmony-proxies --harmony-reflect
6+
7+
8+
traps = [
9+
"getPrototypeOf", "setPrototypeOf", "isExtensible", "preventExtensions",
10+
"getOwnPropertyDescriptor", "has", "get", "set", "deleteProperty",
11+
"defineProperty", "ownKeys", "apply", "construct"
12+
];
13+
// TODO(neis): Fix enumerate.
14+
15+
var {proxy, revoke} = Proxy.revocable({}, {});
16+
assertEquals(0, revoke.length);
17+
18+
assertEquals(undefined, revoke());
19+
for (var trap of traps) {
20+
assertThrows(() => Reflect[trap](proxy), TypeError);
21+
}
22+
23+
assertEquals(undefined, revoke());
24+
for (var trap of traps) {
25+
assertThrows(() => Reflect[trap](proxy), TypeError);
26+
}

0 commit comments

Comments
 (0)