Skip to content

Commit 3999122

Browse files
[GR-70201] [GR-68576] Crema: Add support for invokedynamic.
PullRequest: graal/22357
2 parents 98cca29 + 32ae962 commit 3999122

File tree

40 files changed

+1669
-198
lines changed

40 files changed

+1669
-198
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/crema/CremaSupport.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,15 @@
3232

3333
import com.oracle.svm.core.hub.DynamicHub;
3434
import com.oracle.svm.core.hub.registry.SymbolsSupport;
35+
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
3536
import com.oracle.svm.espresso.classfile.ParserKlass;
3637
import com.oracle.svm.espresso.classfile.descriptors.ByteSequence;
38+
import com.oracle.svm.espresso.classfile.descriptors.Signature;
3739
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
3840
import com.oracle.svm.espresso.classfile.descriptors.Type;
3941

4042
import jdk.vm.ci.meta.JavaType;
43+
import jdk.vm.ci.meta.ResolvedJavaField;
4144
import jdk.vm.ci.meta.ResolvedJavaMethod;
4245
import jdk.vm.ci.meta.ResolvedJavaType;
4346

@@ -47,6 +50,20 @@ public interface CremaSupport {
4750

4851
int getAfterFieldsOffset(DynamicHub hub);
4952

53+
Target_java_lang_invoke_MemberName resolveMemberName(Target_java_lang_invoke_MemberName mn, Class<?> caller);
54+
55+
Object invokeBasic(Target_java_lang_invoke_MemberName memberName, Object methodHandle, Object[] args);
56+
57+
Object linkToVirtual(Object[] args);
58+
59+
Object linkToStatic(Object[] args);
60+
61+
Object linkToSpecial(Object[] args);
62+
63+
Object linkToInterface(Object[] args);
64+
65+
Object getStaticStorage(ResolvedJavaField resolved);
66+
5067
interface CremaDispatchTable {
5168
int vtableLength();
5269

@@ -97,6 +114,8 @@ default Class<?> findLoadedClass(JavaType unresolvedJavaType, ResolvedJavaType a
97114

98115
Object getStaticStorage(Class<?> cls, boolean primitives, int layerNum);
99116

117+
ResolvedJavaMethod findMethodHandleIntrinsic(ResolvedJavaMethod signaturePolymorphicMethod, Symbol<Signature> signature);
118+
100119
static CremaSupport singleton() {
101120
return ImageSingletons.lookup(CremaSupport.class);
102121
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/registry/AbstractRuntimeClassRegistry.java

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,20 +175,17 @@ private static boolean isParallelClassLoader(ClassLoader loader) {
175175
protected abstract boolean loaderIsBootOrPlatform();
176176

177177
public final Class<?> defineClass(Symbol<Type> typeOrNull, byte[] b, int off, int len, ClassDefinitionInfo info) {
178-
if (isParallelClassLoader()) {
178+
// GR-62338: for parallel class loaders this synchronization should be skipped.
179+
Object syncObject = getClassLoader();
180+
if (syncObject == null) {
181+
syncObject = this;
182+
}
183+
synchronized (syncObject) {
179184
return defineClassInner(typeOrNull, b, off, len, info);
180-
} else {
181-
synchronized (getClassLoader()) {
182-
return defineClassInner(typeOrNull, b, off, len, info);
183-
}
184185
}
185186
}
186187

187188
private Class<?> defineClassInner(Symbol<Type> typeOrNull, byte[] b, int off, int len, ClassDefinitionInfo info) {
188-
if (isParallelClassLoader() || getClassLoader() == null) {
189-
// GR-62338
190-
throw VMError.unimplemented("Parallel class loading:" + getClassLoader());
191-
}
192189
byte[] data = b;
193190
if (off != 0 || b.length != len) {
194191
if (len < 0) {
@@ -201,7 +198,7 @@ private Class<?> defineClassInner(Symbol<Type> typeOrNull, byte[] b, int off, in
201198
}
202199
ParserKlass parsed = parseClass(typeOrNull, info, data);
203200
Symbol<Type> type = typeOrNull == null ? parsed.getType() : typeOrNull;
204-
assert typeOrNull == null || type == parsed.getType();
201+
assert typeOrNull == null || type == parsed.getType() : typeOrNull + " vs. " + parsed.getType();
205202
if (info.addedToRegistry() && findLoadedClass(type) != null) {
206203
String kind;
207204
if (Modifier.isInterface(parsed.getFlags())) {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/interpreter/InterpreterSupport.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,14 @@ public static InterpreterSupport singleton() {
6464
return ImageSingletons.lookup(InterpreterSupport.class);
6565
}
6666

67-
/*
68-
* Check if a given argument matches the inner class Interpreter.Root (holder of the interpreter
69-
* dispatch loop).
67+
/**
68+
* Check if a given frame should be processed by {@link #getInterpretedMethodFrameInfo}.
7069
*/
71-
public abstract boolean isInterpreterRoot(Class<?> clazz);
70+
public abstract boolean isInterpreterRoot(FrameInfoQueryResult frameInfo);
7271

7372
/**
74-
* Transforms an interpreter (root) frame into a frame of the interpreted method. The passed
75-
* frame must be an interpreter root e.g. {@code isInterpreterRoot(frameInfo.getSourceClass())}
76-
* otherwise a fatal exception is thrown.
73+
* Transforms an interpreter (root) frame into a frame of the interpreted method. An error is
74+
* thrown if the passed frame is not an {@link #isInterpreterRoot interpreter root}.
7775
*
7876
* @param frameInfo interpreter root frame
7977
* @param sp stack pointer of the interpreter frame

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/invoke/MethodHandleUtils.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.lang.invoke.MethodHandle;
3030

3131
import com.oracle.svm.core.AlwaysInline;
32+
import com.oracle.svm.core.hub.RuntimeClassLoading;
3233

3334
import sun.invoke.util.Wrapper;
3435

@@ -127,4 +128,15 @@ public static short shortUnbox(Object retVal, Class<?> returnType) {
127128
throw shouldNotReachHere("Unexpected type for unbox function");
128129
}
129130
}
131+
132+
/**
133+
* Returns the resolved member if runtime class loading is enabled. Otherwise, always returns
134+
* {@code null}.
135+
*/
136+
public static ResolvedMember getResolvedMember(Target_java_lang_invoke_MemberName memberName) {
137+
if (RuntimeClassLoading.isSupported()) {
138+
return memberName.resolved;
139+
}
140+
return null;
141+
}
130142
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
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+
package com.oracle.svm.core.invoke;
26+
27+
/**
28+
* This interface should be implemented by the possible resolution results of member names.
29+
*
30+
* @see Target_java_lang_invoke_MemberName#resolved
31+
*/
32+
public interface ResolvedMember {
33+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/invoke/Target_java_lang_invoke_MemberName.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3535
import com.oracle.svm.core.annotate.Substitute;
3636
import com.oracle.svm.core.annotate.TargetClass;
37+
import com.oracle.svm.core.annotate.TargetElement;
38+
import com.oracle.svm.core.hub.RuntimeClassLoading.WithRuntimeClassLoading;
3739
import com.oracle.svm.core.methodhandles.Target_java_lang_invoke_MethodHandleNatives;
3840
import com.oracle.svm.core.util.BasedOnJDKFile;
3941
import com.oracle.svm.core.util.VMError;
@@ -46,7 +48,16 @@ public final class Target_java_lang_invoke_MemberName {
4648
@Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)//
4749
public MethodHandleIntrinsic intrinsic;
4850

51+
/**
52+
* This is used by crema to store metadata for the resolved field or method.
53+
*/
54+
@Inject @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)//
55+
@TargetElement(onlyWith = WithRuntimeClassLoading.class)//
56+
public ResolvedMember resolved;
57+
58+
@Alias public Class<?> clazz;
4959
@Alias public String name;
60+
@Alias public Object type;
5061
@Alias public int flags;
5162
@Alias public Object resolution;
5263

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_ClassLoader.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ private static Class<?> defineClass0(ClassLoader loader, Class<?> lookup, String
353353
@SuppressWarnings("unused") boolean initialize, int flags, Object classData) {
354354
// Note that if name is not null, it is a binary name in either / or .-form
355355
String actualName = name;
356-
if (LambdaUtils.isLambdaClassName(name)) {
356+
assert !(PredefinedClassesSupport.hasBytecodeClasses() && RuntimeClassLoading.isSupported());
357+
if (!RuntimeClassLoading.isSupported() && LambdaUtils.isLambdaClassName(name)) {
357358
actualName += Digest.digest(b);
358359
}
359360
boolean isNestMate = (flags & ClassLoaderHelper.NESTMATE_CLASS) != 0;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2020, 2020, 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+
package com.oracle.svm.core.methodhandles;
26+
27+
import java.lang.invoke.MethodHandle;
28+
29+
import com.oracle.svm.core.SubstrateUtil;
30+
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
31+
32+
public final class MethodHandleInterpreterUtils {
33+
private MethodHandleInterpreterUtils() {
34+
}
35+
36+
public static Target_java_lang_invoke_MemberName extractVMEntry(MethodHandle handle) {
37+
Target_java_lang_invoke_LambdaForm lform = SubstrateUtil.cast(handle, Target_java_lang_invoke_MethodHandle.class).internalForm();
38+
return lform.vmentry;
39+
}
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
package com.oracle.svm.core.methodhandles;
26+
27+
import static com.oracle.svm.core.util.VMError.unsupportedFeature;
28+
29+
import java.lang.invoke.MethodHandle;
30+
import java.lang.invoke.MethodHandles;
31+
32+
import com.oracle.svm.core.annotate.Substitute;
33+
import com.oracle.svm.core.annotate.TargetClass;
34+
import com.oracle.svm.core.hub.RuntimeClassLoading.WithRuntimeClassLoading;
35+
import com.oracle.svm.core.util.BasedOnJDKFile;
36+
37+
/**
38+
* This is used in a special case of {@code BootstrapMethodInvoker.invoke} (See
39+
* {@code @BasedOnJDKFile} annotation on this class) which is not currently used in SVM.
40+
* <p>
41+
* These substitutions cut paths that would lead to useless code being included and some deleted
42+
* methods being reached.
43+
*/
44+
@TargetClass(className = "java.lang.invoke.BootstrapMethodInvoker", innerClass = "VM_BSCI", onlyWith = WithRuntimeClassLoading.class)
45+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+36/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java#L113-L126")
46+
final class Target_java_lang_invoke_BootstrapMethodInvoker_VM_BSCI {
47+
@Substitute
48+
@SuppressWarnings("unused")
49+
Target_java_lang_invoke_BootstrapMethodInvoker_VM_BSCI(MethodHandle bsm, String name, Object type, MethodHandles.Lookup lookup, int[] indexInfo) {
50+
throw unsupportedFeature("BootstrapMethodInvoker$VM_BSCI");
51+
}
52+
53+
@Substitute
54+
@SuppressWarnings({"unused", "static-method"})
55+
Object fillCache(int i) {
56+
throw unsupportedFeature("BootstrapMethodInvoker$VM_BSCI.fillCache");
57+
}
58+
59+
@Substitute
60+
@SuppressWarnings({"unused", "static-method"})
61+
public int copyConstants(int start, int end, Object[] buf, int pos) {
62+
throw unsupportedFeature("BootstrapMethodInvoker$VM_BSCI.copyConstants");
63+
}
64+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_BoundMethodHandle.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.oracle.svm.core.annotate.TargetClass;
3939
import com.oracle.svm.core.annotate.TargetElement;
4040
import com.oracle.svm.core.fieldvaluetransformer.NewEmptyArrayFieldValueTransformer;
41+
import com.oracle.svm.core.hub.RuntimeClassLoading.NoRuntimeClassLoading;
4142

4243
/**
4344
* In the JDK implementation of method handles, each bound method handle is an instance of a
@@ -73,7 +74,7 @@ final class Target_java_lang_invoke_BoundMethodHandle {
7374
* We hijack the species with no bound parameters for our implementation since it already inherits
7475
* from BoundMethodHandle and doesn't contain any superfluous members.
7576
*/
76-
@TargetClass(className = "java.lang.invoke.SimpleMethodHandle")
77+
@TargetClass(className = "java.lang.invoke.SimpleMethodHandle", onlyWith = NoRuntimeClassLoading.class)
7778
final class Target_java_lang_invoke_SimpleMethodHandle {
7879
/*
7980
* Since we represent all the bound method handle species with the basic one, the species data
@@ -130,7 +131,7 @@ Target_java_lang_invoke_BoundMethodHandle copyWith(MethodType type, Target_java_
130131
}
131132

132133
/* Hardcoded species, needs a special case to avoid initialization */
133-
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", innerClass = "Species_L")
134+
@TargetClass(className = "java.lang.invoke.BoundMethodHandle", innerClass = "Species_L", onlyWith = NoRuntimeClassLoading.class)
134135
final class Target_java_lang_invoke_BoundMethodHandle_Species_L {
135136
@Substitute
136137
static Target_java_lang_invoke_BoundMethodHandle make(MethodType mt, Target_java_lang_invoke_LambdaForm lf, Object argL0) {

0 commit comments

Comments
 (0)