Skip to content

Commit 35039fb

Browse files
committed
[GR-60508] Include more information in the hash of method handle invoker substitution names
PullRequest: graal/19627
2 parents c4f22c3 + df1039d commit 35039fb

File tree

1 file changed

+52
-32
lines changed

1 file changed

+52
-32
lines changed

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

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.oracle.graal.pointsto.meta.AnalysisType;
4343
import com.oracle.graal.pointsto.meta.BaseLayerType;
4444
import com.oracle.svm.core.SubstrateUtil;
45+
import com.oracle.svm.core.util.BasedOnJDKClass;
4546
import com.oracle.svm.core.util.VMError;
4647
import com.oracle.svm.util.ReflectionUtil;
4748

@@ -52,6 +53,20 @@
5253
* which are assigned more or less arbitrary names by the host VM, to stable names that are based on
5354
* the {@code LambdaForm} which they were compiled from.
5455
*/
56+
@BasedOnJDKClass(value = MethodHandle.class)
57+
@BasedOnJDKClass(value = MethodType.class)
58+
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleStatics")
59+
@BasedOnJDKClass(className = "java.lang.invoke.ClassSpecializer")
60+
@BasedOnJDKClass(className = "java.lang.invoke.ClassSpecializer", innerClass = "SpeciesData")
61+
@BasedOnJDKClass(className = "java.lang.invoke.MemberName")
62+
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleNatives")
63+
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm")
64+
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "BasicType")
65+
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "Name")
66+
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "NamedFunction")
67+
@BasedOnJDKClass(className = "java.lang.invoke.BoundMethodHandle")
68+
@BasedOnJDKClass(className = "java.lang.invoke.DirectMethodHandle")
69+
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleImpl", innerClass = "IntrinsicMethodHandle")
5570
public class MethodHandleInvokerRenamingSubstitutionProcessor extends SubstitutionProcessor {
5671
private static final Class<?> METHOD_HANDLE_STATICS_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodHandleStatics");
5772
private static final Field DEBUG_METHOD_HANDLE_NAMES_FIELD = ReflectionUtil.lookupField(METHOD_HANDLE_STATICS_CLASS, "DEBUG_METHOD_HANDLE_NAMES");
@@ -85,6 +100,8 @@ public class MethodHandleInvokerRenamingSubstitutionProcessor extends Substituti
85100
private static final Method BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD = ReflectionUtil.lookupMethod(BOUND_METHOD_HANDLE_CLASS, "speciesData");
86101
private static final Class<?> DIRECT_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle");
87102
private static final Method DIRECT_METHOD_HANDLE_INTERNAL_MEMBER_NAME_METHOD = ReflectionUtil.lookupMethod(DIRECT_METHOD_HANDLE_CLASS, "internalMemberName");
103+
private static final Class<?> METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$IntrinsicMethodHandle");
104+
private static final Method METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_INTRINSIC_DATA_METHOD = ReflectionUtil.lookupMethod(METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS, "intrinsicData");
88105

89106
private static final String DMH_CLASS_NAME_SUBSTRING = "LambdaForm$DMH";
90107
private static final String DMH_STABLE_NAME_TEMPLATE = "Ljava/lang/invoke/LambdaForm$DMH.s";
@@ -289,41 +306,44 @@ private int getUniqueStableHash(Object lambdaForm) throws ReflectiveOperationExc
289306
* result.
290307
*/
291308
hash = hash * 31 + memberNameToString(member).hashCode();
292-
} else {
309+
}
310+
/*
311+
* The method handle of the NamedFunction is used in the string representation. To
312+
* avoid potential aliasing, the hash of the descriptor string is mixed in the
313+
* result.
314+
*/
315+
Object resolvedHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
316+
MethodType methodType = ((MethodHandle) resolvedHandle).type();
317+
hash = hash * 31 + methodType.descriptorString().hashCode();
318+
if (METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS.isInstance(resolvedHandle)) {
319+
if (METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_INTRINSIC_DATA_METHOD.invoke(resolvedHandle) instanceof Integer integer) {
320+
hash = hash * 31 + integer;
321+
}
322+
}
323+
324+
if (BOUND_METHOD_HANDLE_CLASS.isInstance(resolvedHandle)) {
293325
/*
294-
* If the member field is null, the method handle of the NamedFunction is used
295-
* in the string representation. To avoid potential aliasing, the hash of the
296-
* descriptor string is mixed in the result.
326+
* BoundMethodHandle.internalValues calls BoundMethodHandle.arg, which retrieves
327+
* the object that was bound to the corresponding argument, and return its
328+
* string representation. This method is only used if the debug method handle
329+
* names are activated. The object used may not have a stable string
330+
* representation, which would lead to an unstable name.
297331
*/
298-
Object innerMethodHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
299-
MethodType methodType = ((MethodHandle) innerMethodHandle).type();
300-
hash = hash * 31 + methodType.descriptorString().hashCode();
301-
302-
if (BOUND_METHOD_HANDLE_CLASS.isInstance(innerMethodHandle)) {
303-
/*
304-
* BoundMethodHandle.internalValues calls BoundMethodHandle.arg, which
305-
* retrieves the object that was bound to the corresponding argument, and
306-
* return its string representation. This method is only used if the debug
307-
* method handle names are activated. The object used may not have a stable
308-
* string representation, which would lead to an unstable name.
309-
*/
310-
assert !DEBUG_METHOD_HANDLE_NAMES_FIELD.getBoolean(null) : "The method handle " + innerMethodHandle +
311-
" with debug method handle names can contain the string representation from any object, which would cause the name to be unstable.";
312-
313-
/*
314-
* Without the debug method handle names, the MethodHandle.toString method
315-
* does not include any additional detail if the method handle is a bound
316-
* method handle. To avoid potential aliasing, the custom hash of the
317-
* species data is mixed with the result.
318-
*/
319-
Object speciesData = BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD.invoke(innerMethodHandle);
320-
hash = hash * 31 + getSpeciesDataHash(speciesData);
321-
}
332+
assert !DEBUG_METHOD_HANDLE_NAMES_FIELD.getBoolean(null) : "The method handle " + resolvedHandle +
333+
" with debug method handle names can contain the string representation from any object, which would cause the name to be unstable.";
334+
335+
/*
336+
* Without the debug method handle names, the MethodHandle.toString method does
337+
* not include any additional detail if the method handle is a bound method
338+
* handle. To avoid potential aliasing, the custom hash of the species data is
339+
* mixed with the result.
340+
*/
341+
Object speciesData = BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD.invoke(resolvedHandle);
342+
hash = hash * 31 + getSpeciesDataHash(speciesData);
322343
}
323344

324-
Object innerMethodHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
325-
Object innerLambdaForm = FORM_FIELD.get(innerMethodHandle);
326-
hash = hash * 31 + computeLambdaFormHash(innerLambdaForm, DIRECT_METHOD_HANDLE_CLASS.isInstance(innerMethodHandle));
345+
Object innerLambdaForm = FORM_FIELD.get(resolvedHandle);
346+
hash = hash * 31 + computeLambdaFormHash(innerLambdaForm, DIRECT_METHOD_HANDLE_CLASS.isInstance(resolvedHandle));
327347
}
328348
}
329349
return hash * 31 + lambdaFormString.hashCode();
@@ -379,7 +399,7 @@ public boolean isNameAlwaysStable(String methodHandleName) {
379399
if (lastIndex < 0) {
380400
return true;
381401
}
382-
return !uniqueTypeNames.contains(methodHandleName.substring(lastIndex) + "_1;");
402+
return !uniqueTypeNames.contains(methodHandleName.substring(0, lastIndex) + "_1;");
383403
}
384404

385405
boolean checkAllTypeNames() {

0 commit comments

Comments
 (0)