64 import org.graalvm.compiler.nodes.StructuredGraph; |
64 import org.graalvm.compiler.nodes.StructuredGraph; |
65 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; |
65 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; |
66 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; |
66 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; |
67 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; |
67 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; |
68 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; |
68 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; |
|
69 import org.graalvm.compiler.nodes.spi.CoreProviders; |
69 import org.graalvm.compiler.options.OptionValues; |
70 import org.graalvm.compiler.options.OptionValues; |
70 import org.graalvm.compiler.phases.OptimisticOptimizations; |
71 import org.graalvm.compiler.phases.OptimisticOptimizations; |
71 import org.graalvm.compiler.phases.PhaseSuite; |
72 import org.graalvm.compiler.phases.PhaseSuite; |
72 import org.graalvm.compiler.phases.VerifyPhase; |
73 import org.graalvm.compiler.phases.VerifyPhase; |
73 import org.graalvm.compiler.phases.VerifyPhase.VerificationError; |
74 import org.graalvm.compiler.phases.VerifyPhase.VerificationError; |
74 import org.graalvm.compiler.phases.contract.VerifyNodeCosts; |
75 import org.graalvm.compiler.phases.contract.VerifyNodeCosts; |
75 import org.graalvm.compiler.phases.tiers.HighTierContext; |
76 import org.graalvm.compiler.phases.tiers.HighTierContext; |
76 import org.graalvm.compiler.phases.tiers.PhaseContext; |
|
77 import org.graalvm.compiler.phases.util.Providers; |
77 import org.graalvm.compiler.phases.util.Providers; |
78 import org.graalvm.compiler.runtime.RuntimeProvider; |
78 import org.graalvm.compiler.runtime.RuntimeProvider; |
|
79 import org.graalvm.compiler.serviceprovider.JavaVersionUtil; |
|
80 import org.graalvm.compiler.test.AddExports; |
|
81 import org.graalvm.compiler.test.ModuleSupport; |
79 import jdk.internal.vm.compiler.word.LocationIdentity; |
82 import jdk.internal.vm.compiler.word.LocationIdentity; |
80 import org.junit.Assert; |
83 import org.junit.Assert; |
81 import org.junit.Assume; |
84 import org.junit.Assume; |
82 import org.junit.Test; |
85 import org.junit.Test; |
83 |
86 |
95 /** |
98 /** |
96 * Checks that all classes in *graal*.jar and *jvmci*.jar entries on the boot class path comply with |
99 * Checks that all classes in *graal*.jar and *jvmci*.jar entries on the boot class path comply with |
97 * global invariants such as using {@link Object#equals(Object)} to compare certain types instead of |
100 * global invariants such as using {@link Object#equals(Object)} to compare certain types instead of |
98 * identity comparisons. |
101 * identity comparisons. |
99 */ |
102 */ |
|
103 @AddExports("jdk.internal.vm.ci/*=jdk.aot") |
100 public class CheckGraalInvariants extends GraalCompilerTest { |
104 public class CheckGraalInvariants extends GraalCompilerTest { |
|
105 |
|
106 /** |
|
107 * Magic token to denote the classes in the Java runtime image (i.e. in the {@code jrt:/} file |
|
108 * system). |
|
109 */ |
|
110 public static final String JRT_CLASS_PATH_ENTRY = "<jrt>"; |
101 |
111 |
102 private static boolean shouldVerifyEquals(ResolvedJavaMethod m) { |
112 private static boolean shouldVerifyEquals(ResolvedJavaMethod m) { |
103 if (m.getName().equals("identityEquals")) { |
113 if (m.getName().equals("identityEquals")) { |
104 ResolvedJavaType c = m.getDeclaringClass(); |
114 ResolvedJavaType c = m.getDeclaringClass(); |
105 if (c.getName().equals("Ljdk/vm/ci/meta/AbstractValue;") || c.getName().equals("jdk/vm/ci/meta/Value")) { |
115 if (c.getName().equals("Ljdk/vm/ci/meta/AbstractValue;") || c.getName().equals("jdk/vm/ci/meta/Value")) { |
116 } |
126 } |
117 |
127 |
118 public static class InvariantsTool { |
128 public static class InvariantsTool { |
119 |
129 |
120 protected boolean shouldProcess(String classpathEntry) { |
130 protected boolean shouldProcess(String classpathEntry) { |
|
131 if (classpathEntry.equals(JRT_CLASS_PATH_ENTRY)) { |
|
132 return true; |
|
133 } |
121 if (classpathEntry.endsWith(".jar")) { |
134 if (classpathEntry.endsWith(".jar")) { |
122 String name = new File(classpathEntry).getName(); |
135 String name = new File(classpathEntry).getName(); |
123 return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler"); |
136 return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler"); |
124 } |
137 } |
125 return false; |
138 return false; |
126 } |
139 } |
127 |
140 |
128 protected String getClassPath() { |
141 protected String getClassPath() { |
129 String bootclasspath; |
142 String bootclasspath; |
130 if (Java8OrEarlier) { |
143 if (JavaVersionUtil.JAVA_SPEC <= 8) { |
131 bootclasspath = System.getProperty("sun.boot.class.path"); |
144 bootclasspath = System.getProperty("sun.boot.class.path"); |
132 } else { |
145 } else { |
133 bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path"); |
146 bootclasspath = JRT_CLASS_PATH_ENTRY; |
134 } |
147 } |
135 return bootclasspath; |
148 return bootclasspath; |
136 } |
149 } |
137 |
150 |
138 protected boolean shouldLoadClass(String className) { |
151 protected boolean shouldLoadClass(String className) { |
139 if (className.equals("module-info") || className.startsWith("META-INF.versions.")) { |
152 if (className.equals("module-info") || className.startsWith("META-INF.versions.")) { |
140 return false; |
153 return false; |
141 } |
154 } |
142 if (!Java8OrEarlier) { |
155 if (JavaVersionUtil.JAVA_SPEC > 8) { |
143 // @formatter:off |
156 // @formatter:off |
144 /* |
157 /* |
145 * Work around to prevent: |
158 * Work around to prevent: |
146 * |
159 * |
147 * org.graalvm.compiler.debug.GraalError: java.lang.IllegalAccessError: class org.graalvm.compiler.serviceprovider.GraalServices$Lazy (in module |
160 * org.graalvm.compiler.debug.GraalError: java.lang.IllegalAccessError: class org.graalvm.compiler.serviceprovider.GraalServices$Lazy (in module |
205 |
218 |
206 final List<String> classNames = new ArrayList<>(); |
219 final List<String> classNames = new ArrayList<>(); |
207 for (String path : bootclasspath.split(File.pathSeparator)) { |
220 for (String path : bootclasspath.split(File.pathSeparator)) { |
208 if (tool.shouldProcess(path)) { |
221 if (tool.shouldProcess(path)) { |
209 try { |
222 try { |
210 final ZipFile zipFile = new ZipFile(new File(path)); |
223 if (path.equals(JRT_CLASS_PATH_ENTRY)) { |
211 for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) { |
224 for (String className : ModuleSupport.getJRTGraalClassNames()) { |
212 final ZipEntry zipEntry = entry.nextElement(); |
|
213 String name = zipEntry.getName(); |
|
214 if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { |
|
215 String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); |
|
216 if (isInNativeImage(className)) { |
|
217 /* |
|
218 * Native Image is an external tool and does not need to follow the |
|
219 * Graal invariants. |
|
220 */ |
|
221 continue; |
|
222 } |
|
223 if (isGSON(className)) { |
225 if (isGSON(className)) { |
224 /* |
226 /* |
225 * GSON classes are compiled with old JDK |
227 * GSON classes are compiled with old JDK |
226 */ |
228 */ |
227 continue; |
229 continue; |
228 } |
230 } |
229 classNames.add(className); |
231 classNames.add(className); |
230 } |
232 } |
|
233 } else { |
|
234 final ZipFile zipFile = new ZipFile(new File(path)); |
|
235 for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) { |
|
236 final ZipEntry zipEntry = entry.nextElement(); |
|
237 String name = zipEntry.getName(); |
|
238 if (name.endsWith(".class") && !name.startsWith("META-INF/versions/")) { |
|
239 String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); |
|
240 if (isInNativeImage(className)) { |
|
241 /* |
|
242 * Native Image is an external tool and does not need to follow |
|
243 * the Graal invariants. |
|
244 */ |
|
245 continue; |
|
246 } |
|
247 if (isGSON(className)) { |
|
248 /* |
|
249 * GSON classes are compiled with old JDK |
|
250 */ |
|
251 continue; |
|
252 } |
|
253 classNames.add(className); |
|
254 } |
|
255 } |
231 } |
256 } |
232 } catch (IOException ex) { |
257 } catch (IOException ex) { |
233 Assert.fail(ex.toString()); |
258 Assert.fail(ex.toString()); |
234 } |
259 } |
235 } |
260 } |
245 int availableProcessors = Runtime.getRuntime().availableProcessors(); |
270 int availableProcessors = Runtime.getRuntime().availableProcessors(); |
246 ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory); |
271 ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory); |
247 |
272 |
248 List<String> errors = Collections.synchronizedList(new ArrayList<>()); |
273 List<String> errors = Collections.synchronizedList(new ArrayList<>()); |
249 |
274 |
250 List<VerifyPhase<PhaseContext>> verifiers = new ArrayList<>(); |
275 List<VerifyPhase<CoreProviders>> verifiers = new ArrayList<>(); |
251 |
276 |
252 // If you add a new type to test here, be sure to add appropriate |
277 // If you add a new type to test here, be sure to add appropriate |
253 // methods to the BadUsageWithEquals class below |
278 // methods to the BadUsageWithEquals class below |
254 verifiers.add(new VerifyUsageWithEquals(Value.class)); |
279 verifiers.add(new VerifyUsageWithEquals(Value.class)); |
255 verifiers.add(new VerifyUsageWithEquals(Register.class)); |
280 verifiers.add(new VerifyUsageWithEquals(Register.class)); |
268 verifiers.add(new VerifyUpdateUsages()); |
293 verifiers.add(new VerifyUpdateUsages()); |
269 verifiers.add(new VerifyBailoutUsage()); |
294 verifiers.add(new VerifyBailoutUsage()); |
270 verifiers.add(new VerifySystemPropertyUsage()); |
295 verifiers.add(new VerifySystemPropertyUsage()); |
271 verifiers.add(new VerifyInstanceOfUsage()); |
296 verifiers.add(new VerifyInstanceOfUsage()); |
272 verifiers.add(new VerifyGraphAddUsage()); |
297 verifiers.add(new VerifyGraphAddUsage()); |
|
298 verifiers.add(new VerifyBufferUsage()); |
273 verifiers.add(new VerifyGetOptionsUsage()); |
299 verifiers.add(new VerifyGetOptionsUsage()); |
274 verifiers.add(new VerifyUnsafeAccess()); |
300 verifiers.add(new VerifyUnsafeAccess()); |
275 |
301 |
276 VerifyFoldableMethods foldableMethodsVerifier = new VerifyFoldableMethods(); |
302 VerifyFoldableMethods foldableMethodsVerifier = new VerifyFoldableMethods(); |
277 if (tool.shouldVerifyFoldableMethods()) { |
303 if (tool.shouldVerifyFoldableMethods()) { |
310 } |
336 } |
311 }); |
337 }); |
312 |
338 |
313 ResolvedJavaType type = metaAccess.lookupJavaType(c); |
339 ResolvedJavaType type = metaAccess.lookupJavaType(c); |
314 List<ResolvedJavaMethod> methods = new ArrayList<>(); |
340 List<ResolvedJavaMethod> methods = new ArrayList<>(); |
315 methods.addAll(Arrays.asList(type.getDeclaredMethods())); |
341 try { |
316 methods.addAll(Arrays.asList(type.getDeclaredConstructors())); |
342 methods.addAll(Arrays.asList(type.getDeclaredMethods())); |
|
343 methods.addAll(Arrays.asList(type.getDeclaredConstructors())); |
|
344 } catch (Throwable e) { |
|
345 errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e))); |
|
346 } |
317 ResolvedJavaMethod clinit = type.getClassInitializer(); |
347 ResolvedJavaMethod clinit = type.getClassInitializer(); |
318 if (clinit != null) { |
348 if (clinit != null) { |
319 methods.add(clinit); |
349 methods.add(clinit); |
320 } |
350 } |
321 |
351 |
400 continue; |
430 continue; |
401 } |
431 } |
402 try { |
432 try { |
403 Class<?> c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader()); |
433 Class<?> c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader()); |
404 classes.add(c); |
434 classes.add(c); |
|
435 } catch (UnsupportedClassVersionError e) { |
|
436 // graal-test.jar can contain classes compiled for different Java versions |
|
437 } catch (NoClassDefFoundError e) { |
|
438 if (!e.getMessage().contains("Could not initialize class")) { |
|
439 throw e; |
|
440 } else { |
|
441 // A second or later attempt to initialize a class |
|
442 // results in this confusing error where the |
|
443 // original cause of initialization failure is lost |
|
444 } |
405 } catch (Throwable t) { |
445 } catch (Throwable t) { |
406 tool.handleClassLoadingException(t); |
446 tool.handleClassLoadingException(t); |
407 } |
447 } |
408 } |
448 } |
409 return classes; |
449 return classes; |
411 |
451 |
412 /** |
452 /** |
413 * @param metaAccess |
453 * @param metaAccess |
414 * @param verifiers |
454 * @param verifiers |
415 */ |
455 */ |
416 private static void checkClass(Class<?> c, MetaAccessProvider metaAccess, List<VerifyPhase<PhaseContext>> verifiers) { |
456 private static void checkClass(Class<?> c, MetaAccessProvider metaAccess, List<VerifyPhase<CoreProviders>> verifiers) { |
417 if (Node.class.isAssignableFrom(c)) { |
457 if (Node.class.isAssignableFrom(c)) { |
418 if (c.getAnnotation(NodeInfo.class) == null) { |
458 if (c.getAnnotation(NodeInfo.class) == null) { |
419 throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName())); |
459 throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName())); |
420 } |
460 } |
421 VerifyNodeCosts.verifyNodeClass(c); |
461 VerifyNodeCosts.verifyNodeClass(c); |
422 } |
462 } |
423 for (VerifyPhase<PhaseContext> verifier : verifiers) { |
463 for (VerifyPhase<CoreProviders> verifier : verifiers) { |
424 verifier.verifyClass(c, metaAccess); |
464 verifier.verifyClass(c, metaAccess); |
425 } |
465 } |
426 } |
466 } |
427 |
467 |
428 private static void checkMethod(ResolvedJavaMethod method) { |
468 private static void checkMethod(ResolvedJavaMethod method) { |
443 } |
483 } |
444 |
484 |
445 /** |
485 /** |
446 * Checks the invariants for a single graph. |
486 * Checks the invariants for a single graph. |
447 */ |
487 */ |
448 private static void checkGraph(List<VerifyPhase<PhaseContext>> verifiers, HighTierContext context, StructuredGraph graph) { |
488 private static void checkGraph(List<VerifyPhase<CoreProviders>> verifiers, HighTierContext context, StructuredGraph graph) { |
449 for (VerifyPhase<PhaseContext> verifier : verifiers) { |
489 for (VerifyPhase<CoreProviders> verifier : verifiers) { |
450 if (!(verifier instanceof VerifyUsageWithEquals) || shouldVerifyEquals(graph.method())) { |
490 if (!(verifier instanceof VerifyUsageWithEquals) || shouldVerifyEquals(graph.method())) { |
451 verifier.apply(graph, context); |
491 verifier.apply(graph, context); |
452 } else { |
492 } else { |
453 verifier.apply(graph, context); |
493 verifier.apply(graph, context); |
454 } |
494 } |