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;
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;
}
}