Skip to content

Commit

Permalink
[feature] NodeCosts: Verify node cost model integrity in CheckGraalIn…
Browse files Browse the repository at this point in the history
…variants.
  • Loading branch information
davleopo committed Apr 6, 2017
1 parent 7cd39f5 commit caf9721
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.VerifyPhase;
import org.graalvm.compiler.phases.VerifyPhase.VerificationError;
import org.graalvm.compiler.phases.contract.VerifyNodeCosts;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
Expand Down Expand Up @@ -114,17 +115,52 @@ private static boolean shouldVerifyEquals(ResolvedJavaMethod m) {
return true;
}

private static boolean shouldProcess(String classpathEntry) {
public static String relativeFileName(String absolutePath) {
int lastFileSeparatorIndex = absolutePath.lastIndexOf(File.separator);
return absolutePath.substring(lastFileSeparatorIndex >= 0 ? lastFileSeparatorIndex : 0);
}

public static class InvariantsTool {

protected boolean shouldProcess(String classpathEntry) {
if (classpathEntry.endsWith(".jar")) {
String name = new File(classpathEntry).getName();
return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler");
}
return false;
}

protected String getClassPath() {
String bootclasspath;
if (Java8OrEarlier) {
bootclasspath = System.getProperty("sun.boot.class.path");
} else {
bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
}
return bootclasspath;
}

protected boolean shouldLoadClass(String className) {
return !className.equals("module-info");
}

protected void handleClassLoadingException(Throwable t) {
GraalError.shouldNotReachHere(t);
}

protected void handleParsingException(Throwable t) {
GraalError.shouldNotReachHere(t);
}
}

@Test
@SuppressWarnings("try")
public void test() {
runTest(new InvariantsTool());
}

@SuppressWarnings("try")
public static void runTest(InvariantsTool tool) {
RuntimeProvider rt = Graal.getRequiredCapability(RuntimeProvider.class);
Providers providers = rt.getHostBackend().getProviders();
MetaAccessProvider metaAccess = providers.getMetaAccess();
Expand All @@ -137,17 +173,12 @@ public void test() {

Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());

String bootclasspath;
if (Java8OrEarlier) {
bootclasspath = System.getProperty("sun.boot.class.path");
} else {
bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
}
String bootclasspath = tool.getClassPath();
Assert.assertNotNull("Cannot find boot class path", bootclasspath);

final List<String> classNames = new ArrayList<>();
for (String path : bootclasspath.split(File.pathSeparator)) {
if (shouldProcess(path)) {
if (tool.shouldProcess(path)) {
try {
final ZipFile zipFile = new ZipFile(new File(path));
for (final Enumeration<? extends ZipEntry> entry = zipFile.entries(); entry.hasMoreElements();) {
Expand Down Expand Up @@ -200,7 +231,7 @@ public GraalDebugConfig getDebugConfig() {
// Order outer classes before the inner classes
classNames.sort((String a, String b) -> a.compareTo(b));
// Initialize classes in single thread to avoid deadlocking issues during initialization
List<Class<?>> classes = initializeClasses(classNames);
List<Class<?>> classes = initializeClasses(tool, classNames);
for (Class<?> c : classes) {
String className = c.getName();
executor.execute(() -> {
Expand Down Expand Up @@ -234,7 +265,11 @@ public GraalDebugConfig getDebugConfig() {
// Graal bail outs on certain patterns in Java bytecode (e.g.,
// unbalanced monitors introduced by jacoco).
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
try {
tool.handleParsingException(e);
} catch (Throwable t) {
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
}
}
});
}
Expand All @@ -261,17 +296,17 @@ public GraalDebugConfig getDebugConfig() {
}
}

private static List<Class<?>> initializeClasses(List<String> classNames) {
private static List<Class<?>> initializeClasses(InvariantsTool tool, List<String> classNames) {
List<Class<?>> classes = new ArrayList<>(classNames.size());
for (String className : classNames) {
if (className.equals("module-info")) {
if (!tool.shouldLoadClass(className)) {
continue;
}
try {
Class<?> c = Class.forName(className, true, CheckGraalInvariants.class.getClassLoader());
classes.add(c);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Throwable t) {
tool.handleClassLoadingException(t);
}
}
return classes;
Expand All @@ -285,6 +320,7 @@ private static void checkClass(Class<?> c, MetaAccessProvider metaAccess) {
if (c.getAnnotation(NodeInfo.class) == null) {
throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
}
VerifyNodeCosts.verifyNodeClass(c);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,10 @@ public int getLeafId() {
return this.leafId;
}

public NodeClass<? super T> getSuperNodeClass() {
return superNodeClass;
}

public long inputsIteration() {
return inputsIteration;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2017, 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 org.graalvm.compiler.phases.contract;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.function.Predicate;

import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.NodeSize;
import org.graalvm.compiler.phases.VerifyPhase;

/**
* Utility class that verifies that every {@link Class} extending {@link Node} specifies non default
* values for {@link NodeCycles} and {@link NodeSize} in its {@link NodeInfo} annotation.
*/
public class VerifyNodeCosts {

public static void verifyNodeClass(Class<?> clazz) {
Class<?> nodeClass = Node.class;
if (nodeClass.isAssignableFrom(clazz)) {
if (!clazz.isAnnotationPresent(NodeInfo.class)) {
throw new VerifyPhase.VerificationError("%s.java extends Node.java but does not specify a NodeInfo annotation.", clazz.getName());
}

if (!Modifier.isAbstract(clazz.getModifiers())) {
boolean cyclesSet = walkCHUntil(getType(clazz), getType(nodeClass), cur -> {
return cur.cycles() != NodeCycles.CYCLES_UNSET;
});
boolean sizeSet = walkCHUntil(getType(clazz), getType(nodeClass), cur -> {
return cur.size() != NodeSize.SIZE_UNSET;
});
if (!cyclesSet) {
throw new VerifyPhase.VerificationError("%s.java does not specify a NodeCycles value in its class hierarchy.", clazz.getName());
}
if (!sizeSet) {
throw new VerifyPhase.VerificationError("%s.java does not specify a NodeSize value in its class hierarchy.", clazz.getName());
}
}
}
}

private static NodeClass<?> getType(Class<?> c) {
Field f;
try {
f = c.getField("TYPE");
f.setAccessible(true);
Object val = f.get(null);
NodeClass<?> nodeType = (NodeClass<?>) val;
return nodeType;
} catch (Throwable t) {
throw new VerifyPhase.VerificationError("%s.java does not specify a TYPE field.", c.getName());
}
}

private static boolean walkCHUntil(NodeClass<?> start, NodeClass<?> until, Predicate<NodeClass<?>> p) {
NodeClass<?> cur = start;
while (cur != until && cur != null) {
if (p.test(cur)) {
return true;
}
cur = cur.getSuperNodeClass();
}
return false;
}

}

0 comments on commit caf9721

Please sign in to comment.