|
42 | 42 | import com.oracle.graal.pointsto.meta.AnalysisType;
|
43 | 43 | import com.oracle.graal.pointsto.meta.BaseLayerType;
|
44 | 44 | import com.oracle.svm.core.SubstrateUtil;
|
| 45 | +import com.oracle.svm.core.util.BasedOnJDKClass; |
45 | 46 | import com.oracle.svm.core.util.VMError;
|
46 | 47 | import com.oracle.svm.util.ReflectionUtil;
|
47 | 48 |
|
|
52 | 53 | * which are assigned more or less arbitrary names by the host VM, to stable names that are based on
|
53 | 54 | * the {@code LambdaForm} which they were compiled from.
|
54 | 55 | */
|
| 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") |
55 | 70 | public class MethodHandleInvokerRenamingSubstitutionProcessor extends SubstitutionProcessor {
|
56 | 71 | private static final Class<?> METHOD_HANDLE_STATICS_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.MethodHandleStatics");
|
57 | 72 | 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
|
85 | 100 | private static final Method BOUND_METHOD_HANDLE_SPECIES_DATA_METHOD = ReflectionUtil.lookupMethod(BOUND_METHOD_HANDLE_CLASS, "speciesData");
|
86 | 101 | private static final Class<?> DIRECT_METHOD_HANDLE_CLASS = ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle");
|
87 | 102 | 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"); |
88 | 105 |
|
89 | 106 | private static final String DMH_CLASS_NAME_SUBSTRING = "LambdaForm$DMH";
|
90 | 107 | 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
|
289 | 306 | * result.
|
290 | 307 | */
|
291 | 308 | 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)) { |
293 | 325 | /*
|
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. |
297 | 331 | */
|
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); |
322 | 343 | }
|
323 | 344 |
|
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)); |
327 | 347 | }
|
328 | 348 | }
|
329 | 349 | return hash * 31 + lambdaFormString.hashCode();
|
@@ -379,7 +399,7 @@ public boolean isNameAlwaysStable(String methodHandleName) {
|
379 | 399 | if (lastIndex < 0) {
|
380 | 400 | return true;
|
381 | 401 | }
|
382 |
| - return !uniqueTypeNames.contains(methodHandleName.substring(lastIndex) + "_1;"); |
| 402 | + return !uniqueTypeNames.contains(methodHandleName.substring(0, lastIndex) + "_1;"); |
383 | 403 | }
|
384 | 404 |
|
385 | 405 | boolean checkAllTypeNames() {
|
|
0 commit comments