# HG changeset patch # User Doug Simon # Date 1394657450 -3600 # Node ID ab1c093f15c21b1454489409670dab8ac0e6bc6b # Parent f14fb79ab265ce7276091bfb6a1a0b8a32630c12 added unit test to ensure all classes in graal.jar comply with select global invariants diff -r f14fb79ab265 -r ab1c093f15c2 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java Wed Mar 12 21:50:50 2014 +0100 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.test; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.zip.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.api.runtime.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.debug.internal.*; +import com.oracle.graal.java.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.tiers.*; +import com.oracle.graal.phases.util.*; +import com.oracle.graal.phases.verify.*; +import com.oracle.graal.runtime.*; + +/** + * Checks that all classes in graal.jar (which must be on the class path) comply with global + * invariants such as using {@link Object#equals(Object)} to compare certain types instead of + * identity comparisons. + */ +public class CheckGraalInvariants { + + @Test + public void test() { + RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class); + Providers providers = rt.getHostBackend().getProviders(); + MetaAccessProvider metaAccess = providers.getMetaAccess(); + + PhaseSuite graphBuilderSuite = new PhaseSuite<>(); + graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getEagerDefault())); + HighTierContext context = new HighTierContext(providers, new Assumptions(false), null, graphBuilderSuite, OptimisticOptimizations.NONE); + + Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus()); + + String bootclasspath = System.getProperty("sun.boot.class.path"); + Assert.assertNotNull("Cannot find value of boot class path", bootclasspath); + + bootclasspath.split(File.pathSeparator); + + String graalJar = null; + for (String e : bootclasspath.split(File.pathSeparator)) { + if (e.endsWith("graal.jar")) { + graalJar = e; + break; + } + } + Assert.assertNotNull("Could not find graal.jar on boot class path: " + bootclasspath, graalJar); + + final List classNames = new ArrayList<>(); + try { + final ZipFile zipFile = new ZipFile(new File(graalJar)); + for (final Enumeration e = zipFile.entries(); e.hasMoreElements();) { + final ZipEntry zipEntry = e.nextElement(); + String name = zipEntry.getName(); + if (name.endsWith(".class")) { + String className = name.substring(0, name.length() - ".class".length()).replace('/', '.'); + classNames.add(className); + } + } + } catch (IOException e) { + Assert.fail(e.toString()); + } + + // Allows a subset of methods to be checked through use of a system property + String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters"); + String[] filters = property == null ? null : property.split(","); + + List errors = new ArrayList<>(); + for (String className : classNames) { + try { + Class c = Class.forName(className, false, CheckGraalInvariants.class.getClassLoader()); + for (Method m : c.getDeclaredMethods()) { + if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) { + // ignore + } else { + String methodName = className + "." + m.getName(); + if (matches(filters, methodName)) { + StructuredGraph graph = new StructuredGraph(metaAccess.lookupJavaMethod(m)); + DebugConfig debugConfig = DebugScope.getConfig(); + DebugConfig noInterceptConfig = new DelegatingDebugConfig(debugConfig) { + @Override + public RuntimeException interceptException(Throwable e) { + return null; + } + }; + try (DebugConfigScope s = Debug.setConfig(noInterceptConfig)) { + graphBuilderSuite.apply(graph, context); + checkGraph(context, graph); + } catch (AssertionError e) { + errors.add(e.getMessage()); + } catch (LinkageError e) { + // suppress linkages errors resulting from eager resolution + } + + } + } + } + + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + if (!errors.isEmpty()) { + StringBuilder msg = new StringBuilder(); + String nl = String.format("%n"); + for (String e : errors) { + if (msg.length() != 0) { + msg.append(nl); + } + msg.append(e); + } + Assert.fail(msg.toString()); + } + } + + /** + * Checks the invariants for a single graph. + */ + private static void checkGraph(HighTierContext context, StructuredGraph graph) { + new VerifyUsageWithEquals(Value.class).apply(graph, context); + new VerifyUsageWithEquals(Register.class).apply(graph, context); + new VerifyUsageWithEquals(JavaType.class).apply(graph, context); + new VerifyUsageWithEquals(JavaMethod.class).apply(graph, context); + new VerifyUsageWithEquals(JavaField.class).apply(graph, context); + } + + private static boolean matches(String[] filters, String s) { + if (filters == null || filters.length == 0) { + return true; + } + for (String filter : filters) { + if (s.contains(filter)) { + return true; + } + } + return false; + } +} diff -r f14fb79ab265 -r ab1c093f15c2 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java Wed Mar 12 21:48:51 2014 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java Wed Mar 12 21:50:50 2014 +0100 @@ -62,19 +62,12 @@ return isAssignableType(x, metaAccess) && !isNullConstant(y); } - private static boolean isEqualsMethod(StructuredGraph graph) { - Signature signature = graph.method().getSignature(); - return graph.method().getName().equals("equals") && signature.getParameterCount(false) == 1 && signature.getParameterKind(0).equals(Kind.Object); - } - @Override protected boolean verify(StructuredGraph graph, PhaseContext context) { for (ObjectEqualsNode cn : graph.getNodes().filter(ObjectEqualsNode.class)) { - if (!isEqualsMethod(graph)) { - // bail out if we compare an object of type klass with == or != (except null checks) - assert !(checkUsage(cn.x(), cn.y(), context.getMetaAccess()) && checkUsage(cn.y(), cn.x(), context.getMetaAccess())) : "Verification of " + klass.getName() + - " usage failed: Comparing " + cn.x() + " and " + cn.y() + " in " + graph.method() + " must use .equals() for object equality, not '==' or '!='"; - } + // bail out if we compare an object of type klass with == or != (except null checks) + assert !(checkUsage(cn.x(), cn.y(), context.getMetaAccess()) && checkUsage(cn.y(), cn.x(), context.getMetaAccess())) : "Verification of " + klass.getName() + " usage failed: Comparing " + + cn.x() + " and " + cn.y() + " in " + graph.method() + " must use .equals() for object equality, not '==' or '!='"; } return true; }