# HG changeset patch # User Christian Humer # Date 1363084732 -3600 # Node ID edc414f52e2b32179ab6fcaec8d791d70bbd29b4 # Parent aad7e9f4f71c040d232e2411fa95b143152c3913# Parent 2c5df42999dd9236e31f5ff01c1033affdb96679 Merge. diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,76 @@ +/* + * 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.test; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class BinaryOperationTest { + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @NodeClass(BinaryNode.class) + abstract static class BinaryNode extends ValueNode { + + @Child protected ValueNode leftNode; + @Child protected ValueNode rightNode; + + public BinaryNode(ValueNode left, ValueNode right) { + this.leftNode = left; + this.rightNode = right; + } + + public BinaryNode(BinaryNode prev) { + this(prev.leftNode, prev.rightNode); + } + + @Specialization + int add(int left, int right) { + return left + right; + } + + @Generic + int add(Object left, Object right) { + return convertInt(left) + convertInt(right); + } + + @Specialization + int sub(int left, int right) { + return left + right; + } + + @Generic + int sub(Object left, Object right) { + return convertInt(left) + convertInt(right); + } + + } + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,158 @@ +/* + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; + +public class RuntimeStringTest { + + @Test + public void testSubstr() { + assertExecute(new RuntimeString("es"), "substr", new RuntimeString("test"), 1, 3); + } + + @Test + public void testConcat() { + assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"), new RuntimeString("concat")); + } + + @Test(expected = ArrayIndexOutOfBoundsException.class) + public void testConcatFail() { + assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat")); + } + + @Test + public void testFindMethodByMethodName() { + // TODO + } + + private static void assertExecute(Object expectedResult, String name, Object... argumentsArray) { + ArgNode[] args = new ArgNode[argumentsArray.length]; + for (int i = 0; i < args.length; i++) { + args[i] = new ArgNode(argumentsArray, i); + } + + BuiltinNode node = null; + for (NodeFactory nodeFactory : RuntimeStringTestFactory.getFactories()) { + GeneratedBy generated = nodeFactory.getClass().getAnnotation(GeneratedBy.class); + Assert.assertNotNull(generated); + Assert.assertNotSame("", generated.methodName()); + if (generated.methodName().equals(name)) { + node = nodeFactory.createNode((Object) args); + break; + } + } + Assert.assertNotNull("Node not found", node); + CallTarget target = Truffle.getRuntime().createCallTarget(new TestRootNode(node)); + Assert.assertEquals(expectedResult, target.call()); + } + + static class ArgNode extends ValueNode { + + final Object[] arguments; + final int index; + + ArgNode(Object[] args, int index) { + this.arguments = args; + this.index = index; + } + + @Override + Object execute() { + return arguments[index]; + } + } + + abstract static class BuiltinNode extends ValueNode { + + @Children ArgNode[] parameters; + + BuiltinNode(ArgNode[] parameters) { + this.parameters = adoptChildren(parameters); + } + + BuiltinNode(BuiltinNode prev) { + this(prev.parameters); + } + + } + + @NodeClass(BuiltinNode.class) + static class RuntimeString { + + private final String internal; + + public RuntimeString(String internal) { + this.internal = internal; + } + + @Specialization + static RuntimeString concat(RuntimeString s1, RuntimeString s2) { + return new RuntimeString(s1.internal + s2.internal); + } + + @Specialization + RuntimeString substr(int beginIndex, int endIndex) { + return new RuntimeString(internal.substring(beginIndex, endIndex)); + } + + @Generic + RuntimeString substr(Object beginIndex, Object endIndex) { + return substr(convertInt(beginIndex), convertInt(endIndex)); + } + + static int convertInt(Object value) { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof String) { + return Integer.parseInt((String) value); + } + throw new RuntimeException("Invalid datatype"); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RuntimeString) { + return internal.equals(((RuntimeString) obj).internal); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return internal.hashCode(); + } + + @Override + public String toString() { + return internal; + } + + } + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,71 @@ +/* + * 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.test; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.codegen.test.RuntimeStringTest.RuntimeString; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +public class TypeSystemTest { + + @TypeSystem({int.class, RuntimeString.class}) + static class SimpleTypes { + } + + @TypeSystemReference(SimpleTypes.class) + abstract static class ValueNode extends Node { + + int executeInt() throws UnexpectedResultException { + return SimpleTypesGen.SIMPLETYPES.expectInteger(execute()); + } + + RuntimeString executeString() { + return new RuntimeString(execute().toString()); + } + + @SuppressWarnings("static-method") + final long executeSpecial() { + return 42L; + } + + abstract Object execute(); + + } + + @TypeSystemReference(SimpleTypes.class) + static class TestRootNode extends RootNode { + + @Child private ValueNode node; + + public TestRootNode(ValueNode node) { + this.node = adoptChild(node); + } + + @Override + public Object execute(VirtualFrame frame) { + return node.execute(); + } + } + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,50 @@ +/* + * 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. + */ +/** + *

This package contains basic tests of the Truffle-Source-Code-Generation (short Codegen) API and serves at the same + * time as an introduction to the Codegen API for language implementors. Every test gives an example on how to use the construct explained in the class description.

+ * + *

+ * This API relies heavily on the concepts described in {@link com.oracle.truffle.api.test}. We assume that the + * reader is already familiarized with those concepts. + *

+ * + *

+ * TODO general description + *

+ * + *

+ * This introduction to Codegen contains items in the following recommended order: + * + * Prerequisites: + * + * + *

+ *

+ * + */ +package com.oracle.truffle.api.codegen.test; + diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java Tue Mar 12 11:38:52 2013 +0100 @@ -25,12 +25,14 @@ import java.lang.annotation.*; /** - * Marks a type to be generated by another class. + * Marks a type to be generated by another class or a method. */ -@Retention(RetentionPolicy.CLASS) +@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface GeneratedBy { Class value(); + String methodName() default ""; + } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java Tue Mar 12 10:02:20 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * 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.lang.annotation.*; - -/** - * - * - * @see SpecializationGuard - */ -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface GuardCheck { - -} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,35 @@ +/* + * 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.lang.annotation.*; + +import com.oracle.truffle.api.nodes.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE}) +public @interface NodeClass { + + Class value(); + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java Tue Mar 12 11:38:52 2013 +0100 @@ -24,6 +24,8 @@ import java.util.*; +import com.oracle.truffle.api.nodes.*; + /** * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate * generated node classes without using reflection. @@ -63,4 +65,10 @@ */ List>> getNodeSignatures(); + /** + * Returns a list of children that will be executed by the created node. This is useful for base + * nodes that can execute a variable amount of nodes. + */ + List> getChildrenSignature(); + } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,33 @@ +/* + * 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.lang.annotation.*; + +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface NodeId { + + String value(); + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java Tue Mar 12 11:38:52 2013 +0100 @@ -32,8 +32,8 @@ int order() default DEFAULT_ORDER; - SpecializationThrows[] exceptions() default {}; + Class[] rewriteOn() default {}; - SpecializationGuard[] guards() default {}; + String[] guards() default {}; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java Tue Mar 12 10:02:20 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * 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.lang.annotation.*; - -/** - * Specifies the use of a guard for a specialization. - */ -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface SpecializationGuard { - - /** - * Specifies the name of the guard method annotated by {@link GuardCheck} specified as method in - * the {@link TypeSystem} class. - */ - String methodName(); - - /** - * Determines if a guard check is invoked on specialization. Defaults to true. - */ - boolean onSpecialization() default true; - - /** - * Determines if a guard check is invoked on execution. Defaults to true. - */ - boolean onExecution() default true; - -} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java Tue Mar 12 10:02:20 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - * 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.lang.annotation.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.METHOD}) -public @interface SpecializationThrows { - - Class javaClass(); - - String transitionTo(); -} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Tue Mar 12 11:38:52 2013 +0100 @@ -28,8 +28,8 @@ *

* Annotates a type system class that represents type information for a node. Generates code for * converting and managing types. Methods contained in the type system may be annotated with - * {@link TypeCast}, {@link TypeCheck} or {@link GuardCheck}. These methods alter the default - * behavior of the type system. + * {@link TypeCast} or {@link TypeCheck}. These methods alter the default behavior of the type + * system. *

