Skip to content

Commit 34889f1

Browse files
Crema: Resolve METHODHANDLE in constant pool
Use the JDK's `MethodHandleNatives.linkMethodHandleConstant` to create the resolved `MethodHandle`.
1 parent 6c0fe6e commit 34889f1

File tree

5 files changed

+84
-1
lines changed

5 files changed

+84
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,12 @@ public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke
223223
public static native MethodType findMethodHandleType(Class<?> rtype, Class<?>[] ptypes);
224224

225225
@Delete
226-
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);
227232
}
228233

229234
/**

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.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterConstantPool.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

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

29+
import java.lang.invoke.MethodHandle;
2930
import java.lang.invoke.MethodType;
3031
import java.util.List;
3132

@@ -271,6 +272,12 @@ public String resolveStringAt(int cpi) {
271272
return (String) resolvedEntry;
272273
}
273274

275+
public MethodHandle resolvedMethodHandleAt(int cpi, InterpreterResolvedObjectType accessingClass) {
276+
Object resolvedEntry = resolvedAt(cpi, accessingClass);
277+
assert resolvedEntry != null;
278+
return (MethodHandle) resolvedEntry;
279+
}
280+
274281
public MethodType resolvedMethodTypeAt(char cpi, InterpreterResolvedObjectType accessingClass) {
275282
Object resolvedEntry = resolvedAt(cpi, accessingClass);
276283
assert resolvedEntry != null;

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/Interpreter.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@
264264
import static com.oracle.svm.interpreter.metadata.Bytecodes.TABLESWITCH;
265265
import static com.oracle.svm.interpreter.metadata.Bytecodes.WIDE;
266266

267+
import java.lang.invoke.MethodHandle;
267268
import java.lang.invoke.MethodType;
268269

269270
import com.oracle.svm.core.jdk.InternalVMMethod;
@@ -1212,6 +1213,9 @@ private static void loadConstant(InterpreterFrame frame, InterpreterResolvedJava
12121213
case METHODTYPE -> {
12131214
putObject(frame, top, resolveMethodType(pool, method, opcode, cpi));
12141215
}
1216+
case METHODHANDLE -> {
1217+
putObject(frame, top, resolveMethodHandle(pool, method, opcode, cpi));
1218+
}
12151219
case INVOKEDYNAMIC -> {
12161220
// TODO(peterssen): GR-68576 Storing the pre-resolved appendix in the CP is a
12171221
// workaround for the JDWP debugger until proper INVOKEDYNAMIC resolution is
@@ -1295,6 +1299,15 @@ private static MethodType resolveMethodType(InterpreterConstantPool pool, Interp
12951299
}
12961300
}
12971301

1302+
private static MethodHandle resolveMethodHandle(InterpreterConstantPool pool, InterpreterResolvedJavaMethod method, int opcode, char cpi) {
1303+
assert opcode == LDC || opcode == LDC_W;
1304+
try {
1305+
return pool.resolvedMethodHandleAt(cpi, method.getDeclaringClass());
1306+
} catch (Throwable t) {
1307+
throw SemanticJavaException.raise(t);
1308+
}
1309+
}
1310+
12981311
// region Class/Method/Field resolution
12991312

13001313
private static InterpreterResolvedJavaType resolveType(InterpreterResolvedJavaMethod method, int opcode, char cpi) {

substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/RuntimeInterpreterConstantPool.java

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import com.oracle.svm.interpreter.metadata.InterpreterResolvedJavaType;
4444
import com.oracle.svm.interpreter.metadata.InterpreterResolvedObjectType;
4545

46+
import jdk.vm.ci.meta.JavaType;
4647
import jdk.vm.ci.meta.UnresolvedJavaField;
4748
import jdk.vm.ci.meta.UnresolvedJavaMethod;
4849
import jdk.vm.ci.meta.UnresolvedJavaType;
@@ -68,10 +69,52 @@ protected Object resolve(int cpi, InterpreterResolvedObjectType accessingClass)
6869
case METHOD_REF -> resolveClassMethodRefConstant(cpi, accessingClass);
6970
case CLASS -> resolveClassConstant(cpi, accessingClass);
7071
case METHODTYPE -> resolveMethodType(cpi, accessingClass);
72+
case METHODHANDLE -> resolveMethodHandle(cpi, accessingClass);
7173
default -> throw VMError.unimplemented("Unimplemented CP resolution for " + tag);
7274
};
7375
}
7476

77+
private Object resolveMethodHandle(int cpi, InterpreterResolvedObjectType accessingClass) {
78+
Object mtype;
79+
InterpreterResolvedJavaType mklass;
80+
Symbol<Name> refName;
81+
82+
int memberIndex = this.methodHandleMemberIndex(cpi);
83+
84+
Tag refTag = this.tagAt(memberIndex);
85+
if (refTag == Tag.METHOD_REF || refTag == Tag.INTERFACE_METHOD_REF) {
86+
InterpreterResolvedJavaMethod target = this.resolvedMethodAt(accessingClass, memberIndex);
87+
Symbol<Type>[] parsed = target.getParsedSymbolicSignature(CremaRuntimeAccess.getInstance().getSymbolPool());
88+
89+
mtype = signatureToMethodType(parsed, accessingClass);
90+
/*
91+
* we should use the klass from the method ref here rather than the declaring klass of
92+
* the target this is because the resolved target might come from a default method and
93+
* have an interface as declaring klass however if the refKind is invokeVirtual, it
94+
* would be illegal to use the interface type
95+
*/
96+
int holderIndex = this.memberClassIndex(memberIndex);
97+
mklass = this.resolvedTypeAt(accessingClass, holderIndex);
98+
refName = target.getSymbolicName();
99+
} else {
100+
assert refTag == Tag.FIELD_REF;
101+
InterpreterResolvedJavaField field = this.resolvedFieldAt(accessingClass, memberIndex);
102+
JavaType fieldType = field.getType();
103+
if (fieldType instanceof InterpreterResolvedJavaType resolvedJavaType) {
104+
mtype = resolvedJavaType.getJavaClass();
105+
} else {
106+
mtype = resolveSymbolAndAccessCheck(field.getDeclaringClass(), (UnresolvedJavaType) fieldType);
107+
}
108+
mklass = field.getDeclaringClass();
109+
refName = field.getSymbolicName();
110+
}
111+
String mname = refName.toString();
112+
int refKind = this.methodHandleRefKind(cpi);
113+
return Target_java_lang_invoke_MethodHandleNatives.linkMethodHandleConstant(
114+
accessingClass.getJavaClass(), refKind,
115+
mklass.getJavaClass(), mname, mtype);
116+
}
117+
75118
private Object resolveMethodType(int cpi, InterpreterResolvedObjectType accessingClass) {
76119
Symbol<Signature> sig = this.methodTypeSignature(cpi);
77120
Symbol<Type>[] parsed = SymbolsSupport.getSignatures().parsed(sig);
@@ -255,4 +298,10 @@ private static Class<?> resolveSymbolAndAccessCheck(InterpreterResolvedObjectTyp
255298
// GR-62339 check access
256299
return clazz;
257300
}
301+
302+
private static Class<?> resolveSymbolAndAccessCheck(InterpreterResolvedObjectType accessingClass, UnresolvedJavaType type) {
303+
Class<?> clazz = CremaSupport.singleton().resolveOrThrow(type, accessingClass);
304+
// GR-62339 check access
305+
return clazz;
306+
}
258307
}

0 commit comments

Comments
 (0)