Skip to content

Commit 5d916fb

Browse files
authored
Correctly handle the Proxy IsCallable and IsConstructor information (#4264)
The `IsCallable(target)` and `IsConstructor(target)` info can't be stored in the target/handler values. If the input for the ProxyCreate was a revocable Proxy the original target's callable/constructor information must be retained even after the Proxy was revoked. JerryScript-DCO-1.0-Signed-off-by: Peter Gal [email protected]
1 parent 7262b98 commit 5d916fb

File tree

6 files changed

+99
-8
lines changed

6 files changed

+99
-8
lines changed

jerry-core/ecma/base/ecma-gc.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,11 @@ ecma_gc_mark (ecma_object_t *object_p) /**< object to mark from */
786786
case ECMA_OBJECT_TYPE_PROXY:
787787
{
788788
ecma_gc_mark_proxy_object (object_p);
789-
break;
789+
/* No need to free the properties of a proxy (there should be none).
790+
* Aside from the tag bits every other bit should be zero,
791+
*/
792+
JERRY_ASSERT ((object_p->u1.property_list_cp & ~JMEM_TAG_MASK) == 0);
793+
return;
790794
}
791795
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
792796
case ECMA_OBJECT_TYPE_BOUND_FUNCTION:
@@ -1499,8 +1503,12 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
14991503
#if ENABLED (JERRY_BUILTIN_PROXY)
15001504
case ECMA_OBJECT_TYPE_PROXY:
15011505
{
1502-
ext_object_size = sizeof (ecma_proxy_object_t);
1503-
break;
1506+
/* No need to free the properties of a proxy (there should be none).
1507+
* Aside from the tag bits every other bit should be zero,
1508+
*/
1509+
JERRY_ASSERT ((object_p->u1.property_list_cp & ~JMEM_TAG_MASK) == 0);
1510+
ecma_dealloc_extended_object (object_p, sizeof (ecma_proxy_object_t));
1511+
return;
15041512
}
15051513
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
15061514
case ECMA_OBJECT_TYPE_FUNCTION:

jerry-core/ecma/base/ecma-globals.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,10 @@ do \
21282128
#if ENABLED (JERRY_BUILTIN_PROXY)
21292129
/**
21302130
* Description of Proxy objects.
2131+
*
2132+
* A Proxy object's property list is used to store extra information:
2133+
* * The "header.u1.property_list_cp" 1st tag bit stores the IsCallable information.
2134+
* * The "header.u1.property_list_cp" 2nd tag bit stores the IsConstructor information.
21312135
*/
21322136
typedef struct
21332137
{

jerry-core/ecma/operations/ecma-function-object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ ecma_op_object_is_callable (ecma_object_t *obj_p) /**< ecma object */
106106
#if ENABLED (JERRY_BUILTIN_PROXY)
107107
if (ECMA_OBJECT_TYPE_IS_PROXY (type))
108108
{
109-
return ecma_op_is_callable (((ecma_proxy_object_t *) obj_p)->target);
109+
return ECMA_GET_FIRST_BIT_FROM_POINTER_TAG (obj_p->u1.property_list_cp) != 0;
110110
}
111111
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
112112

@@ -159,7 +159,7 @@ ecma_object_is_constructor (ecma_object_t *obj_p) /**< ecma object */
159159
#if ENABLED (JERRY_BUILTIN_PROXY)
160160
if (ECMA_OBJECT_TYPE_IS_PROXY (type))
161161
{
162-
return ecma_is_constructor (((ecma_proxy_object_t *) obj_p)->target);
162+
return ECMA_GET_SECOND_BIT_FROM_POINTER_TAG (obj_p->u1.property_list_cp) != 0;
163163
}
164164
#endif /* ENABLED (JERRY_BUILTIN_PROXY) */
165165

jerry-core/ecma/operations/ecma-proxy-object.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ ecma_proxy_create (ecma_value_t target, /**< proxy target */
6666

6767
ecma_proxy_object_t *proxy_obj_p = (ecma_proxy_object_t *) obj_p;
6868

69+
/* ES2015: 7. */
70+
/* ES11+: 5. */
71+
if (ecma_op_is_callable (target))
72+
{
73+
ECMA_SET_FIRST_BIT_TO_POINTER_TAG (obj_p->u1.property_list_cp);
74+
75+
/* ES2015: 7.b. */
76+
/* ES11+: 5.b. */
77+
if (ecma_is_constructor (target))
78+
{
79+
ECMA_SET_SECOND_BIT_TO_POINTER_TAG (obj_p->u1.property_list_cp);
80+
}
81+
}
82+
6983
/* ES2015: 8. */
7084
/* ES11+: 6. */
7185
proxy_obj_p->target = target;

tests/jerry/es.next/proxy_flags.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright JS Foundation and other contributors, http://js.foundation
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
var target_called = 0;
16+
function target_method() {
17+
target_called++;
18+
}
19+
20+
var proxy_revocable_function = Proxy.revocable(target_method, {})
21+
var proxy_function = proxy_revocable_function.proxy;
22+
23+
/* Test Proxy IsCallable(target) */
24+
/* The proxy target should have a function type. */
25+
assert(typeof(proxy_function) === "function");
26+
27+
/* The proxy can be called with new */
28+
var new_obj = new proxy_function()
29+
assert(new_obj instanceof target_method);
30+
assert(target_called === 1);
31+
32+
/* Test Proxy IsConstructor(target) */
33+
/* Array.from tries to use the "this" value as constructor. */
34+
var array_result = Array.from.call(proxy_function, [1, 2, 3]);
35+
assert(Array.isArray(array_result) === false);
36+
assert(target_called === 2);
37+
38+
proxy_revocable_function.revoke();
39+
40+
/* Test Proxy IsCallable(target) if the proxy is revoked. */
41+
/* After the proxy was revoked the type is still function. */
42+
assert(typeof(proxy_function) === "function");
43+
44+
/* After the proxy was revoked the constructor should not be called
45+
* and an error should be reported
46+
*/
47+
try {
48+
new proxy_function();
49+
assert(false);
50+
} catch (ex) {
51+
assert(ex instanceof TypeError);
52+
}
53+
54+
assert(target_called === 2);
55+
56+
/* Test Proxy IsConstructor(target) if the proxy is revoked. */
57+
/* Array.from tries to use the "this" value as constructor and as the
58+
* proxy is revoked the constructor call should fail.
59+
* The IsConstructor(proxy_function) is still true.
60+
*/
61+
try {
62+
Array.from.call(proxy_function, [1, 2, 3]);
63+
assert(false);
64+
} catch (ex) {
65+
assert(ex instanceof TypeError);
66+
}
67+
68+
assert(target_called === 2);

tests/test262-esnext-excludelist.xml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,7 @@
109109
<test id="built-ins/Promise/race/invoke-resolve-get-error.js"><reason>Test expects incorrect call order</reason></test>
110110
<test id="built-ins/Promise/race/resolve-element-function-name.js"><reason></reason></test>
111111
<test id="built-ins/Promise/race/resolve-non-callable.js"><reason>Test expects incorrect call order</reason></test>
112-
<test id="built-ins/Proxy/create-target-is-revoked-function-proxy.js"><reason></reason></test>
113112
<test id="built-ins/Proxy/preventExtensions/trap-is-undefined-target-is-proxy.js"><reason></reason></test>
114-
<test id="built-ins/Proxy/revocable/target-is-revoked-function-proxy.js"><reason></reason></test>
115113
<test id="built-ins/Proxy/setPrototypeOf/toboolean-trap-result-false.js"><reason></reason></test>
116114
<test id="built-ins/RegExp/prototype/Symbol.matchAll/isregexp-called-once.js"><reason></reason></test>
117115
<test id="built-ins/RegExp/prototype/Symbol.matchAll/isregexp-this-throws.js"><reason></reason></test>
@@ -544,7 +542,6 @@
544542
<test id="language/expressions/super/prop-expr-obj-ref-non-strict.js"><reason></reason></test>
545543
<test id="language/expressions/super/prop-expr-obj-ref-strict.js"><reason></reason></test>
546544
<test id="language/expressions/tagged-template/invalid-escape-sequences.js"><reason></reason></test>
547-
<test id="language/expressions/typeof/proxy.js"><reason></reason></test>
548545
<test id="language/expressions/yield/star-return-is-null.js"><reason></reason></test>
549546
<test id="language/expressions/yield/star-throw-is-null.js"><reason></reason></test>
550547
<test id="language/global-code/decl-lex-configurable-global.js"><reason></reason></test>

0 commit comments

Comments
 (0)