Skip to content

Commit addce59

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 359783c commit addce59

File tree

11 files changed

+519
-40
lines changed

11 files changed

+519
-40
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/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;
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 = RuntimeClassLoading.WithRuntimeClassLoading.class)//
56+
public Object 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;
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 = RuntimeClassLoading.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 = RuntimeClassLoading.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;
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 = RuntimeClassLoading.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 = RuntimeClassLoading.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: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
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.crema.CremaSupport;
4851
import com.oracle.svm.core.invoke.MethodHandleUtils;
4952
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
5053
import com.oracle.svm.core.reflect.SubstrateAccessor;
@@ -83,6 +86,17 @@ final class Target_java_lang_invoke_MethodHandle {
8386
/* All MethodHandle.invoke* methods funnel through here. */
8487
@Substitute(polymorphicSignature = true)
8588
Object invokeBasic(Object... args) throws Throwable {
89+
if (RuntimeClassLoading.isSupported()) {
90+
Target_java_lang_invoke_LambdaForm form = internalForm();
91+
Target_java_lang_invoke_MemberName vmentry = form.vmentry;
92+
if (vmentry == null) {
93+
// if the form comes from the image, its entry might have been reset
94+
form.prepare();
95+
vmentry = form.vmentry;
96+
assert vmentry != null;
97+
}
98+
return CremaSupport.singleton().invokeBasic(vmentry, this, args);
99+
}
86100
Target_java_lang_invoke_MemberName memberName = internalMemberName();
87101
Object ret;
88102
if (memberName != null) {
@@ -125,21 +139,33 @@ Object invokeExact(Object... args) throws Throwable {
125139

126140
@Substitute(polymorphicSignature = true)
127141
static Object linkToVirtual(Object... args) throws Throwable {
142+
if (RuntimeClassLoading.isSupported()) {
143+
return CremaSupport.singleton().linkToVirtual(args);
144+
}
128145
return Util_java_lang_invoke_MethodHandle.linkTo(args);
129146
}
130147

131148
@Substitute(polymorphicSignature = true)
132149
static Object linkToStatic(Object... args) throws Throwable {
150+
if (RuntimeClassLoading.isSupported()) {
151+
return CremaSupport.singleton().linkToStatic(args);
152+
}
133153
return Util_java_lang_invoke_MethodHandle.linkTo(args);
134154
}
135155

136156
@Substitute(polymorphicSignature = true)
137157
static Object linkToInterface(Object... args) throws Throwable {
158+
if (RuntimeClassLoading.isSupported()) {
159+
return CremaSupport.singleton().linkToInterface(args);
160+
}
138161
return Util_java_lang_invoke_MethodHandle.linkTo(args);
139162
}
140163

141164
@Substitute(polymorphicSignature = true)
142165
static Object linkToSpecial(Object... args) throws Throwable {
166+
if (RuntimeClassLoading.isSupported()) {
167+
return CremaSupport.singleton().linkToSpecial(args);
168+
}
143169
return Util_java_lang_invoke_MethodHandle.linkTo(args);
144170
}
145171

@@ -153,6 +179,7 @@ static Object linkToNative(Object... args) throws Throwable {
153179
}
154180

155181
@Substitute
182+
@TargetElement(onlyWith = RuntimeClassLoading.NoRuntimeClassLoading.class)
156183
void maybeCustomize() {
157184
/*
158185
* JDK 8 update 60 added an additional customization possibility for method handles. For all
@@ -161,6 +188,7 @@ void maybeCustomize() {
161188
}
162189

163190
@Delete
191+
@TargetElement(onlyWith = RuntimeClassLoading.NoRuntimeClassLoading.class)
164192
native void customize();
165193
}
166194

@@ -173,6 +201,11 @@ static Object linkTo(Object... args) throws Throwable {
173201
}
174202

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

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

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,12 @@
4545
import com.oracle.svm.core.annotate.Alias;
4646
import com.oracle.svm.core.annotate.AnnotateOriginal;
4747
import com.oracle.svm.core.annotate.Delete;
48-
import com.oracle.svm.core.annotate.RecomputeFieldValue;
49-
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
5048
import com.oracle.svm.core.annotate.Substitute;
5149
import com.oracle.svm.core.annotate.TargetClass;
5250
import com.oracle.svm.core.annotate.TargetElement;
5351
import com.oracle.svm.core.hub.DynamicHub;
5452
import com.oracle.svm.core.hub.RuntimeClassLoading;
53+
import com.oracle.svm.core.hub.crema.CremaSupport;
5554
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
5655
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
5756
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
@@ -61,6 +60,7 @@
6160
import com.oracle.svm.util.ReflectionUtil;
6261

6362
import jdk.graal.compiler.debug.GraalError;
63+
import jdk.vm.ci.meta.ResolvedJavaField;
6464
import sun.invoke.util.VerifyAccess;
6565

6666
/**
@@ -127,7 +127,7 @@ private static void expand(Target_java_lang_invoke_MemberName self) {
127127

128128
@Substitute
129129
private static long objectFieldOffset(Target_java_lang_invoke_MemberName self) {
130-
if (self.reflectAccess == null && self.intrinsic == null) {
130+
if (self.reflectAccess == null && self.intrinsic == null && self.resolved == null) {
131131
throw new InternalError("Unresolved field");
132132
}
133133
if (!self.isField() || self.isStatic()) {
@@ -138,12 +138,15 @@ private static long objectFieldOffset(Target_java_lang_invoke_MemberName self) {
138138
if (self.intrinsic != null) {
139139
return -1L;
140140
}
141+
if (RuntimeClassLoading.isSupported() && self.resolved != null) {
142+
return ((ResolvedJavaField) self.resolved).getOffset();
143+
}
141144
return UnsafeFieldUtil.getFieldOffset(SubstrateUtil.cast(self.reflectAccess, Target_java_lang_reflect_Field.class));
142145
}
143146

144147
@Substitute
145148
private static long staticFieldOffset(Target_java_lang_invoke_MemberName self) {
146-
if (self.reflectAccess == null && self.intrinsic == null) {
149+
if (self.reflectAccess == null && self.intrinsic == null && self.resolved == null) {
147150
throw new InternalError("Unresolved field");
148151
}
149152
if (!self.isField() || !self.isStatic()) {
@@ -153,17 +156,23 @@ private static long staticFieldOffset(Target_java_lang_invoke_MemberName self) {
153156
if (self.intrinsic != null) {
154157
return -1L;
155158
}
159+
if (RuntimeClassLoading.isSupported() && self.resolved != null) {
160+
return ((ResolvedJavaField) self.resolved).getOffset();
161+
}
156162
return UnsafeFieldUtil.getFieldOffset(SubstrateUtil.cast(self.reflectAccess, Target_java_lang_reflect_Field.class));
157163
}
158164

159165
@Substitute
160166
private static Object staticFieldBase(Target_java_lang_invoke_MemberName self) {
161-
if (self.reflectAccess == null) {
167+
if (self.reflectAccess == null && self.resolved == null) {
162168
throw new InternalError("Unresolved field");
163169
}
164170
if (!self.isField() || !self.isStatic()) {
165171
throw new InternalError("Static field required");
166172
}
173+
if (RuntimeClassLoading.isSupported() && self.resolved != null) {
174+
return CremaSupport.singleton().getStaticStorage((ResolvedJavaField) self.resolved);
175+
}
167176
Field field = (Field) self.reflectAccess;
168177
int layerNumber;
169178
if (ImageLayerBuildingSupport.buildingImageLayer()) {
@@ -209,7 +218,7 @@ public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke
209218
throws LinkageError, ClassNotFoundException {
210219
Class<?> declaringClass = self.getDeclaringClass();
211220
Target_java_lang_invoke_MemberName resolved = Util_java_lang_invoke_MethodHandleNatives.resolve(self, caller, speculativeResolve);
212-
assert resolved == null || resolved.reflectAccess != null || resolved.intrinsic != null;
221+
assert resolved == null || resolved.reflectAccess != null || resolved.intrinsic != null || resolved.resolved != null;
213222
if (resolved != null && resolved.reflectAccess != null && caller != null &&
214223
!Util_java_lang_invoke_MethodHandleNatives.verifyAccess(declaringClass, resolved.reflectAccess.getDeclaringClass(), resolved.reflectAccess.getModifiers(), caller,
215224
lookupMode)) {
@@ -317,14 +326,24 @@ private static void forceAccess(AccessibleObject target) {
317326

318327
@SuppressWarnings("unused")
319328
public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class<?> caller, boolean speculativeResolve)
320-
throws LinkageError, ClassNotFoundException {
321-
if (self.reflectAccess != null || self.intrinsic != null) {
322-
return self;
323-
}
329+
throws LinkageError {
324330
Class<?> declaringClass = self.getDeclaringClass();
325331
if (declaringClass == null) {
326332
return null;
327333
}
334+
if (RuntimeClassLoading.isSupported()) {
335+
try {
336+
return CremaSupport.singleton().resolveMemberName(self, caller);
337+
} catch (Throwable t) {
338+
if (speculativeResolve) {
339+
return null;
340+
}
341+
throw t;
342+
}
343+
}
344+
if (self.reflectAccess != null || self.intrinsic != null) {
345+
return self;
346+
}
328347

329348
/* Intrinsic methods */
330349
self.intrinsic = MethodHandleIntrinsicImpl.resolve(self);
@@ -397,30 +416,3 @@ static boolean verifyAccess(Class<?> refc, Class<?> defc, int mods, Class<?> loo
397416
}
398417
}
399418
}
400-
401-
@TargetClass(className = "java.lang.invoke.MethodHandleNatives", innerClass = "Constants")
402-
final class Target_java_lang_invoke_MethodHandleNatives_Constants {
403-
// Checkstyle: stop
404-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_IS_METHOD;
405-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_IS_CONSTRUCTOR;
406-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_IS_FIELD;
407-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_IS_TYPE;
408-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_CALLER_SENSITIVE;
409-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static int MN_REFERENCE_KIND_SHIFT;
410-
411-
/**
412-
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.
413-
*/
414-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_NONE; // null
415-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_getField;
416-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_getStatic;
417-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_putField;
418-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_putStatic;
419-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_invokeVirtual;
420-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_invokeStatic;
421-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_invokeSpecial;
422-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_newInvokeSpecial;
423-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_invokeInterface;
424-
@Alias @RecomputeFieldValue(isFinal = true, kind = Kind.None) static byte REF_LIMIT;
425-
// Checkstyle: resume
426-
}

0 commit comments

Comments
 (0)