Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.oracle.graal.pointsto.meta.AnalysisType;
import com.oracle.graal.pointsto.meta.BaseLayerType;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.util.BasedOnJDKClass;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.ReflectionUtil;

Expand All @@ -52,6 +53,20 @@
* which are assigned more or less arbitrary names by the host VM, to stable names that are based on
* the {@code LambdaForm} which they were compiled from.
*/
@BasedOnJDKClass(value = MethodHandle.class)
@BasedOnJDKClass(value = MethodType.class)
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleStatics")
@BasedOnJDKClass(className = "java.lang.invoke.ClassSpecializer")
@BasedOnJDKClass(className = "java.lang.invoke.ClassSpecializer", innerClass = "SpeciesData")
@BasedOnJDKClass(className = "java.lang.invoke.MemberName")
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleNatives")
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm")
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "BasicType")
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "Name")
@BasedOnJDKClass(className = "java.lang.invoke.LambdaForm", innerClass = "NamedFunction")
@BasedOnJDKClass(className = "java.lang.invoke.BoundMethodHandle")
@BasedOnJDKClass(className = "java.lang.invoke.DirectMethodHandle")
@BasedOnJDKClass(className = "java.lang.invoke.MethodHandleImpl", innerClass = "IntrinsicMethodHandle")
public class MethodHandleInvokerRenamingSubstitutionProcessor extends SubstitutionProcessor {
private static final Class<?> METHOD_HANDLE_STATICS_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodHandleStatics");
private static final Field DEBUG_METHOD_HANDLE_NAMES_FIELD = ReflectionUtil.lookupField(METHOD_HANDLE_STATICS_CLASS, "DEBUG_METHOD_HANDLE_NAMES");
Expand Down Expand Up @@ -85,6 +100,8 @@ public class MethodHandleInvokerRenamingSubstitutionProcessor extends Substituti
private static final Method BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD = ReflectionUtil.lookupMethod(BOUND_METHOD_HANDLE_CLASS, "speciesData");
private static final Class<?> DIRECT_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle");
private static final Method DIRECT_METHOD_HANDLE_INTERNAL_MEMBER_NAME_METHOD = ReflectionUtil.lookupMethod(DIRECT_METHOD_HANDLE_CLASS, "internalMemberName");
private static final Class<?> METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass("java.lang.invoke.MethodHandleImpl$IntrinsicMethodHandle");
private static final Method METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_INTRINSIC_DATA_METHOD = ReflectionUtil.lookupMethod(METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS, "intrinsicData");

private static final String DMH_CLASS_NAME_SUBSTRING = "LambdaForm$DMH";
private static final String DMH_STABLE_NAME_TEMPLATE = "Ljava/lang/invoke/LambdaForm$DMH.s";
Expand Down Expand Up @@ -289,41 +306,44 @@ private int getUniqueStableHash(Object lambdaForm) throws ReflectiveOperationExc
* result.
*/
hash = hash * 31 + memberNameToString(member).hashCode();
} else {
}
/*
* The method handle of the NamedFunction is used in the string representation. To
* avoid potential aliasing, the hash of the descriptor string is mixed in the
* result.
*/
Object resolvedHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
MethodType methodType = ((MethodHandle) resolvedHandle).type();
hash = hash * 31 + methodType.descriptorString().hashCode();
if (METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_CLASS.isInstance(resolvedHandle)) {
if (METHOD_HANDLE_IMPL_INTRINSIC_METHOD_HANDLE_INTRINSIC_DATA_METHOD.invoke(resolvedHandle) instanceof Integer integer) {
hash = hash * 31 + integer;
}
}

if (BOUND_METHOD_HANDLE_CLASS.isInstance(resolvedHandle)) {
/*
* If the member field is null, the method handle of the NamedFunction is used
* in the string representation. To avoid potential aliasing, the hash of the
* descriptor string is mixed in the result.
* BoundMethodHandle.internalValues calls BoundMethodHandle.arg, which retrieves
* the object that was bound to the corresponding argument, and return its
* string representation. This method is only used if the debug method handle
* names are activated. The object used may not have a stable string
* representation, which would lead to an unstable name.
*/
Object innerMethodHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
MethodType methodType = ((MethodHandle) innerMethodHandle).type();
hash = hash * 31 + methodType.descriptorString().hashCode();

if (BOUND_METHOD_HANDLE_CLASS.isInstance(innerMethodHandle)) {
/*
* BoundMethodHandle.internalValues calls BoundMethodHandle.arg, which
* retrieves the object that was bound to the corresponding argument, and
* return its string representation. This method is only used if the debug
* method handle names are activated. The object used may not have a stable
* string representation, which would lead to an unstable name.
*/
assert !DEBUG_METHOD_HANDLE_NAMES_FIELD.getBoolean(null) : "The method handle " + innerMethodHandle +
" with debug method handle names can contain the string representation from any object, which would cause the name to be unstable.";

/*
* Without the debug method handle names, the MethodHandle.toString method
* does not include any additional detail if the method handle is a bound
* method handle. To avoid potential aliasing, the custom hash of the
* species data is mixed with the result.
*/
Object speciesData = BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD.invoke(innerMethodHandle);
hash = hash * 31 + getSpeciesDataHash(speciesData);
}
assert !DEBUG_METHOD_HANDLE_NAMES_FIELD.getBoolean(null) : "The method handle " + resolvedHandle +
" with debug method handle names can contain the string representation from any object, which would cause the name to be unstable.";

/*
* Without the debug method handle names, the MethodHandle.toString method does
* not include any additional detail if the method handle is a bound method
* handle. To avoid potential aliasing, the custom hash of the species data is
* mixed with the result.
*/
Object speciesData = BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD.invoke(resolvedHandle);
hash = hash * 31 + getSpeciesDataHash(speciesData);
}

Object innerMethodHandle = NAMED_FUNCTION_RESOLVED_HANDLE_METHOD.invoke(function);
Object innerLambdaForm = FORM_FIELD.get(innerMethodHandle);
hash = hash * 31 + computeLambdaFormHash(innerLambdaForm, DIRECT_METHOD_HANDLE_CLASS.isInstance(innerMethodHandle));
Object innerLambdaForm = FORM_FIELD.get(resolvedHandle);
hash = hash * 31 + computeLambdaFormHash(innerLambdaForm, DIRECT_METHOD_HANDLE_CLASS.isInstance(resolvedHandle));
}
}
return hash * 31 + lambdaFormString.hashCode();
Expand Down Expand Up @@ -379,7 +399,7 @@ public boolean isNameAlwaysStable(String methodHandleName) {
if (lastIndex < 0) {
return true;
}
return !uniqueTypeNames.contains(methodHandleName.substring(lastIndex) + "_1;");
return !uniqueTypeNames.contains(methodHandleName.substring(0, lastIndex) + "_1;");
}

boolean checkAllTypeNames() {
Expand Down