Skip to content

Commit 42006c2

Browse files
committed
[GR-39067] Backport fixes around foreign prototype.
PullRequest: js/2508
2 parents be6860b + cf1a945 commit 42006c2

File tree

2 files changed

+89
-23
lines changed

2 files changed

+89
-23
lines changed

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,24 +206,75 @@ public void testJSBuiltinCanBeOverwritten() {
206206

207207
@Test
208208
public void testForeignInstanceof() {
209-
testInstanceofIntl("Array", ProxyArray.fromArray("fun", "with", "proxy", "array"));
210-
testPrototypeIntl("Date", Instant.now());
211-
testPrototypeIntl("Map", new TestTruffleHash());
212-
testPrototypeIntl("String", new TestTruffleString());
213-
testPrototypeIntl("Boolean", new TestTruffleBoolean());
214-
testPrototypeIntl("Number", new TestTruffleNumber());
215-
testPrototypeIntl("Function", (ProxyExecutable) v -> true);
216-
testPrototypeIntl("Object", new Object());
209+
// test expected Instance
210+
Assert.assertTrue(testInstanceofIntl("Array", ProxyArray.fromArray("fun", "with", "proxy", "array")));
211+
// Assert.assertTrue(testInstanceofIntl("Date", Instant.now())); //see GR-39319
212+
Assert.assertTrue(testInstanceofIntl("Map", new TestTruffleHash()));
213+
Assert.assertTrue(testInstanceofIntl("String", new TestTruffleString()));
214+
Assert.assertTrue(testInstanceofIntl("Boolean", new TestTruffleBoolean()));
215+
Assert.assertTrue(testInstanceofIntl("Number", new TestTruffleNumber()));
216+
Assert.assertTrue(testInstanceofIntl("Function", (ProxyExecutable) v -> true));
217+
Assert.assertTrue(testInstanceofIntl("Object", new Object()));
218+
219+
// test non-matching instance
220+
Assert.assertFalse(testInstanceofIntl("RegExp", ProxyArray.fromArray("fun", "with", "proxy", "array")));
221+
Assert.assertFalse(testInstanceofIntl("RegExp", Instant.now()));
222+
Assert.assertFalse(testInstanceofIntl("RegExp", new TestTruffleHash()));
223+
Assert.assertFalse(testInstanceofIntl("RegExp", new TestTruffleString()));
224+
Assert.assertFalse(testInstanceofIntl("RegExp", new TestTruffleBoolean()));
225+
Assert.assertFalse(testInstanceofIntl("RegExp", new TestTruffleNumber()));
226+
Assert.assertFalse(testInstanceofIntl("RegExp", (ProxyExecutable) v -> true));
227+
Assert.assertFalse(testInstanceofIntl("RegExp", new Object()));
217228
}
218229

219-
private static void testInstanceofIntl(String prototype, Object obj) {
220-
String code = "(obj) => { return (obj instanceof " + prototype + "); }";
230+
private static boolean testInstanceofIntl(String prototype, Object obj) {
231+
String code = "(obj) => { return (obj instanceof " + prototype + ") && (obj instanceof Object); }";
221232
try (Context context = JSTest.newContextBuilder(ID).build()) {
222233
Value result = context.eval(ID, code).execute(obj);
223-
Assert.assertTrue(result.asBoolean());
234+
return result.asBoolean();
224235
}
225236
}
226237

238+
@Test
239+
public void testForeignRightPrototype() {
240+
String code = "ForeignObjectPrototype = Object.getPrototypeOf(new java.lang.Object());\n" +
241+
"function f() {}; \n" +
242+
"f.prototype = ForeignObjectPrototype;\n" +
243+
"new java.lang.Object() instanceof f;";
244+
testTrue(code);
245+
}
246+
247+
private static void testTrue(String code) {
248+
Assert.assertTrue(testIntl(code));
249+
}
250+
251+
private static void testFalse(String code) {
252+
Assert.assertFalse(testIntl(code));
253+
}
254+
255+
private static boolean testIntl(String code) {
256+
try (Context context = JSTest.newContextBuilder(ID).allowAllAccess(true).allowHostAccess(HostAccess.ALL).build()) {
257+
Value result = context.eval(ID, code);
258+
return result.asBoolean();
259+
}
260+
}
261+
262+
@Test
263+
public void testCallableProxies() {
264+
String code = "new java.lang.Object instanceof new Proxy(Object, {});";
265+
testTrue(code);
266+
267+
code = "var handler = { get(target, prop, recv) { return (prop === 'prototype') ? Object.prototype : Reflect.get(target, prop, recv); } };\n" +
268+
"var proxy = new Proxy(function() {}, handler);\n" +
269+
"new java.lang.Object() instanceof proxy";
270+
testTrue(code);
271+
272+
code = "var handler = { get(target, prop, recv) { if (prop === 'prototype') { throw new Error() } else { return Reflect.get(target, prop, recv); } } };\n" +
273+
"var proxy = new Proxy(function() {}, handler);\n" +
274+
"42 instanceof proxy";
275+
testFalse(code);
276+
}
277+
227278
@ExportLibrary(InteropLibrary.class)
228279
public static class TestTruffleHash implements TruffleObject {
229280

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/InstanceofNode.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -239,29 +239,44 @@ protected boolean doIsBound(Object obj, JSDynamicObject check,
239239

240240
@Specialization(guards = {"!isJSObject(left)", "isForeignObject(left)", "isJSFunction(right)", "!isBoundFunction(right)"})
241241
protected boolean doForeignObject(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right,
242-
@Cached ForeignObjectPrototypeNode getForeignPrototypeNode,
243-
@Cached @Shared("getPrototype1Node") GetPrototypeNode getPrototype1Node,
244-
@Cached @Shared("invalidPrototypeBranch") BranchProfile invalidPrototypeBranch) {
242+
@Cached @Shared("foreignPrototypeNode") ForeignObjectPrototypeNode getForeignPrototypeNode,
243+
@Cached @Shared("invalidPrototypeBranch") BranchProfile invalidPrototypeBranch,
244+
@Cached("create(context)") @Shared("ordinaryHasInstance") OrdinaryHasInstanceNode ordinaryHasInstanceNode) {
245245
if (context.isOptionForeignObjectPrototype()) {
246-
Object rightProto = getConstructorPrototype(right, invalidPrototypeBranch);
247-
if (rightProto == getRealm().getDatePrototype()) {
248-
return false;
249-
}
250-
Object foreignProto = getForeignPrototypeNode.execute(left);
251-
Object foreignProtoProto = getPrototype1Node.execute(foreignProto);
252-
return rightProto == foreignProtoProto;
246+
return foreignObjectIntl(left, right, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode);
253247
} else {
254248
return false;
255249
}
256250
}
257251

252+
private boolean foreignObjectIntl(Object left, JSDynamicObject right, ForeignObjectPrototypeNode getForeignPrototypeNode, BranchProfile invalidPrototypeBranch,
253+
OrdinaryHasInstanceNode ordinaryHasInstanceNode) {
254+
Object rightProto = getConstructorPrototype(right, invalidPrototypeBranch);
255+
if (rightProto == getRealm().getDatePrototype()) {
256+
// necessary because of GR-39319
257+
return false;
258+
}
259+
Object foreignProto = getForeignPrototypeNode.execute(left);
260+
if (foreignProto == rightProto) {
261+
return true;
262+
}
263+
return ordinaryHasInstanceNode.executeBoolean(foreignProto, right);
264+
}
265+
258266
@Specialization(guards = {"!isJSObject(left)", "!isForeignObject(left)", "isJSFunction(right)", "!isBoundFunction(right)"})
259267
protected boolean doNotAnObject(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right) {
260268
return false;
261269
}
262270

263-
@Specialization(guards = {"!isJSObject(left)", "isJSProxy(right)", "isCallableProxy(right)"})
264-
protected boolean doNotAnObjectProxy(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right) {
271+
@Specialization(guards = {"!isJSObject(left)", "isForeignObject(left)", "isJSProxy(right)", "isCallableProxy(right)"})
272+
protected boolean doNotAnObjectProxyForeign(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right,
273+
@Cached @Shared("foreignPrototypeNode") ForeignObjectPrototypeNode getForeignPrototypeNode, @Cached @Shared("invalidPrototypeBranch") BranchProfile invalidPrototypeBranch,
274+
@Cached("create(context)") @Shared("ordinaryHasInstance") OrdinaryHasInstanceNode ordinaryHasInstanceNode) {
275+
return doForeignObject(left, right, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode);
276+
}
277+
278+
@Specialization(guards = {"!isJSObject(left)", "!isForeignObject(left)", "isJSProxy(right)", "isCallableProxy(right)"})
279+
protected boolean doNotAnObjectProxyPrimitive(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right) {
265280
return false;
266281
}
267282

0 commit comments

Comments
 (0)