Skip to content

Commit 16185e8

Browse files
committed
[GR-48285] More stable renaming for method handle invokers.
1 parent 7103471 commit 16185e8

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/methodhandles/MethodHandleInvokerRenamingSubstitutionProcessor.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.svm.hosted.methodhandles;
2626

27+
import java.lang.reflect.Field;
2728
import java.lang.reflect.Method;
2829
import java.util.HashSet;
2930
import java.util.List;
@@ -47,8 +48,11 @@
4748
* the {@code LambdaForm} which they were compiled from.
4849
*/
4950
public class MethodHandleInvokerRenamingSubstitutionProcessor extends SubstitutionProcessor {
50-
private static final Class<?> LAMBDA_FORM_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm");
5151
private static final Method CLASS_GET_CLASS_DATA_METHOD = ReflectionUtil.lookupMethod(Class.class, "getClassData");
52+
private static final Class<?> LAMBDA_FORM_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.LambdaForm");
53+
private static final Field LAMBDA_FORM_CUSTOMIZED_FIELD = ReflectionUtil.lookupField(LAMBDA_FORM_CLASS, "customized");
54+
private static final Class<?> DIRECT_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle");
55+
private static final Method DIRECT_METHOD_HANDLE_INTERNAL_MEMBER_NAME_METHOD = ReflectionUtil.lookupMethod(DIRECT_METHOD_HANDLE_CLASS, "internalMemberName");
5256

5357
/*
5458
* We currently only replace the invokers of direct method handles which have a simpler
@@ -88,15 +92,39 @@ public ResolvedJavaType resolve(ResolvedJavaType type) {
8892

8993
private ResolvedJavaType getSubstitution(ResolvedJavaType type) {
9094
return typeSubstitutions.computeIfAbsent(type, original -> {
95+
Object lambdaForm;
96+
Object customizedMemberName = null;
9197
try {
9298
Class<?> clazz = OriginalClassProvider.getJavaClass(original);
9399
Object classData = CLASS_GET_CLASS_DATA_METHOD.invoke(clazz);
94-
VMError.guarantee(LAMBDA_FORM_CLASS.isInstance(classData));
95-
int hash = classData.hashCode();
96-
return new MethodHandleInvokerSubstitutionType(original, findUniqueName(hash));
100+
if (LAMBDA_FORM_CLASS.isInstance(classData)) {
101+
lambdaForm = classData;
102+
} else if (classData instanceof List<?> list && list.size() == 2) {
103+
lambdaForm = list.get(0);
104+
Object customizedHandle = list.get(1);
105+
VMError.guarantee(LAMBDA_FORM_CLASS.isInstance(lambdaForm) && DIRECT_METHOD_HANDLE_CLASS.isInstance(customizedHandle) &&
106+
LAMBDA_FORM_CUSTOMIZED_FIELD.get(lambdaForm) == customizedHandle, "Expected classData to contain LambdaForm and its customization: %s", classData);
107+
customizedMemberName = DIRECT_METHOD_HANDLE_INTERNAL_MEMBER_NAME_METHOD.invoke(customizedHandle);
108+
} else {
109+
throw VMError.shouldNotReachHere("Unexpected classData: %s", classData);
110+
}
97111
} catch (ReflectiveOperationException e) {
98112
throw VMError.shouldNotReachHere(e);
99113
}
114+
/*
115+
* LambdaForm.hashCode() is not stable between image builds because it incorporates
116+
* identity hash codes of objects such as those of Class<?> that don't override
117+
* hashCode(). For that reason, we compute a hash code from LambdaForm.toString(). It
118+
* might also not be perfectly unique because the string contains unqualified class
119+
* names and can contain string representations of constraints that may be arbitrary
120+
* objects, but it should typically be distinct and stable.
121+
*/
122+
int hash = lambdaForm.toString().hashCode();
123+
if (customizedMemberName != null) {
124+
/* MemberName.hashCode() also includes identity hash codes of Class<?> objects. */
125+
hash = hash * 31 + customizedMemberName.toString().hashCode();
126+
}
127+
return new MethodHandleInvokerSubstitutionType(original, findUniqueName(hash));
100128
});
101129
}
102130

0 commit comments

Comments
 (0)