# HG changeset patch # User Christian Humer # Date 1408027785 -7200 # Node ID 445f6456c4a5005586e5eeb2ff642278a640fc50 # Parent 13cf9b6b325c2adb806147213f847711f06d68a1# Parent 217eee2ddead7ed6b97ae3dbab20fb9fd799eff3 Merge. diff -r 217eee2ddead -r 445f6456c4a5 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.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/ImportGuardsTest.java Thu Aug 14 16:49:45 2014 +0200 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2012, 2013, 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 static com.oracle.truffle.api.dsl.test.TestHelper.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.ImportGuardsTestFactory.ImportGuards6Factory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class ImportGuardsTest { + + @ImportGuards(Imports0.class) + @NodeChild("a") + static class ImportGuards0 extends ValueNode { + + @Specialization(guards = "staticGuard") + int f0(int a) { + return a; + } + } + + @NodeChild("a") + @ImportGuards(Imports0.class) + static class ImportGuards1 extends ValueNode { + + @ExpectError("No compatible guard with method name 'nonStaticGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @Specialization(guards = "nonStaticGuard") + int f1(int a) { + return a; + } + + @ExpectError("No compatible guard with method name 'protectedGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @Specialization(guards = "protectedGuard") + int f2(int a) { + return a; + } + + @ExpectError("No compatible guard with method name 'packageGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @Specialization(guards = "packageGuard") + int f3(int a) { + return a; + } + + @ExpectError("No compatible guard with method name 'privateGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @Specialization(guards = "privateGuard") + int f4(int a) { + return a; + } + } + + public static class Imports0 { + public static boolean staticGuard(int a) { + return a == 0; + } + + public boolean nonStaticGuard(int a) { + return a == 0; + } + + protected static boolean protectedGuard(int a) { + return a == 0; + } + + static boolean packageGuard(int a) { + return a == 0; + } + + @SuppressWarnings("unused") + private static boolean privateGuard(int a) { + return a == 0; + } + + } + + @ExpectError("The specified import guard class 'com.oracle.truffle.api.dsl.test.ImportGuardsTest.Imports1' must be public.") + @NodeChild("a") + @ImportGuards(Imports1.class) + static class ImportGuards2 extends ValueNode { + + int do1(int a) { + return a; + } + } + + static class Imports1 { + + } + + @ExpectError("The specified import guard class 'com.oracle.truffle.api.dsl.test.ImportGuardsTest.Imports2' must be public.") + @NodeChild("a") + @ImportGuards(Imports2.class) + static class ImportGuards3 extends ValueNode { + + int do1(int a) { + return a; + } + } + + @ExpectError("The specified import guard class 'boolean' is not a declared type.") + @NodeChild("a") + @ImportGuards(boolean.class) + static class ImportGuards4 extends ValueNode { + + int do1(int a) { + return a; + } + } + + private static class Imports2 { + + } + + @ExpectError("At least import guard classes must be specified.") + @NodeChild("a") + @ImportGuards({}) + static class ImportGuards5 extends ValueNode { + + int do1(int a) { + return a; + } + } + + @Test + public void testImportGuards6() { + // should use the guar declared in the node instead of the imported one. + assertRuns(ImportGuards6Factory.getInstance(), // + array(1, 1), // + array(1, 1)); + } + + @ImportGuards(Imports0.class) + @NodeChild("a") + static class ImportGuards6 extends ValueNode { + + static boolean staticGuard(int a) { + return a == 1; + } + + @Specialization(guards = "staticGuard") + int f0(int a) { + return a; + } + } + +} diff -r 217eee2ddead -r 445f6456c4a5 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ImportGuards.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ImportGuards.java Thu Aug 14 16:49:45 2014 +0200 @@ -0,0 +1,42 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.dsl; + +import java.lang.annotation.*; + +/** + * Imports all public static methods usable as guards for {@link Specialization} annotations to the + * current class. Using this annotation common guards can be shared across nodes. Imported guards + * are derived from super classes. Guards declared in the node type hierarchy are always preferred + * to imported guards. Imported guards for a more concrete type are preferred to guards imported in + * the base class. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ImportGuards { + + Class[] value(); + +} diff -r 217eee2ddead -r 445f6456c4a5 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Thu Aug 14 15:35:20 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Thu Aug 14 16:49:45 2014 +0200 @@ -35,11 +35,11 @@ private final List messages = new ArrayList<>(); public final void addWarning(String text, Object... params) { - getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING)); + getMessages().add(new Message(null, null, this, String.format(text, params), Kind.WARNING)); } public final void addWarning(AnnotationValue value, String text, Object... params) { - getMessages().add(new Message(value, this, String.format(text, params), Kind.WARNING)); + getMessages().add(new Message(null, value, this, String.format(text, params), Kind.WARNING)); } public final void addError(String text, Object... params) { @@ -47,7 +47,11 @@ } public final void addError(AnnotationValue value, String text, Object... params) { - getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR)); + getMessages().add(new Message(null, value, this, String.format(text, params), Kind.ERROR)); + } + + public final void addError(AnnotationMirror mirror, AnnotationValue value, String text, Object... params) { + getMessages().add(new Message(mirror, value, this, String.format(text, params), Kind.ERROR)); } protected List findChildContainers() { @@ -137,6 +141,9 @@ if (message.getAnnotationValue() != null) { messageValue = message.getAnnotationValue(); } + if (message.getAnnotationMirror() != null) { + messageAnnotation = message.getAnnotationMirror(); + } String text = message.getText(); @@ -224,17 +231,23 @@ public static final class Message { private final MessageContainer originalContainer; + private final AnnotationMirror annotationMirror; private final AnnotationValue annotationValue; private final String text; private final Kind kind; - public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { + public Message(AnnotationMirror annotationMirror, AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { + this.annotationMirror = annotationMirror; this.annotationValue = annotationValue; this.originalContainer = originalContainer; this.text = text; this.kind = kind; } + public AnnotationMirror getAnnotationMirror() { + return annotationMirror; + } + public AnnotationValue getAnnotationValue() { return annotationValue; } diff -r 217eee2ddead -r 445f6456c4a5 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/AbstractParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/AbstractParser.java Thu Aug 14 15:35:20 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/AbstractParser.java Thu Aug 14 16:49:45 2014 +0200 @@ -83,7 +83,7 @@ // redirect message MessageContainer original = message.getOriginalContainer(); String text = wrapText(original.getMessageElement(), original.getMessageAnnotation(), message.getText()); - Message redirectedMessage = new Message(null, baseContainer, text, message.getKind()); + Message redirectedMessage = new Message(null, null, baseContainer, text, message.getKind()); model.getMessages().remove(i); baseContainer.getMessages().add(redirectedMessage); } diff -r 217eee2ddead -r 445f6456c4a5 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 Thu Aug 14 15:35:20 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Thu Aug 14 16:49:45 2014 +0200 @@ -125,6 +125,7 @@ return node; } + @SuppressWarnings("unchecked") private NodeData parseNode(TypeElement originalTemplateType) { // reloading the type elements is needed for ecj TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType)); @@ -141,6 +142,9 @@ List elements = CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType); NodeData node = parseNodeData(templateType, elements, lookupTypes); + + parseImportGuards(node, lookupTypes, (List) elements); + if (node.hasErrors()) { return node; // error sync point } @@ -169,6 +173,40 @@ return node; } + private void parseImportGuards(NodeData node, List lookupTypes, List elements) { + for (TypeElement lookupType : lookupTypes) { + AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportGuards.class); + if (importAnnotation == null) { + continue; + } + AnnotationValue importClassesValue = ElementUtils.getAnnotationValue(importAnnotation, "value"); + List importClasses = ElementUtils.getAnnotationValueList(TypeMirror.class, importAnnotation, "value"); + if (importClasses.isEmpty()) { + node.addError(importAnnotation, importClassesValue, "At least import guard classes must be specified."); + continue; + } + for (TypeMirror importGuardClass : importClasses) { + if (importGuardClass.getKind() != TypeKind.DECLARED) { + node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' is not a declared type.", ElementUtils.getQualifiedName(importGuardClass)); + continue; + } + TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass); + if (!typeElement.getModifiers().contains(Modifier.PUBLIC)) { + node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass)); + continue; + } + + List importMethods = ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(typeElement)); + for (ExecutableElement importMethod : importMethods) { + if (!importMethod.getModifiers().contains(Modifier.PUBLIC) || !importMethod.getModifiers().contains(Modifier.STATIC)) { + continue; + } + elements.add(importMethod); + } + } + } + } + private NodeData parseNodeData(TypeElement templateType, List elements, List typeHierarchy) { AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) {