Skip to content

Commit 21ba056

Browse files
When enabled, let crema handle MethodHandle, MemberName, & LambdaForm
In that mode re-enable a number of JDK code path that are usually substituted.
1 parent ca98011 commit 21ba056

File tree

14 files changed

+571
-42
lines changed

14 files changed

+571
-42
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +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;
3738
import com.oracle.svm.espresso.classfile.descriptors.Signature;
3839
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
3940
import com.oracle.svm.espresso.classfile.descriptors.Type;
4041

4142
import jdk.vm.ci.meta.JavaType;
43+
import jdk.vm.ci.meta.ResolvedJavaField;
4244
import jdk.vm.ci.meta.ResolvedJavaMethod;
4345
import jdk.vm.ci.meta.ResolvedJavaType;
4446

@@ -48,6 +50,20 @@ public interface CremaSupport {
4850

4951
int getAfterFieldsOffset(DynamicHub hub);
5052

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+
5167
interface CremaDispatchTable {
5268
int vtableLength();
5369

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/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) {

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3131
import com.oracle.svm.core.annotate.Substitute;
3232
import com.oracle.svm.core.annotate.TargetClass;
33+
import com.oracle.svm.core.annotate.TargetElement;
34+
import com.oracle.svm.core.hub.RuntimeClassLoading.NoRuntimeClassLoading;
3335
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
3436
import com.oracle.svm.util.ReflectionUtil;
3537

@@ -42,10 +44,18 @@ public final class Target_java_lang_invoke_LambdaForm {
4244
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = LambdaFormCacheTransformer.class)//
4345
volatile Object transformCache;
4446

47+
// isCompiled needs to be reset if vmentry is reset
48+
@Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Reset)//
49+
boolean isCompiled;
50+
4551
@Alias
4652
native String lambdaName();
4753

54+
@Alias
55+
native void prepare();
56+
4857
@Substitute
58+
@TargetElement(onlyWith = NoRuntimeClassLoading.class)
4959
void compileToBytecode() {
5060
/*
5161
* Those lambda form types are required to be precompiled to bytecode during method handles
@@ -62,6 +72,7 @@ void compileToBytecode() {
6272
*/
6373
@Substitute
6474
@SuppressWarnings("static-method")
75+
@TargetElement(onlyWith = NoRuntimeClassLoading.class)
6576
private boolean forceInterpretation() {
6677
return true;
6778
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,11 @@
4444
import com.oracle.svm.core.annotate.RecomputeFieldValue;
4545
import com.oracle.svm.core.annotate.Substitute;
4646
import com.oracle.svm.core.annotate.TargetClass;
47+
import com.oracle.svm.core.annotate.TargetElement;
4748
import com.oracle.svm.core.classinitialization.EnsureClassInitializedNode;
49+
import com.oracle.svm.core.hub.RuntimeClassLoading;
50+
import com.oracle.svm.core.hub.RuntimeClassLoading.NoRuntimeClassLoading;
51+
import com.oracle.svm.core.hub.crema.CremaSupport;
4852
import com.oracle.svm.core.invoke.MethodHandleUtils;
4953
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
5054
import com.oracle.svm.core.reflect.SubstrateAccessor;
@@ -83,6 +87,17 @@ final class Target_java_lang_invoke_MethodHandle {
8387
/* All MethodHandle.invoke* methods funnel through here. */
8488
@Substitute(polymorphicSignature = true)
8589
Object invokeBasic(Object... args) throws Throwable {
90+
if (RuntimeClassLoading.isSupported()) {
91+
Target_java_lang_invoke_LambdaForm form = internalForm();
92+
Target_java_lang_invoke_MemberName vmentry = form.vmentry;
93+
if (vmentry == null) {
94+
// if the form comes from the image, its entry might have been reset
95+
form.prepare();
96+
vmentry = form.vmentry;
97+
assert vmentry != null;
98+
}
99+
return CremaSupport.singleton().invokeBasic(vmentry, this, args);
100+
}
86101
Target_java_lang_invoke_MemberName memberName = internalMemberName();
87102
Object ret;
88103
if (memberName != null) {
@@ -125,21 +140,33 @@ Object invokeExact(Object... args) throws Throwable {
125140

126141
@Substitute(polymorphicSignature = true)
127142
static Object linkToVirtual(Object... args) throws Throwable {
143+
if (RuntimeClassLoading.isSupported()) {
144+
return CremaSupport.singleton().linkToVirtual(args);
145+
}
128146
return Util_java_lang_invoke_MethodHandle.linkTo(args);
129147
}
130148

131149
@Substitute(polymorphicSignature = true)
132150
static Object linkToStatic(Object... args) throws Throwable {
151+
if (RuntimeClassLoading.isSupported()) {
152+
return CremaSupport.singleton().linkToStatic(args);
153+
}
133154
return Util_java_lang_invoke_MethodHandle.linkTo(args);
134155
}
135156

136157
@Substitute(polymorphicSignature = true)
137158
static Object linkToInterface(Object... args) throws Throwable {
159+
if (RuntimeClassLoading.isSupported()) {
160+
return CremaSupport.singleton().linkToInterface(args);
161+
}
138162
return Util_java_lang_invoke_MethodHandle.linkTo(args);
139163
}
140164

141165
@Substitute(polymorphicSignature = true)
142166
static Object linkToSpecial(Object... args) throws Throwable {
167+
if (RuntimeClassLoading.isSupported()) {
168+
return CremaSupport.singleton().linkToSpecial(args);
169+
}
143170
return Util_java_lang_invoke_MethodHandle.linkTo(args);
144171
}
145172

@@ -153,6 +180,7 @@ static Object linkToNative(Object... args) throws Throwable {
153180
}
154181

155182
@Substitute
183+
@TargetElement(onlyWith = NoRuntimeClassLoading.class)
156184
void maybeCustomize() {
157185
/*
158186
* JDK 8 update 60 added an additional customization possibility for method handles. For all
@@ -161,6 +189,7 @@ void maybeCustomize() {
161189
}
162190

163191
@Delete
192+
@TargetElement(onlyWith = NoRuntimeClassLoading.class)
164193
native void customize();
165194
}
166195

@@ -173,6 +202,11 @@ static Object linkTo(Object... args) throws Throwable {
173202
}
174203

175204
static Object invokeInternal(Target_java_lang_invoke_MemberName memberName, MethodType methodType, Object... args) throws Throwable {
205+
/*
206+
* This is never reached in the "crema" case since invokeBasic & linkTo* are instead
207+
* redirected to CremaSupport.
208+
*/
209+
assert !RuntimeClassLoading.isSupported();
176210
/*
177211
* The method handle may have been resolved at build time. If that is the case, the
178212
* SVM-specific information needed to perform the invoke is not stored in the handle yet, so

0 commit comments

Comments
 (0)