# HG changeset patch # User Christian Humer # Date 1419892705 -3600 # Node ID 59bf50cc5a32c2c8a1a7ca5913809b3377267f7a # Parent f6b8787dc11309e1aaba1e8e18f8f87e6a49e448 Truffle-DSL: implemented @GenerateNodeFactory to enable generation of factories. Factory generation is now disabled by default. diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateNodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/GenerateNodeFactory.java Mon Dec 29 23:38:25 2014 +0100 @@ -0,0 +1,38 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.truffle.api.dsl; + +import java.lang.annotation.*; + +/** + * Annotate nodes or base classes of nodes to generate factory handlers implementing the + * {@link NodeFactory} interface. The generated factory handlers class name starts with the source + * original class and ends with 'Factory'. + */ +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface GenerateNodeFactory { + +} diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Dec 29 23:38:25 2014 +0100 @@ -69,6 +69,7 @@ private final DeclaredType nodeFactoryBase; private final DeclaredType dslMetadata; private final DeclaredType implies; + private final DeclaredType generateNodeFactory; private final TypeElement expectError; private final List errors = new ArrayList<>(); @@ -98,6 +99,11 @@ dslMetadata = getRequired(context, DSLMetadata.class); implies = getRequired(context, Implies.class); expectError = (TypeElement) getRequired(context, ExpectError.class).asElement(); + generateNodeFactory = getRequired(context, GenerateNodeFactory.class); + } + + public DeclaredType getGenerateNodeFactory() { + return generateNodeFactory; } public DeclaredType getImplies() { diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Dec 29 23:38:25 2014 +0100 @@ -71,7 +71,7 @@ } public CodeTypeElement create() { - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, ABSTRACT), baseClassName(node), node.getNodeType(), false); clazz.getImplements().add(context.getTruffleTypes().getDslNode()); for (NodeChildData child : node.getChildren()) { @@ -1847,10 +1847,10 @@ return builder.getRoot(); } - private static String baseClassName(NodeData node) { + public static String baseClassName(NodeData node) { String nodeid = resolveNodeId(node); String name = ElementUtils.firstLetterUpperCase(nodeid); - name += "BaseNode"; + name += "NodeGen"; return name; } @@ -1874,12 +1874,12 @@ /** *
      * variant1 $condition != null
-     *
+     * 
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     *
+     * 
      * variant2 $condition != null
      * $type $name = $value;
      * 
diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Dec 29 23:38:25 2014 +0100 @@ -22,11 +22,18 @@ */ package com.oracle.truffle.dsl.processor.generator; +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.java.model.*; import com.oracle.truffle.dsl.processor.model.*; @@ -44,28 +51,82 @@ List generatedNodes = generateNodes(context, node); if (!generatedNodes.isEmpty() || !enclosedTypes.isEmpty()) { - CodeTypeElement type = wrapGeneratedNodes(context, node, generatedNodes); + + CodeTypeElement type; + if (generatedNodes.isEmpty()) { + type = createContainer(node); + } else { + type = wrapGeneratedNodes(context, node, generatedNodes); + } for (CodeTypeElement enclosedFactory : enclosedTypes) { - Set modifiers = enclosedFactory.getModifiers(); - if (!modifiers.contains(Modifier.STATIC)) { - modifiers.add(Modifier.STATIC); + type.add(makeInnerClass(enclosedFactory)); + } + + if (node.getDeclaringNode() == null && enclosedTypes.size() > 0) { + ExecutableElement getFactories = createGetFactories(context, node); + if (getFactories != null) { + type.add(getFactories); } - type.add(enclosedFactory); } + return type; } else { return null; } } + private static CodeTypeElement makeInnerClass(CodeTypeElement type) { + Set modifiers = type.getModifiers(); + if (!modifiers.contains(Modifier.STATIC)) { + modifiers.add(Modifier.STATIC); + } + return type; + } + private static CodeTypeElement wrapGeneratedNodes(ProcessorContext context, NodeData node, List generatedNodes) { - // wrap all types into a generated factory - CodeTypeElement factoryElement = new NodeFactoryFactory(context, node, generatedNodes.isEmpty() ? null : generatedNodes.get(0)).create(); - for (CodeTypeElement generatedNode : generatedNodes) { - factoryElement.add(generatedNode); + if (node.isGenerateFactory()) { + // wrap all types into a generated factory + CodeTypeElement factoryElement = new NodeFactoryFactory(context, node, generatedNodes.get(0)).create(); + for (CodeTypeElement generatedNode : generatedNodes) { + factoryElement.add(makeInnerClass(generatedNode)); + } + return factoryElement; + } else { + // wrap all types into the first node + CodeTypeElement first = generatedNodes.get(0); + CodeTypeElement last = generatedNodes.get(1); + + for (CodeTypeElement generatedNode : generatedNodes) { + if (first != generatedNode) { + first.add(makeInnerClass(generatedNode)); + } + } + ElementUtils.setVisibility(first.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); + for (ExecutableElement constructor : ElementFilter.constructorsIn(first.getEnclosedElements())) { + ElementUtils.setVisibility(((CodeExecutableElement) constructor).getModifiers(), Modifier.PRIVATE); + } + + NodeFactoryFactory.createFactoryMethods(context, node, first, last, ElementUtils.getVisibility(node.getTemplateType().getModifiers())); + return first; } - return factoryElement; + } + + private static CodeTypeElement createContainer(NodeData node) { + CodeTypeElement container; + Modifier visibility = ElementUtils.getVisibility(node.getTemplateType().getModifiers()); + String containerName = NodeFactoryFactory.factoryClassName(node); + container = GeneratorUtils.createClass(node, modifiers(), containerName, null, false); + if (visibility != null) { + container.getModifiers().add(visibility); + } + container.getModifiers().add(Modifier.FINAL); + + return container; + } + + private static String getAccessorClassName(NodeData node) { + return node.isGenerateFactory() ? NodeFactoryFactory.factoryClassName(node) : NodeBaseFactory.baseClassName(node); } private static List generateNodes(ProcessorContext context, NodeData node) { @@ -91,4 +152,64 @@ return nodeTypes; } + private static ExecutableElement createGetFactories(ProcessorContext context, NodeData node) { + List factoryList = node.getNodesWithFactories(); + if (node.needsFactory() && node.isGenerateFactory()) { + factoryList.add(node); + } + + if (factoryList.isEmpty()) { + return null; + } + + List nodeTypesList = new ArrayList<>(); + TypeMirror prev = null; + boolean allSame = true; + for (NodeData child : factoryList) { + nodeTypesList.add(child.getNodeType()); + if (prev != null && !ElementUtils.typeEquals(child.getNodeType(), prev)) { + allSame = false; + } + prev = child.getNodeType(); + } + TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); + + Types types = context.getEnvironment().getTypeUtils(); + TypeMirror factoryType = context.getType(NodeFactory.class); + TypeMirror baseType; + if (allSame) { + baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), commonNodeSuperType); + } else { + baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); + } + TypeMirror listType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(context.getType(List.class)), baseType); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(context.getType(Arrays.class), "asList"); + + for (NodeData child : factoryList) { + builder.startGroup(); + NodeData childNode = child; + List factories = new ArrayList<>(); + while (childNode.getDeclaringNode() != null) { + factories.add(childNode); + childNode = childNode.getDeclaringNode(); + } + Collections.reverse(factories); + for (NodeData nodeData : factories) { + + builder.string(getAccessorClassName(nodeData)).string("."); + } + builder.string("getInstance()"); + builder.end(); + } + builder.end(); + builder.end(); + + return method; + } + } diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java Mon Dec 29 23:38:25 2014 +0100 @@ -29,7 +29,6 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; -import javax.lang.model.util.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.dsl.processor.*; @@ -52,7 +51,7 @@ this.createdFactoryElement = createdClass; } - private static String factoryClassName(NodeData node) { + public static String factoryClassName(NodeData node) { return node.getNodeId() + "Factory"; } @@ -67,8 +66,7 @@ clazz.getModifiers().add(Modifier.FINAL); if (createdFactoryElement != null) { - createFactoryMethods(clazz, visibility); - + createFactoryMethods(context, node, clazz, createdFactoryElement, visibility); clazz.setSuperClass(nodeFactory); clazz.add(createNodeFactoryConstructor()); clazz.add(createCreateNodeMethod()); @@ -76,11 +74,6 @@ clazz.add(createInstanceConstant(clazz.asType())); } - List children = node.getNodeDeclaringChildren(); - if (node.getDeclaringNode() == null && children.size() > 0) { - clazz.add(createGetFactories()); - } - return clazz; } @@ -231,68 +224,14 @@ return var; } - private ExecutableElement createGetFactories() { - List children = node.getNodeDeclaringChildren(); - if (node.needsFactory()) { - children.add(node); - } - - List nodeTypesList = new ArrayList<>(); - TypeMirror prev = null; - boolean allSame = true; - for (NodeData child : children) { - nodeTypesList.add(child.getNodeType()); - if (prev != null && !ElementUtils.typeEquals(child.getNodeType(), prev)) { - allSame = false; - } - prev = child.getNodeType(); - } - TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); - - Types types = context.getEnvironment().getTypeUtils(); - TypeMirror factoryType = context.getType(NodeFactory.class); - TypeMirror baseType; - if (allSame) { - baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), commonNodeSuperType); - } else { - baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); - } - TypeMirror listType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(context.getType(List.class)), baseType); - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); - - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn(); - builder.startStaticCall(context.getType(Arrays.class), "asList"); - - for (NodeData child : children) { - builder.startGroup(); - NodeData childNode = child; - List factories = new ArrayList<>(); - while (childNode.getDeclaringNode() != null) { - factories.add(childNode); - childNode = childNode.getDeclaringNode(); - } - Collections.reverse(factories); - for (NodeData nodeData : factories) { - builder.string(factoryClassName(nodeData)).string("."); - } - builder.string("getInstance()"); - builder.end(); - } - builder.end(); - builder.end(); - return method; - } - - private void createFactoryMethods(CodeTypeElement clazz, Modifier createVisibility) { + public static void createFactoryMethods(ProcessorContext context, NodeData node, CodeTypeElement clazz, CodeTypeElement createdFactoryElement, Modifier createVisibility) { List constructors = NodeBaseFactory.findUserConstructors(createdFactoryElement.asType()); for (ExecutableElement constructor : constructors) { - clazz.add(createCreateMethod(createVisibility, constructor)); + clazz.add(createCreateMethod(context, node, createVisibility, constructor)); } } - private CodeExecutableElement createCreateMethod(Modifier visibility, ExecutableElement constructor) { + private static CodeExecutableElement createCreateMethod(ProcessorContext context, NodeData node, Modifier visibility, ExecutableElement constructor) { CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), constructor); method.setSimpleName(CodeNames.of("create")); method.getModifiers().clear(); diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java Mon Dec 29 23:38:25 2014 +0100 @@ -46,7 +46,7 @@ if (nodeGen != null) { baseType = nodeGen.asType(); } - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, FINAL), nodePolymorphicClassName(node), baseType, false); clazz.getAnnotationMirrors().add(createNodeInfo(NodeCost.POLYMORPHIC)); diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java Mon Dec 29 23:38:25 2014 +0100 @@ -54,7 +54,7 @@ if (nodeGen != null) { baseType = nodeGen.asType(); } - CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); + CodeTypeElement clazz = GeneratorUtils.createClass(node, modifiers(PRIVATE, FINAL), nodeSpecializationClassName(specialization), baseType, false); if (specialization.isSpecialized() || specialization.isUninitialized()) { clazz.add(createGetMetadata0(false)); diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Dec 29 23:38:25 2014 +0100 @@ -998,6 +998,18 @@ return false; } + public static void setVisibility(Set modifiers, Modifier visibility) { + Modifier current = getVisibility(modifiers); + if (current != visibility) { + if (current != null) { + modifiers.remove(current); + } + if (visibility != null) { + modifiers.add(visibility); + } + } + } + public static Modifier getVisibility(Set modifier) { for (Modifier mod : modifier) { if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) { diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Dec 29 23:38:25 2014 +0100 @@ -52,9 +52,10 @@ private Map> executableTypes; private final NodeExecutionData thisExecution; + private final boolean generateFactory; public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, List children, List executions, - List fields, List assumptions) { + List fields, List assumptions, boolean generateFactory) { super(context, type, null, null); this.nodeId = type.getSimpleName().toString(); this.shortName = shortName; @@ -65,10 +66,15 @@ this.assumptions = assumptions; this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false); this.thisExecution.getChild().setNode(this); + this.generateFactory = generateFactory; } public NodeData(ProcessorContext context, TypeElement type) { - this(context, type, null, null, null, null, null, null); + this(context, type, null, null, null, null, null, null, false); + } + + public boolean isGenerateFactory() { + return generateFactory; } public NodeExecutionData getThisExecution() { @@ -231,13 +237,13 @@ return null; } - public List getNodeDeclaringChildren() { + public List getNodesWithFactories() { List nodeChildren = new ArrayList<>(); for (NodeData child : getEnclosingNodes()) { - if (child.needsFactory()) { + if (child.needsFactory() && child.isGenerateFactory()) { nodeChildren.add(child); } - nodeChildren.addAll(child.getNodeDeclaringChildren()); + nodeChildren.addAll(child.getNodesWithFactories()); } return nodeChildren; } diff -r f6b8787dc113 -r 59bf50cc5a32 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Dec 29 23:38:21 2014 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Dec 29 23:38:25 2014 +0100 @@ -251,8 +251,9 @@ List fields = parseFields(typeHierarchy, elements); List children = parseChildren(typeHierarchy, elements); List executions = parseExecutions(children, elements); + boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null; - NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList); + NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList, useNodeFactory); parsedNodes.put(ElementUtils.getQualifiedName(templateType), nodeData);