|
24 | 24 | */ |
25 | 25 | package com.oracle.svm.shared.util; |
26 | 26 |
|
| 27 | +import java.lang.reflect.Method; |
| 28 | + |
27 | 29 | import org.graalvm.nativeimage.Platform; |
28 | 30 | import org.graalvm.nativeimage.Platforms; |
29 | 31 |
|
30 | | -import jdk.vm.ci.meta.ResolvedJavaField; |
31 | | -import jdk.vm.ci.meta.ResolvedJavaMethod; |
32 | | -import jdk.vm.ci.meta.ResolvedJavaType; |
33 | | - |
34 | 32 | /** |
35 | 33 | * A collection of static methods for error reporting of fatal error. A fatal error leaves the VM in |
36 | 34 | * an inconsistent state, so no meaningful recovery is possible. |
@@ -62,6 +60,49 @@ public static final class HostedError extends Error { |
62 | 60 |
|
63 | 61 | } |
64 | 62 |
|
| 63 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 64 | + private static final Class<?> ResolvedJavaType; |
| 65 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 66 | + private static final Class<?> ResolvedJavaMethod; |
| 67 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 68 | + private static final Class<?> ResolvedJavaField; |
| 69 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 70 | + private static final Method ResolvedJavaType_toJavaName; |
| 71 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 72 | + private static final Method ResolvedJavaMethod_format; |
| 73 | + @Platforms(Platform.HOSTED_ONLY.class) // |
| 74 | + private static final Method ResolvedJavaField_format; |
| 75 | + |
| 76 | + static { |
| 77 | + Class<?> rjt; |
| 78 | + Class<?> rjm; |
| 79 | + Class<?> rjf; |
| 80 | + Method toJavaName; |
| 81 | + Method methodFormat; |
| 82 | + Method fieldFormat; |
| 83 | + try { |
| 84 | + rjt = Class.forName("jdk.vm.ci.meta.ResolvedJavaType"); |
| 85 | + toJavaName = rjt.getMethod("toJavaName", boolean.class); |
| 86 | + rjm = Class.forName("jdk.vm.ci.meta.ResolvedJavaMethod"); |
| 87 | + methodFormat = rjm.getMethod("format", String.class); |
| 88 | + rjf = Class.forName("jdk.vm.ci.meta.ResolvedJavaField"); |
| 89 | + fieldFormat = rjf.getMethod("format", String.class); |
| 90 | + } catch (Throwable t) { |
| 91 | + rjt = null; |
| 92 | + toJavaName = null; |
| 93 | + rjm = null; |
| 94 | + methodFormat = null; |
| 95 | + rjf = null; |
| 96 | + fieldFormat = null; |
| 97 | + } |
| 98 | + ResolvedJavaType = rjt; |
| 99 | + ResolvedJavaMethod = rjm; |
| 100 | + ResolvedJavaField = rjf; |
| 101 | + ResolvedJavaType_toJavaName = toJavaName; |
| 102 | + ResolvedJavaMethod_format = methodFormat; |
| 103 | + ResolvedJavaField_format = fieldFormat; |
| 104 | + } |
| 105 | + |
65 | 106 | public static final String msgShouldNotReachHere = "should not reach here"; |
66 | 107 | public static final String msgShouldNotReachHereSubstitution = msgShouldNotReachHere + ": substitution reached at runtime"; |
67 | 108 | public static final String msgShouldNotReachHereUnexpectedInput = msgShouldNotReachHere + ": unexpected input could not be handled"; |
@@ -213,31 +254,45 @@ public static RuntimeException unsupportedFeature(String msg) { |
213 | 254 | /** |
214 | 255 | * Processes {@code args} to convert selected values to strings. |
215 | 256 | * <ul> |
216 | | - * <li>A {@link ResolvedJavaType} is converted with {@link ResolvedJavaType#toJavaName} |
| 257 | + * <li>A {@code ResolvedJavaType} is converted with {@code ResolvedJavaType#toJavaName} |
217 | 258 | * {@code (true)}.</li> |
218 | | - * <li>A {@link ResolvedJavaMethod} is converted with {@link ResolvedJavaMethod#format} |
| 259 | + * <li>A {@code ResolvedJavaMethod} is converted with {@code ResolvedJavaMethod#format} |
219 | 260 | * {@code ("%H.%n($p)")}.</li> |
220 | | - * <li>A {@link ResolvedJavaField} is converted with {@link ResolvedJavaField#format} |
| 261 | + * <li>A {@code ResolvedJavaField} is converted with {@code ResolvedJavaField#format} |
221 | 262 | * {@code ("%H.%n")}.</li> |
222 | 263 | * </ul> |
223 | 264 | * All other values are copied to the returned array unmodified. |
224 | 265 | * |
| 266 | + * @implNote This method uses reflection instead of direct references to JVMCI types to avoid a |
| 267 | + * source level dependency on JVMCI. |
| 268 | + * |
225 | 269 | * @param args arguments to process |
226 | 270 | * @return a copy of {@code args} with certain values converted to strings as described above |
227 | 271 | */ |
228 | 272 | public static Object[] formatArguments(Object... args) { |
| 273 | + if (args == null) { |
| 274 | + return new Object[0]; |
| 275 | + } |
229 | 276 | Object[] newArgs = new Object[args.length]; |
| 277 | + |
230 | 278 | for (int i = 0; i < args.length; i++) { |
231 | 279 | Object arg = args[i]; |
232 | | - if (arg instanceof ResolvedJavaType) { |
233 | | - newArgs[i] = ((ResolvedJavaType) arg).toJavaName(true); |
234 | | - } else if (arg instanceof ResolvedJavaMethod) { |
235 | | - newArgs[i] = ((ResolvedJavaMethod) arg).format("%H.%n(%p)"); |
236 | | - } else if (arg instanceof ResolvedJavaField) { |
237 | | - newArgs[i] = ((ResolvedJavaField) arg).format("%H.%n"); |
238 | | - } else { |
239 | | - newArgs[i] = arg; |
| 280 | + if (ResolvedJavaType != null) { |
| 281 | + /* If ResolvedJavaType is available, all JVMCI classes must be available. */ |
| 282 | + try { |
| 283 | + if (ResolvedJavaType.isInstance(arg)) { |
| 284 | + arg = ResolvedJavaType_toJavaName.invoke(arg, Boolean.TRUE); |
| 285 | + } else if (ResolvedJavaMethod.isInstance(arg)) { |
| 286 | + arg = ResolvedJavaMethod_format.invoke(arg, "%H.%n(%p)"); |
| 287 | + } else if (ResolvedJavaField.isInstance(arg)) { |
| 288 | + arg = ResolvedJavaField_format.invoke(arg, "%H.%n"); |
| 289 | + } |
| 290 | + } catch (ReflectiveOperationException t) { |
| 291 | + // fall through to default case |
| 292 | + } |
240 | 293 | } |
| 294 | + // default |
| 295 | + newArgs[i] = arg; |
241 | 296 | } |
242 | 297 | return newArgs; |
243 | 298 | } |
|
0 commit comments