* * @@ -62,7 +62,6 @@ * * @see TypeCast * @see TypeCheck - * @see GuardCheck */ @Retention(RetentionPolicy.CLASS) @Target({ElementType.TYPE}) diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Tue Mar 12 11:38:52 2013 +0100 @@ -55,9 +55,17 @@ return boxedType; } + public static List asTypeMirrors(List elements) { + List types = new ArrayList<>(elements.size()); + for (Element element : elements) { + types.add(element.asType()); + } + return types; + } + public static List collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, Class annotationClass) { - List result = Utils.getAnnotationValueList(markerAnnotation, elementName); + List result = Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName); AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); if (explicit != null) { result.add(explicit); @@ -167,6 +175,46 @@ return new LinkedHashSet<>(Arrays.asList(modifier)); } + public static String getTypeId(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "Boolean"; + case BYTE: + return "Byte"; + case CHAR: + return "Char"; + case DOUBLE: + return "Double"; + case FLOAT: + return "Float"; + case SHORT: + return "Short"; + case INT: + return "Int"; + case LONG: + return "Long"; + case DECLARED: + return ((DeclaredType) mirror).asElement().getSimpleName().toString(); + case ARRAY: + return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; + case VOID: + return "Void"; + case WILDCARD: + StringBuilder b = new StringBuilder(); + WildcardType type = (WildcardType) mirror; + if (type.getExtendsBound() != null) { + b.append("Extends").append(getTypeId(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("Super").append(getTypeId(type.getExtendsBound())); + } + return b.toString(); + case TYPEVAR: + return "Any"; + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + public static String getSimpleName(TypeElement element) { return getSimpleName(element.asType()); } @@ -428,29 +476,32 @@ } @SuppressWarnings("unchecked") - public static List getAnnotationValueList(AnnotationMirror mirror, String name) { + public static List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { + List values = getAnnotationValue(List.class, mirror, name); List result = new ArrayList<>(); - List values = (List) getAnnotationValue(mirror, name).getValue(); + for (AnnotationValue value : values) { - result.add((T) value.getValue()); + result.add(resolveAnnotationValue(expectedListType, value)); } return result; } - public static TypeMirror getAnnotationValueType(AnnotationMirror mirror, String name) { - return (TypeMirror) getAnnotationValue(mirror, name).getValue(); + public static T getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { + return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); } - public static TypeMirror getAnnotationValueTypeMirror(AnnotationMirror mirror, String name) { - return (TypeMirror) getAnnotationValue(mirror, name).getValue(); - } - - public static String getAnnotationValueString(AnnotationMirror mirror, String name) { - return (String) getAnnotationValue(mirror, name).getValue(); - } - - public static int getAnnotationValueInt(AnnotationMirror mirror, String name) { - return (int) getAnnotationValue(mirror, name).getValue(); + @SuppressWarnings({"unchecked"}) + private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { + Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); + if (unboxedValue != null) { + if (expectedType == TypeMirror.class && unboxedValue instanceof String) { + return null; + } + if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { + throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); + } + } + return (T) unboxedValue; } public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { @@ -470,9 +521,79 @@ if (value == null) { value = valueMethod.getDefaultValue(); } + return value; } + private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7 { + + @Override + public Object visitBoolean(boolean b, Void p) { + return Boolean.valueOf(b); + } + + @Override + public Object visitByte(byte b, Void p) { + return Byte.valueOf(b); + } + + @Override + public Object visitChar(char c, Void p) { + return c; + } + + @Override + public Object visitDouble(double d, Void p) { + return d; + } + + @Override + public Object visitFloat(float f, Void p) { + return f; + } + + @Override + public Object visitInt(int i, Void p) { + return i; + } + + @Override + public Object visitLong(long i, Void p) { + return i; + } + + @Override + public Object visitShort(short s, Void p) { + return s; + } + + @Override + public Object visitString(String s, Void p) { + return s; + } + + @Override + public Object visitType(TypeMirror t, Void p) { + return t; + } + + @Override + public Object visitEnumConstant(VariableElement c, Void p) { + return c.getConstantValue(); + } + + @Override + public Object visitAnnotation(AnnotationMirror a, Void p) { + return a; + } + + @Override + public Object visitArray(List vals, Void p) { + return vals; + } + + } + public static boolean getAnnotationValueBoolean(AnnotationMirror mirror, String name) { return (Boolean) getAnnotationValue(mirror, name).getValue(); } @@ -591,6 +712,14 @@ } String qualified1 = getQualifiedName(type1); String qualified2 = getQualifiedName(type2); + + if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) { + if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) { + return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType()); + } else { + return false; + } + } return qualified1.equals(qualified2); } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Tue Mar 12 11:38:52 2013 +0100 @@ -204,7 +204,7 @@ return v.visitExecutable(this, p); } - public static CodeExecutableElement clone(ProcessingEnvironment env, ExecutableElement method) { + public static CodeExecutableElement clone(@SuppressWarnings("unused") ProcessingEnvironment env, ExecutableElement method) { CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); for (TypeMirror thrownType : method.getThrownTypes()) { copy.addThrownType(thrownType); @@ -220,7 +220,6 @@ for (Element element : method.getEnclosedElements()) { copy.add(element); } - copy.setBody(Utils.getMethodBody(env, method)); copy.getModifiers().addAll(method.getModifiers()); return copy; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Tue Mar 12 11:38:52 2013 +0100 @@ -495,7 +495,7 @@ } public CodeTreeBuilder create() { - return new CodeTreeBuilder(null); + return new CodeTreeBuilder(this); } public CodeTreeBuilder type(TypeMirror type) { diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Tue Mar 12 11:38:52 2013 +0100 @@ -123,6 +123,14 @@ writeClassImpl(e); } + private String useImport(TypeMirror type) { + if (imports != null) { + return imports.useImport(type); + } else { + return Utils.getSimpleName(type); + } + } + private void writeClassImpl(CodeTypeElement e) { for (AnnotationMirror annotation : e.getAnnotationMirrors()) { visitAnnotation(annotation); @@ -137,12 +145,12 @@ } write(e.getSimpleName()); if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) { - write(" extends ").write(typeSimpleName(e.getSuperclass())); + write(" extends ").write(useImport(e.getSuperclass())); } if (e.getImplements().size() > 0) { write(" implements "); for (int i = 0; i < e.getImplements().size(); i++) { - write(typeSimpleName(e.getImplements().get(i))); + write(useImport(e.getImplements().get(i))); if (i < e.getImplements().size() - 1) { write(", "); } @@ -267,7 +275,7 @@ } } else { writeModifiers(f.getModifiers()); - write(typeSimpleName(f.asType())); + write(useImport(f.asType())); if (f.getEnclosingElement().getKind() == ElementKind.METHOD) { ExecutableElement method = (ExecutableElement) f.getEnclosingElement(); @@ -287,7 +295,7 @@ } public void visitAnnotation(AnnotationMirror e) { - write("@").write(typeSimpleName(e.getAnnotationType())); + write("@").write(useImport(e.getAnnotationType())); if (!e.getElementValues().isEmpty()) { write("("); @@ -395,14 +403,14 @@ @Override public Void visitType(TypeMirror t, Void p) { - write(typeSimpleName(t)); + write(useImport(t)); write(".class"); return null; } @Override public Void visitEnumConstant(VariableElement c, Void p) { - write(typeSimpleName(c.asType())); + write(useImport(c.asType())); write("."); write(c.getSimpleName().toString()); return null; @@ -458,7 +466,7 @@ writeModifiers(e.getModifiers()); if (e.getReturnType() != null) { - write(typeSimpleName(e.getReturnType())); + write(useImport(e.getReturnType())); write(" "); } write(e.getSimpleName()); @@ -477,7 +485,7 @@ if (throwables.size() > 0) { write(" throws "); for (int i = 0; i < throwables.size(); i++) { - write(typeSimpleName(throwables.get(i))); + write(useImport(throwables.get(i))); if (i < throwables.size() - 1) { write(", "); } @@ -554,7 +562,7 @@ } break; case TYPE: - write(imports.useImport(e.getType())); + write(useImport(e.getType())); break; default: assert false; @@ -562,10 +570,6 @@ } } - private static String typeSimpleName(TypeMirror type) { - return Utils.getSimpleName(type); - } - protected void writeHeader() { // default implementation does nothing } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Tue Mar 12 11:38:52 2013 +0100 @@ -359,6 +359,100 @@ public void visitAnnotation(AnnotationMirror e) { addImport(e.getAnnotationType()); + if (!e.getElementValues().isEmpty()) { + Map values = e.getElementValues(); + Set methodsSet = values.keySet(); + List methodsList = new ArrayList<>(); + for (ExecutableElement method : methodsSet) { + if (values.get(method) == null) { + continue; + } + methodsList.add(method); + } + + for (int i = 0; i < methodsList.size(); i++) { + AnnotationValue value = values.get(methodsList.get(i)); + visitAnnotationValue(value); + } + } + } + + public void visitAnnotationValue(AnnotationValue e) { + e.accept(new AnnotationValueReferenceVisitor(), null); + } + + private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7 { + + @Override + public Void visitBoolean(boolean b, Void p) { + return null; + } + + @Override + public Void visitByte(byte b, Void p) { + return null; + } + + @Override + public Void visitChar(char c, Void p) { + return null; + } + + @Override + public Void visitDouble(double d, Void p) { + return null; + } + + @Override + public Void visitFloat(float f, Void p) { + return null; + } + + @Override + public Void visitInt(int i, Void p) { + return null; + } + + @Override + public Void visitLong(long i, Void p) { + return null; + } + + @Override + public Void visitShort(short s, Void p) { + return null; + } + + @Override + public Void visitString(String s, Void p) { + return null; + } + + @Override + public Void visitType(TypeMirror t, Void p) { + addImport(t); + return null; + } + + @Override + public Void visitEnumConstant(VariableElement c, Void p) { + addImport(c.asType()); + return null; + } + + @Override + public Void visitAnnotation(AnnotationMirror a, Void p) { + ReferenceCollector.this.visitAnnotation(a); + return null; + } + + @Override + public Void visitArray(List vals, Void p) { + for (int i = 0; i < vals.size(); i++) { + ReferenceCollector.this.visitAnnotationValue(vals.get(i)); + } + return null; + } } @Override diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java Tue Mar 12 11:38:52 2013 +0100 @@ -39,6 +39,9 @@ } protected static Object field(Object o, String fieldName) throws Exception { + if (o == null) { + return null; + } Field field = o.getClass().getField(fieldName); field.setAccessible(true); return field.get(o); diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -88,7 +88,7 @@ } else { AnnotationMirror foundExtension = Utils.findAnnotationMirror(context.getEnvironment(), mirror.getAnnotationType().asElement(), ExtensionAnnotation.class); if (foundExtension != null) { - String className = Utils.getAnnotationValueString(foundExtension, "processorClassName"); + String className = Utils.getAnnotationValue(String.class, foundExtension, "processorClassName"); Class processorClass; try { processorClass = Class.forName(className); diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -51,7 +51,7 @@ List parameters = new ArrayList<>(); parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); - return new MethodSpec(returnTypeSpec, parameters); + return new MethodSpec(new ArrayList(), returnTypeSpec, parameters); } @Override diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -41,7 +41,7 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(null); + return createDefaultMethodSpec(method, mirror, null); } @Override diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -25,9 +25,10 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; @@ -54,10 +55,21 @@ return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } - protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { + @SuppressWarnings("unused") + protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) { List defaultParameters = new ArrayList<>(); - ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true); - defaultParameters.add(frameSpec); + + if (getNode().supportsFrame()) { + defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); + } + + TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); + + List prefixTypes = new ArrayList<>(); + + if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) { + prefixTypes.add(getNode().getTemplateType().asType()); + } for (NodeFieldData field : getNode().getFields()) { if (field.getExecutionKind() == ExecutionKind.IGNORE) { @@ -65,7 +77,12 @@ } if (field.getExecutionKind() == ExecutionKind.DEFAULT) { - defaultParameters.add(createValueParameterSpec(field.getName(), field.getNodeData(), false)); + ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData(), false); + if (field.getKind() == FieldKind.CHILDREN) { + spec.setCardinality(Cardinality.MULTIPLE); + spec.setIndexed(true); + } + defaultParameters.add(spec); } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { String valueName = field.getName(); if (shortCircuitName != null && valueName.equals(shortCircuitName)) { @@ -79,7 +96,7 @@ } } - return new MethodSpec(createReturnParameterSpec(), defaultParameters); + return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters); } private static String shortCircuitValueName(String valueName) { diff -r 2c5df42999dd -r edc414f52e2b 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 Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Tue Mar 12 11:38:52 2013 +0100 @@ -34,7 +34,7 @@ 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; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.typesystem.*; @@ -51,73 +51,49 @@ } private static String factoryClassName(NodeData node) { - return nodeClassName(node) + "Factory"; - } - - private static String nodeClassName(NodeData node) { - return Utils.getSimpleName(node.getTemplateType().asType()); + return node.getNodeId() + "Factory"; } - private static String nodeClassName(SpecializationData specialization) { - String name = specializationId(specialization); - name += nodeClassName(specialization.getNode()); - if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) { - name = name + "Impl"; + private static String nodeSpecializationClassName(SpecializationData specialization) { + String nodeid = specialization.getNode().getNodeId(); + if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { + nodeid = nodeid.substring(0, nodeid.length() - 4); } + String name = Utils.firstLetterUpperCase(nodeid); + name += Utils.firstLetterUpperCase(specialization.getId()); + name += "Node"; return name; } - private static String specializationId(SpecializationData specialization) { - String name = ""; - NodeData node = specialization.getNode(); - if (node.getSpecializations().length > 1) { - name = specialization.getMethodName(); - if (name.startsWith("do")) { - name = name.substring(2); - } - } - return name; - } - - private static String valueName(NodeFieldData field) { - return field.getName() + "Value"; - } - private static String valueName(ActualParameter param) { - NodeData node = (NodeData) param.getMethod().getTemplate(); - NodeFieldData field = node.findField(param.getSpecification().getName()); - if (field != null) { - return valueName(field); - } else { - return param.getSpecification().getName(); - } + return param.getName(); } private static String castValueName(ActualParameter parameter) { return valueName(parameter) + "Cast"; } - private static String castValueName(NodeFieldData field) { - return valueName(field) + "Cast"; - } - - private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { - if (forceFrame) { - method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame")); + private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean includeHidden) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); } for (ActualParameter parameter : specialization.getParameters()) { ParameterSpec spec = parameter.getSpecification(); if (forceFrame && spec.getName().equals("frame")) { continue; } + if (!includeHidden && parameter.isHidden()) { + continue; + } + method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter))); } } - private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) { - if (forceFrame) { - builder.string("frame"); + private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeHidden) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + builder.string("frameValue"); } for (ActualParameter parameter : specialization.getParameters()) { ParameterSpec spec = parameter.getSpecification(); @@ -125,7 +101,11 @@ continue; } - if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) { + if (!includeHidden && parameter.isHidden()) { + continue; + } + + if (unexpectedValueName != null && parameter.getName().equals(unexpectedValueName)) { builder.string("ex.getResult()"); } else { builder.string(valueName(parameter)); @@ -133,14 +113,18 @@ } } - private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) { + private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization, boolean includeHidden) { NodeData node = targetSpecialization.getNode(); TypeSystemData typeSystem = node.getTypeSystem(); for (ActualParameter targetParameter : targetSpecialization.getParameters()) { - ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getSpecification().getName()); + ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getName()); TypeData targetType = targetParameter.getActualTypeData(typeSystem); + if (!includeHidden && (targetParameter.isHidden() || valueParameter.isHidden())) { + continue; + } + TypeData valueType = null; if (valueParameter != null) { valueType = valueParameter.getActualTypeData(typeSystem); @@ -158,15 +142,41 @@ return getSimpleName(operation.getTemplateType()) + "Gen"; } - private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) { + private void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) { body.startGroup(); - if (body.findMethod().getModifiers().contains(STATIC)) { - body.string(THIS_NODE_LOCAL_VAR_NAME); + ExecutableElement method = templateMethod.getMethod(); + + TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); + NodeData node = (NodeData) templateMethod.getTemplate(); + + boolean accessible = templateMethod.canBeAccessedByInstanceOf(node.getNodeType()); + if (accessible) { + if (body.findMethod().getModifiers().contains(STATIC)) { + body.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + body.string("super"); + } } else { - body.string("super"); + if (method.getModifiers().contains(STATIC)) { + body.type(targetClass.asType()); + } else { + ActualParameter parameter = templateMethod.getParameters().get(0); + if (castedValues) { + NodeFieldData field = node.findField(parameter.getSpecification().getName()); + NodeData fieldNode = field.getNodeData(); + ExecutableTypeData execType = fieldNode.findExecutableType(parameter.getActualTypeData(node.getTypeSystem())); + if (execType.hasUnexpectedValue(getContext())) { + body.string(castValueName(parameter)); + } else { + body.string(valueName(parameter)); + } + } else { + body.string(valueName(parameter)); + } + } } body.string("."); - body.startCall(method.getMethodName()); + body.startCall(method.getSimpleName().toString()); } private static String generatedGenericMethodName(SpecializationData specialization) { @@ -182,7 +192,7 @@ if (prev == null || prev.isUninitialized()) { return prefix; } else { - return prefix + specializationId(current); + return prefix + current.getId(); } } prev = current; @@ -253,8 +263,7 @@ return builder.getRoot(); } - private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, - boolean onSpecialization) { + private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; if (guardedSpecialization.getGuards().length > 0) { @@ -263,8 +272,8 @@ if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { builder.string(andOperator); - startCallOperationMethod(builder, guard.getGuardDeclaration()); - addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization); + startCallOperationMethod(builder, guard.getGuardDeclaration(), true); + addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization, false); builder.end().end(); // call andOperator = " && "; @@ -276,13 +285,14 @@ } private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { - NodeData node = guardedSpecialization.getNode(); - CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature - for (NodeFieldData field : node.getFields()) { - ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); - ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { + NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); + if (field == null) { + continue; + } + ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getName()); CodeTree cast = createCast(parent, field, valueParam, guardedParam); if (cast == null) { @@ -295,14 +305,15 @@ } private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { - NodeData node = guardedSpecialization.getNode(); - CodeTreeBuilder builder = new CodeTreeBuilder(parent); // Implict guards based on method signature String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; - for (NodeFieldData field : node.getFields()) { - ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); - ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); + for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { + NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); + if (field == null) { + continue; + } + ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getName()); CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); if (implicitGuard == null) { @@ -339,7 +350,7 @@ } startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem()))); - builder.string(valueName(field)); + builder.string(valueName(source)); builder.end().end(); // call if (field.isShortCircuit()) { @@ -371,7 +382,7 @@ CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target)); - return createLazyAssignment(parent, castValueName(field), target.getActualType(), condition, value); + return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value); } /** @@ -492,7 +503,7 @@ if (node.needsFactory()) { createFactoryMethods(node, clazz, createVisibility); - if (node.getSpecializations().length > 1) { + if (node.getSpecializations().size() > 1) { clazz.add(createCreateSpecializedMethod(node, createVisibility)); } @@ -515,6 +526,7 @@ clazz.add(createCreateNodeSpecializedMethod(node)); clazz.add(createGetNodeClassMethod(node)); clazz.add(createGetNodeSignaturesMethod(node)); + clazz.add(createGetChildrenSignatureMethod(node)); clazz.add(createGetInstanceMethod(node, createVisibility)); clazz.add(createInstanceConstant(node, clazz.asType())); } @@ -565,21 +577,62 @@ 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.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType)); } builder.end(); builder.end(); return method; } + private CodeExecutableElement createGetChildrenSignatureMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); + TypeMirror classType = getContext().getType(Class.class); + TypeMirror nodeType = getContext().getTruffleTypes().getNode(); + TypeMirror wildcardNodeType = types.getWildcardType(nodeType, null); + classType = types.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType); + TypeMirror returnType = types.getDeclaredType(listType, classType); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getChildrenSignature"); + CodeTreeBuilder builder = method.createBuilder(); + + List signatureTypes = new ArrayList<>(); + assert !node.getSpecializations().isEmpty(); + SpecializationData data = node.getSpecializations().get(0); + for (ActualParameter parameter : data.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + NodeFieldData field = node.findField(spec.getName()); + if (field == null) { + continue; + } + + TypeMirror type; + if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) { + type = ((ArrayType) field.getType()).getComponentType(); + } else { + type = field.getType(); + } + + signatureTypes.add(type); + } + + builder.startReturn().tree(createAsList(builder, signatureTypes, classType)).end(); + return method; + } + + private CodeTree createAsList(CodeTreeBuilder parent, List types, TypeMirror elementClass) { + CodeTreeBuilder builder = parent.create(); + builder.startGroup(); + builder.type(getContext().getType(Arrays.class)); + builder.string(".<").type(elementClass).string(">"); + builder.startCall("asList"); + for (TypeMirror typeMirror : types) { + builder.typeLiteral(typeMirror); + } + builder.end().end(); + return builder.getRoot(); + } + private CodeExecutableElement createCreateNodeMethod(NodeData node) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); @@ -717,15 +770,21 @@ } List nodeTypesList = new ArrayList<>(); + TypeMirror prev = null; + boolean allSame = true; for (NodeData child : children) { - nodeTypesList.add(child.getTemplateType().asType()); + nodeTypesList.add(child.getNodeType()); + if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) { + allSame = false; + } + prev = child.getNodeType(); } TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); Types types = getContext().getEnvironment().getTypeUtils(); TypeMirror factoryType = getContext().getType(NodeFactory.class); TypeMirror baseType; - if (children.size() == 1) { + if (allSame) { baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); } else { baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); @@ -793,10 +852,10 @@ CodeTreeBuilder body = method.createBuilder(); body.startReturn(); - if (node.getSpecializations().length == 0) { + if (node.getSpecializations().isEmpty()) { body.null_(); } else { - body.startNew(nodeClassName(node.getSpecializations()[0])); + body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0))); for (VariableElement var : method.getParameters()) { body.string(var.getSimpleName().toString()); } @@ -828,14 +887,14 @@ body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeClassName(specialization)); + body.startReturn().startNew(nodeSpecializationClassName(specialization)); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); // new, return body.end(); // if } } - body.startReturn().startNew(nodeClassName(node.getGenericSpecialization())); + body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization())); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); return method; @@ -845,17 +904,17 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addValueParameters(method, node.getGenericSpecialization(), false); + addValueParameters(method, node.getGenericSpecialization(), false, true); CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[0])).string(".class)").end(); + body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); - for (int i = 1; i < node.getSpecializations().length; i++) { - SpecializationData specialization = node.getSpecializations()[i]; - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); + for (int i = 1; i < node.getSpecializations().size(); i++) { + SpecializationData specialization = node.getSpecializations().get(i); + body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); CodeTreeBuilder guarded = new CodeTreeBuilder(body); - guarded.startReturn().startNew(nodeClassName(specialization)); + guarded.startReturn().startNew(nodeSpecializationClassName(specialization)); guarded.string(THIS_NODE_LOCAL_VAR_NAME); guarded.end().end(); @@ -871,11 +930,11 @@ if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) { List methods = new ArrayList<>(); - SpecializationData[] specializations = node.getSpecializations(); + List specializations = node.getSpecializations(); SpecializationData prev = null; - for (int i = 0; i < specializations.length; i++) { - SpecializationData current = specializations[i]; - SpecializationData next = i + 1 < specializations.length ? specializations[i + 1] : null; + for (int i = 0; i < specializations.size(); i++) { + SpecializationData current = specializations.get(i); + SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; if (prev == null || current.isUninitialized()) { prev = current; continue; @@ -883,7 +942,7 @@ String methodName = generatedGenericMethodName(current); CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addValueParameters(method, node.getGenericSpecialization(), true, true); emitGeneratedGenericSpecialization(method.createBuilder(), current, next); @@ -896,7 +955,7 @@ } else { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addValueParameters(method, node.getGenericSpecialization(), true, true); emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); return Arrays.asList(method); } @@ -918,29 +977,29 @@ builder.startReturn().startCall(generatedGenericMethodName(next)); builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, next, null, true); + addValueParameterNames(builder, next, null, true, true); builder.end().end(); } } private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { builder.startTryBlock(); } builder.startReturn(); - startCallOperationMethod(builder, specialization); - addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization); + startCallOperationMethod(builder, specialization, true); + addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false); builder.end().end(); // start call operation builder.end(); // return - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, exception.getTransitionTo(), null, true); + addValueParameterNames(builder, exception.getTransitionTo(), null, true, true); builder.end().end(); } builder.end(); @@ -957,7 +1016,7 @@ @Override public CodeTypeElement create(SpecializationData specialization) { NodeData node = specialization.getNode(); - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false); return clazz; } @@ -981,7 +1040,7 @@ CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); if (method.getParameters().size() == 1) { CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0)); - var.setName("frame"); + var.setName("frameValue"); method.getParameters().set(0, var); } method.getModifiers().remove(Modifier.ABSTRACT); @@ -996,7 +1055,7 @@ } if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { - buildSpecializeStateMethod(clazz, specialization); + buildSpecializeAndExecute(clazz, specialization); } } @@ -1014,7 +1073,7 @@ CodeTree primaryExecuteCall = null; CodeTreeBuilder executeBuilder = CodeTreeBuilder.createBuilder(); - buildExecute(executeBuilder, null, execType); + buildExecute(executeBuilder, null, null, execType); primaryExecuteCall = executeBuilder.getRoot(); if (needsTry) { @@ -1122,7 +1181,7 @@ builder.startCall(factoryClassName(node), "specialize"); builder.string("this"); builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addValueParameterNames(builder, specialization, null, false); + addValueParameterNames(builder, specialization, null, false, true); builder.end(); // call replace, call specialize } else { builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); @@ -1134,29 +1193,29 @@ private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) { NodeData node = specialization.getNode(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { builder.startTryBlock(); } if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); builder.string("this"); - addValueParameterNames(builder, specialization, null, true); + addValueParameterNames(builder, specialization, null, true, true); builder.end().end(); } else { builder.startReturn(); if (specialization.isUninitialized()) { - startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization()); + startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false); } else { - startCallOperationMethod(builder, specialization); + startCallOperationMethod(builder, specialization, false); } - addValueParameterNames(builder, specialization, null, false); + addValueParameterNames(builder, specialization, null, false, false); builder.end().end(); // operation call builder.end(); // return } - if (specialization.getExceptions().length > 0) { + if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null)); @@ -1168,18 +1227,14 @@ private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); - for (NodeFieldData field : specialization.getNode().getFields()) { - if (field.getExecutionKind() == ExecutionKind.IGNORE) { + + for (ActualParameter parameter : specialization.getParameters()) { + NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName()); + if (field == null) { continue; } - ActualParameter parameterType = specialization.findParameter(field.getName()); - - if (parameterType.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) { - buildGenericValueExecute(builder, specialization, field, null); - } else { - buildSpecializedValueExecute(builder, specialization, field); - } + buildFieldExecute(builder, specialization, parameter, field, null); } return builder.getRoot(); } @@ -1187,37 +1242,58 @@ private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { for (TemplateMethod listener : node.getSpecializationListeners()) { builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); + startCallOperationMethod(builder, listener, false); + addValueParameterNames(builder, listener, null, false, false); builder.end().end(); builder.end(); // statement } } - private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field, NodeFieldData exceptionSpec) { - ActualParameter specParameter = specialization.findParameter(field.getName()); - NodeData node = specialization.getNode(); - boolean shortCircuit = startShortCircuit(builder, specialization, field, exceptionSpec); + private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) { + boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam); + ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); + boolean unexpected = execType.hasUnexpectedValue(getContext()); - builder.startStatement(); - if (!shortCircuit) { - builder.type(specialization.getNode().getTypeSystem().getGenericType()); - builder.string(" "); + if (!shortCircuit && unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); + } + + if (unexpected) { + builder.startTryBlock(); } - builder.string(valueName(specParameter)); - builder.string(" = "); - ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), specParameter.getActualTypeData(node.getTypeSystem())); - if (genericExecutableType == null) { - throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes())); + if (!shortCircuit && !unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = "); + } else { + builder.startStatement().string(valueName(param)).string(" = "); } - buildExecute(builder, field, genericExecutableType); + buildExecute(builder, param, field, execType); builder.end(); + if (unexpected) { + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + SpecializationData generic = specialization.getNode().getGenericSpecialization(); + boolean execute = false; + for (ActualParameter exParam : generic.getParameters()) { + NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName()); + if (exField == null) { + continue; + } + if (execute) { + buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param); + } else if (exParam.getName().equals(param.getName())) { + execute = true; + } + } + builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param)); + builder.end(); // catch block + } + endShortCircuit(builder, shortCircuit); + builder.newLine(); } - private void buildExecute(CodeTreeBuilder builder, NodeFieldData field, ExecutableTypeData execType) { + private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) { if (field != null) { Element accessElement = field.getAccessElement(); if (accessElement.getKind() == ElementKind.METHOD) { @@ -1227,60 +1303,28 @@ } else { throw new AssertionError(); } + if (parameter.getSpecification().isIndexed()) { + builder.string("[" + parameter.getIndex() + "]"); + } builder.string("."); } builder.startCall(execType.getMethodName()); - if (execType.getParameters().length == 1) { - builder.string("frame"); + if (execType.getParameters().size() == 1) { + builder.string("frameValue"); } builder.end(); } - private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field) { - ActualParameter param = specialization.findParameter(field.getName()); - boolean shortCircuit = startShortCircuit(builder, specialization, field, null); - - if (!shortCircuit) { - builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); - } - - ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); - - if (execType.hasUnexpectedValue(getContext())) { - builder.startTryBlock(); + private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { + NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName()); + if (forField == null) { + return false; } - builder.startStatement().string(valueName(field)).string(" = "); - buildExecute(builder, field, execType); - builder.end(); - - if (execType.hasUnexpectedValue(getContext())) { - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - boolean execute = false; - for (NodeFieldData exField : specialization.getNode().getFields()) { - if (exField.getExecutionKind() == ExecutionKind.IGNORE) { - continue; - } - if (execute) { - buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field); - } else if (exField == field) { - execute = true; - } - } - builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification())); - builder.end(); // catch block - } - - endShortCircuit(builder, shortCircuit); - builder.newLine(); - } - - private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData forField, NodeFieldData exceptionField) { if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { return false; } - ActualParameter parameter = specialization.findParameter(forField.getName()); ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); int shortCircuitIndex = 0; @@ -1296,14 +1340,14 @@ builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; - startCallOperationMethod(builder, shortCircuitData); - addValueParameterNames(builder, shortCircuitData, exceptionField != null ? exceptionField.getName() : null, false); + startCallOperationMethod(builder, shortCircuitData, false); + addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false, false); builder.end().end(); // call operation builder.end(); // statement builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); - builder.startIf().string(shortCircuitParam.getSpecification().getName()).end(); + builder.startIf().string(shortCircuitParam.getName()).end(); builder.startBlock(); return true; @@ -1315,11 +1359,11 @@ } } - private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { + private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) { CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); specializeCall.startCall("specializeAndExecute"); - specializeCall.string(nodeClassName(nextSpecialization) + ".class"); - addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); + specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); + addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true, true); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1329,7 +1373,7 @@ return builder.getRoot(); } - private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { + private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) { NodeData node = specialization.getNode(); TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); ExecutableTypeData returnExecutableType = node.findExecutableType(returnType); @@ -1340,7 +1384,7 @@ if (canThrowUnexpected) { method.addThrownType(getUnexpectedValueException()); } - addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); + addValueParameters(method, specialization.getNode().getGenericSpecialization(), true, true); clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); @@ -1351,7 +1395,7 @@ builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false); + addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true); builder.end(); builder.end(); // call replace builder.end(); // statement @@ -1362,7 +1406,7 @@ CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); genericExecute.string("this"); - addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true); + addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true); genericExecute.end(); // call generated generic CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot()); diff -r 2c5df42999dd -r edc414f52e2b 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 Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Tue Mar 12 11:38:52 2013 +0100 @@ -35,22 +35,59 @@ public class NodeData extends Template { - private NodeData parent; - private List declaredChildren; + private final String nodeId; + private NodeData declaringNode; + private List declaredChildren = new ArrayList<>(); private final TypeSystemData typeSystem; + private List fields; + private TypeMirror nodeType; + private ParameterSpec instanceParameterSpec; - private NodeFieldData[] fields; - private SpecializationData[] specializations; - private TemplateMethod[] specializationListeners; - private GuardData[] guards; - private ExecutableTypeData[] executableTypes; + private List specializations; + private List specializationListeners; + private List guards; + private List executableTypes; + private List shortCircuits; + + public NodeData(TypeElement type, TypeSystemData typeSystem, String id) { + super(type, null, null); + this.nodeId = id; + this.typeSystem = typeSystem; + } - private TypeMirror nodeType; + public NodeData(NodeData copy, String templateMethodName, String nodeId) { + super(copy.getTemplateType(), templateMethodName, null); + this.nodeId = nodeId; + this.declaringNode = copy.declaringNode; + this.declaredChildren = copy.declaredChildren; + this.typeSystem = copy.typeSystem; + this.nodeType = copy.nodeType; + this.specializations = copy.specializations; + this.specializationListeners = copy.specializationListeners; + this.guards = copy.guards; + this.executableTypes = copy.executableTypes; + this.shortCircuits = copy.shortCircuits; - public NodeData(TypeElement type, TypeSystemData typeSystem) { - super(type, null); - this.typeSystem = typeSystem; + List fieldsCopy = new ArrayList<>(); + for (NodeFieldData field : copy.fields) { + NodeFieldData newField = new NodeFieldData(field); + newField.setNode(this); + fieldsCopy.add(newField); + } + this.fields = fieldsCopy; + } + + public ParameterSpec getInstanceParameterSpec() { + return instanceParameterSpec; + } + + public void setInstanceParameterSpec(ParameterSpec instanceParameter) { + this.instanceParameterSpec = instanceParameter; + } + + public String getNodeId() { + return nodeId; } public TypeMirror getNodeType() { @@ -71,6 +108,15 @@ return !noSpecialization; } + public boolean supportsFrame() { + for (ExecutableTypeData execType : executableTypes) { + if (execType.findParameter("frameValue") == null) { + return false; + } + } + return true; + } + public List getNodeChildren() { List children = new ArrayList<>(); for (NodeData child : getDeclaredChildren()) { @@ -86,12 +132,12 @@ this.declaredChildren = declaredChildren; for (NodeData child : declaredChildren) { - child.parent = this; + child.declaringNode = this; } } public NodeData getParent() { - return parent; + return declaringNode; } public List getDeclaredChildren() { @@ -112,17 +158,14 @@ } } - methods.addAll(Arrays.asList(getSpecializationListeners())); - methods.addAll(Arrays.asList(getExecutableTypes())); - methods.addAll(Arrays.asList(getGuards())); + methods.addAll(getSpecializationListeners()); + methods.addAll(getExecutableTypes()); + methods.addAll(getGuards()); + methods.addAll(getShortCircuits()); return methods; } - public TemplateMethod[] getSpecializationListeners() { - return specializationListeners; - } - public List findGuards(String name) { List foundGuards = new ArrayList<>(); for (GuardData guardData : getGuards()) { @@ -133,10 +176,6 @@ return foundGuards; } - public ExecutableTypeData[] getExecutableTypes() { - return executableTypes; - } - public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) { List types = findGenericExecutableTypes(context); for (ExecutableTypeData availableType : types) { @@ -180,47 +219,20 @@ return result; } - public TypeMirror[] getExecutablePrimitiveTypeMirrors() { - TypeMirror[] typeMirrors = new TypeMirror[executableTypes.length]; - for (int i = 0; i < executableTypes.length; i++) { - typeMirrors[i] = executableTypes[i].getType().getPrimitiveType(); + public List getExecutablePrimitiveTypeMirrors() { + List typeMirrors = new ArrayList<>(); + for (ExecutableTypeData executableType : executableTypes) { + typeMirrors.add(executableType.getType().getPrimitiveType()); } return typeMirrors; } - void setExecutableTypes(ExecutableTypeData[] declaredExecuableTypes) { - this.executableTypes = declaredExecuableTypes; - } - - void setFields(NodeFieldData[] fields) { - this.fields = fields; - } - - void setSpecializations(SpecializationData[] specializations) { - this.specializations = specializations; - } - - void setSpecializationListeners(TemplateMethod[] specializationListeners) { - this.specializationListeners = specializationListeners; - } - - void setGuards(GuardData[] guards) { - this.guards = guards; - } - - public GuardData[] getGuards() { - return guards; - } - public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) { List filteredFields = new ArrayList<>(); - NodeFieldData[] resolvedFields = getFields(); - if (fields != null) { - for (NodeFieldData field : resolvedFields) { - if (usage == null || field.getExecutionKind() == usage) { - if (fieldKind == null || field.getKind() == fieldKind) { - filteredFields.add(field); - } + for (NodeFieldData field : getFields()) { + if (usage == null || field.getExecutionKind() == usage) { + if (fieldKind == null || field.getKind() == fieldKind) { + filteredFields.add(field); } } } @@ -249,7 +261,7 @@ } } - needsRewrites &= specializations.length >= 2; + needsRewrites &= specializations.size() >= 2; return needsRewrites; } @@ -270,26 +282,15 @@ } } - public NodeFieldData[] getFields() { - return fields; - } - - public NodeFieldData[] getDeclaredFields() { - return fields; - } - - public SpecializationData[] getSpecializations() { - return specializations; - } - public String dump() { StringBuilder b = new StringBuilder(); - b.append(String.format("[name = %s\n" + " typeSystem = %s\n" + " fields = %s\n" + " types = %s\n" + " specializations = %s\n" + " guards = %s\n" + "]", - Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards))); + b.append(String.format("[id = %s, name = %s\n typeSystem = %s\n fields = %s\n types = %s\n specializations = %s\n guards = %s\n enclosing = %s\n enclosed = %s\n]", getNodeId(), + Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards), + dumpList(getDeclaredChildren()), getParent())); return b.toString(); } - private static String dumpList(Object[] array) { + private static String dumpList(List array) { if (array == null) { return "null"; } @@ -315,4 +316,76 @@ return null; } + public List getFields() { + return fields; + } + + void setFields(List fields) { + this.fields = fields; + } + + public List getSpecializations() { + return getSpecializations(false); + } + + public List getSpecializations(boolean userDefinedOnly) { + if (userDefinedOnly) { + List specs = new ArrayList<>(); + for (SpecializationData spec : specializations) { + if (spec.getMethod() != null) { + specs.add(spec); + } + } + return specs; + } else { + return specializations; + } + } + + public List getSpecializationListeners() { + return specializationListeners; + } + + public List getGuards() { + return guards; + } + + public List getExecutableTypes() { + return executableTypes; + } + + public List getShortCircuits() { + return shortCircuits; + } + + void setSpecializations(List specializations) { + this.specializations = specializations; + if (this.specializations != null) { + for (SpecializationData specialization : specializations) { + specialization.setNode(this); + } + } + } + + void setSpecializationListeners(List specializationListeners) { + this.specializationListeners = specializationListeners; + } + + void setGuards(List guards) { + this.guards = guards; + } + + void setExecutableTypes(List executableTypes) { + this.executableTypes = executableTypes; + } + + void setShortCircuits(List shortCircuits) { + this.shortCircuits = shortCircuits; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getNodeId() + "]"; + } + } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Tue Mar 12 11:38:52 2013 +0100 @@ -28,7 +28,7 @@ public class NodeFieldData { public enum FieldKind { - FIELD, CHILD, CHILDREN + CHILD, CHILDREN } public enum ExecutionKind { @@ -41,7 +41,7 @@ private final FieldKind fieldKind; private final ExecutionKind executionKind; - private final NodeData nodeData; + private NodeData nodeData; public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) { this.fieldElement = fieldElement; @@ -52,10 +52,23 @@ this.executionKind = executionKind; } + NodeFieldData(NodeFieldData field) { + this.fieldElement = field.fieldElement; + this.accessElement = field.accessElement; + this.childAnnotationMirror = field.childAnnotationMirror; + this.fieldKind = field.fieldKind; + this.executionKind = field.executionKind; + this.nodeData = field.nodeData; + } + public boolean isShortCircuit() { return executionKind == ExecutionKind.SHORT_CIRCUIT; } + void setNode(NodeData nodeData) { + this.nodeData = nodeData; + } + public VariableElement getFieldElement() { return fieldElement; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -41,11 +41,9 @@ public class NodeParser extends TemplateParser { - public static final List> ANNOTATIONS = Arrays.asList(Generic.class, GuardCheck.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, - SpecializationGuard.class, SpecializationListener.class, SpecializationThrows.class); + public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class); private Map parsedNodes; - private TypeElement originalType; public NodeParser(ProcessorContext c) { super(c); @@ -54,23 +52,14 @@ @Override protected NodeData parse(Element element, AnnotationMirror mirror) { assert element instanceof TypeElement; + NodeData node = null; try { parsedNodes = new HashMap<>(); - originalType = (TypeElement) element; - - return parseInnerClassHierarchy((TypeElement) element); + node = resolveNode((TypeElement) element); } finally { - if (Log.DEBUG) { - NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType)); - if (parsed != null) { - String dump = parsed.dump(); - log.error("Node parsed: %s", dump); - System.out.println("Parsed: " + dump); - } - } parsedNodes = null; - originalType = null; } + return node; } @Override @@ -78,182 +67,450 @@ return true; } - private NodeData parseInnerClassHierarchy(TypeElement rootType) { + private NodeData resolveNode(TypeElement rootType) { + String typeName = Utils.getQualifiedName(rootType); + if (parsedNodes.containsKey(typeName)) { + return parsedNodes.get(typeName); + } + List types = ElementFilter.typesIn(rootType.getEnclosedElements()); + List children = new ArrayList<>(); for (TypeElement childElement : types) { - NodeData childNode = parseInnerClassHierarchy(childElement); + NodeData childNode = resolveNode(childElement); if (childNode != null) { children.add(childNode); } } - NodeData rootNode = resolveNode(rootType); + NodeData rootNode = parseNode(rootType); if (rootNode == null && children.size() > 0) { - rootNode = new NodeData(rootType, null); + rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString()); + } + + parsedNodes.put(typeName, rootNode); + + if (rootNode != null) { + children.addAll(rootNode.getDeclaredChildren()); + rootNode.setDeclaredChildren(children); } - if (rootNode != null) { - rootNode.setDeclaredChildren(children); + + if (Log.DEBUG) { + NodeData parsed = parsedNodes.get(typeName); + if (parsed != null) { + String dump = parsed.dump(); + String valid = rootNode != null ? "" : " failed"; + String msg = String.format("Node parsing %s : %s", valid, dump); + log.error(msg); + System.out.println(msg); + } } return rootNode; } - private NodeData resolveNode(TypeElement currentType) { - String typeName = Utils.getQualifiedName(currentType); - if (!parsedNodes.containsKey(typeName)) { - NodeData node = parseNode(currentType); - if (node != null) { - parsedNodes.put(typeName, node); - } - return node; - } - return parsedNodes.get(typeName); - } - private NodeData parseNode(TypeElement type) { if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) { - // generated nodes get called again. + // generated nodes should not get called again. return null; } - if (!Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { + + AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class); + + if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { return null; // not a node } + TypeElement nodeType; + boolean needsSplit; + if (methodNodes != null) { + needsSplit = methodNodes != null; + nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value")); + } else { + needsSplit = false; + nodeType = type; + } + if (type.getModifiers().contains(Modifier.PRIVATE)) { return null; // not visible } - List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); - List typeHierarchy = findSuperClasses(new ArrayList(), type); - Collections.reverse(typeHierarchy); - - AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); - if (typeSystemMirror == null) { - log.error(type, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName()); + NodeData nodeData = parseNodeData(type, nodeType); + if (nodeData == null) { return null; } - TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); - if (typeSystem == null) { - log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); - return null; - } - - NodeData nodeData = new NodeData(type, typeSystem); - + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements)); if (nodeData.getExtensionElements() != null) { elements.addAll(nodeData.getExtensionElements()); } - List executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); - - nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()])); - - parsedNodes.put(Utils.getQualifiedName(type), nodeData); - - NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy); - if (fields == null) { + if (!parseMethods(nodeData, elements)) { return null; } - nodeData.setFields(fields); - List genericSpecializations = new GenericParser(context, nodeData).parse(elements); - List guards = new GuardParser(context, nodeData, nodeData.getTypeSystem()).parse(elements); - nodeData.setGuards(guards.toArray(new GuardData[guards.size()])); + List nodes; + if (needsSplit) { + nodes = splitNodeData(nodeData); + if (nodes == null) { + return null; + } + } else { + nodes = new ArrayList<>(); + nodes.add(nodeData); + } - SpecializationMethodParser specializationParser = new SpecializationMethodParser(context, nodeData); - List specializations = specializationParser.parse(elements); - List shortCircuits = new ShortCircuitParser(context, nodeData).parse(elements); - List listeners = new SpecializationListenerParser(context, nodeData).parse(elements); + boolean valid = true; + for (NodeData splittedNode : nodes) { + if (!finalizeSpecializations(splittedNode)) { + valid = false; + } + if (!verifyNode(splittedNode)) { + valid = false; + } + } - if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) { + if (!valid) { return null; } + if (needsSplit) { + nodeData.setDeclaredChildren(nodes); + nodeData.setSpecializationListeners(new ArrayList()); + nodeData.setSpecializations(new ArrayList()); + return nodeData; + } else { + return nodeData; + } + } + + private static List splitNodeData(NodeData node) { + SortedMap> groupedSpecializations = groupByNodeId(node.getSpecializations()); + SortedMap> groupedListeners = groupByNodeId(node.getSpecializationListeners()); + + Set ids = new TreeSet<>(); + ids.addAll(groupedSpecializations.keySet()); + ids.addAll(groupedListeners.keySet()); + + List splitted = new ArrayList<>(); + for (String id : ids) { + List specializations = groupedSpecializations.get(id); + List listeners = groupedListeners.get(id); + + if (specializations == null) { + specializations = new ArrayList<>(); + } + + if (listeners == null) { + listeners = new ArrayList<>(); + } + + String nodeId = node.getNodeId(); + if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { + nodeId = nodeId.substring(0, nodeId.length() - 4); + } + String newNodeId = nodeId + Utils.firstLetterUpperCase(id); + NodeData copy = new NodeData(node, id, newNodeId); + + copy.setSpecializations(specializations); + copy.setSpecializationListeners(listeners); + + splitted.add(copy); + } + + node.setSpecializations(new ArrayList()); + node.setSpecializationListeners(new ArrayList()); + + return splitted; + } + + private static SortedMap> groupByNodeId(List methods) { + SortedMap> grouped = new TreeMap<>(); + for (M m : methods) { + List list = grouped.get(m.getId()); + if (list == null) { + list = new ArrayList<>(); + grouped.put(m.getId(), list); + } + list.add(m); + } + return grouped; + } + + private boolean parseMethods(final NodeData node, List elements) { + node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); + node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); + node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements)); + List generics = new GenericParser(context, node).parse(elements); + List specializations = new SpecializationMethodParser(context, node).parse(elements); + + if (generics == null || specializations == null || node.getGuards() == null || node.getShortCircuits() == null || node.getSpecializationListeners() == null) { + return false; + } + + List allSpecializations = new ArrayList<>(); + allSpecializations.addAll(generics); + allSpecializations.addAll(specializations); + + node.setSpecializations(allSpecializations); + + return true; + } + + private boolean finalizeSpecializations(final NodeData node) { + List specializations = new ArrayList<>(node.getSpecializations()); + + if (specializations.isEmpty()) { + return true; + } + + List generics = new ArrayList<>(); + for (SpecializationData spec : specializations) { + if (spec.isGeneric()) { + generics.add(spec); + } + } + SpecializationData genericSpecialization = null; - if (genericSpecializations.size() > 1) { - for (SpecializationData generic : genericSpecializations) { + if (generics.size() > 1) { + for (SpecializationData generic : generics) { log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); } - return null; - } else if (genericSpecializations.size() == 1) { - genericSpecialization = genericSpecializations.get(0); + return false; + } else if (generics.size() == 1) { + genericSpecialization = generics.get(0); + } else { + // TODO support generation of generic if not ambiguous. } if (specializations.size() > 1 && genericSpecialization == null) { - log.error(type, "Need a @%s method.", Generic.class.getSimpleName()); - return null; + log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName()); + return false; + } + + if (genericSpecialization != null) { + CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized"); + TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getId(), node, genericSpecialization.getSpecification(), uninitializedMethod, + genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters()); + specializations.add(new SpecializationData(uninializedMethod, false, true)); } Collections.sort(specializations, new Comparator() { @Override public int compare(SpecializationData o1, SpecializationData o2) { - return compareSpecialization(typeSystem, o1, o2); + return compareSpecialization(node.getTypeSystem(), o1, o2); } }); - List allSpecializations = new ArrayList<>(specializations); - if (genericSpecialization != null) { - allSpecializations.add(genericSpecialization); - CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized"); - TemplateMethod uninializedMethod = new TemplateMethod(nodeData, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(), - genericSpecialization.getReturnType(), genericSpecialization.getParameters()); - allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true)); + node.setSpecializations(specializations); + + for (SpecializationData specialization : specializations) { + specialization.setId(findUniqueSpecializationId(specialization)); } - for (SpecializationData specialization : allSpecializations) { - specialization.setNode(nodeData); + return true; + } + + private static String findUniqueSpecializationId(SpecializationData specialization) { + + String name; + if (specialization.isGeneric()) { + name = "Generic"; + } else if (specialization.isUninitialized()) { + name = "Uninitialized"; + } else { + List specializations = new ArrayList<>(specialization.getNode().getSpecializations()); + for (ListIterator iterator = specializations.listIterator(); iterator.hasNext();) { + SpecializationData data = iterator.next(); + if (data.isGeneric() || data.isUninitialized()) { + iterator.remove(); + } + } + + Map> usedIds = new HashMap<>(); + for (SpecializationData other : specializations) { + for (ActualParameter param : other.getReturnTypeAndParameters()) { + if (other.getNode().findField(param.getSpecification().getName()) == null) { + continue; + } + + Set types = usedIds.get(param.getSpecification()); + if (types == null) { + types = new HashSet<>(); + usedIds.put(param.getSpecification(), types); + } + types.add(Utils.getTypeId(param.getActualType())); + } + } + + List ambiguousSpecs = new ArrayList<>(); + for (ActualParameter param : specialization.getReturnTypeAndParameters()) { + Set ids = usedIds.get(param.getSpecification()); + if (ids != null && ids.size() > 1) { + ambiguousSpecs.add(param.getSpecification()); + } + } + + String specializationId = findSpecializationId(specialization, ambiguousSpecs); + int specializationIndex = 0; + int totalIndex = 0; + + for (SpecializationData other : specializations) { + String id = findSpecializationId(other, ambiguousSpecs); + if (id.equals(specializationId)) { + totalIndex++; + if (specialization == other) { + specializationIndex = totalIndex; + } + } + } + + if (specializationIndex != totalIndex) { + name = specializationId + specializationIndex; + } else { + name = specializationId; + } + } + return name; + } + + private static String findSpecializationId(SpecializationData specialization, List specs) { + boolean allSame = true; + ActualParameter prevParam = specialization.getReturnType(); + for (ParameterSpec spec : specs) { + ActualParameter param = specialization.findParameter(spec); + if (!Utils.typeEquals(prevParam.getActualType(), param.getActualType())) { + allSame = false; + break; + } + prevParam = param; + } + + if (allSame) { + return Utils.getTypeId(prevParam.getActualType()); + } else { + StringBuilder nameBuilder = new StringBuilder(); + nameBuilder.append(Utils.getTypeId(prevParam.getActualType())); + for (ParameterSpec spec : specs) { + ActualParameter param = specialization.findParameter(spec); + nameBuilder.append(Utils.getTypeId(param.getActualType())); + } + return nameBuilder.toString(); + } + } + + private boolean verifyNode(NodeData nodeData) { + // verify specialization parameter length + if (!verifySpecializationParameters(nodeData)) { + return false; } // verify order is not ambiguous - if (!verifySpecializationOrder(typeSystem, specializations)) { + if (!verifySpecializationOrder(nodeData)) { + return false; + } + + if (!verifyMissingAbstractMethods(nodeData)) { + return false; + } + + if (!assignShortCircuitsToSpecializations(nodeData)) { + return false; + } + + if (!verifyConstructors(nodeData)) { + return false; + } + +// if (!verifyNamingConvention(specializations, "do")) { +// return null; +// } +// +// if (!verifyNamesUnique(specializations)) { +// return null; +// } + + if (!verifyNamingConvention(nodeData.getShortCircuits(), "needs")) { + return false; + } + + if (!verifySpecializationThrows(nodeData)) { + return false; + } + + return true; + } + + private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) { + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType)); + List typeHierarchy = findSuperClasses(new ArrayList(), nodeType); + Collections.reverse(typeHierarchy); + + AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); + if (typeSystemMirror == null) { + log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString()); return null; } - nodeData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()])); - nodeData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()])); - - if (!verifyMissingAbstractMethods(nodeData, elements)) { - return null; - } - - if (!assignShortCircuitsToSpecializations(nodeData, allSpecializations, shortCircuits)) { - return null; - } - - if (!verifyConstructors(nodeData)) { + TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); + if (typeSystem == null) { + log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); return null; } - if (!verifyNamingConvention(specializations, "do")) { - return null; - } + NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString()); + nodeData.setNodeType(nodeType.asType()); + + List executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); - if (!verifyNamesUnique(specializations)) { + nodeData.setExecutableTypes(executableTypes); + + parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); + + List fields = parseFields(nodeData, elements, typeHierarchy); + if (fields == null) { return null; } - - if (!verifyNamingConvention(shortCircuits, "needs")) { - return null; - } - - if (!verifySpecializationThrows(typeSystem, specializations)) { - return null; - } + nodeData.setFields(fields); return nodeData; } - private boolean verifyMissingAbstractMethods(NodeData nodeData, List elements) { + private boolean verifySpecializationParameters(NodeData nodeData) { + boolean valid = true; + int args = -1; + for (SpecializationData specializationData : nodeData.getSpecializations()) { + int specializationArgs = 0; + for (ActualParameter param : specializationData.getParameters()) { + if (!param.getSpecification().isOptional()) { + specializationArgs++; + } + } + if (args != -1 && args != specializationArgs) { + valid = false; + break; + } + args = specializationArgs; + } + if (!valid) { + for (SpecializationData specialization : nodeData.getSpecializations()) { + context.getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), "All specializations must have the same number of arguments."); + } + } + return valid; + } + + private boolean verifyMissingAbstractMethods(NodeData nodeData) { if (nodeData.needsFactory()) { // missing abstract methods only needs to be implemented // if we need go generate factory for it. return true; } + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType())); + Set unusedElements = new HashSet<>(elements); for (TemplateMethod method : nodeData.getAllTemplateMethods()) { unusedElements.remove(method.getMethod()); @@ -347,13 +604,13 @@ return null; } - private NodeFieldData[] parseFields(NodeData nodeData, List elements, final List typeHierarchy) { + private List parseFields(NodeData nodeData, List elements, final List typeHierarchy) { AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class); List executionDefinition = null; if (executionOrderMirror != null) { executionDefinition = new ArrayList<>(); - for (Object object : Utils.getAnnotationValueList(executionOrderMirror, "value")) { - executionDefinition.add((String) object); + for (String object : Utils.getAnnotationValueList(String.class, executionOrderMirror, "value")) { + executionDefinition.add(object); } } @@ -361,7 +618,7 @@ for (ExecutableElement method : ElementFilter.methodsIn(elements)) { AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValueString(mirror, "value")); + shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); } } @@ -394,9 +651,8 @@ return null; } - NodeFieldData[] fieldArray = fields.toArray(new NodeFieldData[fields.size()]); - sortByExecutionOrder(fieldArray, executionDefinition == null ? Collections. emptyList() : executionDefinition, typeHierarchy); - return fieldArray; + sortByExecutionOrder(fields, executionDefinition == null ? Collections. emptyList() : executionDefinition, typeHierarchy); + return fields; } private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set foundShortCircuits) { @@ -424,10 +680,10 @@ nodeType = getComponentType(var.asType()); kind = FieldKind.CHILDREN; } else { - mirror = null; + execution = ExecutionKind.IGNORE; nodeType = null; - kind = FieldKind.FIELD; - execution = ExecutionKind.IGNORE; + mirror = null; + kind = null; } NodeData fieldNodeData = null; @@ -444,13 +700,12 @@ context.getLog().error(errorElement, "No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType)); return null; } + + // TODO correct handling of access elements + if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) { + execution = ExecutionKind.IGNORE; + } } - - // TODO correct handling of access elements - if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) { - execution = ExecutionKind.IGNORE; - } - return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution); } @@ -482,8 +737,8 @@ } } - private static void sortByExecutionOrder(NodeFieldData[] fields, final List executionOrder, final List typeHierarchy) { - Arrays.sort(fields, new Comparator() { + private static void sortByExecutionOrder(List fields, final List executionOrder, final List typeHierarchy) { + Collections.sort(fields, new Comparator() { @Override public int compare(NodeFieldData o1, NodeFieldData o2) { @@ -505,18 +760,17 @@ }); } - private boolean assignShortCircuitsToSpecializations(NodeData nodeData, List specializations, List shortCircuits) { - - Map> groupedShortCircuits = groupShortCircuits(shortCircuits); + private boolean assignShortCircuitsToSpecializations(NodeData node) { + Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); boolean valid = true; - for (NodeFieldData field : nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { + for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) { String valueName = field.getName(); List availableCircuits = groupedShortCircuits.get(valueName); if (availableCircuits == null || availableCircuits.isEmpty()) { - log.error(nodeData.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); + log.error(node.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); valid = false; continue; } @@ -539,14 +793,14 @@ ShortCircuitData genericCircuit = null; for (ShortCircuitData circuit : availableCircuits) { - if (isGenericShortCutMethod(nodeData, circuit)) { + if (isGenericShortCutMethod(node, circuit)) { genericCircuit = circuit; break; } } if (genericCircuit == null) { - log.error(nodeData.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); + log.error(node.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); valid = false; continue; } @@ -562,8 +816,8 @@ return valid; } - NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT); - for (SpecializationData specialization : specializations) { + NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT); + for (SpecializationData specialization : node.getSpecializations()) { ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length]; for (int i = 0; i < fields.length; i++) { @@ -599,6 +853,7 @@ return valid; } + @SuppressWarnings("unused") private boolean verifyNamesUnique(List methods) { boolean valid = true; for (int i = 0; i < methods.size(); i++) { @@ -617,9 +872,9 @@ } private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { - for (NodeFieldData field : node.getFields()) { - ActualParameter parameter = method.findParameter(field.getName()); - if (parameter == null) { + for (ActualParameter parameter : method.getParameters()) { + NodeFieldData field = node.findField(parameter.getSpecification().getName()); + if (field == null) { continue; } ExecutableTypeData found = null; @@ -668,7 +923,10 @@ return collection; } - private boolean verifySpecializationOrder(TypeSystemData typeSystem, List specializations) { + private boolean verifySpecializationOrder(NodeData node) { + TypeSystemData typeSystem = node.getTypeSystem(); + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size(); i++) { SpecializationData m1 = specializations.get(i); for (int j = i + 1; j < specializations.size(); j++) { @@ -696,31 +954,19 @@ return true; } - private boolean verifySpecializationThrows(TypeSystemData typeSystem, List specializations) { + private boolean verifySpecializationThrows(NodeData node) { Map specializationMap = new HashMap<>(); - for (SpecializationData spec : specializations) { + for (SpecializationData spec : node.getSpecializations()) { specializationMap.put(spec.getMethodName(), spec); } boolean valid = true; - for (SpecializationData sourceSpecialization : specializations) { + for (SpecializationData sourceSpecialization : node.getSpecializations()) { if (sourceSpecialization.getExceptions() != null) { for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { - SpecializationData targetSpecialization = specializationMap.get(throwsData.getTransitionToName()); - AnnotationValue value = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "transitionTo"); - - if (targetSpecialization == null) { - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, "Specialization with name '%s' not found.", throwsData.getTransitionToName()); - valid = false; - } else if (compareSpecialization(typeSystem, sourceSpecialization, targetSpecialization) >= 0) { - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, - "The order of the target specializalization must be higher than the source specialization.", throwsData.getTransitionToName()); - valid = false; - } - for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { - AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "javaClass"); - log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type.", throwsData.getTransitionToName()); + AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "rewriteOn"); + log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type."); valid = false; } } @@ -744,8 +990,22 @@ } private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { - if (m1.getSpecification() != m2.getSpecification()) { - throw new UnsupportedOperationException("Cannot compare two specializations with different specifications."); + if (m1 == m2) { + return 0; + } + + if (m1.isUninitialized() && !m2.isUninitialized()) { + return -1; + } else if (!m1.isUninitialized() && m2.isUninitialized()) { + return 1; + } else if (m1.isGeneric() && !m2.isGeneric()) { + return 1; + } else if (!m1.isGeneric() && m2.isGeneric()) { + return -1; + } + + if (m1.getTemplate() != m2.getTemplate()) { + throw new UnsupportedOperationException("Cannot compare two specializations with different templates."); } int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java Tue Mar 12 11:38:52 2013 +0100 @@ -61,8 +61,7 @@ } for (ActualParameter param : getParameters()) { - ParameterSpec paramSpec = param.getSpecification(); - ActualParameter specializationParam = specialization.findParameter(paramSpec.getName()); + ActualParameter specializationParam = specialization.findParameter(param.getName()); if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) { return false; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -48,14 +48,14 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value"); + String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value"); if (!shortCircuitValues.contains(shortCircuitValue)) { getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue); return null; } - return createDefaultMethodSpec(shortCircuitValue); + return createDefaultMethodSpec(method, mirror, shortCircuitValue); } @Override @@ -65,7 +65,7 @@ @Override public ShortCircuitData create(TemplateMethod method) { - String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value"); + String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value"); assert shortCircuitValue != null; assert shortCircuitValues.contains(shortCircuitValue); return new ShortCircuitData(method, shortCircuitValue); diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Tue Mar 12 11:38:52 2013 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.truffle.codegen.processor.node; +import java.util.*; + import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.template.*; @@ -30,13 +32,13 @@ private final int order; private final boolean generic; private final boolean uninitialized; - private final SpecializationThrowsData[] exceptions; + private final List exceptions; private SpecializationGuardData[] guards; private ShortCircuitData[] shortCircuits; private boolean useSpecializationsForGeneric = true; private NodeData node; - public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) { + public SpecializationData(TemplateMethod template, int order, List exceptions) { super(template); this.order = order; this.generic = false; @@ -53,7 +55,7 @@ this.order = Specialization.DEFAULT_ORDER; this.generic = generic; this.uninitialized = uninitialized; - this.exceptions = new SpecializationThrowsData[0]; + this.exceptions = Collections.emptyList(); this.guards = new SpecializationGuardData[0]; } @@ -81,7 +83,7 @@ return uninitialized; } - public SpecializationThrowsData[] getExceptions() { + public List getExceptions() { return exceptions; } @@ -106,10 +108,10 @@ } public SpecializationData findNextSpecialization() { - SpecializationData[] specializations = node.getSpecializations(); - for (int i = 0; i < specializations.length - 1; i++) { - if (specializations[i] == this) { - return specializations[i + 1]; + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size() - 1; i++) { + if (specializations.get(i) == this) { + return specializations.get(i + 1); } } return null; diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java Tue Mar 12 11:38:52 2013 +0100 @@ -0,0 +1,33 @@ +/* + * 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.codegen.processor.node; + +import com.oracle.truffle.codegen.processor.template.*; + +public class SpecializationListenerData extends TemplateMethod { + + public SpecializationListenerData(TemplateMethod method) { + super(method); + } + +} diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -30,18 +30,15 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; -public class SpecializationListenerParser extends MethodParser { - - private final MethodSpec specification; +public class SpecializationListenerParser extends MethodParser { public SpecializationListenerParser(ProcessorContext context, NodeData node) { super(context, node); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override @@ -50,8 +47,8 @@ } @Override - public TemplateMethod create(TemplateMethod method) { - return method; + public SpecializationListenerData create(TemplateMethod method) { + return new SpecializationListenerData(method); } @Override diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -35,16 +35,13 @@ public class SpecializationMethodParser extends MethodParser { - private final MethodSpec specification; - public SpecializationMethodParser(ProcessorContext context, NodeData operation) { super(context, operation); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override @@ -58,27 +55,24 @@ } private SpecializationData parseSpecialization(TemplateMethod method) { - int order = Utils.getAnnotationValueInt(method.getMarkerAnnotation(), "order"); + int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order"); if (order < 0 && order != Specialization.DEFAULT_ORDER) { getContext().getLog().error(method.getMethod(), method.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value."); return null; } - List exceptionDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "exceptions", method.getMethod(), SpecializationThrows.class); - SpecializationThrowsData[] exceptionData = new SpecializationThrowsData[exceptionDefs.size()]; - for (int i = 0; i < exceptionData.length; i++) { - AnnotationMirror mirror = exceptionDefs.get(i); - TypeMirror javaClass = Utils.getAnnotationValueType(mirror, "javaClass"); - String transitionTo = Utils.getAnnotationValueString(mirror, "transitionTo"); - exceptionData[i] = new SpecializationThrowsData(mirror, javaClass, transitionTo); + List exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); + List exceptionData = new ArrayList<>(); + for (TypeMirror exceptionType : exceptionTypes) { + exceptionData.add(new SpecializationThrowsData(method.getMarkerAnnotation(), exceptionType)); - if (!Utils.canThrowType(method.getMethod().getThrownTypes(), javaClass)) { - getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(javaClass)); + if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { + getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType)); return null; } } - Arrays.sort(exceptionData, new Comparator() { + Collections.sort(exceptionData, new Comparator() { @Override public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { @@ -87,24 +81,24 @@ }); SpecializationData specialization = new SpecializationData(method, order, exceptionData); boolean valid = true; - List guardDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "guards", method.getMethod(), SpecializationGuard.class); + List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); SpecializationGuardData[] guardData = new SpecializationGuardData[guardDefs.size()]; for (int i = 0; i < guardData.length; i++) { - AnnotationMirror guardMirror = guardDefs.get(i); - String guardMethod = Utils.getAnnotationValueString(guardMirror, "methodName"); - boolean onSpecialization = Utils.getAnnotationValueBoolean(guardMirror, "onSpecialization"); - boolean onExecution = Utils.getAnnotationValueBoolean(guardMirror, "onExecution"); + String guardMethod = guardDefs.get(i); + + boolean onSpecialization = true; + boolean onExecution = true; if (!onSpecialization && !onExecution) { String message = "Either onSpecialization, onExecution or both must be enabled."; - getContext().getLog().error(method.getMethod(), guardMirror, message); + getContext().getLog().error(method.getMethod(), message); valid = false; continue; } guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution); - GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]); + GuardData compatibleGuard = matchSpecializationGuard(specialization, guardData[i]); if (compatibleGuard != null) { guardData[i].setGuardDeclaration(compatibleGuard); } else { @@ -121,7 +115,7 @@ return specialization; } - private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) { + private GuardData matchSpecializationGuard(SpecializationData specialization, SpecializationGuardData specializationGuard) { List foundGuards = getNode().findGuards(specializationGuard.getGuardMethod()); GuardData compatibleGuard = null; @@ -142,8 +136,8 @@ } List typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs); String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs); - AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName"); - getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature); + AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "guards"); + getContext().getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), value, "No guard with signature '%s' found in type system.", expectedSignature); return null; } @@ -151,7 +145,7 @@ } private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { - Iterator guardParameters = Arrays.asList(guard.getParameters()).iterator(); + Iterator guardParameters = guard.getParameters().iterator(); for (ActualParameter param : specialization.getParameters()) { if (param.getSpecification().isOptional()) { continue; diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java Tue Mar 12 11:38:52 2013 +0100 @@ -29,13 +29,11 @@ private final AnnotationMirror annotationMirror; private final TypeMirror javaClass; - private final String transitionTo; private SpecializationData specialization; - public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) { + public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass) { this.annotationMirror = annotationMirror; this.javaClass = javaClass; - this.transitionTo = transitionTo; } void setSpecialization(SpecializationData specialization) { @@ -54,16 +52,7 @@ return annotationMirror; } - public String getTransitionToName() { - return transitionTo; - } - public SpecializationData getTransitionTo() { - for (SpecializationData s : specialization.getNode().getSpecializations()) { - if (s.getMethodName().equals(transitionTo)) { - return s; - } - } - return null; + return specialization.findNextSpecialization(); } } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Tue Mar 12 11:38:52 2013 +0100 @@ -31,10 +31,33 @@ private final ParameterSpec specification; private final TypeMirror actualType; private TemplateMethod method; + private final String name; + private final int index; + private final boolean implicit; - public ActualParameter(ParameterSpec specification, TypeMirror actualType) { + public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) { this.specification = specification; this.actualType = actualType; + + this.index = index; + this.implicit = implicit; + String valueName = specification.getName() + "Value"; + if (specification.isIndexed()) { + valueName = valueName + index; + } + this.name = valueName; + } + + public boolean isHidden() { + return implicit; + } + + public int getIndex() { + return index; + } + + public String getName() { + return name; } void setMethod(TemplateMethod method) { diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Tue Mar 12 11:38:52 2013 +0100 @@ -128,6 +128,10 @@ CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class)); generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); + if (model.getTemplateMethodName() != null) { + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName())); + } + clazz.addAnnotationMirror(generatedByAnnotation); context.registerType(model.getTemplateType(), clazz.asType()); diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Tue Mar 12 11:38:52 2013 +0100 @@ -24,16 +24,25 @@ import java.util.*; +import javax.lang.model.type.*; + public class MethodSpec { + private final List implicitTypes; + private final ParameterSpec returnType; private final List parameters; - public MethodSpec(ParameterSpec returnType, List parameters) { + public MethodSpec(List prefixTypes, ParameterSpec returnType, List parameters) { + this.implicitTypes = prefixTypes; this.returnType = returnType; this.parameters = parameters; } + public List getImplicitTypes() { + return implicitTypes; + } + public ParameterSpec getReturnType() { return returnType; } @@ -41,4 +50,14 @@ public List getParameters() { return parameters; } + + public ParameterSpec findParameterSpec(String name) { + for (ParameterSpec spec : parameters) { + if (spec.getName().equals(name)) { + return spec; + } + } + return null; + } + } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Tue Mar 12 11:38:52 2013 +0100 @@ -39,7 +39,8 @@ private final String name; private final TypeMirror[] allowedTypes; private final boolean optional; - private final Cardinality cardinality; + private Cardinality cardinality; + private boolean indexed; public ParameterSpec(String name, TypeMirror[] allowedTypes, boolean optional, Cardinality cardinality) { this.allowedTypes = allowedTypes; @@ -63,6 +64,18 @@ this(name, nodeTypeMirrors(nodeData), optional, cardinality); } + public boolean isIndexed() { + return indexed; + } + + public void setIndexed(boolean indexed) { + this.indexed = indexed; + } + + public void setCardinality(Cardinality cardinality) { + this.cardinality = cardinality; + } + private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) { Set typeMirrors = new LinkedHashSet<>(); @@ -95,6 +108,7 @@ for (int i = 0; i < allowedTypes.length; i++) { TypeMirror mirror = allowedTypes[i]; if (Utils.typeEquals(actualType, mirror)) { + return true; } } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java Tue Mar 12 11:38:52 2013 +0100 @@ -32,15 +32,21 @@ public abstract class Template { private final TypeElement templateType; + private final String templateMethodName; private final AnnotationMirror annotation; private List extensionElements; - public Template(TypeElement templateType, AnnotationMirror annotation) { + public Template(TypeElement templateType, String templateMethodName, AnnotationMirror annotation) { this.templateType = templateType; + this.templateMethodName = templateMethodName; this.annotation = annotation; } + public String getTemplateMethodName() { + return templateMethodName; + } + public TypeElement getTemplateType() { return templateType; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Tue Mar 12 11:38:52 2013 +0100 @@ -22,24 +22,32 @@ */ package com.oracle.truffle.codegen.processor.template; +import java.util.*; + import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; public class TemplateMethod { + private String id; private final Template template; private final MethodSpec specification; private final ExecutableElement method; private final AnnotationMirror markerAnnotation; private final ActualParameter returnType; - private final ActualParameter[] parameters; + private final List parameters; - public TemplateMethod(Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, + List parameters) { this.template = template; this.specification = specification; this.method = method; this.markerAnnotation = markerAnnotation; this.returnType = returnType; this.parameters = parameters; + this.id = id; if (parameters != null) { for (ActualParameter param : parameters) { @@ -49,7 +57,15 @@ } public TemplateMethod(TemplateMethod method) { - this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); + this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); + } + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; } public Template getTemplate() { @@ -64,28 +80,40 @@ return returnType; } - public ActualParameter[] getParameters() { + public List getParameters() { return parameters; } public ActualParameter findParameter(String valueName) { for (ActualParameter param : getParameters()) { - if (param.getSpecification().getName().equals(valueName)) { + if (param.getName().equals(valueName)) { return param; } } return null; } + public List getReturnTypeAndParameters() { + List allParameters = new ArrayList<>(getParameters().size() + 1); + allParameters.add(getReturnType()); + allParameters.addAll(getParameters()); + return Collections.unmodifiableList(allParameters); + } + public ActualParameter findParameter(ParameterSpec spec) { for (ActualParameter param : getParameters()) { - if (param.getSpecification() == spec) { + if (param.getSpecification().getName().equals(spec.getName())) { return param; } } return null; } + public boolean canBeAccessedByInstanceOf(TypeMirror type) { + TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType(); + return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type); + } + public ExecutableElement getMethod() { return method; } @@ -100,7 +128,7 @@ @Override public String toString() { - return getClass().getSimpleName() + " [method = " + method + "]"; + return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]"; } public ActualParameter getPreviousParam(ActualParameter searchParam) { diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Tue Mar 12 11:38:52 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.template.ParameterSpec.Cardinality; @@ -95,7 +96,7 @@ mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); } - if (method.getModifiers().contains(Modifier.PRIVATE)) { + if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { getContext().getLog().error(method, "Method must not be private."); valid = false; continue; @@ -126,7 +127,7 @@ List parameterSpecs = new ArrayList<>(); parameterSpecs.addAll(methodSpecification.getParameters()); - ActualParameter returnTypeMirror = resolveTypeMirror(returnTypeSpec, method.getReturnType(), template); + ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false); if (returnTypeMirror == null) { if (isEmitErrors()) { String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true); @@ -140,88 +141,101 @@ return null; } - Iterator variableIterator = method.getParameters().iterator(); + List parameterTypes = new ArrayList<>(); + parameterTypes.addAll(methodSpecification.getImplicitTypes()); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + List parameters = parseParameters(parameterTypes, parameterSpecs, methodSpecification.getImplicitTypes().size()); + if (parameters == null) { + if (isEmitErrors()) { + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method), + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + context.getLog().error(method, annotation, message); + } + return null; + } + + String id = method.getSimpleName().toString(); + AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class); + if (idAnnotation != null) { + id = Utils.getAnnotationValue(String.class, idAnnotation, "value"); + } + + return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters)); + } + + private static String createActualSignature(MethodSpec spec, ExecutableElement method) { + List types = new ArrayList<>(); + for (TypeMirror implicitType : spec.getImplicitTypes()) { + types.add("implicit " + Utils.getSimpleName(implicitType)); + } + for (VariableElement var : method.getParameters()) { + types.add(Utils.getSimpleName(var.asType())); + } + + StringBuilder b = new StringBuilder("("); + for (Iterator iterator = types.iterator(); iterator.hasNext();) { + b.append(iterator.next()); + if (iterator.hasNext()) { + b.append(", "); + } + } + b.append(")"); + return b.toString(); + } + + private List parseParameters(List types, List parameterSpecs, int hiddenCount) { + Iterator parameterIterator = types.iterator(); Iterator specificationIterator = parameterSpecs.iterator(); - List resolvedMirrors = new ArrayList<>(); - VariableElement parameter = null; - ParameterSpec specification = null; - while (specificationIterator.hasNext() || specification != null) { - if (specification == null) { - specification = specificationIterator.next(); - } - - if (parameter == null && variableIterator.hasNext()) { - parameter = variableIterator.next(); - } - - if (parameter == null) { - if (specification.getCardinality() == Cardinality.MULTIPLE) { - specification = null; - continue; - } else if (!specification.isOptional()) { - if (isEmitErrors()) { - // non option type specification found -> argument missing - String expectedType = createTypeSignature(specification, typeDefs, false); - - String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); + TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - context.getLog().error(method, message); - } - return null; - } else { - // specification is optional -> continue - specification = null; + int globalParameterIndex = 0; + int specificationParameterIndex = 0; + List resolvedParameters = new ArrayList<>(); + while (parameter != null || specification != null) { + if (parameter == null || specification == null) { + if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) { + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + specificationParameterIndex = 0; continue; } - } - - ActualParameter resolvedMirror = resolveTypeMirror(specification, parameter.asType(), template); - - if (resolvedMirror == null) { - if (specification.isOptional()) { - specification = null; - continue; - } - - if (isEmitErrors()) { - String expectedReturnType = createTypeSignature(specification, typeDefs, false); - String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); - - String message = String.format("The provided argument type \"%s\" does not match expected type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); - - context.getLog().error(parameter, message); - } return null; } - resolvedMirrors.add(resolvedMirror); - parameter = null; // consume parameter + boolean hidden = globalParameterIndex < hiddenCount; + ActualParameter resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, hidden); + if (resolvedParameter == null) { + // mismatch + if (specification.isOptional()) { + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + specificationParameterIndex = 0; + } else { + return null; + } + } else { + resolvedParameters.add(resolvedParameter); - if (specification.getCardinality() != Cardinality.MULTIPLE) { - specification = null; + // match + if (specification.getCardinality() == Cardinality.ONE) { + parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + specification = specificationIterator.hasNext() ? specificationIterator.next() : null; + globalParameterIndex++; + specificationParameterIndex = 0; + } else if (specification.getCardinality() == Cardinality.MULTIPLE) { + parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + globalParameterIndex++; + specificationParameterIndex++; + } } } - - if (variableIterator.hasNext()) { - parameter = variableIterator.next(); - if (isEmitErrors()) { - String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); - String message = String.format("No argument expected but found \"%s\".\nExpected signature: \n %s", actualReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); - - context.getLog().error(parameter, message); - } - return null; - } - - ActualParameter[] paramMirrors = resolvedMirrors.toArray(new ActualParameter[resolvedMirrors.size()]); - return create(new TemplateMethod(template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); + return resolvedParameters; } - private ActualParameter resolveTypeMirror(ParameterSpec specification, TypeMirror mirror, Template typeSystem) { + private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean hidden) { TypeMirror resolvedType = mirror; if (hasError(resolvedType)) { resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem); @@ -230,7 +244,7 @@ if (!specification.matches(resolvedType)) { return null; } - return new ActualParameter(specification, resolvedType); + return new ActualParameter(specification, resolvedType, index, hidden); } protected List createTypeDefinitions(ParameterSpec returnType, List parameters) { diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Tue Mar 12 11:38:52 2013 +0100 @@ -26,15 +26,8 @@ public class GuardData extends TemplateMethod { - private final Template origin; - - public GuardData(TemplateMethod method, Template origin) { + public GuardData(TemplateMethod method) { super(method); - this.origin = origin; - } - - public Template getOrigin() { - return origin; } } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -26,8 +26,8 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; -import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; @@ -39,6 +39,8 @@ public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) { super(context, template); this.typeSystem = typeSystem; + setEmitErrors(false); + setParseNullOnError(false); } @Override @@ -46,22 +48,22 @@ List specs = new ArrayList<>(); specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - return new MethodSpec(returnTypeSpec, specs); + return new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); } @Override public boolean isParsable(ExecutableElement method) { - return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + return true; } @Override public GuardData create(TemplateMethod method) { - return new GuardData(method, template); + return new GuardData(method); } @Override public Class getAnnotationType() { - return GuardCheck.class; + return null; } } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -47,14 +48,14 @@ List specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); return spec; } @Override public TypeCastData create(TemplateMethod method) { TypeData targetType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "as"); - ActualParameter parameter = method.findParameter("value"); + ActualParameter parameter = method.findParameter("valueValue"); return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType); } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -47,7 +48,7 @@ List specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections. emptyList(), returnTypeSpec, specs); return spec; } @@ -55,7 +56,7 @@ public TypeCheckData create(TemplateMethod method) { TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is"); assert checkedType != null; - ActualParameter parameter = method.findParameter("value"); + ActualParameter parameter = method.findParameter("valueValue"); assert parameter != null; return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem())); } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Tue Mar 12 11:38:52 2013 +0100 @@ -40,7 +40,7 @@ private final List typeChecks = new ArrayList<>(); public TypeData(TypeElement templateType, AnnotationMirror annotation, TypeMirror primitiveType, TypeMirror boxedType) { - super(templateType, annotation); + super(templateType, null, annotation); this.primitiveType = primitiveType; this.boxedType = boxedType; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Tue Mar 12 11:38:52 2013 +0100 @@ -41,7 +41,7 @@ private final TypeData voidType; public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, TypeData[] types, TypeMirror genericType, TypeData voidType) { - super(templateType, annotation); + super(templateType, null, annotation); this.types = types; this.genericType = genericType; this.voidType = voidType; diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Tue Mar 12 11:38:52 2013 +0100 @@ -145,7 +145,7 @@ } private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) { - List typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "value"); + List typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, templateTypeAnnotation, "value"); if (typeMirrors.size() == 0) { log.error(templateType, templateTypeAnnotation, "At least one type must be defined."); return null; diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java Tue Mar 12 11:38:52 2013 +0100 @@ -37,11 +37,6 @@ super(node); } - @Generic - public Object doGeneric(Object left, Object right) { - throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); - } - public abstract static class AddNode extends ArithmeticNode { public AddNode(TypedNode left, TypedNode right) { @@ -52,9 +47,8 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int doInt(int left, int right) { return ExactMath.addExact(left, right); } @@ -64,15 +58,19 @@ } @Specialization - String doStringDirect(String left, String right) { + String doString(String left, String right) { return left + right; } - @Specialization - @SpecializationGuard(methodName = "isString") - String doString(Object left, Object right) { + @Specialization(guards = "isString") + String add(Object left, Object right) { return left.toString() + right.toString(); } + + @Generic + public Object addGeneric(Object left, Object right) { + throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); + } } public abstract static class SubNode extends ArithmeticNode { @@ -85,16 +83,20 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int sub(int left, int right) { return ExactMath.subtractExact(left, right); } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger sub(BigInteger left, BigInteger right) { return left.subtract(right); } + + @Generic + public Object sub(Object left, Object right) { + throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); + } } public abstract static class DivNode extends ArithmeticNode { @@ -107,16 +109,20 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int div(int left, int right) { return left / right; } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger div(BigInteger left, BigInteger right) { return left.divide(right); } + + @Generic + public Object div(Object left, Object right) { + throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); + } } public abstract static class MulNode extends ArithmeticNode { @@ -129,16 +135,20 @@ super(node); } - @Specialization - @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger") - int doInteger(int left, int right) { + @Specialization(rewriteOn = ArithmeticException.class) + int mul(int left, int right) { return ExactMath.multiplyExact(left, right); } @Specialization - BigInteger doBigInteger(BigInteger left, BigInteger right) { + BigInteger mul(BigInteger left, BigInteger right) { return left.multiply(right); } + + @Generic + public Object mul(Object left, Object right) { + throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName()); + } } } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java Tue Mar 12 11:38:52 2013 +0100 @@ -46,8 +46,7 @@ return left.compareTo(right) < 0; } - @Specialization - @SpecializationGuard(methodName = "isString") + @Specialization(guards = "isString") public boolean doString(Object left, Object right) { return left.toString().compareTo(right.toString()) < 0; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java Tue Mar 12 11:38:52 2013 +0100 @@ -24,7 +24,6 @@ import java.math.*; -import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; @@ -49,7 +48,6 @@ public abstract Object executeGeneric(VirtualFrame frame); - @GuardCheck public boolean isString(Object a, Object b) { return a instanceof String || b instanceof String; } diff -r 2c5df42999dd -r edc414f52e2b graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Tue Mar 12 10:02:20 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java Tue Mar 12 11:38:52 2013 +0100 @@ -41,31 +41,31 @@ } @Specialization - public int doInteger(VirtualFrame frame, int right) { + public int write(VirtualFrame frame, int right) { frame.setInt(slot, right); return right; } @Specialization - public BigInteger doBigInteger(VirtualFrame frame, BigInteger right) { + public BigInteger write(VirtualFrame frame, BigInteger right) { frame.setObject(slot, right); return right; } @Specialization - public boolean doBoolean(VirtualFrame frame, boolean right) { + public boolean write(VirtualFrame frame, boolean right) { frame.setBoolean(slot, right); return right; } @Specialization - public String doString(VirtualFrame frame, String right) { + public String write(VirtualFrame frame, String right) { frame.setObject(slot, right); return right; } @Generic - public Object doGeneric(VirtualFrame frame, Object right) { + public Object write(VirtualFrame frame, Object right) { frame.setObject(slot, right); return right; } diff -r 2c5df42999dd -r edc414f52e2b mx/projects --- a/mx/projects Tue Mar 12 10:02:20 2013 +0100 +++ b/mx/projects Tue Mar 12 11:38:52 2013 +0100 @@ -366,10 +366,18 @@ # truffle.api.codegen project@com.oracle.truffle.api.codegen@subDir=graal project@com.oracle.truffle.api.codegen@sourceDirs=src -project@com.oracle.truffle.api.codegen@dependencies= +project@com.oracle.truffle.api.codegen@dependencies=com.oracle.truffle.api project@com.oracle.truffle.api.codegen@checkstyle=com.oracle.graal.graph project@com.oracle.truffle.api.codegen@javaCompliance=1.7 +# truffle.api.codegen.test +project@com.oracle.truffle.api.codegen.test@subDir=graal +project@com.oracle.truffle.api.codegen.test@sourceDirs=src +project@com.oracle.truffle.api.codegen.test@dependencies=com.oracle.truffle.api.codegen,JUNIT,com.oracle.truffle.api.test +project@com.oracle.truffle.api.codegen.test@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.api.codegen.test@javaCompliance=1.7 +project@com.oracle.truffle.api.codegen.test@annotationProcessors=com.oracle.truffle.codegen.processor + # truffle.codegen.processor project@com.oracle.truffle.codegen.processor@subDir=graal project@com.oracle.truffle.codegen.processor@sourceDirs=src