# HG changeset patch # User Christian Humer # Date 1420417868 -3600 # Node ID a069a87b9a0230688e7b3732399e4bddbeefabc5 # Parent 674c8a6d5e6c2fb83a273e43be890d96660a55f5 Truffle-DSL: Added tests and verification of overridable generic execute methods. diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java Mon Jan 05 01:31:08 2015 +0100 @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl.test; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; + +public class ExecuteMethodTest { + + private static final String NO_EXECUTE = "No accessible and overridable generic execute method found. Generic execute methods usually have the signature 'public abstract {Type} " + + "executeGeneric(VirtualFrame)' and must not throw any checked exceptions."; + + @TypeSystem({int.class, Object[].class}) + static class ExecuteTypeSystem { + + } + + @TypeSystemReference(ExecuteTypeSystem.class) + abstract static class ValidChildNode extends Node { + abstract Object execute(); + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError(NO_EXECUTE) + abstract static class ExecuteThis1 extends Node { + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError(NO_EXECUTE) + abstract static class ExecuteThis2 extends Node { + + abstract Object execute() throws UnexpectedResultException; + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError(NO_EXECUTE) + abstract static class ExecuteThis3 extends Node { + + abstract int execute() throws UnexpectedResultException; + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + abstract static class ExecuteThis4 extends Node { + + protected abstract Object execute(); + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + abstract static class ExecuteThis5 extends Node { + + public abstract Object execute(); + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError(NO_EXECUTE) + abstract static class ExecuteThis6 extends Node { + + @SuppressWarnings({"unused", "static-method"}) + private Object execute() { + return 0; + } + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError(NO_EXECUTE) + abstract static class ExecuteThis7 extends Node { + + @SuppressWarnings("static-method") + public final int executeInt() { + return 0; + } + + @Specialization + int doInt(int a) { + return a; + } + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + @ExpectError("Multiple accessible and overridable generic execute methods found [executeInt(), executeObject()]. Remove all but one or mark all but one as final.") + abstract static class ExecuteThis8 extends Node { + + abstract int executeInt(); + + abstract Object executeObject(); + + @Specialization + int doInt(int a) { + return a; + } + + } + + @TypeSystemReference(ExecuteTypeSystem.class) + @NodeChild(value = "a", type = ValidChildNode.class) + abstract static class ExecuteThis9 extends Node { + + abstract int executeInt(); + + // disambiguate executeObject + final Object executeObject() { + return executeInt(); + } + + @Specialization + int doInt(int a) { + return a; + } + } + +} diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Jan 05 01:31:07 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java Mon Jan 05 01:31:08 2015 +0100 @@ -1170,7 +1170,7 @@ } private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) { - ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(context, type); + ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(type); if (targetExecutable == null) { targetExecutable = execution.getChild().findAnyGenericExecutableType(context); } @@ -1343,14 +1343,14 @@ builder.startElseBlock(); } - ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(context, sourceType); + ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(sourceType); if (implictExecutableTypeData == null) { /* * For children with executeWith.size() > 0 an executable type may not exist so use * the generic executable type which is guaranteed to exist. An expect call is * inserted automatically by #createExecuteExpression. */ - implictExecutableTypeData = execution.getChild().getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), execution.getChild().getExecuteWith().size()); + implictExecutableTypeData = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size()); } ImplicitCastData cast = execution.getChild().getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType()); @@ -1838,12 +1838,12 @@ /** *
      * variant1 $condition != null
-     *
+     * 
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     *
+     * 
      * variant2 $condition != null
      * $type $name = $value;
      * 
diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java Mon Jan 05 01:31:07 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java Mon Jan 05 01:31:08 2015 +0100 @@ -74,12 +74,8 @@ this.executeWith = executeWith; } - public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) { - ExecutableTypeData executableType = childNode.findExecutableType(targetType, getExecuteWith().size()); - if (executableType == null) { - executableType = findAnyGenericExecutableType(context); - } - return executableType; + public ExecutableTypeData findExecutableType(TypeData targetType) { + return childNode.findExecutableType(targetType, getExecuteWith().size()); } public List findGenericExecutableTypes(ProcessorContext context) { diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Mon Jan 05 01:31:07 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Mon Jan 05 01:31:08 2015 +0100 @@ -133,7 +133,11 @@ return true; } for (Parameter parameter : getSignatureParameters()) { - ExecutableTypeData type = parameter.getSpecification().getExecution().getChild().findExecutableType(context, parameter.getTypeSystemType()); + NodeChildData child = parameter.getSpecification().getExecution().getChild(); + ExecutableTypeData type = child.findExecutableType(parameter.getTypeSystemType()); + if (type == null) { + type = child.findAnyGenericExecutableType(context); + } if (type.hasUnexpectedValue(context)) { return true; } diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Jan 05 01:31:07 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Jan 05 01:31:08 2015 +0100 @@ -81,6 +81,8 @@ return false; } else if (ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, Specialization.class) != null) { return false; + } else if (method.getModifiers().contains(Modifier.PRIVATE)) { + return false; } return method.getSimpleName().toString().startsWith("execute"); } diff -r 674c8a6d5e6c -r a069a87b9a02 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Jan 05 01:31:07 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Jan 05 01:31:08 2015 +0100 @@ -148,7 +148,7 @@ return node; // error sync point } - node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements))); + initializeExecutableTypes(elements, node); initializeChildren(node); // ensure the processed element has at least one @Specialization annotation. @@ -374,7 +374,6 @@ } Element getter = findGetter(elements, name, childType); - NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality); parsedChildren.add(nodeChild); @@ -527,6 +526,31 @@ return executions; } + private void initializeExecutableTypes(List elements, NodeData node) { + node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements))); + List genericExecutes = node.getThisExecution().getChild().findGenericExecutableTypes(context); + + List overridableGenericExecutes = new ArrayList<>(); + for (ExecutableTypeData executableTypeData : genericExecutes) { + if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) { + overridableGenericExecutes.add(executableTypeData); + } + } + + if (overridableGenericExecutes.isEmpty()) { + node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the " + + "signature 'public abstract {Type} executeGeneric(VirtualFrame)' and must not throw any checked exceptions."); + } + + if (overridableGenericExecutes.size() > 1) { + List methodSignatures = new ArrayList<>(); + for (ExecutableTypeData type : overridableGenericExecutes) { + methodSignatures.add(type.createReferenceName()); + } + node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); + } + } + private static Map> groupExecutableTypes(List executableTypes) { Map> groupedTypes = new TreeMap<>(); for (ExecutableTypeData type : executableTypes) { @@ -556,6 +580,9 @@ nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()), ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); + } else if (nodeChild.findAnyGenericExecutableType(context) == null) { + nodeChild.addError("No generic execute method found for child type %s. Generic execute methods usually have the signature 'Object executeGeneric(VirtualFrame)'.", + ElementUtils.getQualifiedName(nodeChild.getNodeType())); } if (fieldNodeData != null) { List types = nodeChild.findGenericExecutableTypes(context); @@ -983,13 +1010,18 @@ NodeChildData child = execution.getChild(); TypeData genericType = null; if (types.size() == 1) { - ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); + TypeData singleType = types.iterator().next(); + ExecutableTypeData executable = child.findExecutableType(singleType); if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) { - genericType = types.iterator().next(); + genericType = singleType; } } if (genericType == null) { - genericType = child.findAnyGenericExecutableType(context).getType(); + ExecutableTypeData type = child.findAnyGenericExecutableType(context); + if (type == null) { + throw new AssertionError("No generic type not yet catched by parser."); + } + genericType = type.getType(); } return genericType.getPrimitiveType(); }