Mercurial > hg > graal-compiler
diff graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java @ 16895:06c15e88d383
added factory method to all Node classes; replaced Node classes instantiation with calls to factory methods; replaced identity tests on Node classes with ' == <node class>.getGenClass()' idiom
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Mon, 18 Aug 2014 14:04:21 +0200 |
parents | 03a4d382c122 |
children | f90dcdbbb75e |
line wrap: on
line diff
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java Mon Aug 18 13:49:25 2014 +0200 +++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java Mon Aug 18 14:04:21 2014 +0200 @@ -23,6 +23,7 @@ package com.oracle.graal.nodeinfo.processor; import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static java.util.Arrays.*; import static javax.lang.model.element.Modifier.*; import java.util.*; @@ -60,6 +61,11 @@ this.NodeSuccessorList = getType("com.oracle.graal.graph.NodeSuccessorList"); } + /** + * Returns a type element given a canonical name. + * + * @throw {@link NoClassDefFoundError} if a type element does not exist for {@code name} + */ public TypeElement getType(String name) { TypeElement typeElement = env.getProcessingEnv().getElementUtils().getTypeElement(name); if (typeElement == null) { @@ -121,14 +127,11 @@ } } - public boolean isAssignable(Element from, Element to) { + public boolean isAssignableWithErasure(Element from, Element to) { Types types = env.getProcessingEnv().getTypeUtils(); TypeMirror fromType = types.erasure(from.asType()); TypeMirror toType = types.erasure(to.asType()); - boolean res = types.isAssignable(fromType, toType); - // System.out.printf("%s:%s is %sassignable to %s:%s%n", from, fromType, res ? "" : "NOT ", -// to, toType); - return res; + return types.isAssignable(fromType, toType); } public void scanFields(TypeElement node, FieldScanner scanner) { @@ -151,7 +154,7 @@ throw new ElementException(field, "Field cannot be both input and successor"); } else if (isNonOptionalInput && isOptionalInput) { throw new ElementException(field, "Inputs must be either optional or non-optional"); - } else if (isAssignable(field, NodeInputList)) { + } else if (isAssignableWithErasure(field, NodeInputList)) { if (!modifiers.contains(FINAL)) { throw new ElementException(field, "Input list field must be final"); } @@ -162,7 +165,7 @@ return; } } else { - if (!isAssignable(field, Node) && field.getKind() == ElementKind.INTERFACE) { + if (!isAssignableWithErasure(field, Node) && field.getKind() == ElementKind.INTERFACE) { throw new ElementException(field, "Input field type must be an interface or assignable to Node"); } if (modifiers.contains(FINAL)) { @@ -179,7 +182,7 @@ } } } else if (isSuccessor) { - if (isAssignable(field, NodeSuccessorList)) { + if (isAssignableWithErasure(field, NodeSuccessorList)) { if (!modifiers.contains(FINAL)) { throw new ElementException(field, "Successor list field must be final"); } @@ -190,7 +193,7 @@ return; } } else { - if (!isAssignable(field, Node)) { + if (!isAssignableWithErasure(field, Node)) { throw new ElementException(field, "Successor field must be a Node type"); } if (modifiers.contains(FINAL)) { @@ -208,13 +211,13 @@ } } else { - if (isAssignable(field, Node) && !field.getSimpleName().contentEquals("Null")) { + if (isAssignableWithErasure(field, Node) && !field.getSimpleName().contentEquals("Null")) { throw new ElementException(field, "Suspicious Node field: " + field); } - if (isAssignable(field, NodeInputList)) { + if (isAssignableWithErasure(field, NodeInputList)) { throw new ElementException(field, "Suspicious NodeInputList field"); } - if (isAssignable(field, NodeSuccessorList)) { + if (isAssignableWithErasure(field, NodeSuccessorList)) { throw new ElementException(field, "Suspicious NodeSuccessorList field"); } if (!scanner.scanDataField(field)) { @@ -226,6 +229,37 @@ } while (!isObject(getSuperType(currentClazz).asType())); } + /** + * Determines if two parameter lists contain the + * {@linkplain Types#isSameType(TypeMirror, TypeMirror) same} types. + */ + private boolean parametersMatch(List<? extends VariableElement> p1, List<? extends VariableElement> p2) { + if (p1.size() == p2.size()) { + for (int i = 0; i < p1.size(); i++) { + if (!env.getProcessingEnv().getTypeUtils().isSameType(p1.get(i).asType(), p2.get(i).asType())) { + return false; + } + } + return true; + } + return false; + } + + /** + * Searches a type for a method based on a given name and parameter types. + */ + public ExecutableElement findMethod(TypeElement type, String name, List<? extends VariableElement> parameters) { + List<? extends ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements()); + for (ExecutableElement method : methods) { + if (method.getSimpleName().toString().equals(name)) { + if (parametersMatch(method.getParameters(), parameters)) { + return method; + } + } + } + return null; + } + public CodeCompilationUnit process(TypeElement node) { CodeCompilationUnit compilationUnit = new CodeCompilationUnit(); @@ -239,11 +273,15 @@ nodeGenElement.setSuperClass(node.asType()); for (ExecutableElement constructor : ElementFilter.constructorsIn(node.getEnclosedElements())) { - if (constructor.getModifiers().contains(Modifier.PRIVATE)) { - // ignore private constructors - continue; + if (constructor.getModifiers().contains(PUBLIC)) { + throw new ElementException(constructor, "Node class constructor must not be public"); } - nodeGenElement.add(createSuperConstructor(nodeGenElement, constructor)); + + checkFactoryMethodExists(node, newClassName, constructor); + + CodeExecutableElement subConstructor = createConstructor(nodeGenElement, constructor); + subConstructor.getModifiers().removeAll(Arrays.asList(PUBLIC, PRIVATE, PROTECTED)); + nodeGenElement.add(subConstructor); } DeclaredType generatedNode = (DeclaredType) ElementUtils.getType(getProcessingEnv(), GeneratedNode.class); @@ -257,7 +295,33 @@ return compilationUnit; } - private CodeExecutableElement createSuperConstructor(TypeElement type, ExecutableElement element) { + /** + * Checks that a public static factory method named {@code "create"} exists in {@code node} + * whose signature matches that of a given constructor. + * + * @throws ElementException if the check fails + */ + private void checkFactoryMethodExists(TypeElement node, String newClassName, ExecutableElement constructor) { + ExecutableElement create = findMethod(node, "create", constructor.getParameters()); + if (create == null) { + Formatter f = new Formatter(); + f.format("public static %s create(", node.getSimpleName()); + String sep = ""; + Formatter callArgs = new Formatter(); + for (VariableElement v : constructor.getParameters()) { + f.format("%s%s %s", sep, ElementUtils.getSimpleName(v.asType()), v.getSimpleName()); + callArgs.format("%s%s", sep, v.getSimpleName()); + sep = ", "; + } + f.format(") { return new %s(%s); }", newClassName, callArgs); + throw new ElementException(constructor, "Missing Node class factory method '%s'", f); + } + if (!create.getModifiers().containsAll(asList(PUBLIC, STATIC))) { + throw new ElementException(constructor, "Node class factory method must be public and static"); + } + } + + private CodeExecutableElement createConstructor(TypeElement type, ExecutableElement element) { CodeExecutableElement executable = CodeExecutableElement.clone(getProcessingEnv(), element); // to create a constructor we have to set the return type to null.(TODO needs fix)