changeset 14162:ab1c093f15c2

added unit test to ensure all classes in graal.jar comply with select global invariants
author Doug Simon <doug.simon@oracle.com>
date Wed, 12 Mar 2014 21:50:50 +0100
parents f14fb79ab265
children 7831c74266a7
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyUsageWithEquals.java
diffstat 2 files changed, 170 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- /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<HighTierContext> 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<String> classNames = new ArrayList<>();
+        try {
+            final ZipFile zipFile = new ZipFile(new File(graalJar));
+            for (final Enumeration<? extends ZipEntry> 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<String> 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;
+    }
+}
--- 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;
     }