Skip to content

Commit 302c4ef

Browse files
committed
Add InterceptJSInvokeNodes in WasmGC backend
Without them, functional interfaces passed to JavaScript could have their method not generated, making them not callable from JavaScript
1 parent 8fa7b17 commit 302c4ef

File tree

3 files changed

+112
-52
lines changed

3 files changed

+112
-52
lines changed

web-image/src/com.oracle.svm.hosted.webimage.test/src/com/oracle/svm/hosted/webimage/test/spec/JS_JTT_JSAnnotation.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,13 @@
5151
public class JS_JTT_JSAnnotation extends JTTTestSuite {
5252

5353
// @formatter:off
54-
// TODO GR-62854 Remove Runnable#run once JSBodyFeature is enabled for WasmGC and InterceptJSInvokeTypeFlow is used
5554
private static final String REFLECT_CONFIG = """
5655
[
5756
{
5857
"name" : "java.lang.String",
5958
"methods": [
6059
{"name" : "indexOf"}
6160
]
62-
},
63-
{
64-
"name" : "java.lang.Runnable",
65-
"methods": [
66-
{"name" : "run"}
67-
]
6861
}
6962
]""";
7063

web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,7 @@
2424
*/
2525
package com.oracle.svm.hosted.webimage.codegen;
2626

27-
import java.lang.reflect.Executable;
28-
import java.lang.reflect.Method;
2927
import java.lang.reflect.Modifier;
30-
import java.util.List;
31-
import java.util.Set;
3228

3329
import org.graalvm.nativeimage.AnnotationAccess;
3430
import org.graalvm.nativeimage.Platforms;
@@ -46,11 +42,8 @@
4642
import com.oracle.svm.core.feature.InternalFeature;
4743
import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode;
4844
import com.oracle.svm.hosted.FeatureImpl;
49-
import com.oracle.svm.hosted.ImageClassLoader;
50-
import com.oracle.svm.hosted.webimage.codegen.node.InterceptJSInvokeNode;
5145
import com.oracle.svm.hosted.webimage.codegen.oop.ClassWithMirrorLowerer;
5246
import com.oracle.svm.hosted.webimage.js.JSObjectAccessMethodSupport;
53-
import com.oracle.svm.hosted.webimage.util.ReflectUtil;
5447
import com.oracle.svm.util.ReflectionUtil;
5548
import com.oracle.svm.webimage.api.Nothing;
5649
import com.oracle.svm.webimage.platform.WebImageJSPlatform;
@@ -79,17 +72,6 @@
7972
@AutomaticallyRegisteredFeature
8073
@Platforms(WebImageJSPlatform.class)
8174
public final class JSBodyFeature implements InternalFeature {
82-
// The set of methods that are potentially overridden by a JS-annotated method.
83-
private Set<Method> jsOverridden;
84-
85-
@Override
86-
public void afterRegistration(AfterRegistrationAccess access) {
87-
FeatureImpl.AfterRegistrationAccessImpl accessImpl = (FeatureImpl.AfterRegistrationAccessImpl) access;
88-
ImageClassLoader imageClassLoader = accessImpl.getImageClassLoader();
89-
List<Class<?>> allClasses = imageClassLoader.findSubclasses(Object.class, true);
90-
jsOverridden = ReflectUtil.findBaseMethodsOfJSAnnotated(allClasses);
91-
}
92-
9375
@Override
9476
public void registerGraphBuilderPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
9577
plugins.appendNodePlugin(new NodePlugin() {
@@ -98,28 +80,6 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Va
9880
if (AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), JS.Import.class)) {
9981
((AnalysisType) method.getDeclaringClass()).registerAsInstantiated("JS.Import classes might be allocated in JavaScript. We need to tell the static analysis about that");
10082
}
101-
if (canBeJavaScriptCall((AnalysisMethod) method)) {
102-
InterceptJSInvokeNode intercept = b.append(new InterceptJSInvokeNode(method, b.bci()));
103-
for (final ValueNode arg : args) {
104-
intercept.arguments().add(arg);
105-
}
106-
}
107-
return false;
108-
}
109-
110-
private boolean canBeJavaScriptCall(AnalysisMethod method) {
111-
Executable executable;
112-
try {
113-
executable = method.getJavaMethod();
114-
} catch (Throwable e) {
115-
// Either a substituted method, or a method with a malformed bytecode signature.
116-
// This is most likely not a JS-annotated method.
117-
return false;
118-
}
119-
if (executable instanceof Method) {
120-
return jsOverridden.contains(executable);
121-
}
122-
// Not a normal method (constructor).
12383
return false;
12484
}
12585

@@ -314,9 +274,4 @@ private static void findJSObjectSubtypes(FeatureImpl.DuringAnalysisAccessImpl ac
314274
access.requireAnalysisIteration();
315275
}
316276
}
317-
318-
@Override
319-
public void afterAnalysis(AfterAnalysisAccess access) {
320-
jsOverridden = null;
321-
}
322277
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package com.oracle.svm.hosted.webimage.codegen;
27+
28+
import java.lang.reflect.Executable;
29+
import java.lang.reflect.Method;
30+
import java.util.Set;
31+
32+
import org.graalvm.nativeimage.Platforms;
33+
34+
import com.oracle.graal.pointsto.meta.AnalysisMethod;
35+
import com.oracle.svm.core.ParsingReason;
36+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
37+
import com.oracle.svm.core.feature.InternalFeature;
38+
import com.oracle.svm.hosted.FeatureImpl;
39+
import com.oracle.svm.hosted.ImageClassLoader;
40+
import com.oracle.svm.hosted.webimage.codegen.node.InterceptJSInvokeNode;
41+
import com.oracle.svm.hosted.webimage.util.ReflectUtil;
42+
import com.oracle.svm.webimage.platform.WebImagePlatform;
43+
44+
import jdk.graal.compiler.nodes.ValueNode;
45+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
46+
import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
47+
import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin;
48+
import jdk.graal.compiler.phases.util.Providers;
49+
import jdk.vm.ci.meta.ResolvedJavaMethod;
50+
51+
/**
52+
* Inserts {@link InterceptJSInvokeNode} into the IR at any invoke that may target a
53+
* {@link org.graalvm.webimage.api.JS} annotated method to deal with types that may leak to
54+
* JavaScript.
55+
* <p>
56+
* TODO GR-62854 Merge into JSBodyFeature once it is enabled by default
57+
*/
58+
@AutomaticallyRegisteredFeature
59+
@Platforms(WebImagePlatform.class)
60+
public class JSBodyTypeFlowFeature implements InternalFeature {
61+
/**
62+
* The set of methods that are potentially overridden by a JS-annotated method.
63+
* <p>
64+
* Any call to such a method needs to have a {@link InterceptJSInvokeNode} attached to it.
65+
*/
66+
private Set<Method> jsOverridden;
67+
68+
@Override
69+
public void afterRegistration(AfterRegistrationAccess access) {
70+
FeatureImpl.AfterRegistrationAccessImpl accessImpl = (FeatureImpl.AfterRegistrationAccessImpl) access;
71+
ImageClassLoader imageClassLoader = accessImpl.getImageClassLoader();
72+
jsOverridden = ReflectUtil.findBaseMethodsOfJSAnnotated(imageClassLoader);
73+
}
74+
75+
@Override
76+
public void registerGraphBuilderPlugins(Providers providers, GraphBuilderConfiguration.Plugins plugins, ParsingReason reason) {
77+
plugins.appendNodePlugin(new NodePlugin() {
78+
@Override
79+
public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
80+
if (canBeJavaScriptCall((AnalysisMethod) method)) {
81+
InterceptJSInvokeNode intercept = b.append(new InterceptJSInvokeNode(method, b.bci()));
82+
for (final ValueNode arg : args) {
83+
intercept.arguments().add(arg);
84+
}
85+
}
86+
return false;
87+
}
88+
89+
private boolean canBeJavaScriptCall(AnalysisMethod method) {
90+
Executable executable;
91+
try {
92+
executable = method.getJavaMethod();
93+
} catch (Throwable e) {
94+
// Either a substituted method, or a method with a malformed bytecode signature.
95+
// This is most likely not a JS-annotated method.
96+
return false;
97+
}
98+
if (executable instanceof Method) {
99+
return jsOverridden.contains(executable);
100+
}
101+
// Not a normal method (constructor).
102+
return false;
103+
}
104+
105+
});
106+
}
107+
108+
@Override
109+
public void afterAnalysis(AfterAnalysisAccess access) {
110+
jsOverridden = null;
111+
}
112+
}

0 commit comments

Comments
 (0)