diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-52824.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-52824.js new file mode 100644 index 00000000000..7f5bb1cec9c --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-52824.js @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +var javaNull = new java.util.ArrayDeque().peek(); + +assertFalse(javaNull instanceof Object); +assertFalse(javaNull instanceof new Proxy(Object, {})); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignBoxedObjectTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignBoxedObjectTest.java index bc6ca051bdb..3cbadc61595 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignBoxedObjectTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignBoxedObjectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,9 @@ package com.oracle.truffle.js.test.interop; import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.graalvm.polyglot.Context; import org.junit.Test; @@ -62,6 +63,7 @@ public void testForeignNull() { assertTrue(context.eval(ID, "Object.getPrototypeOf(Object.create(obj)) === null").asBoolean()); assertTrue(context.eval(ID, "try { obj.foo; false; } catch (e) { e instanceof TypeError }").asBoolean()); assertTrue(context.eval(ID, "try { obj.foo(); false; } catch (e) { e instanceof TypeError }").asBoolean()); + assertFalse(context.eval(ID, "obj instanceof Object").asBoolean()); } } @@ -76,6 +78,7 @@ public void testForeignBoxedString() { assertEquals("foo", context.eval(ID, "obj.valueOf()").asString()); assertEquals("foo", context.eval(ID, "obj['valueOf']()").asString()); assertTrue(context.eval(ID, "obj.includes('o')").asBoolean()); + assertFalse(context.eval(ID, "obj instanceof Object").asBoolean()); } } @@ -95,6 +98,7 @@ public void testForeignBoxedNumber() { assertEquals("42", context.eval(ID, "obj.toString()").asString()); assertEquals(42, context.eval(ID, "obj.valueOf()").asInt()); assertEquals(42, context.eval(ID, "obj['valueOf']()").asInt()); + assertFalse(context.eval(ID, "obj instanceof Object").asBoolean()); } } @@ -108,6 +112,7 @@ public void testForeignBoxedBoolean() { assertTrue(context.eval(ID, "obj.valueOf()").asBoolean()); assertTrue(context.eval(ID, "obj['valueOf']()").asBoolean()); assertEquals("true", context.eval(ID, "obj.toString()").asString()); + assertFalse(context.eval(ID, "obj instanceof Object").asBoolean()); } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java index c128ea1f499..42d27f410cf 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -211,9 +211,9 @@ public void testForeignInstanceof() { Assert.assertTrue(testInstanceofIntl("Array", ProxyArray.fromArray("fun", "with", "proxy", "array"))); Assert.assertTrue(testInstanceofIntl("Date", Instant.now())); Assert.assertTrue(testInstanceofIntl("Map", new TestTruffleHash())); - Assert.assertTrue(testInstanceofIntl("String", new TestTruffleString())); - Assert.assertTrue(testInstanceofIntl("Boolean", new TestTruffleBoolean())); - Assert.assertTrue(testInstanceofIntl("Number", new TestTruffleNumber())); + Assert.assertFalse(testInstanceofIntl("String", new TestTruffleString())); + Assert.assertFalse(testInstanceofIntl("Boolean", new TestTruffleBoolean())); + Assert.assertFalse(testInstanceofIntl("Number", new TestTruffleNumber())); Assert.assertTrue(testInstanceofIntl("Function", (ProxyExecutable) v -> true)); Assert.assertTrue(testInstanceofIntl("Object", new Object())); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/InstanceofNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/InstanceofNode.java index 97c2bda9e26..bc3da65c3a5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/InstanceofNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/InstanceofNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -67,6 +67,7 @@ import com.oracle.truffle.js.nodes.access.GetMethodNode; import com.oracle.truffle.js.nodes.access.GetPrototypeNode; import com.oracle.truffle.js.nodes.access.IsJSObjectNode; +import com.oracle.truffle.js.nodes.access.IsObjectNode; import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.binary.InstanceofNodeGen.IsBoundFunctionCacheNodeGen; import com.oracle.truffle.js.nodes.binary.InstanceofNodeGen.OrdinaryHasInstanceNodeGen; @@ -249,18 +250,22 @@ protected boolean doIsBound(Object obj, JSDynamicObject check, @Specialization(guards = {"!isJSObject(left)", "isForeignObject(left)", "isJSFunction(right)", "!isBoundFunction(right)"}) protected boolean doForeignObject(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right, + @Cached @Shared IsObjectNode isAnyObjectNode, @Cached @Shared("foreignPrototypeNode") ForeignObjectPrototypeNode getForeignPrototypeNode, @Cached @Shared("invalidPrototypeBranch") InlinedBranchProfile invalidPrototypeBranch, @Cached("create(context)") @Shared("ordinaryHasInstance") OrdinaryHasInstanceNode ordinaryHasInstanceNode) { if (context.isOptionForeignObjectPrototype()) { - return foreignObjectIntl(left, right, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode); + return foreignObjectIntl(left, right, isAnyObjectNode, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode); } else { return false; } } - private boolean foreignObjectIntl(Object left, JSDynamicObject right, ForeignObjectPrototypeNode getForeignPrototypeNode, InlinedBranchProfile invalidPrototypeBranch, - OrdinaryHasInstanceNode ordinaryHasInstanceNode) { + private boolean foreignObjectIntl(Object left, JSDynamicObject right, IsObjectNode isObjectNode, ForeignObjectPrototypeNode getForeignPrototypeNode, + InlinedBranchProfile invalidPrototypeBranch, OrdinaryHasInstanceNode ordinaryHasInstanceNode) { + if (!isObjectNode.executeBoolean(left)) { + return false; + } Object rightProto = getConstructorPrototype(right, invalidPrototypeBranch); Object foreignProto = getForeignPrototypeNode.execute(left); if (foreignProto == rightProto) { @@ -276,10 +281,11 @@ protected boolean doNotAnObject(@SuppressWarnings("unused") Object left, @Suppre @Specialization(guards = {"!isJSObject(left)", "isForeignObject(left)", "isJSProxy(right)", "isCallableProxy(right)"}) protected boolean doNotAnObjectProxyForeign(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") JSDynamicObject right, + @Cached @Shared IsObjectNode isAnyObjectNode, @Cached @Shared("foreignPrototypeNode") ForeignObjectPrototypeNode getForeignPrototypeNode, @Cached @Shared("invalidPrototypeBranch") InlinedBranchProfile invalidPrototypeBranch, @Cached("create(context)") @Shared("ordinaryHasInstance") OrdinaryHasInstanceNode ordinaryHasInstanceNode) { - return doForeignObject(left, right, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode); + return doForeignObject(left, right, isAnyObjectNode, getForeignPrototypeNode, invalidPrototypeBranch, ordinaryHasInstanceNode); } @Specialization(guards = {"!isJSObject(left)", "!isForeignObject(left)", "isJSProxy(right)", "isCallableProxy(right)"})