# HG changeset patch # User Christian Humer # Date 1361794382 -3600 # Node ID 6e4fb0ccebb1230587e60fc7c6d1a18e5356d597 # Parent 8e56c6951c86009e95198bf39581f55e7be49cdb Generated factories implement the new NodeFactory interface. diff -r 8e56c6951c86 -r 6e4fb0ccebb1 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java Mon Feb 25 13:13:02 2013 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2012, 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.truffle.api.codegen; + +import java.util.*; + +/** + * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate + * generated node classes without using reflection. + */ +public interface NodeFactory { + + /** + * Instantiates the node using the arguments array. The arguments length and types must suffice + * one of the returned signatures in {@link #getNodeSignatures()}. If the arguments array does + * not suffice one of the node signatures an {@link IllegalArgumentException} is thrown. + * + * @param arguments the argument values + * @return the instantiated node + * @throws IllegalArgumentException + */ + T createNode(Object... arguments); + + /** + * Instantiates a new specialized variant of the node. This is an optional method and throws an + * {@link UnsupportedOperationException} if not supported. + * + * @param thisNode the current node + * @param specializionClasses + * @return the specialized node + */ + T createNodeSpecialized(T thisNode, Class... specializionClasses); + + /** + * Returns the node class that will get created by {@link #createNode(Object...)}. The node + * class does not match exactly to the instantiated object but they are guaranteed to be + * assignable. + */ + Class getNodeClass(); + + /** + * Returns a list of signatures that can be used to invoke {@link #createNode(Object...)}. + */ + List>> getNodeSignatures(); + +} diff -r 8e56c6951c86 -r 6e4fb0ccebb1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon Feb 25 13:05:23 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon Feb 25 13:13:02 2013 +0100 @@ -31,6 +31,7 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; +import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.ast.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; @@ -422,10 +423,6 @@ add(factory, node); } - if (node.getSpecializations() == null) { - return; - } - if (node.needsFactory() || childTypes.size() > 0) { add(new NodeFactoryFactory(context, childTypes), node); } @@ -511,6 +508,15 @@ for (SpecializationData specialization : node.getSpecializations()) { add(new SpecializedNodeFactory(context), specialization); } + + TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); + clazz.getImplements().add(nodeFactory); + clazz.add(createCreateNodeMethod(node, createVisibility)); + clazz.add(createCreateNodeSpecializedMethod(node, createVisibility)); + clazz.add(createGetNodeClassMethod(node)); + clazz.add(createGetNodeSignaturesMethod(node)); + clazz.add(createGetInstanceMethod(node, clazz.asType(), createVisibility)); + clazz.add(createInstanceConstant(node, clazz.asType())); } for (NodeData childNode : childTypes.keySet()) { @@ -531,9 +537,235 @@ clazz.add(type); } } + + if (node.getParent() == null && node.getDeclaredChildren().size() > 0) { + List children = node.getNodeChildren(); + List types = new ArrayList<>(); + if (node.needsFactory()) { + types.add(node.getNodeType()); + } + for (NodeData child : children) { + types.add(child.getTemplateType().asType()); + } + TypeMirror commonSuperType = Utils.getCommonSuperType(getContext(), types.toArray(new TypeMirror[types.size()])); + clazz.add(createGetFactories(node, commonSuperType)); + } + + } + + private CodeExecutableElement createGetNodeClassMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().typeLiteral(node.getNodeType()).end(); + return method; + } + + private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); + TypeMirror classType = getContext().getType(Class.class); + TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + List constructors = findUserConstructors(node); + for (ExecutableElement constructor : constructors) { + builder.startGroup(); + builder.type(getContext().getType(Arrays.class)); + builder.string(".<").type(getContext().getType(Class.class)).string(">"); + builder.startCall("asList"); + for (VariableElement param : constructor.getParameters()) { + builder.typeLiteral(param.asType()); + } + builder.end(); + builder.end(); + } + builder.end(); + builder.end(); + return method; + } + + private CodeExecutableElement createCreateNodeMethod(NodeData node, Modifier visibility) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); + method.setVarArgs(true); + method.addParameter(arguments); + + if (visibility != null) { + method.getModifiers().add(visibility); + } + + CodeTreeBuilder builder = method.createBuilder(); + List signatures = findUserConstructors(node); + boolean ifStarted = false; + + for (ExecutableElement element : signatures) { + ifStarted = builder.startIf(ifStarted); + builder.string("arguments.length == " + element.getParameters().size()); + + int index = 0; + for (VariableElement param : element.getParameters()) { + builder.string(" && "); + if (!param.asType().getKind().isPrimitive()) { + builder.string("(arguments[" + index + "] == null || "); + } + builder.string("arguments[" + index + "] instanceof "); + builder.type(Utils.boxType(getContext(), param.asType())); + if (!param.asType().getKind().isPrimitive()) { + builder.string(")"); + } + index++; + } + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("create"); + index = 0; + for (VariableElement param : element.getParameters()) { + builder.startGroup(); + builder.string("(").type(param.asType()).string(") "); + builder.string("arguments[").string(String.valueOf(index)).string("]"); + builder.end(); + index++; + } + builder.end().end(); + + builder.end(); // block + } + + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid create signature."); + builder.end().end(); + builder.end(); // else block + return method; + } + + private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node, Modifier visibility) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createNodeSpecialized"); + CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); + method.addParameter(nodeParam); + method.addParameter(arguments); + method.setVarArgs(true); + if (visibility != null) { + method.getModifiers().add(visibility); + } + + CodeTreeBuilder builder = method.createBuilder(); + if (!node.needsRewrites(getContext())) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + } else { + builder.startIf(); + builder.string("types.length == 1"); + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("createSpecialized"); + builder.string("thisNode"); + builder.string("types[0]"); + builder.end().end(); + + builder.end(); + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid createSpecialized signature."); + builder.end().end(); + builder.end(); + } + + return method; + } + + private ExecutableElement createGetInstanceMethod(NodeData node, TypeMirror factoryType, Modifier visibility) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(), factoryType, "getInstance"); + if (visibility != null) { + method.getModifiers().add(visibility); + } + method.getModifiers().add(Modifier.STATIC); + + String varName = instanceVarName(node); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startIf(); + builder.string(varName).string(" == null"); + builder.end().startBlock(); + + builder.startStatement(); + builder.string(varName); + builder.string(" = "); + builder.startNew(factoryClassName(node)).end(); + builder.end(); + + builder.end(); + builder.startReturn().string(varName).end(); + return method; + } + + private String instanceVarName(NodeData node) { + if (node.getParent() != null) { + return Utils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; + } else { + return "instance"; + } + } + + private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { + String varName = instanceVarName(node); + CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); + var.getModifiers().add(Modifier.PRIVATE); + var.getModifiers().add(Modifier.STATIC); + return var; + } + + private ExecutableElement createGetFactories(NodeData node, TypeMirror commonSuperType) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror classType = getContext().getType(NodeFactory.class); + TypeMirror classWithWildcards = types.getDeclaredType(Utils.fromTypeMirror(classType), types.getWildcardType(commonSuperType, null)); + TypeMirror listType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), classWithWildcards); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + List children = node.getNodeChildren(); + if (node.needsFactory()) { + children.add(node); + } + + for (NodeData child : children) { + builder.startGroup(); + NodeData childNode = child; + List factories = new ArrayList<>(); + while (childNode.getParent() != null) { + factories.add(childNode); + childNode = childNode.getParent(); + } + 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(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { + List constructors = findUserConstructors(node); + for (ExecutableElement constructor : constructors) { + clazz.add(createCreateMethod(node, createVisibility, constructor)); + } + } + + private List findUserConstructors(NodeData node) { + List constructors = new ArrayList<>(); for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) { if (constructor.getModifiers().contains(PRIVATE)) { continue; @@ -543,9 +775,9 @@ if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) { continue; } - - clazz.add(createCreateMethod(node, createVisibility, constructor)); + constructors.add(constructor); } + return constructors; } private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { diff -r 8e56c6951c86 -r 6e4fb0ccebb1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Mon Feb 25 13:05:23 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Mon Feb 25 13:13:02 2013 +0100 @@ -71,6 +71,17 @@ return !noSpecialization; } + public List getNodeChildren() { + List children = new ArrayList<>(); + for (NodeData child : getDeclaredChildren()) { + if (child.needsFactory()) { + children.add(child); + } + children.addAll(child.getNodeChildren()); + } + return children; + } + void setDeclaredChildren(List declaredChildren) { this.declaredChildren = declaredChildren;