Skip to content

Commit 2134cd2

Browse files
[GR-60111] Support MethodHandle & MethodType entries in crema constant pool.
PullRequest: graal/22255
2 parents 7c5b89a + a4bdaca commit 2134cd2

File tree

15 files changed

+370
-89
lines changed

15 files changed

+370
-89
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/RuntimeClassLoading.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@
2727
import static jdk.graal.compiler.options.OptionStability.EXPERIMENTAL;
2828

2929
import java.security.ProtectionDomain;
30+
import java.util.function.BooleanSupplier;
3031

3132
import org.graalvm.collections.EconomicMap;
33+
import org.graalvm.nativeimage.Platform;
34+
import org.graalvm.nativeimage.Platforms;
3235

3336
import com.oracle.svm.core.SubstrateOptions;
3437
import com.oracle.svm.core.hub.crema.CremaSupport;
@@ -122,6 +125,22 @@ public static boolean isSupported() {
122125
return Options.RuntimeClassLoading.getValue();
123126
}
124127

128+
@Platforms(Platform.HOSTED_ONLY.class)
129+
public static final class NoRuntimeClassLoading implements BooleanSupplier {
130+
@Override
131+
public boolean getAsBoolean() {
132+
return !isSupported();
133+
}
134+
}
135+
136+
@Platforms(Platform.HOSTED_ONLY.class)
137+
public static final class WithRuntimeClassLoading implements BooleanSupplier {
138+
@Override
139+
public boolean getAsBoolean() {
140+
return isSupported();
141+
}
142+
}
143+
125144
public static Class<?> defineClass(ClassLoader loader, String expectedName, byte[] b, int off, int len, ClassDefinitionInfo info) {
126145
if (PredefinedClassesSupport.hasBytecodeClasses()) {
127146
Class<?> knownClass = PredefinedClassesSupport.knownClass(b, off, len);

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

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@
3131
import org.graalvm.nativeimage.Platforms;
3232

3333
import com.oracle.svm.core.hub.DynamicHub;
34+
import com.oracle.svm.core.hub.registry.SymbolsSupport;
3435
import com.oracle.svm.espresso.classfile.ParserKlass;
36+
import com.oracle.svm.espresso.classfile.descriptors.ByteSequence;
37+
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
38+
import com.oracle.svm.espresso.classfile.descriptors.Type;
3539

3640
import jdk.vm.ci.meta.JavaType;
3741
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -57,17 +61,39 @@ interface CremaDispatchTable {
5761

5862
void fillDynamicHubInfo(DynamicHub hub, CremaDispatchTable table, List<Class<?>> transitiveSuperInterfaces, int[] interfaceIndices);
5963

60-
Object newInstance(ResolvedJavaMethod targetMethod, Object[] args);
64+
/**
65+
* Creates a new instance of {@code type} without running any constructor yet. The caller should
66+
* make sure to run a constructor before publishing the result.
67+
*/
68+
Object rawNewInstance(ResolvedJavaType type);
6169

6270
Object execute(ResolvedJavaMethod targetMethod, Object[] args);
6371

6472
Class<?> toClass(ResolvedJavaType resolvedJavaType);
6573

66-
Class<?> resolveOrThrow(JavaType unresolvedJavaType, ResolvedJavaType accessingClass);
74+
default Class<?> resolveOrThrow(JavaType unresolvedJavaType, ResolvedJavaType accessingClass) {
75+
ByteSequence type = ByteSequence.create(unresolvedJavaType.getName());
76+
Symbol<Type> symbolicType = SymbolsSupport.getTypes().getOrCreateValidType(type);
77+
return resolveOrThrow(symbolicType, accessingClass);
78+
}
79+
80+
Class<?> resolveOrThrow(Symbol<Type> type, ResolvedJavaType accessingClass);
81+
82+
default Class<?> resolveOrNull(JavaType unresolvedJavaType, ResolvedJavaType accessingClass) {
83+
ByteSequence type = ByteSequence.create(unresolvedJavaType.getName());
84+
Symbol<Type> symbolicType = SymbolsSupport.getTypes().getOrCreateValidType(type);
85+
return resolveOrNull(symbolicType, accessingClass);
86+
}
87+
88+
Class<?> resolveOrNull(Symbol<Type> type, ResolvedJavaType accessingClass);
6789

68-
Class<?> resolveOrNull(JavaType unresolvedJavaType, ResolvedJavaType accessingClass);
90+
default Class<?> findLoadedClass(JavaType unresolvedJavaType, ResolvedJavaType accessingClass) {
91+
ByteSequence type = ByteSequence.create(unresolvedJavaType.getName());
92+
Symbol<Type> symbolicType = SymbolsSupport.getTypes().getOrCreateValidType(type);
93+
return findLoadedClass(symbolicType, accessingClass);
94+
}
6995

70-
Class<?> findLoadedClass(JavaType unresolvedJavaType, ResolvedJavaType accessingClass);
96+
Class<?> findLoadedClass(Symbol<Type> type, ResolvedJavaType accessingClass);
7197

7298
Object getStaticStorage(Class<?> cls, boolean primitives, int layerNum);
7399

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public static void ensureInitialized() {
4747

4848
public static final class SVMTypes {
4949
public static final Symbol<Type> com_oracle_svm_core_hub_Hybrid = SYMBOLS.putType("Lcom/oracle/svm/core/hub/Hybrid;");
50+
public static final Symbol<Type> java_lang_Throwable = SYMBOLS.putType("Ljava/lang/Throwable;");
5051

5152
private SVMTypes() {
5253
}

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import java.lang.invoke.CallSite;
3131
import java.lang.invoke.MethodHandle;
32+
import java.lang.invoke.MethodType;
3233
import java.lang.reflect.AccessibleObject;
3334
import java.lang.reflect.Constructor;
3435
import java.lang.reflect.Field;
@@ -48,7 +49,9 @@
4849
import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind;
4950
import com.oracle.svm.core.annotate.Substitute;
5051
import com.oracle.svm.core.annotate.TargetClass;
52+
import com.oracle.svm.core.annotate.TargetElement;
5153
import com.oracle.svm.core.hub.DynamicHub;
54+
import com.oracle.svm.core.hub.RuntimeClassLoading;
5255
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
5356
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
5457
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
@@ -215,8 +218,17 @@ public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke
215218
return resolved;
216219
}
217220

221+
@Alias
222+
@TargetElement(onlyWith = RuntimeClassLoading.WithRuntimeClassLoading.class)
223+
public static native MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes);
224+
218225
@Delete
219-
static native MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind, Class<?> defc, String name, Object type);
226+
@TargetElement(onlyWith = RuntimeClassLoading.NoRuntimeClassLoading.class, name = "linkMethodHandleConstant")
227+
static native MethodHandle linkMethodHandleConstantDeleted(Class<?> callerClass, int refKind, Class<?> defc, String name, Object type);
228+
229+
@Alias
230+
@TargetElement(onlyWith = RuntimeClassLoading.WithRuntimeClassLoading.class)
231+
public static native MethodHandle linkMethodHandleConstant(Class<?> callerClass, int refKind, Class<?> defc, String name, Object type);
220232
}
221233

222234
/**

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,21 @@
3535
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3636
import com.oracle.svm.core.annotate.Substitute;
3737
import com.oracle.svm.core.annotate.TargetClass;
38+
import com.oracle.svm.core.annotate.TargetElement;
3839
import com.oracle.svm.core.hub.DynamicHub;
40+
import com.oracle.svm.core.hub.RuntimeClassLoading;
3941
import com.oracle.svm.core.invoke.Target_java_lang_invoke_MemberName;
4042

4143
@TargetClass(value = MethodHandles.class, innerClass = "Lookup")
4244
final class Target_java_lang_invoke_MethodHandles_Lookup {
4345
// Checkstyle: stop
4446
@Delete //
47+
@TargetElement(onlyWith = RuntimeClassLoading.NoRuntimeClassLoading.class, name = "LOOKASIDE_TABLE") //
48+
static ConcurrentHashMap<Target_java_lang_invoke_MemberName, MethodHandle> LOOKASIDE_TABLE_DELETED;
49+
50+
@Alias //
51+
@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.NewInstance, declClass = ConcurrentHashMap.class)//
52+
@TargetElement(onlyWith = RuntimeClassLoading.WithRuntimeClassLoading.class) //
4553
static ConcurrentHashMap<Target_java_lang_invoke_MemberName, MethodHandle> LOOKASIDE_TABLE;
4654
// Checkstyle: resume
4755

@@ -87,5 +95,6 @@ private IllegalAccessException makeAccessException(Class<?> targetClass) {
8795
}
8896

8997
@Delete
98+
@TargetElement(onlyWith = RuntimeClassLoading.NoRuntimeClassLoading.class) //
9099
native MethodHandle linkMethodHandleConstant(byte refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException;
91100
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/CremaConstructorAccessor.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@
2424
*/
2525
package com.oracle.svm.core.reflect;
2626

27+
import java.lang.reflect.InvocationTargetException;
28+
2729
import com.oracle.svm.core.hub.crema.CremaSupport;
2830
import com.oracle.svm.core.jdk.InternalVMMethod;
2931

3032
import jdk.internal.reflect.ConstructorAccessor;
3133
import jdk.vm.ci.meta.ResolvedJavaMethod;
3234

33-
import org.graalvm.nativeimage.ImageSingletons;
34-
3535
@InternalVMMethod
3636
public final class CremaConstructorAccessor extends AbstractCremaAccessor implements ConstructorAccessor {
3737

@@ -40,9 +40,19 @@ public CremaConstructorAccessor(ResolvedJavaMethod targetMethod, Class<?> declar
4040
}
4141

4242
@Override
43-
public Object newInstance(Object[] args) {
43+
public Object newInstance(Object[] args) throws InvocationTargetException {
4444
verifyArguments(args);
4545
ensureDeclaringClassInitialized();
46-
return ImageSingletons.lookup(CremaSupport.class).newInstance(targetMethod, args);
46+
47+
Object newReference = CremaSupport.singleton().rawNewInstance(targetMethod.getDeclaringClass());
48+
Object[] finalArgs = new Object[args.length + 1];
49+
finalArgs[0] = newReference;
50+
System.arraycopy(args, 0, finalArgs, 1, args.length);
51+
try {
52+
CremaSupport.singleton().execute(targetMethod, finalArgs);
53+
} catch (Throwable t) {
54+
throw new InvocationTargetException(t);
55+
}
56+
return newReference;
4757
}
4858
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/CremaMethodAccessor.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,15 @@
2424
*/
2525
package com.oracle.svm.core.reflect;
2626

27+
import java.lang.reflect.InvocationTargetException;
28+
2729
import com.oracle.svm.core.hub.crema.CremaSupport;
2830
import com.oracle.svm.core.jdk.InternalVMMethod;
2931
import com.oracle.svm.core.util.VMError;
3032

3133
import jdk.internal.reflect.MethodAccessor;
32-
3334
import jdk.vm.ci.meta.ResolvedJavaMethod;
3435

35-
import java.lang.reflect.InvocationTargetException;
36-
3736
@InternalVMMethod
3837
public final class CremaMethodAccessor extends AbstractCremaAccessor implements MethodAccessor {
3938

@@ -54,7 +53,11 @@ public Object invoke(Object obj, Object[] args) throws IllegalArgumentException,
5453
Object[] finalArgs = new Object[args.length + 1];
5554
finalArgs[0] = obj;
5655
System.arraycopy(args, 0, finalArgs, 1, args.length);
57-
return CremaSupport.singleton().execute(targetMethod, finalArgs);
56+
try {
57+
return CremaSupport.singleton().execute(targetMethod, finalArgs);
58+
} catch (Throwable t) {
59+
throw new InvocationTargetException(t);
60+
}
5861
}
5962

6063
@Override

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaResolvedJavaMethodImpl.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,83 @@
2424
*/
2525
package com.oracle.svm.interpreter.metadata;
2626

27+
import java.lang.invoke.VarHandle;
28+
2729
import com.oracle.svm.core.hub.crema.CremaResolvedJavaMethod;
30+
import com.oracle.svm.core.hub.registry.SVMSymbols;
2831
import com.oracle.svm.core.reflect.CremaConstructorAccessor;
2932
import com.oracle.svm.core.reflect.CremaMethodAccessor;
3033
import com.oracle.svm.core.util.VMError;
34+
import com.oracle.svm.espresso.classfile.ExceptionHandler;
3135
import com.oracle.svm.espresso.classfile.ParserMethod;
36+
import com.oracle.svm.espresso.classfile.attributes.CodeAttribute;
37+
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
38+
import com.oracle.svm.espresso.classfile.descriptors.Type;
3239

3340
import jdk.vm.ci.meta.JavaType;
41+
import jdk.vm.ci.meta.ResolvedJavaType;
3442

3543
public final class CremaResolvedJavaMethodImpl extends InterpreterResolvedJavaMethod implements CremaResolvedJavaMethod {
44+
private final ExceptionHandler[] rawExceptionHandlers;
3645

3746
private CremaResolvedJavaMethodImpl(InterpreterResolvedObjectType declaringClass, ParserMethod parserMethod, int vtableIndex) {
3847
super(declaringClass, parserMethod, vtableIndex);
48+
CodeAttribute codeAttribute = (CodeAttribute) parserMethod.getAttribute(CodeAttribute.NAME);
49+
if (codeAttribute != null) {
50+
this.rawExceptionHandlers = codeAttribute.getExceptionHandlers();
51+
} else {
52+
this.rawExceptionHandlers = null;
53+
}
3954
}
4055

4156
public static InterpreterResolvedJavaMethod create(InterpreterResolvedObjectType declaringClass, ParserMethod m, int vtableIndex) {
4257
return new CremaResolvedJavaMethodImpl(declaringClass, m, vtableIndex);
4358
}
4459

60+
@Override
61+
public jdk.vm.ci.meta.ExceptionHandler[] getExceptionHandlers() {
62+
/*
63+
* GR-70247 The interpreter should primarily use classfile.ExceptionHandler. This would
64+
* avoid having to deal with the JavaType which is not needed during interpretation.
65+
*/
66+
jdk.vm.ci.meta.ExceptionHandler[] result = exceptionHandlers;
67+
if (result == null) {
68+
boolean canCache = true;
69+
if (rawExceptionHandlers == null || rawExceptionHandlers.length == 0) {
70+
result = EMPTY_EXCEPTION_HANDLERS;
71+
} else {
72+
result = new jdk.vm.ci.meta.ExceptionHandler[rawExceptionHandlers.length];
73+
InterpreterConstantPool constantPool = getConstantPool();
74+
for (int i = 0; i < rawExceptionHandlers.length; i++) {
75+
ExceptionHandler exceptionHandler = rawExceptionHandlers[i];
76+
Symbol<Type> catchTypeSymbol = exceptionHandler.getCatchType();
77+
int catchTypeCPI = exceptionHandler.catchTypeCPI();
78+
JavaType catchType;
79+
if (SVMSymbols.SVMTypes.java_lang_Throwable.equals(catchTypeSymbol)) {
80+
catchTypeCPI = 0;
81+
catchType = null;
82+
} else if (catchTypeCPI != 0) {
83+
catchType = constantPool.findClassAt(catchTypeCPI);
84+
canCache = canCache && (catchType instanceof ResolvedJavaType);
85+
} else {
86+
assert catchTypeSymbol == null;
87+
catchType = null;
88+
}
89+
result[i] = new jdk.vm.ci.meta.ExceptionHandler(exceptionHandler.getStartBCI(),
90+
exceptionHandler.getEndBCI(),
91+
exceptionHandler.getHandlerBCI(),
92+
catchTypeCPI,
93+
catchType);
94+
}
95+
VarHandle.fullFence();
96+
}
97+
if (canCache) {
98+
this.exceptionHandlers = result;
99+
}
100+
}
101+
return result;
102+
}
103+
45104
@Override
46105
public JavaType[] getDeclaredExceptions() {
47106
// (GR-69097)

substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterConstantPool.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,34 @@
2626

2727
import static com.oracle.svm.interpreter.metadata.Bytecodes.INVOKEDYNAMIC;
2828

29+
import java.lang.invoke.MethodHandle;
30+
import java.lang.invoke.MethodType;
2931
import java.util.List;
3032

31-
import jdk.vm.ci.meta.JavaKind;
32-
import jdk.vm.ci.meta.PrimitiveConstant;
3333
import org.graalvm.nativeimage.Platform;
3434
import org.graalvm.nativeimage.Platforms;
3535

3636
import com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis;
3737
import com.oracle.svm.core.heap.UnknownObjectField;
38+
import com.oracle.svm.core.hub.DynamicHub;
39+
import com.oracle.svm.core.hub.crema.CremaSupport;
40+
import com.oracle.svm.core.hub.registry.SymbolsSupport;
3841
import com.oracle.svm.core.util.VMError;
3942
import com.oracle.svm.espresso.classfile.ConstantPool;
4043
import com.oracle.svm.espresso.classfile.ParserConstantPool;
44+
import com.oracle.svm.espresso.classfile.descriptors.ByteSequence;
45+
import com.oracle.svm.espresso.classfile.descriptors.Name;
46+
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
47+
import com.oracle.svm.espresso.classfile.descriptors.Type;
48+
import com.oracle.svm.espresso.classfile.descriptors.TypeSymbols;
4149
import com.oracle.svm.interpreter.metadata.serialization.VisibleForSerialization;
4250

4351
import jdk.vm.ci.meta.JavaConstant;
4452
import jdk.vm.ci.meta.JavaField;
53+
import jdk.vm.ci.meta.JavaKind;
4554
import jdk.vm.ci.meta.JavaMethod;
4655
import jdk.vm.ci.meta.JavaType;
56+
import jdk.vm.ci.meta.PrimitiveConstant;
4757
import jdk.vm.ci.meta.ResolvedJavaMethod;
4858
import jdk.vm.ci.meta.Signature;
4959
import jdk.vm.ci.meta.UnresolvedJavaField;
@@ -270,6 +280,18 @@ public String resolveStringAt(int cpi) {
270280
return (String) resolvedEntry;
271281
}
272282

283+
public MethodHandle resolvedMethodHandleAt(int cpi, InterpreterResolvedObjectType accessingClass) {
284+
Object resolvedEntry = resolvedAt(cpi, accessingClass);
285+
assert resolvedEntry != null;
286+
return (MethodHandle) resolvedEntry;
287+
}
288+
289+
public MethodType resolvedMethodTypeAt(char cpi, InterpreterResolvedObjectType accessingClass) {
290+
Object resolvedEntry = resolvedAt(cpi, accessingClass);
291+
assert resolvedEntry != null;
292+
return (MethodType) resolvedEntry;
293+
}
294+
273295
@Override
274296
public int intAt(int index) {
275297
checkTag(index, CONSTANT_Integer);
@@ -317,4 +339,22 @@ public long longAt(int index) {
317339
}
318340
return super.longAt(index);
319341
}
342+
343+
public JavaType findClassAt(int cpi) {
344+
if (peekCachedEntry(cpi) instanceof InterpreterResolvedObjectType type) {
345+
return type;
346+
}
347+
Symbol<Name> nameSymbol = className(cpi);
348+
ByteSequence typeBytes = TypeSymbols.nameToType(nameSymbol);
349+
Symbol<Type> typeSymbol = SymbolsSupport.getTypes().lookupValidType(typeBytes);
350+
if (typeSymbol == null) {
351+
return null;
352+
}
353+
Class<?> cls = CremaSupport.singleton().findLoadedClass(typeSymbol, getHolder());
354+
if (cls == null) {
355+
return UnresolvedJavaType.create(typeBytes.toString());
356+
} else {
357+
return DynamicHub.fromClass(cls).getInterpreterType();
358+
}
359+
}
320360
}

0 commit comments

Comments
 (0)