Skip to content

Commit 0734181

Browse files
committed
[GR-38976] Consider properties of foreign targets in JSProxy.getOwnProperty().
PullRequest: js/2472
2 parents 2f4befa + 5ab9240 commit 0734181

File tree

4 files changed

+137
-37
lines changed

4 files changed

+137
-37
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.js.test.regress;
42+
43+
import com.oracle.truffle.js.lang.JavaScriptLanguage;
44+
import com.oracle.truffle.js.test.JSTest;
45+
import java.util.HashMap;
46+
import java.util.Map;
47+
import org.graalvm.polyglot.Context;
48+
import org.graalvm.polyglot.Value;
49+
import org.graalvm.polyglot.proxy.ProxyObject;
50+
import org.junit.Assert;
51+
import org.junit.Test;
52+
53+
/**
54+
* Tests the reading of a property of JavaScript Proxy with a foreign target.
55+
*/
56+
public class GH4613 {
57+
58+
// Derived from https://github.com/oracle/graal/issues/4613
59+
@Test
60+
public void test() {
61+
try (Context context = JSTest.newContextBuilder().build()) {
62+
Map<String, Object> map = new HashMap<>();
63+
map.put("key", "value");
64+
context.getBindings(JavaScriptLanguage.ID).putMember("target", ProxyObject.fromMap(map));
65+
66+
Value proxy = context.eval(JavaScriptLanguage.ID, "new Proxy(target, {})");
67+
Value value = proxy.getMember("key");
68+
69+
Assert.assertTrue(value.isString());
70+
Assert.assertEquals("value", value.asString());
71+
}
72+
}
73+
74+
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ObjectFunctionBuiltins.java

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -360,30 +360,9 @@ protected JSDynamicObject getForeignObject(Object thisObj, Object property,
360360
@Cached TruffleString.ReadCharUTF16Node charAtNode) {
361361
Object propertyKey = toPropertyKeyNode.execute(property);
362362
if (Strings.isTString(propertyKey)) {
363-
try {
364-
String member = Strings.toJavaString((TruffleString) propertyKey);
365-
if (interop.hasMembers(thisObj)) {
366-
if (interop.isMemberExisting(thisObj, member) && interop.isMemberReadable(thisObj, member)) {
367-
PropertyDescriptor desc = PropertyDescriptor.createData(
368-
toJSType.executeWithTarget(interop.readMember(thisObj, member)),
369-
!interop.isMemberInternal(thisObj, member),
370-
interop.isMemberWritable(thisObj, member),
371-
interop.isMemberRemovable(thisObj, member));
372-
return fromPropertyDescriptorNode.execute(desc, getContext());
373-
}
374-
}
375-
long index = JSRuntime.propertyNameToArrayIndex((TruffleString) propertyKey, charAtNode);
376-
if (JSRuntime.isArrayIndex(index) && interop.hasArrayElements(thisObj)) {
377-
if (interop.isArrayElementExisting(thisObj, index) && interop.isArrayElementReadable(thisObj, index)) {
378-
PropertyDescriptor desc = PropertyDescriptor.createData(
379-
toJSType.executeWithTarget(interop.readArrayElement(thisObj, index)),
380-
true,
381-
interop.isArrayElementWritable(thisObj, index),
382-
interop.isArrayElementRemovable(thisObj, index));
383-
return fromPropertyDescriptorNode.execute(desc, getContext());
384-
}
385-
}
386-
} catch (InteropException iex) {
363+
PropertyDescriptor desc = JSInteropUtil.getOwnProperty(thisObj, (TruffleString) propertyKey, interop, toJSType, charAtNode);
364+
if (desc != null) {
365+
return fromPropertyDescriptorNode.execute(desc, getContext());
387366
}
388367
}
389368
return Undefined.instance;
@@ -449,12 +428,8 @@ protected JSDynamicObject getForeignObject(Object thisObj,
449428
}
450429
for (int i = 0; i < size; i++) {
451430
String member = (String) members.readArrayElement(keysObj, i);
452-
if (interop.isMemberReadable(thisObj, member)) {
453-
PropertyDescriptor desc = PropertyDescriptor.createData(
454-
toJSType.executeWithTarget(interop.readMember(thisObj, member)),
455-
!interop.isMemberInternal(thisObj, member),
456-
interop.isMemberWritable(thisObj, member),
457-
interop.isMemberRemovable(thisObj, member));
431+
PropertyDescriptor desc = JSInteropUtil.getExistingMemberProperty(thisObj, member, interop, toJSType);
432+
if (desc != null) {
458433
JSDynamicObject propDesc = fromPropertyDescriptorNode.execute(desc, getContext());
459434
Properties.putWithFlags(putPropDescNode, result, Strings.fromJavaString(member), propDesc, JSAttributes.configurableEnumerableWritable());
460435
}
@@ -467,12 +442,8 @@ protected JSDynamicObject getForeignObject(Object thisObj,
467442
throw Errors.createRangeErrorInvalidArrayLength();
468443
}
469444
for (long i = 0; i < size; i++) {
470-
if (interop.isArrayElementExisting(thisObj, i) && interop.isArrayElementReadable(thisObj, i)) {
471-
PropertyDescriptor desc = PropertyDescriptor.createData(
472-
toJSType.executeWithTarget(interop.readArrayElement(thisObj, i)),
473-
true,
474-
interop.isArrayElementWritable(thisObj, i),
475-
interop.isArrayElementRemovable(thisObj, i));
445+
PropertyDescriptor desc = JSInteropUtil.getArrayElementProperty(thisObj, i, interop, toJSType);
446+
if (desc != null) {
476447
JSDynamicObject propDesc = fromPropertyDescriptorNode.execute(desc, getContext());
477448
Properties.putWithFlags(putPropDescNode, result, Strings.fromLong(i), propDesc, JSAttributes.configurableEnumerableWritable());
478449
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSProxy.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
import com.oracle.truffle.js.runtime.JSRuntime;
6868
import com.oracle.truffle.js.runtime.JavaScriptRootNode;
6969
import com.oracle.truffle.js.runtime.Strings;
70+
import com.oracle.truffle.js.runtime.Symbol;
7071
import com.oracle.truffle.js.runtime.ToDisplayStringFormat;
7172
import com.oracle.truffle.js.runtime.interop.JSInteropUtil;
7273
import com.oracle.truffle.js.runtime.objects.JSDynamicObject;
@@ -774,7 +775,12 @@ public PropertyDescriptor getOwnProperty(JSDynamicObject thisObj, Object key) {
774775
if (JSDynamicObject.isJSDynamicObject(target)) {
775776
return JSObject.getOwnProperty((JSDynamicObject) target, key);
776777
} else {
777-
return null;
778+
if (Strings.isTString(key)) {
779+
return JSInteropUtil.getOwnProperty(target, (TruffleString) key);
780+
} else {
781+
assert key instanceof Symbol;
782+
return null; // No symbols in foreign objects
783+
}
778784
}
779785
}
780786
Object trapResultObj = checkTrapReturnValue(JSRuntime.call(getOwnPropertyFn, handler, new Object[]{target, key}));

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/JSInteropUtil.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545

4646
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
4747
import com.oracle.truffle.api.interop.ArityException;
48+
import com.oracle.truffle.api.interop.InteropException;
4849
import com.oracle.truffle.api.interop.InteropLibrary;
4950
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
5051
import com.oracle.truffle.api.interop.UnknownIdentifierException;
@@ -60,6 +61,7 @@
6061
import com.oracle.truffle.js.runtime.objects.JSObject;
6162
import com.oracle.truffle.js.runtime.Strings;
6263
import com.oracle.truffle.js.runtime.objects.Null;
64+
import com.oracle.truffle.js.runtime.objects.PropertyDescriptor;
6365
import com.oracle.truffle.js.runtime.objects.Undefined;
6466

6567
/**
@@ -236,4 +238,51 @@ public static Object construct(Object target, Object[] args) {
236238
public static boolean isBoxedPrimitive(Object receiver, InteropLibrary interop) {
237239
return interop.isString(receiver) || interop.isNumber(receiver) || interop.isBoolean(receiver);
238240
}
241+
242+
public static PropertyDescriptor getOwnProperty(Object object, TruffleString propertyKey) {
243+
return getOwnProperty(object, propertyKey, InteropLibrary.getUncached(), ImportValueNode.getUncached(), TruffleString.ReadCharUTF16Node.getUncached());
244+
}
245+
246+
public static PropertyDescriptor getOwnProperty(Object object, TruffleString propertyKey, InteropLibrary interop, ImportValueNode importValueNode, TruffleString.ReadCharUTF16Node charAtNode) {
247+
try {
248+
String key = Strings.toJavaString(propertyKey);
249+
if (interop.hasMembers(object) && interop.isMemberExisting(object, key)) {
250+
PropertyDescriptor desc = getExistingMemberProperty(object, key, interop, importValueNode);
251+
if (desc != null) {
252+
return desc;
253+
}
254+
}
255+
long index = JSRuntime.propertyNameToArrayIndex(propertyKey, charAtNode);
256+
if (JSRuntime.isArrayIndex(index) && interop.hasArrayElements(object)) {
257+
return getArrayElementProperty(object, index, interop, importValueNode);
258+
}
259+
} catch (InteropException iex) {
260+
}
261+
return null;
262+
}
263+
264+
public static PropertyDescriptor getExistingMemberProperty(Object object, String key, InteropLibrary interop, ImportValueNode importValueNode) throws InteropException {
265+
assert interop.hasMembers(object) && interop.isMemberExisting(object, key);
266+
if (interop.isMemberReadable(object, key)) {
267+
return PropertyDescriptor.createData(
268+
importValueNode.executeWithTarget(interop.readMember(object, key)),
269+
!interop.isMemberInternal(object, key),
270+
interop.isMemberWritable(object, key),
271+
interop.isMemberRemovable(object, key));
272+
}
273+
return null;
274+
}
275+
276+
public static PropertyDescriptor getArrayElementProperty(Object object, long index, InteropLibrary interop, ImportValueNode importValueNode) throws InteropException {
277+
assert interop.hasArrayElements(object) && JSRuntime.isArrayIndex(index);
278+
if (interop.isArrayElementExisting(object, index) && interop.isArrayElementReadable(object, index)) {
279+
return PropertyDescriptor.createData(
280+
importValueNode.executeWithTarget(interop.readArrayElement(object, index)),
281+
true,
282+
interop.isArrayElementWritable(object, index),
283+
interop.isArrayElementRemovable(object, index));
284+
}
285+
return null;
286+
}
287+
239288
}

0 commit comments

Comments
 (0)