# HG changeset patch # User Christian Humer # Date 1358512092 -3600 # Node ID 6343a09b2ec1ca840c4967ee4b4e186d02af1e4f # Parent 0f8c6dbf68be73b6d7760b28df1810100c8bb053 Codegen operation generation is inferred from the node type hierarchy. diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExecuteChildren.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/ExecuteChildren.java Fri Jan 18 13:28:12 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.TYPE}) +public @interface ExecuteChildren { + + String[] value(); + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Operation.java --- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Operation.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +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.*; -import com.oracle.truffle.api.nodes.*; - -@Retention(RetentionPolicy.CLASS) -@Target({ElementType.TYPE}) -public @interface Operation { - - Class< ? > typeSystem(); - - Class baseClass() default Node.class; - - String[] values() default {}; - - String[] shortCircuitValues() default {}; - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java Fri Jan 18 13:28:12 2013 +0100 @@ -33,7 +33,7 @@ /** * Specifies the name of the guard method annotated by {@link GuardCheck} specified as method in the - * {@link TypeSystem} or {@link Operation} class. + * {@link TypeSystem} class. */ String methodName(); diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java Fri Jan 18 13:28:12 2013 +0100 @@ -24,8 +24,6 @@ import java.lang.annotation.*; -import com.oracle.truffle.api.nodes.*; - /** *

* Annotates a type system class that represents type information for a node. Generates code for converting and managing @@ -72,19 +70,6 @@ /** * Sets the types contained by this type system. The order of types also determines the order of specialization. */ - Class[] types(); - - /** - * Specifies whether the node base class has an executeVoid method or not. Operations derived from this type system - * will automatically implement executeVoid for all generated nodes. Defaults to false. - */ - boolean hasVoid() default false; - - /** - * Specifies the node base class used for generated code that uses this type system. The node base class must extend - * {@link Node} and provide a public non-final method ${type} execute${typeName}(VirtualFrame) for all - * types specified in the types attribute. - */ - Class< ? extends Node> nodeBaseClass(); + Class[] value(); } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystemReference.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystemReference.java Fri Jan 18 13:28:12 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.TYPE}) +public @interface TypeSystemReference { + + Class value(); + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor --- a/graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/META-INF/services/javax.annotation.processing.Processor Fri Jan 18 13:28:12 2013 +0100 @@ -1,1 +1,1 @@ -com.oracle.truffle.codegen.processor.TruffleProcessor +com.oracle.truffle.codegen.processor.TruffleProcessor \ No newline at end of file diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -23,6 +23,7 @@ package com.oracle.truffle.codegen.processor; import java.lang.annotation.*; +import java.util.*; import javax.annotation.processing.*; import javax.lang.model.element.*; @@ -49,7 +50,11 @@ public final M parse(RoundEnvironment env, Element element) { this.roundEnv = env; try { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), getAnnotationType()); + AnnotationMirror mirror = null; + if (getAnnotationType() != null) { + mirror = Utils.findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), getAnnotationType()); + } + if (!context.getTruffleTypes().verify(context, element, mirror)) { return null; } @@ -60,7 +65,23 @@ } protected abstract M parse(Element element, AnnotationMirror mirror); - public abstract Class< ? extends Annotation> getAnnotationType(); + public boolean isDelegateToRootDeclaredType() { + return false; + } + + public List> getAllAnnotationTypes() { + List> list = new ArrayList<>(); + if (getAnnotationType() != null) { + list.add(getAnnotationType()); + } + list.addAll(getTypeDelegatedAnnotationTypes()); + return list; + } + + public List> getTypeDelegatedAnnotationTypes() { + return Collections.emptyList(); + } + } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AnnotationProcessor.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AnnotationProcessor.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AnnotationProcessor.java Fri Jan 18 13:28:12 2013 +0100 @@ -84,7 +84,7 @@ context.registerTemplate(type, model); if (model != null) { - CodeCompilationUnit unit = (CodeCompilationUnit) factory.process(model); + CodeCompilationUnit unit = factory.process(null, model); unit.setGeneratorAnnotationMirror(model.getTemplateTypeAnnotation()); unit.setGeneratorElement(model.getTemplateType()); diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java Fri Jan 18 13:28:12 2013 +0100 @@ -51,6 +51,10 @@ message(Kind.ERROR, element, null, null, format, args); } + public void error(String format, Object... args) { + message(Kind.ERROR, null, null, null, format, args); + } + public void error(Element element, AnnotationMirror mirror, String format, Object... args) { message(Kind.ERROR, element, mirror, null, format, args); } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java Fri Jan 18 13:28:12 2013 +0100 @@ -45,18 +45,16 @@ private final ProcessCallback callback; private final Log log; - private TruffleTypes truffleTypes; + private final TruffleTypes truffleTypes; public ProcessorContext(ProcessingEnvironment env, ProcessCallback callback) { this.environment = env; this.callback = callback; this.log = new Log(environment); + this.truffleTypes = new TruffleTypes(this); } public TruffleTypes getTruffleTypes() { - if (truffleTypes == null) { - truffleTypes = new TruffleTypes(this); - } return truffleTypes; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java Fri Jan 18 13:28:12 2013 +0100 @@ -30,7 +30,7 @@ import javax.lang.model.element.*; import com.oracle.truffle.codegen.processor.ProcessorContext.ProcessCallback; -import com.oracle.truffle.codegen.processor.operation.*; +import com.oracle.truffle.codegen.processor.node.*; import com.oracle.truffle.codegen.processor.typesystem.*; /** @@ -53,15 +53,30 @@ return false; } - @SuppressWarnings("unchecked") private void processImpl(RoundEnvironment env) { this.round = env; // TODO run verifications that other annotations are not processed out of scope of the operation or typelattice. try { for (AnnotationProcessor generator : getGenerators()) { - for (Element e : env.getElementsAnnotatedWith(generator.getParser().getAnnotationType())) { - processElement(env, generator, e, false); + AbstractParser parser = generator.getParser(); + if (parser.getAnnotationType() != null) { + for (Element e : env.getElementsAnnotatedWith(parser.getAnnotationType())) { + processElement(env, generator, e, false); + } } + + for (Class annotationType : parser.getTypeDelegatedAnnotationTypes()) { + for (Element e : env.getElementsAnnotatedWith(annotationType)) { + TypeElement processedType; + if (parser.isDelegateToRootDeclaredType()) { + processedType = Utils.findRootEnclosingType(e); + } else { + processedType = Utils.findNearestEnclosingType(e); + } + processElement(env, generator, processedType, false); + } + } + } } finally { this.round = null; @@ -85,9 +100,12 @@ @Override public void callback(TypeElement template) { for (AnnotationProcessor generator : generators) { - Annotation annotation = template.getAnnotation(generator.getParser().getAnnotationType()); - if (annotation != null) { - processElement(round, generator, template, true); + Class annotationType = generator.getParser().getAnnotationType(); + if (annotationType != null) { + Annotation annotation = template.getAnnotation(annotationType); + if (annotation != null) { + processElement(round, generator, template, true); + } } } } @@ -96,7 +114,12 @@ public Set getSupportedAnnotationTypes() { Set annotations = new HashSet<>(); for (AnnotationProcessor< ? > generator : getGenerators()) { - annotations.add(generator.getParser().getAnnotationType().getCanonicalName()); + for (Class annotationClass : generator.getParser().getAllAnnotationTypes()) { + if (annotationClass == null) { + throw new NullPointerException("class is null"); + } + annotations.add(annotationClass.getCanonicalName()); + } } return annotations; } @@ -105,7 +128,7 @@ if (generators == null && processingEnv != null) { generators = new ArrayList<>(); generators.add(new AnnotationProcessor<>(getContext(), new TypeSystemParser(getContext()), new TypeSystemCodeGenerator(getContext()))); - generators.add(new AnnotationProcessor<>(getContext(), new OperationParser(getContext()), new OperationCodeGenerator(getContext()))); + generators.add(new AnnotationProcessor<>(getContext(), new NodeParser(getContext()), new NodeCodeGenerator(getContext()))); } return generators; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Fri Jan 18 13:28:12 2013 +0100 @@ -63,6 +63,11 @@ return result; } + public static String getReadableSignature(ExecutableElement method) { + // TODO toString does not guarantee a good signature + return method.toString(); + } + public static boolean hasError(TypeMirror mirror) { switch (mirror.getKind()) { case BOOLEAN: @@ -243,13 +248,41 @@ return null; } - public static TypeElement findEnclosingType(Element element) { - Element enclosing = element.getEnclosingElement(); - while (enclosing.getKind() != ElementKind.CLASS && enclosing.getKind() != ElementKind.ENUM && enclosing.getKind() != ElementKind.INTERFACE) { - enclosing = element.getEnclosingElement(); + public static TypeElement findRootEnclosingType(Element element) { + List elements = getElementHierarchy(element); + + for (int i = elements.size() - 1; i >= 0; i--) { + if (elements.get(i).getKind().isClass()) { + return (TypeElement) elements.get(i); + } } - return (TypeElement) enclosing; + return null; + } + + private static List getElementHierarchy(Element e) { + List elements = new ArrayList<>(); + elements.add(e); + + Element enclosing = e.getEnclosingElement(); + while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) { + elements.add(enclosing); + enclosing = enclosing.getEnclosingElement(); + } + if (enclosing != null) { + elements.add(enclosing); + } + return elements; + } + + public static TypeElement findNearestEnclosingType(Element element) { + List elements = getElementHierarchy(element); + for (Element e : elements) { + if (e.getKind().isClass()) { + return (TypeElement) e; + } + } + return null; } public static List getSuperTypes(TypeElement element) { @@ -391,7 +424,7 @@ } public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List< ? extends AnnotationMirror> mirrors, Class< ? > annotationClass) { - TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getName()); + TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName()); for (AnnotationMirror mirror : mirrors) { DeclaredType annotationType = mirror.getAnnotationType(); TypeElement actualAnnotationType = (TypeElement) annotationType.asElement(); @@ -403,11 +436,13 @@ } private static PackageElement findPackageElement(Element type) { - Element searchType = type; - while (searchType.getEnclosingElement() != null && searchType.getEnclosingElement().getKind() != ElementKind.PACKAGE) { - searchType = type.getEnclosingElement(); + List hierarchy = getElementHierarchy(type); + for (Element element : hierarchy) { + if (element.getKind() == ElementKind.PACKAGE) { + return (PackageElement) element; + } } - return (PackageElement) searchType.getEnclosingElement(); + return null; } public static String firstLetterUpperCase(String name) { @@ -530,6 +565,19 @@ return false; } + public static Modifier getVisibility(Set modifier) { + for (Modifier mod : modifier) { + if (mod == Modifier.PUBLIC) { + return mod; + } else if (mod == Modifier.PRIVATE) { + return mod; + } else if (mod == Modifier.PROTECTED) { + return mod; + } + } + return null; + } + private static boolean isRuntimeException(TypeMirror type) { Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); String typeName = getQualifiedName(type); @@ -548,4 +596,13 @@ return false; } + public static boolean isTopLevelClass(TypeMirror importType) { + TypeElement type = fromTypeMirror(importType); + if (type != null && type.getEnclosingElement() != null) { + return !type.getEnclosingElement().getKind().isClass(); + } + return true; + } + + } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableExecutableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableExecutableElement.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/api/element/WritableExecutableElement.java Fri Jan 18 13:28:12 2013 +0100 @@ -31,7 +31,7 @@ void setDefaultValue(AnnotationValue defaultValue); void addParameter(VariableElement parameter); - void removeParamter(VariableElement parameter); + void removeParameter(VariableElement parameter); void addThrownType(TypeMirror thrownType); void removeThrownType(TypeMirror thrownType); diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeCompilationUnit.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeCompilationUnit.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeCompilationUnit.java Fri Jan 18 13:28:12 2013 +0100 @@ -50,8 +50,12 @@ @Override public R accept(ElementVisitor v, P p) { - for (TypeElement type : getEnclosedElements()) { - type.accept(v, p); + for (Element type : getEnclosedElements()) { + if (type.getKind().isClass()) { + type.accept(v, p); + } else { + throw new ClassCastException(type.getClass().getName()); + } } return null; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeElement.java Fri Jan 18 13:28:12 2013 +0100 @@ -119,9 +119,6 @@ } void setEnclosingElement(Element parent) { - if (this.enclosingElement != null && parent != null) { - throw new IllegalStateException("Element already added to " + parent); - } this.enclosingElement = parent; } @@ -161,7 +158,7 @@ return writer; } public String getString() { - return new String(((CharArrayWriter) writer).toCharArray()); + return new String(((CharArrayWriter) writer).toCharArray()).trim(); } } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Fri Jan 18 13:28:12 2013 +0100 @@ -71,7 +71,11 @@ @Override public ElementKind getKind() { - return ElementKind.METHOD; + if (getReturnType() == null) { + return ElementKind.CONSTRUCTOR; + } else { + return ElementKind.METHOD; + } } @Override @@ -108,6 +112,7 @@ CodeTreeBuilder builder = new CodeTreeBuilder(); this.bodyTree = builder.getTree(); this.bodyTree.setEnclosingElement(this); + this.body = null; return builder; } @@ -147,10 +152,24 @@ } @Override - public void removeParamter(VariableElement parameter) { + public void removeParameter(VariableElement parameter) { parameters.remove(parameter); } + + public void removeParameter(String varName) { + VariableElement remove = null; + for (VariableElement var : getParameters()) { + if (var.getSimpleName().toString().equals(varName)) { + remove = var; + break; + } + } + if (remove != null) { + parameters.remove(remove); + } + } + @Override public void addThrownType(TypeMirror thrownType) { throwables.add(thrownType); @@ -181,7 +200,6 @@ return v.visitExecutable(this, p); } - public static CodeExecutableElement clone(ProcessingEnvironment env, ExecutableElement method) { CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); for (TypeMirror thrownType : method.getThrownTypes()) { diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Fri Jan 18 13:28:12 2013 +0100 @@ -99,12 +99,10 @@ public CodeTreeBuilder startStatement() { startGroup(); registerCallBack(new EndCallback() { - @Override public void beforeEnd() { string(";").newLine(); } - @Override public void afterEnd() { } @@ -137,7 +135,7 @@ } public CodeTreeBuilder startStaticCall(ExecutableElement method) { - return startStaticCall(Utils.findEnclosingType(method).asType(), method.getSimpleName().toString()); + return startStaticCall(Utils.findNearestEnclosingType(method).asType(), method.getSimpleName().toString()); } public CodeTreeBuilder staticReference(TypeMirror type, String fieldName) { @@ -317,7 +315,17 @@ public CodeTreeBuilder startReturn() { ExecutableElement method = findMethod(); if (method != null && Utils.isVoid(method.getReturnType())) { - startStatement(); + startGroup(); + registerCallBack(new EndCallback() { + @Override + public void beforeEnd() { + string(";").newLine(); // complete statement to execute + } + @Override + public void afterEnd() { + string("return").string(";").newLine(); // emit a return; + } + }); return this; } else { return startStatement().string("return "); @@ -471,7 +479,7 @@ return statement("return"); } - private ExecutableElement findMethod() { + public ExecutableElement findMethod() { Element element = currentElement; while (element != null && (element.getKind() != ElementKind.METHOD)) { element = element.getEnclosingElement(); diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeElement.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeElement.java Fri Jan 18 13:28:12 2013 +0100 @@ -182,6 +182,16 @@ return ElementFilter.fieldsIn(getEnclosedElements()); } + public ExecutableElement getMethod(String name) { + for (Element element : getEnclosedElements()) { + if (element.getKind() == ElementKind.METHOD + && element.getSimpleName().toString().equals(name)) { + return (ExecutableElement) element; + } + } + return null; + } + public List getMethods() { return ElementFilter.methodsIn(getEnclosedElements()); } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Fri Jan 18 13:28:12 2013 +0100 @@ -175,6 +175,10 @@ writeEmptyLn(); } + for (ExecutableElement method : ElementFilter.constructorsIn(e.getEnclosedElements())) { + method.accept(this, null); + } + for (ExecutableElement method : getInstanceMethods(e)) { method.accept(this, null); } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Fri Jan 18 13:28:12 2013 +0100 @@ -182,7 +182,7 @@ continue; // java.lang is automatically imported } - if (importTypePackageName.equals(getPackageName(e))) { + if (importTypePackageName.equals(getPackageName(e)) && Utils.isTopLevelClass(importType)) { continue; // same package name -> no import } @@ -199,8 +199,8 @@ } private static void collectInnerTypeImports(TypeElement e, Set autoImportedTypes) { + autoImportedTypes.add(getQualifiedName(e)); for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) { - collectSuperTypeImports(innerClass, autoImportedTypes); collectInnerTypeImports(innerClass, autoImportedTypes); } } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JDTCompiler.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JDTCompiler.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JDTCompiler.java Fri Jan 18 13:28:12 2013 +0100 @@ -31,7 +31,7 @@ public static boolean isValidElement(Element currentElement) { try { - Class elementClass = Class.forName("org.eclipse.jdt.internal.compiler.apt.model.ElementImpl"); + Class< ? > elementClass = Class.forName("org.eclipse.jdt.internal.compiler.apt.model.ElementImpl"); return elementClass.isAssignableFrom(currentElement.getClass()); } catch (ClassNotFoundException e) { return false; @@ -48,10 +48,9 @@ } /* - AbstractMethodDeclaration decl = ((MethodBinding)(((ElementImpl)method)._binding)).sourceMethod(); - int bodyStart = decl.bodyStart; - int bodyEnd = decl.bodyEnd; - */ + * AbstractMethodDeclaration decl = ((MethodBinding)(((ElementImpl)method)._binding)).sourceMethod(); int + * bodyStart = decl.bodyStart; int bodyEnd = decl.bodyEnd; + */ Object decl = method(field(method, "_binding"), "sourceMethod"); int bodyStart = (int) field(decl, "bodyStart"); int bodyEnd = (int) field(decl, "bodyEnd"); @@ -66,22 +65,19 @@ } } - private static char[] getSource(Element element) throws Exception { /* - Binding binding = ((ElementImpl)element)._binding; - char[] source = null; - if (binding instanceof MethodBinding) { - source = ((MethodBinding) binding).sourceMethod().compilationResult.getCompilationUnit().getContents(); - } else if (binding instanceof SourceTypeBinding) { - source = ((SourceTypeBinding)binding).scope.referenceContext.compilationResult.compilationUnit.getContents(); - } - return source; - */ + * Binding binding = ((ElementImpl)element)._binding; char[] source = null; if (binding instanceof + * MethodBinding) { source = ((MethodBinding) + * binding).sourceMethod().compilationResult.getCompilationUnit().getContents(); } else if (binding instanceof + * SourceTypeBinding) { source = + * ((SourceTypeBinding)binding).scope.referenceContext.compilationResult.compilationUnit.getContents(); } return + * source; + */ Object binding = field(element, "_binding"); - Class methodBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.MethodBinding"); - Class referenceBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); + Class< ? > methodBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.MethodBinding"); + Class< ? > referenceBindingClass = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); char[] source = null; if (methodBindingClass.isAssignableFrom(binding.getClass())) { @@ -96,7 +92,6 @@ return source; } - @Override public String getHeaderComment(ProcessingEnvironment env, Element type) { try { diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JavaCCompiler.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JavaCCompiler.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/JavaCCompiler.java Fri Jan 18 13:28:12 2013 +0100 @@ -90,6 +90,4 @@ } } - - } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -46,11 +46,11 @@ this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory); } - public List parseAll(TypeElement typeElement) { + public List parseAll(TypeElement typeElement, List elements) { List generatedMethods = new ArrayList<>(); parseElement(generatedMethods, typeElement); - List methods = ElementFilter.methodsIn(typeElement.getEnclosedElements()); + List methods = ElementFilter.methodsIn(elements); for (ExecutableElement method : methods) { for (VariableElement var : method.getParameters()) { parseElement(generatedMethods, var); diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.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/ExecutableTypeData.java Fri Jan 18 13:28:12 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.codegen.processor.node; + +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + + +public class ExecutableTypeData extends TemplateMethod { + + private final TypeSystemData typeSystem; + private final TypeData type; + + public ExecutableTypeData(TemplateMethod method, TypeSystemData typeSystem, TypeData type) { + super(method); + this.typeSystem = typeSystem; + this.type = type; + } + + public TypeData getType() { + return type; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public boolean hasFrame() { + return getMethod().getParameters().size() > 0; + } + + public boolean hasUnexpectedValue(ProcessorContext context) { + return Utils.canThrowType(getMethod().getThrownTypes(), context.getTruffleTypes().getUnexpectedValueException()); + } + + public boolean isFinal() { + return getMethod().getModifiers().contains(Modifier.FINAL); + } + + @Override + public int hashCode() { + return type.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ExecutableTypeData) { + return type.equals(((ExecutableTypeData) obj).type); + } + return super.equals(obj); + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.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/ExecutableTypeMethodParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,78 @@ +/* + * 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 java.lang.annotation.*; +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.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class ExecutableTypeMethodParser extends MethodParser { + + public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { + super(context, node); + setEmitErrors(false); + setParseNullOnError(false); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List types = new ArrayList<>(); + types.addAll(Arrays.asList(getNode().getTypeSystem().getPrimitiveTypeMirrors())); + types.add(getContext().getType(void.class)); + + ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types.toArray(new TypeMirror[types.size()]), + getNode().getTypeSystem().getGenericType(), false, Cardinality.ONE); + + List parameters = new ArrayList<>(); + parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); + return new MethodSpec(returnTypeSpec, parameters); + } + + @Override + public final boolean isParsable(ExecutableElement method) { + boolean parsable = method.getSimpleName().toString().startsWith("execute"); + return parsable; + } + + @Override + public ExecutableTypeData create(TemplateMethod method) { + TypeData resolvedType = method.getReturnType().getActualTypeData(getNode().getTypeSystem()); + if (resolvedType == null) { + return null; + } + return new ExecutableTypeData(method, getNode().getTypeSystem(), resolvedType); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return null; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.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/GenericParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,64 @@ +/* + * 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 java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class GenericParser extends MethodParser { + + public GenericParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return createDefaultMethodSpec(null); + } + + @Override + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { + return new ParameterSpec(valueName, nodeData.findGenericExecutableType(getContext()).getType().getPrimitiveType(), false); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return super.createValueParameterSpec("returnValue", getNode()); + } + + @Override + public SpecializationData create(TemplateMethod method) { + return new SpecializationData(method, true, false); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return Generic.class; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.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/MethodParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,93 @@ +/* + * 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 java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; + + +public abstract class MethodParser extends TemplateMethodParser{ + + public MethodParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + public NodeData getNode() { + return template; + } + + + protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) { + return new ParameterSpec(valueName, nodeData, false, Cardinality.ONE); + } + + protected ParameterSpec createReturnParameterSpec() { + return createValueParameterSpec("operation", getNode()); + } + + @Override + public boolean isParsable(ExecutableElement method) { + return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + } + + protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { + List defaultParameters = new ArrayList<>(); + ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true); + defaultParameters.add(frameSpec); + + for (NodeFieldData field : getNode().getFields()) { + if (field.getExecutionKind() == ExecutionKind.IGNORE) { + continue; + } + + if (field.getExecutionKind() == ExecutionKind.DEFAULT) { + defaultParameters.add(createValueParameterSpec(field.getName(), field.getNodeData())); + } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { + String valueName = field.getName(); + if (shortCircuitName != null && valueName.equals(shortCircuitName)) { + break; + } + + defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), + getContext().getType(boolean.class), false)); + + defaultParameters.add(createValueParameterSpec(valueName, field.getNodeData())); + } else { + assert false; + } + } + + return new MethodSpec(createReturnParameterSpec(), defaultParameters); + } + + private static String shortCircuitValueName(String valueName) { + return "has" + Utils.firstLetterUpperCase(valueName); + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.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/NodeCodeGenerator.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,866 @@ +/* + * 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 static com.oracle.truffle.codegen.processor.Utils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.ast.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + + +public class NodeCodeGenerator extends CompilationUnitFactory { + + private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; + + public NodeCodeGenerator(ProcessorContext context) { + super(context); + } + + private TypeMirror getUnexpectedValueException() { + return getContext().getTruffleTypes().getUnexpectedValueException(); + } + + private static String factoryClassName(NodeData node) { + return nodeClassName(node) + "Factory"; + } + + private static String nodeClassName(NodeData node) { + return Utils.getSimpleName(node.getTemplateType().asType()); + } + + private static String nodeClassName(SpecializationData specialization) { + String name = ""; + if (specialization.getNode().getSpecializations().length > 1) { + name = specialization.getMethodName(); + if (name.startsWith("do")) { + name = name.substring(2); + } + } + name += nodeClassName(specialization.getNode()); + if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) + || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) { + name = name + "Impl"; + } + + return name; + } + + private static String valueName(NodeFieldData field) { + return field.getName() + "Value"; + } + + private static String valueName(TemplateMethod method, ActualParameter param) { + NodeData node = (NodeData) method.getTemplate(); + NodeFieldData field = node.findField(param.getSpecification().getName()); + if (field != null) { + return valueName(field); + } else { + return param.getSpecification().getName(); + } + } + + private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { + if (forceFrame) { + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame")); + } + for (ActualParameter parameter : specialization.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (forceFrame && spec.getName().equals("frame")) { + continue; + } + method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter))); + } + } + + private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) { + if (forceFrame) { + builder.string("frame"); + } + for (ActualParameter parameter : specialization.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (forceFrame && spec.getName().equals("frame")) { + continue; + } + + if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) { + builder.string("ex.getResult()"); + } else { + builder.string(valueName(specialization, parameter)); + } + } + } + + private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization) { + for (ActualParameter param : specialization.getParameters()) { + TypeData typeData = param.getActualTypeData(specialization.getNode().getTypeSystem()); + if (typeData == null || typeData.isGeneric()) { + body.string(valueName(specialization, param)); + } else { + String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); + startCallTypeSystemMethod(context, body, specialization.getNode(), methodName); + body.string(valueName(specialization, param)); + body.end().end(); + } + } + } + + private static String genClassName(Template operation) { + return getSimpleName(operation.getTemplateType()) + "Gen"; + } + + private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) { + body.startGroup(); + if (body.findMethod().getModifiers().contains(STATIC)) { + body.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + body.string("super"); + } + body.string("."); + body.startCall(method.getMethodName()); + } + + private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { + VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); + assert singleton != null; + + body.startGroup(); + body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); + body.string(".").startCall(methodName); + } + + private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { + TypeSystemData typeSystem = specialization.getNode().getTypeSystem(); + // Implict guards based on method signature + String andOperator = prefix; + for (NodeFieldData field : specialization.getNode().getFields()) { + ActualParameter param = specialization.findParameter(field.getName()); + TypeData type = param.getActualTypeData(typeSystem); + if (type == null || type.isGeneric()) { + continue; + } + + body.string(andOperator); + startCallTypeSystemMethod(context, body, specialization.getNode(), + TypeSystemCodeGenerator.isTypeMethodName(type)); + body.string(valueName(specialization, param)); + body.end().end(); // call + andOperator = " && "; + } + + if (specialization.getGuards().length > 0) { + // Explicitly specified guards + for (SpecializationGuardData guard : specialization.getGuards()) { + if ((guard.isOnSpecialization() && onSpecialization) + || (guard.isOnExecution() && !onSpecialization)) { + body.string(andOperator); + + startCallOperationMethod(body, guard.getGuardDeclaration()); + + if (needsCast) { + addValueParameterNamesWithCasts(context, body, specialization); + } else { + addValueParameterNames(body, specialization, null, false); + } + body.end().end(); // call + andOperator = " && "; + } + } + } + } + + @Override + protected void createChildren(NodeData node) { + Map> childTypes = new LinkedHashMap<>(); + if (node.getDeclaredChildren() != null && !node.getDeclaredChildren().isEmpty()) { + for (NodeData nodeChild : node.getDeclaredChildren()) { + NodeCodeGenerator generator = new NodeCodeGenerator(getContext()); + childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements()); + } + } + + if (node.getExtensionElements() != null && !node.getExtensionElements().isEmpty()) { + NodeGenFactory factory = new NodeGenFactory(context); + add(factory, node); + } + + if (node.getSpecializations() == null) { + return; + } + + if (node.needsFactory() || childTypes.size() > 0) { + add(new NodeFactoryFactory(context, childTypes), node); + } + } + + private class NodeGenFactory extends ClassElementFactory { + + public NodeGenFactory(ProcessorContext context) { + super(context); + } + + @Override + protected CodeTypeElement create(NodeData node) { + CodeTypeElement clazz = createClass(node, modifiers(PUBLIC, ABSTRACT), genClassName(node), node.getTemplateType().asType(), false); + + for (ExecutableElement executable : ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements())) { + CodeExecutableElement superConstructor = createSuperConstructor(clazz, executable); + + if (superConstructor != null) { + if (superConstructor.getParameters().size() == 1 + && Utils.typeEquals(superConstructor.getParameters().get(0).asType(), node.getTemplateType().asType())) { + String originalName = superConstructor.getParameters().get(0).getSimpleName().toString(); + superConstructor.getParameters().clear(); + superConstructor.getParameters().add(new CodeVariableElement(clazz.asType(), originalName)); + } + clazz.add(superConstructor); + } + } + + if (node.getExtensionElements() != null) { + clazz.getEnclosedElements().addAll(node.getExtensionElements()); + } + + node.setNodeType(clazz.asType()); + + return clazz; + } + + } + + private class NodeFactoryFactory extends ClassElementFactory { + + private final Map> childTypes; + + public NodeFactoryFactory(ProcessorContext context, Map> childElements) { + super(context); + this.childTypes = childElements; + } + + @Override + protected CodeTypeElement create(NodeData node) { + Modifier visibility = Utils.getVisibility(node.getTemplateType().getModifiers()); + CodeTypeElement clazz = createClass(node, modifiers(), factoryClassName(node), null, false); + if (visibility != null) { + clazz.getModifiers().add(visibility); + } + clazz.getModifiers().add(Modifier.FINAL); + clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); + return clazz; + } + + @Override + protected void createChildren(NodeData node) { + CodeTypeElement clazz = getElement(); + + Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); + + if (node.needsFactory()) { + createFactoryMethods(node, clazz, createVisibility); + + if (node.getSpecializations().length > 1) { + clazz.add(createCreateSpecializedMethod(node, createVisibility)); + } + + if (node.needsRewrites(getContext())) { + clazz.add(createSpecializeMethod(node)); + clazz.add(createGeneratedGenericMethod(node)); + } + + for (SpecializationData specialization : node.getSpecializations()) { + add(new SpecializedNodeFactory(context), specialization); + } + } + + for (NodeData childNode : childTypes.keySet()) { + if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { + continue; + } + + for (TypeElement type : childTypes.get(childNode)) { + Set typeModifiers = ((CodeTypeElement) type).getModifiers(); + Modifier visibility = Utils.getVisibility(type.getModifiers()); + typeModifiers.clear(); + if (visibility != null) { + typeModifiers.add(visibility); + } + + typeModifiers.add(Modifier.STATIC); + typeModifiers.add(Modifier.FINAL); + clazz.add(type); + } + } + } + + private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { + for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) { + if (constructor.getModifiers().contains(PRIVATE)) { + continue; + } + + // skip node rewrite constructor + if (constructor.getParameters().size() == 1 + && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) { + continue; + } + + clazz.add(createCreateMethod(node, createVisibility, constructor)); + } + } + + private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor); + method.setSimpleName(CodeNames.of("create")); + method.getModifiers().clear(); + if (visibility != null) { + method.getModifiers().add(visibility); + } + method.getModifiers().add(Modifier.STATIC); + method.setReturnType(node.getNodeType()); + + CodeTreeBuilder body = method.createBuilder(); + body.startReturn(); + if (node.getSpecializations().length == 0) { + body.null_(); + } else { + body.startNew(nodeClassName(node.getSpecializations()[0])); + for (VariableElement var : method.getParameters()) { + body.string(var.getSimpleName().toString()); + } + body.end(); + } + body.end(); + return method; + } + + private CodeExecutableElement createCreateSpecializedMethod(NodeData node, Modifier visibility) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createSpecialized"); + if (visibility != null) { + method.getModifiers().add(visibility); + } + method.getModifiers().add(Modifier.STATIC); + + method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); + + CodeTreeBuilder body = method.createBuilder(); + boolean first = true; + for (TypeData type : node.getTypeSystem().getTypes()) { + SpecializationData specialization = node.findUniqueSpecialization(type); + if (specialization != null && !type.isGeneric()) { + if (first) { + body.startIf(); + first = false; + } else { + body.startElseIf(); + } + body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); + body.startReturn().startNew(nodeClassName(specialization)); + body.string(THIS_NODE_LOCAL_VAR_NAME); + body.end().end(); // new, return + + body.end(); // if + } + } + body.startReturn().startNew(nodeClassName(node.getGenericSpecialization())); + body.string(THIS_NODE_LOCAL_VAR_NAME); + body.end().end(); + return method; + } + + private CodeExecutableElement createSpecializeMethod(NodeData node) { + 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); + + CodeTreeBuilder body = method.createBuilder(); + body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[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(); + + if (specialization.isGeneric()) { + body.startIf().string("allowed").end().startBlock(); + } else { + body.startIf().string("allowed"); + emitGuards(getContext(), body, " && ", specialization, true, true); + body.end().startBlock(); + } + body.startReturn().startNew(nodeClassName(specialization)); + body.string(THIS_NODE_LOCAL_VAR_NAME); + body.end().end(); + body.end(); // block + } + body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); + + return method; + } + + + private CodeExecutableElement createGeneratedGenericMethod(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getGenericSpecialization().getReturnType().getActualType(), "generatedGeneric"); + method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); + addValueParameters(method, node.getGenericSpecialization(), true); + + CodeTreeBuilder builder = method.createBuilder(); + boolean ifStarted = false; + for (int i = 0; i < node.getSpecializations().length; i++) { + SpecializationData specialization = node.getSpecializations()[i]; + if (specialization.isUninitialized()) { + continue; + } + if (!specialization.isGeneric()) { + if (!ifStarted) { + builder.startIf(); + ifStarted = true; + } else { + builder.startElseIf(); + } + emitGuards(getContext(), builder, "", specialization, false, true); + builder.end().startBlock(); + } else { + builder.startElseBlock(); + } + + emitInvokeDoMethod(builder, specialization, 0); + builder.end(); + } + return method; + } + + private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { + if (specialization.getExceptions().length > 0) { + builder.startTryBlock(); + } + + builder.startReturn(); + startCallOperationMethod(builder, specialization); + addValueParameterNamesWithCasts(context, builder, specialization); + builder.end().end(); // start call operation + builder.end(); // return + + if (specialization.getExceptions().length > 0) { + for (SpecializationThrowsData exception : specialization.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); + emitInvokeDoMethod(builder, exception.getTransitionTo(), level + 1); + } + builder.end(); + } + } + } + + private class SpecializedNodeFactory extends ClassElementFactory { + + + public SpecializedNodeFactory(ProcessorContext context) { + super(context); + } + + @Override + public CodeTypeElement create(SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false); + return clazz; + } + + @Override + protected void createChildren(SpecializationData specialization) { + CodeTypeElement clazz = getElement(); + NodeData node = specialization.getNode(); + + TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); + for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { + ExecutableElement superConstructor = createSuperConstructor(clazz, constructor); + if (superConstructor != null) { + clazz.add(superConstructor); + } + } + + for (ExecutableTypeData execType : node.getExecutableTypes()) { + if (execType.isFinal()) { + continue; + } + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); + if (method.getParameters().size() == 1) { + CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0)); + var.setName("frame"); + method.getParameters().set(0, var); + } + method.getModifiers().remove(Modifier.ABSTRACT); + clazz.add(method); + + TypeData primaryType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); + if (primaryType == execType.getType()) { + buildFunctionalExecuteMethod(method.createBuilder(), specialization); + } else { + buildCastingExecuteMethod(method.createBuilder(), specialization, execType.getType()); + } + } + + if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { + buildSpecializeStateMethod(clazz, specialization); + } + } + + private void buildCastingExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization, TypeData type) { + NodeData node = specialization.getNode(); + TypeSystemData typeSystem = node.getTypeSystem(); + + if (!type.isVoid()) { + builder.startStatement().type(specialization.getReturnType().getActualType()).string(" result").end(); + } + + TypeData primaryType = specialization.getReturnType().getActualTypeData(typeSystem); + ExecutableTypeData execType = specialization.getNode().findExecutableType(primaryType); + + boolean needsTry = !specialization.getReturnType().getActualTypeData(typeSystem).isGeneric(); + if (needsTry) { + builder.startTryBlock(); + } + + builder.startStatement(); + if (!type.isVoid()) { + builder.string("result = "); + } + buildExecute(builder, null, execType); + builder.end(); // statement + + if (needsTry) { + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + + if (!type.isVoid()) { + builder.startReturn(); + if (!type.isGeneric()) { + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(type)); + } + + builder.string("ex.getResult()"); + + if (!type.isGeneric()) { + builder.end().end(); + } + builder.end(); // return + } else { + builder.string("// ignore").newLine(); + } + } + builder.end(); // try/catch + + if (!type.isVoid()) { + builder.startReturn(); + if (!type.isGeneric()) { + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(type)); + } + builder.string("result"); + if (!type.isGeneric()) { + builder.end().end(); + } + builder.end(); // return + } + } + + private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { + NodeData node = specialization.getNode(); + TypeSystemData typeSystem = node.getTypeSystem(); + + for (NodeFieldData field : node.getFields()) { + if (field.getExecutionKind() == ExecutionKind.IGNORE) { + continue; + } + + ActualParameter parameterType = specialization.findParameter(field.getName()); + + if (parameterType.getActualTypeData(typeSystem).isGeneric()) { + buildGenericValueExecute(builder, specialization, field, null); + } else { + buildSpecializedValueExecute(builder, specialization, field); + } + } + + if (specialization.hasDynamicGuards()) { + builder.startIf(); + emitGuards(getContext(), builder, "", specialization, false, false); + builder.end().startBlock(); + } + if (specialization.getExceptions().length > 0) { + builder.startTryBlock(); + } + + if (specialization.isUninitialized()) { + for (TemplateMethod listener : node.getSpecializationListeners()) { + builder.startStatement(); + startCallOperationMethod(builder, listener); + addValueParameterNames(builder, listener, null, false); + builder.end().end(); + builder.end(); // statement + } + + builder.startStatement(); + builder.startCall("replace"); + if (node.needsRewrites(getContext())) { + builder.startCall(factoryClassName(node), "specialize"); + builder.string("this"); + builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); + addValueParameterNames(builder, specialization, null, false); + builder.end(); // call replace, call specialize + } else { + builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); + } + builder.end().end(); + } + + if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { + builder.startReturn().startCall(factoryClassName(node), "generatedGeneric"); + builder.string("this"); + addValueParameterNames(builder, specialization, null, true); + builder.end().end(); + } else { + builder.startReturn(); + + if (specialization.isUninitialized()) { + startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization()); + } else { + startCallOperationMethod(builder, specialization); + } + addValueParameterNames(builder, specialization, null, false); + builder.end().end(); // operation call + builder.end(); // return + } + + if (specialization.getExceptions().length > 0) { + for (SpecializationThrowsData exception : specialization.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "ex"); + buildThrowSpecialize(builder, exception.getTransitionTo(), null); + } + builder.end(); + } + if (specialization.hasDynamicGuards()) { + builder.end().startElseBlock(); + buildThrowSpecialize(builder, specialization.findNextSpecialization(), null); + builder.end(); + } + } + + private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field, NodeFieldData exceptionSpec) { + ActualParameter specParameter = specialization.findParameter(field.getName()); + + boolean shortCircuit = startShortCircuit(builder, specialization, + field, exceptionSpec); + + builder.startStatement(); + if (!shortCircuit) { + builder.type(specialization.getNode().getTypeSystem().getGenericType()); + builder.string(" "); + } + + builder.string(valueName(specialization, specParameter)); + builder.string(" = "); + ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext()); + if (genericExecutableType == null) { + throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes())); + } + buildExecute(builder, field, genericExecutableType); + builder.end(); + + endShortCircuit(builder, shortCircuit); + } + + private void buildExecute(CodeTreeBuilder builder, NodeFieldData field, ExecutableTypeData execType) { + if (field != null) { + Element accessElement = field.getAccessElement(); + if (accessElement.getKind() == ElementKind.METHOD) { + builder.startCall(accessElement.getSimpleName().toString()).end(); + } else if (accessElement.getKind() == ElementKind.FIELD) { + builder.string("this.").string(accessElement.getSimpleName().toString()); + } else { + throw new AssertionError(); + } + builder.string("."); + } + builder.startCall(execType.getMethodName()); + if (execType.getParameters().length == 1) { + builder.string("frame"); + } + 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(specialization, param)).end(); + } + + ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); + + if (execType.hasUnexpectedValue(getContext())) { + builder.startTryBlock(); + } + + 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; + } + } + buildThrowSpecialize(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; + for (NodeFieldData field : specialization.getNode().getFields()) { + if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { + if (field == forField) { + break; + } + shortCircuitIndex++; + } + } + + builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = "); + ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; + + startCallOperationMethod(builder, shortCircuitData); + addValueParameterNames(builder, shortCircuitData, exceptionField != null ? exceptionField.getName() : null, false); + builder.end().end(); // call operation + + builder.end(); // statement + + builder.declaration(parameter.getActualType(), valueName(specialization, parameter), + CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); + builder.startIf().string(shortCircuitParam.getSpecification().getName()).end(); + builder.startBlock(); + + return true; + } + + + private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { + if (shortCircuit) { + builder.end(); + } + } + + private void buildThrowSpecialize(CodeTreeBuilder builder, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { + boolean canThrowUnexpected = Utils.canThrowType(builder.findMethod().getThrownTypes(), getContext().getTruffleTypes().getUnexpectedValueException()); + + CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder(); + specializeCall.startCall("specialize"); + specializeCall.string(nodeClassName(nextSpecialization) + ".class"); + addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); + specializeCall.end().end(); + + if (canThrowUnexpected) { + builder.startThrow(); + builder.startNew(getContext().getTruffleTypes().getUnexpectedValueException()); + builder.tree(specializeCall.getRoot()); + builder.end().end(); + } else { + builder.startReturn(); + builder.tree(specializeCall.getRoot()); + builder.end(); + } + + } + + private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), specialization.getNode().getTypeSystem().getGenericType(), "specialize"); + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); + clazz.add(method); + + CodeTreeBuilder builder = method.createBuilder(); + for (TemplateMethod listener : specialization.getNode().getSpecializationListeners()) { + builder.startStatement(); + startCallOperationMethod(builder, listener); + addValueParameterNames(builder, listener, null, false); + builder.end().end(); // call operation + builder.end(); // statement + } + + builder.startStatement(); + builder.startCall("replace"); + builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); + addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false); + builder.end(); + builder.end(); // call replace + builder.end(); // statement + + ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod("generatedGeneric"); + + CodeTreeBuilder genericBuilder = CodeTreeBuilder.createBuilder(); + genericBuilder.startCall(factoryClassName(specialization.getNode()), "generatedGeneric"); + genericBuilder.string("this"); + addValueParameterNames(genericBuilder, specialization.getNode().getGenericSpecialization(), null, true); + genericBuilder.end(); // call generated generic + + if (Utils.isVoid(generatedGeneric.getReturnType())) { + builder.declaration(generatedGeneric.getReturnType(), "genericResult", genericBuilder.getRoot()); + builder.startReturn().string("null").end(); + } else { + builder.startReturn().tree(genericBuilder.getRoot()).end(); + } + } + + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.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/NodeData.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,332 @@ +/* + * Copyright (c) 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 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.FieldKind; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + + +public class NodeData extends Template { + + private NodeData parent; + private List declaredChildren; + + private final TypeSystemData typeSystem; + + private NodeFieldData[] fields; + private SpecializationData[] specializations; + private TemplateMethod[] specializationListeners; + private GuardData[] guards; + private ExecutableTypeData[] executableTypes; + + private TypeMirror nodeType; + + public NodeData(TypeElement type, TypeSystemData typeSystem) { + super(type, null); + this.typeSystem = typeSystem; + } + + public TypeMirror getNodeType() { + if (nodeType != null) { + return nodeType; + } + return getTemplateType().asType(); + } + + public boolean needsFactory() { + if (specializations == null) { + return false; + } + boolean noSpecialization = true; + for (SpecializationData specialization : specializations) { + noSpecialization = noSpecialization && specialization.isGeneric() || specialization.isUninitialized(); + } + return !noSpecialization; + } + + void setDeclaredChildren(List declaredChildren) { + this.declaredChildren = declaredChildren; + + for (NodeData child : declaredChildren) { + child.parent = this; + } + } + + public NodeData getParent() { + return parent; + } + + public List getDeclaredChildren() { + return declaredChildren; + } + + public void setNodeType(TypeMirror nodeType) { + this.nodeType = nodeType; + } + + public List getAllTemplateMethods() { + List methods = new ArrayList<>(); + + for (SpecializationData specialization : getSpecializations()) { + methods.add(specialization); + if (specialization.getShortCircuits() != null) { + methods.addAll(Arrays.asList(specialization.getShortCircuits())); + } + } + + methods.addAll(Arrays.asList(getSpecializationListeners())); + methods.addAll(Arrays.asList(getExecutableTypes())); + methods.addAll(Arrays.asList(getGuards())); + + return methods; + } + + + public TemplateMethod[] getSpecializationListeners() { + return specializationListeners; + } + + public List findGuards(String name) { + List foundGuards = new ArrayList<>(); + for (GuardData guardData : getGuards()) { + if (guardData.getMethodName().equals(name)) { + foundGuards.add(guardData); + } + } + return foundGuards; + } + + public ExecutableTypeData[] getExecutableTypes() { + return executableTypes; + } + + public ExecutableTypeData findGenericExecutableType(ProcessorContext context) { + List types = findGenericExecutableTypes(context); + if (types.size() == 1) { + return types.get(0); + } else { + ExecutableTypeData execType = null; + for (ExecutableTypeData type : types) { + if (!type.getReturnType().getActualTypeData(getTypeSystem()).isVoid()) { + if (execType != null) { + // multiple generic types not allowed + return null; + } + execType = type; + } + } + return execType; + } + } + + private List findGenericExecutableTypes(ProcessorContext context) { + List types = new ArrayList<>(); + for (ExecutableTypeData type : executableTypes) { + if (!type.hasUnexpectedValue(context)) { + types.add(type); + } + } + return types; + } + + public ExecutableTypeData findExecutableType(TypeData prmitiveType) { + for (ExecutableTypeData type : executableTypes) { + if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) { + return type; + } + } + return null; + } + + public SpecializationData findUniqueSpecialization(TypeData type) { + SpecializationData result = null; + for (SpecializationData specialization : specializations) { + if (specialization.getReturnType().getActualTypeData(getTypeSystem()) == type) { + if (result != null) { + // Result not unique; + return null; + } + result = specialization; + } + } + 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(); + } + 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); + } + } + } + } + return filteredFields.toArray(new NodeFieldData[filteredFields.size()]); + } + + public boolean hasUnexpectedExecutableTypes(ProcessorContext context) { + for (ExecutableTypeData type : getExecutableTypes()) { + if (type.hasUnexpectedValue(context)) { + return true; + } + } + return false; + } + + public boolean needsRewrites(ProcessorContext context) { + boolean needsRewrites = false; + for (NodeFieldData field : getFields()) { + if (field.getExecutionKind() == ExecutionKind.DEFAULT + || field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { + if (!field.getNodeData().hasUnexpectedExecutableTypes(context)) { + continue; + } + + needsRewrites = true; + break; + } + } + + needsRewrites &= specializations.length >= 2; + return needsRewrites; + } + + public SpecializationData getGenericSpecialization() { + for (SpecializationData specialization : specializations) { + if (specialization.isGeneric()) { + return specialization; + } + } + return null; + } + + public TypeSystemData getTypeSystem() { + if (typeSystem != null) { + return typeSystem; + } else { + return null; + } + } + + 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) + )); + return b.toString(); + } + + private static String dumpList(Object[] array) { + if (array == null) { + return "null"; + } + + StringBuilder b = new StringBuilder(); + b.append("["); + for (Object object : array) { + b.append("\n"); + b.append(" "); + b.append(object); + b.append(", "); + } + b.append("\n ]"); + return b.toString(); + } + + public NodeFieldData findField(String name) { + for (NodeFieldData field : getFields()) { + if (field.getName().equals(name)) { + return field; + } + } + return null; + } + + + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.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/NodeFieldData.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 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 javax.lang.model.element.*; +import javax.lang.model.type.*; + + +public class NodeFieldData { + + public enum FieldKind { + FIELD, CHILD, CHILDREN + } + + public enum ExecutionKind { + DEFAULT, IGNORE, SHORT_CIRCUIT + } + + private final VariableElement fieldElement; + private final Element accessElement; + private final AnnotationMirror childAnnotationMirror; + + private final FieldKind fieldKind; + private final ExecutionKind executionKind; + private final NodeData nodeData; + + public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, + FieldKind fieldKind, ExecutionKind executionKind) { + this.fieldElement = fieldElement; + this.accessElement = accessElement; + this.childAnnotationMirror = childAnnotationMirror; + this.nodeData = typeNodeData; + this.fieldKind = fieldKind; + this.executionKind = executionKind; + } + + public VariableElement getFieldElement() { + return fieldElement; + } + + public Element getAccessElement() { + return accessElement; + } + + public AnnotationMirror getChildAnnotationMirror() { + return childAnnotationMirror; + } + + public TypeMirror getType() { + return fieldElement.asType(); + } + + public FieldKind getKind() { + return fieldKind; + } + + public ExecutionKind getExecutionKind() { + return executionKind; + } + + public NodeData getNodeData() { + return nodeData; + } + + public String getName() { + return fieldElement.getSimpleName().toString(); + } + + + @Override + public String toString() { + return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + "]"; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.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/NodeParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,785 @@ +/* + * Copyright (c) 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 java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.api.nodes.Node.Child; +import com.oracle.truffle.api.nodes.Node.Children; +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.FieldKind; +import com.oracle.truffle.codegen.processor.template.*; +import com.oracle.truffle.codegen.processor.typesystem.*; + +public class NodeParser extends TemplateParser{ + + private static final List> annotations = Arrays.asList( + Generic.class, GuardCheck.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, + SpecializationGuard.class, SpecializationListener.class, SpecializationThrows.class); + + private static final boolean DEBUG = false; + + private Map parsedNodes; + private TypeElement originalType; + + public NodeParser(ProcessorContext c) { + super(c); + } + + @Override + protected NodeData parse(Element element, AnnotationMirror mirror) { + assert element instanceof TypeElement; + try { + parsedNodes = new HashMap<>(); + originalType = (TypeElement) element; + + return parseInnerClassHierarchy((TypeElement) element); + } finally { + if (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; + } + } + + @Override + public boolean isDelegateToRootDeclaredType() { + return true; + } + + private NodeData parseInnerClassHierarchy(TypeElement rootType) { + List types = ElementFilter.typesIn(rootType.getEnclosedElements()); + List children = new ArrayList<>(); + for (TypeElement childElement : types) { + NodeData childNode = parseInnerClassHierarchy(childElement); + if (childNode != null) { + children.add(childNode); + } + } + NodeData rootNode = resolveNode(rootType); + if (rootNode == null && children.size() > 0) { + rootNode = new NodeData(rootType, null); + } + if (rootNode != null) { + rootNode.setDeclaredChildren(children); + } + 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. + return null; + } + if (!Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { + return null; // not a node + } + + 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(originalType, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName()); + return null; + } + + TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); + if (typeSystem == null) { + log.error(originalType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); + return null; + } + + NodeData nodeData = new NodeData(type, typeSystem); + + 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); // node fields will resolve node types, to avoid endless loops + + NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy); + if (fields == null) { + 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()])); + + 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); + + if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) { + return null; + } + + SpecializationData genericSpecialization = null; + if (genericSpecializations.size() > 1) { + for (SpecializationData generic : genericSpecializations) { + 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); + } + + if (specializations.size() > 1 && genericSpecialization == null) { + log.error(originalType, "Need a @%s method.", Generic.class.getSimpleName()); + return null; + } + + Collections.sort(specializations, new Comparator() { + @Override + public int compare(SpecializationData o1, SpecializationData o2) { + return compareSpecialization(typeSystem, 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)); + } + + for (SpecializationData specialization : allSpecializations) { + specialization.setNode(nodeData); + } + + // verify order is not ambiguous + if (!verifySpecializationOrder(typeSystem, specializations)) { + 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)) { + return null; + } + + if (!verifyNamingConvention(specializations, "do")) { + return null; + } + + if (!verifyNamesUnique(specializations)) { + return null; + } + + if (!verifyNamingConvention(shortCircuits, "needs")) { + return null; + } + + if (!verifySpecializationThrows(typeSystem, specializations)) { + return null; + } + + return nodeData; + } + + private boolean verifyMissingAbstractMethods(NodeData nodeData, List elements) { + if (nodeData.needsFactory()) { + // missing abstract methods only needs to be implemented + // if we need go generate factory for it. + return true; + } + + Set unusedElements = new HashSet<>(elements); + for (TemplateMethod method : nodeData.getAllTemplateMethods()) { + unusedElements.remove(method.getMethod()); + } + if (nodeData.getExtensionElements() != null) { + unusedElements.removeAll(nodeData.getExtensionElements()); + } + + boolean valid = true; + for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { + if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { + context.getLog().error(nodeData.getTemplateType(), "The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod)); + valid = false; + } + } + + return valid; + } + + private boolean verifyConstructors(NodeData nodeData) { + TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType()); + if (!nodeData.needsRewrites(context)) { + // no specialization constructor is needed if the node never rewrites. + return true; + } + + List constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); + for (ExecutableElement e : constructors) { + if (e.getParameters().size() == 1) { + TypeMirror firstArg = e.getParameters().get(0).asType(); + if (Utils.typeEquals(firstArg, nodeData.getNodeType())) { + if (e.getModifiers().contains(Modifier.PRIVATE)) { + context.getLog().error(e, "The specialization constructor must not be private."); + return false; + } else if (constructors.size() <= 1) { + context.getLog().error(e, "The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); + return false; + } + return true; + } + } + } + + // not found + context.getLog().error(type, "Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); + return false; + } + + private static List filterExecutableTypes(List executableTypes) { + List filteredExecutableTypes = new ArrayList<>(); + for (ExecutableTypeData t1 : executableTypes) { + boolean add = true; + for (ExecutableTypeData t2 : executableTypes) { + if (t1 == t2) { + continue; + } + if (Utils.typeEquals(t1.getType().getPrimitiveType(), t2.getType().getPrimitiveType())) { + if (t1.isFinal() && !t2.isFinal()) { + add = false; + } + } + } + if (add) { + filteredExecutableTypes.add(t1); + } + } + return filteredExecutableTypes; + } + + private AnnotationMirror findFirstAnnotation(List elements, Class annotation) { + for (Element element : elements) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, element, annotation); + if (mirror != null) { + return mirror; + } + } + return null; + } + + private NodeFieldData[] 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); + } + } + + Set shortCircuits = new HashSet<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); + if (mirror != null) { + shortCircuits.add(Utils.getAnnotationValueString(mirror, "value")); + } + } + + boolean valid = true; + + List fields = new ArrayList<>(); + for (VariableElement var : ElementFilter.fieldsIn(elements)) { + if (var.getModifiers().contains(Modifier.STATIC)) { + continue; + } + + if (executionDefinition != null) { + if (!executionDefinition.contains(var.getSimpleName().toString())) { + continue; + } + } + + NodeFieldData field = parseField(nodeData, var, shortCircuits); + if (field != null) { + if (field.getExecutionKind() != ExecutionKind.IGNORE) { + fields.add(field); + } + } else { + valid = false; + } + } + + //TODO parse getters + if (!valid) { + return null; + } + + NodeFieldData[] fieldArray = fields.toArray(new NodeFieldData[fields.size()]); + sortByExecutionOrder(fieldArray, executionDefinition == null ? Collections.emptyList() : executionDefinition, typeHierarchy); + return fieldArray; + } + + private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set foundShortCircuits) { + AnnotationMirror childMirror = Utils.findAnnotationMirror(processingEnv, var, Child.class); + AnnotationMirror childrenMirror = Utils.findAnnotationMirror(processingEnv, var, Children.class); + + FieldKind kind; + + ExecutionKind execution; + if (foundShortCircuits.contains(var.getSimpleName().toString())) { + execution = ExecutionKind.SHORT_CIRCUIT; + } else { + execution = ExecutionKind.DEFAULT; + } + + AnnotationMirror mirror; + TypeMirror nodeType; + + if (childMirror != null) { + mirror = childMirror; + nodeType = var.asType(); + kind = FieldKind.CHILD; + } else if (childrenMirror != null) { + mirror = childrenMirror; + nodeType = getComponentType(var.asType()); + kind = FieldKind.CHILDREN; + } else { + mirror = null; + nodeType = null; + kind = FieldKind.FIELD; + execution = ExecutionKind.IGNORE; + } + + NodeData fieldNodeData = null; + if (nodeType != null) { + fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType)); + Element errorElement = Utils.typeEquals(parentNodeData.getTemplateType().asType(), var.getEnclosingElement().asType()) ? var : parentNodeData.getTemplateType(); + + if (fieldNodeData == null) { + //TODO redirect errors from resolve. + context.getLog().error(errorElement, "Node type '%s' is invalid.", Utils.getQualifiedName(nodeType)); + return null; + } else if (fieldNodeData.findGenericExecutableType(context) == null) { + context.getLog().error(errorElement, "No executable generic type 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; + } + + return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution); + } + + private Element findAccessElement(VariableElement variableElement) { + Element enclosed = variableElement.getEnclosingElement(); + if (!enclosed.getKind().isClass()) { + throw new IllegalArgumentException("Field must be enclosed in a class."); + } + + String methodName; + if (Utils.typeEquals(variableElement.asType(), context.getType(boolean.class))) { + methodName = "is" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString()); + } else { + methodName = "get" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString()); + } + + ExecutableElement getter = null; + for (ExecutableElement method : ElementFilter.methodsIn(enclosed.getEnclosedElements())) { + if (method.getSimpleName().toString().equals(methodName) + && method.getParameters().size() == 0 + && !Utils.typeEquals(method.getReturnType(), context.getType(void.class))) { + getter = method; + break; + } + } + + if (getter != null) { + return getter; + } else { + return variableElement; + } + } + + private static void sortByExecutionOrder(NodeFieldData[] fields, final List executionOrder, final List typeHierarchy) { + Arrays.sort(fields, new Comparator() { + @Override + public int compare(NodeFieldData o1, NodeFieldData o2) { + // sort by execution order + int index1 = executionOrder.indexOf(o1.getName()); + int index2 = executionOrder.indexOf(o2.getName()); + if (index1 == -1 || index2 == -1) { + // sort by type hierarchy + index1 = typeHierarchy.indexOf(o1.getFieldElement().getEnclosingElement()); + index2 = typeHierarchy.indexOf(o2.getFieldElement().getEnclosingElement()); + + // finally sort by name (will emit warning) + if (index1 == -1 || index2 == -1) { + return o1.getName().compareTo(o2.getName()); + } + } + return index1 - index2; + } + }); + } + + private boolean assignShortCircuitsToSpecializations(NodeData nodeData, + List specializations, + List shortCircuits) { + + Map> groupedShortCircuits = groupShortCircuits(shortCircuits); + + boolean valid = true; + + for (NodeFieldData field : nodeData.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); + valid = false; + continue; + } + + + boolean sameMethodName = true; + String methodName = availableCircuits.get(0).getMethodName(); + for (ShortCircuitData circuit : availableCircuits) { + if (!circuit.getMethodName().equals(methodName)) { + sameMethodName = false; + } + } + + if (!sameMethodName) { + for (ShortCircuitData circuit : availableCircuits) { + log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName); + } + valid = false; + continue; + } + + ShortCircuitData genericCircuit = null; + for (ShortCircuitData circuit : availableCircuits) { + if (isGenericShortCutMethod(nodeData, 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); + valid = false; + continue; + } + + for (ShortCircuitData circuit : availableCircuits) { + if (circuit != genericCircuit) { + circuit.setGenericShortCircuitMethod(genericCircuit); + } + } + } + + if (!valid) { + return valid; + } + + NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT); + for (SpecializationData specialization : specializations) { + ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length]; + + for (int i = 0; i < fields.length; i++) { + List availableShortCuts = groupedShortCircuits.get(fields[i].getName()); + + ShortCircuitData genericShortCircuit = null; + for (ShortCircuitData circuit : availableShortCuts) { + if (circuit.isGeneric()) { + genericShortCircuit = circuit; + } else if (circuit.isCompatibleTo(specialization)) { + assignedShortCuts[i] = circuit; + } + } + + if (assignedShortCuts[i] == null) { + assignedShortCuts[i] = genericShortCircuit; + } + } + specialization.setShortCircuits(assignedShortCuts); + } + return true; + } + + private boolean verifyNamingConvention(List methods, String prefix) { + boolean valid = true; + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix); + valid = false; + } + } + return valid; + } + + private boolean verifyNamesUnique(List methods) { + boolean valid = true; + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + for (int j = i + 1; j < methods.size(); j++) { + TemplateMethod m2 = methods.get(j); + + if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); + return false; + } + } + } + return valid; + } + + + private static boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { + for (NodeFieldData field : node.getFields()) { + ActualParameter parameter = method.findParameter(field.getName()); + if (parameter == null) { + continue; + } + if (!Utils.typeEquals(node.getTypeSystem().getGenericType(), parameter.getActualType())) { + return false; + } + } + return true; + } + + private static Map> groupShortCircuits(List shortCircuits) { + Map> group = new HashMap<>(); + for (ShortCircuitData shortCircuit : shortCircuits) { + List circuits = group.get(shortCircuit.getValueName()); + if (circuits == null) { + circuits = new ArrayList<>(); + group.put(shortCircuit.getValueName(), circuits); + } + circuits.add(shortCircuit); + } + return group; + } + + + private TypeMirror getComponentType(TypeMirror type) { + if (type instanceof ArrayType) { + return getComponentType(((ArrayType) type).getComponentType()); + } + return type; + } + + private static List findSuperClasses(List collection, TypeElement element) { + if (element.getSuperclass() != null) { + TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + findSuperClasses(collection, superElement); + } + } + collection.add(element); + return collection; + } + + + private boolean verifySpecializationOrder(TypeSystemData typeSystem, List specializations) { + for (int i = 0; i < specializations.size(); i++) { + SpecializationData m1 = specializations.get(i); + for (int j = i + 1; j < specializations.size(); j++) { + SpecializationData m2 = specializations.get(j); + int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); + + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + int specOrder = m1.getOrder() - m2.getOrder(); + if (specOrder == 0) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); + return false; + } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { + log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); + return false; + } + } else if (inferredOrder == 0) { + SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); + log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); + return false; + } + } + } + return true; + } + + + private boolean verifySpecializationThrows(TypeSystemData typeSystem, List specializations) { + Map specializationMap = new HashMap<>(); + for (SpecializationData spec : specializations) { + specializationMap.put(spec.getMethodName(), spec); + } + boolean valid = true; + for (SpecializationData sourceSpecialization : specializations) { + 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("Specialization throws current %s target %s compare %s.", sourceSpecialization.getMethodName(), targetSpecialization.getMethodName(), compareSpecialization(typeSystem, sourceSpecialization, targetSpecialization)); + } + + 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()); + valid = false; + } + } + } + } + } + return valid; + } + + + private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { + if (m1 == m2) { + return 0; + } + int result = compareSpecializationWithoutOrder(typeSystem, m1, m2); + if (result == 0) { + if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { + return m1.getOrder() - m2.getOrder(); + } + } + return result; + } + + 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."); + } + + int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); + + for (ParameterSpec spec : m1.getSpecification().getParameters()) { + ActualParameter p1 = m1.findParameter(spec); + ActualParameter p2 = m2.findParameter(spec); + + if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) { + int typeResult = compareActualParameter(typeSystem, p1, p2); + if (result == 0) { + result = typeResult; + } else if (Math.signum(result) != Math.signum(typeResult)) { + // We cannot define an order. + return 0; + } + } + } + return result; + } + + private static int compareActualParameter(TypeSystemData typeSystem, ActualParameter p1, ActualParameter p2) { + int index1 = typeSystem.findType(p1.getActualType()); + int index2 = typeSystem.findType(p2.getActualType()); + + assert index1 != index2; + assert !(index1 == -1 ^ index2 == -1); + + return index1 - index2; + } + + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return null; + } + + @Override + public List> getTypeDelegatedAnnotationTypes() { + return annotations; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.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/ShortCircuitData.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,73 @@ +/* + * 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.*; +import com.oracle.truffle.codegen.processor.template.*; + + +public class ShortCircuitData extends TemplateMethod { + + private ShortCircuitData genericShortCircuitMethod; + private final String valueName; + + public ShortCircuitData(TemplateMethod template, String valueName) { + super(template); + this.valueName = valueName; + } + + public String getValueName() { + return valueName; + } + + public void setGenericShortCircuitMethod(ShortCircuitData genericShortCircuitMethod) { + this.genericShortCircuitMethod = genericShortCircuitMethod; + } + + public boolean isGeneric() { + return genericShortCircuitMethod == null; + } + + public ShortCircuitData getGeneric() { + if (isGeneric()) { + return this; + } else { + return genericShortCircuitMethod; + } + } + + public boolean isCompatibleTo(SpecializationData specialization) { + if (isGeneric() && specialization.isGeneric()) { + return true; + } + + for (ActualParameter param : getParameters()) { + ParameterSpec paramSpec = param.getSpecification(); + ActualParameter specializationParam = specialization.findParameter(paramSpec.getName()); + if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) { + return false; + } + } + return true; + } +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.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/ShortCircuitParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,80 @@ +/* + * 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 java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.template.*; + + +public class ShortCircuitParser extends MethodParser { + + private final Set shortCircuitValues; + + public ShortCircuitParser(ProcessorContext context, NodeData node) { + super(context, node); + + shortCircuitValues = new HashSet<>(); + NodeFieldData[] shortCircuitFields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT); + for (NodeFieldData field : shortCircuitFields) { + shortCircuitValues.add(field.getName()); + } + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value"); + + if (!shortCircuitValues.contains(shortCircuitValue)) { + getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue); + return null; + } + + return createDefaultMethodSpec(shortCircuitValue); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("has", getContext().getType(boolean.class), false); + } + + @Override + public ShortCircuitData create(TemplateMethod method) { + String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value"); + assert shortCircuitValue != null; + assert shortCircuitValues.contains(shortCircuitValue); + return new ShortCircuitData(method, shortCircuitValue); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return ShortCircuit.class; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.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/SpecializationData.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,130 @@ +/* + * 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.api.codegen.*; +import com.oracle.truffle.codegen.processor.template.*; + +public class SpecializationData extends TemplateMethod { + + private final int order; + private final boolean generic; + private final boolean uninitialized; + private final SpecializationThrowsData[] exceptions; + private SpecializationGuardData[] guards; + private ShortCircuitData[] shortCircuits; + + private NodeData node; + + public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) { + super(template); + this.order = order; + this.generic = false; + this.uninitialized = false; + this.exceptions = exceptions; + + for (SpecializationThrowsData exception : exceptions) { + exception.setSpecialization(this); + } + } + + public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized) { + super(template); + this.order = Specialization.DEFAULT_ORDER; + this.generic = generic; + this.uninitialized = uninitialized; + this.exceptions = new SpecializationThrowsData[0]; + this.guards = new SpecializationGuardData[0]; + } + + public NodeData getNode() { + return node; + } + + public void setNode(NodeData node) { + this.node = node; + } + + public void setGuards(SpecializationGuardData[] guards) { + this.guards = guards; + } + + public int getOrder() { + return order; + } + + public boolean isGeneric() { + return generic; + } + + public boolean isUninitialized() { + return uninitialized; + } + + public SpecializationThrowsData[] getExceptions() { + return exceptions; + } + + public SpecializationGuardData[] getGuards() { + return guards; + } + + public void setShortCircuits(ShortCircuitData[] shortCircuits) { + this.shortCircuits = shortCircuits; + } + + public ShortCircuitData[] getShortCircuits() { + return shortCircuits; + } + + public SpecializationData findNextSpecialization() { + SpecializationData[] specializations = node.getSpecializations(); + for (int i = 0; i < specializations.length - 1; i++) { + if (specializations[i] == this) { + return specializations[i + 1]; + } + } + return null; + } + + public boolean hasDynamicGuards() { + for (SpecializationGuardData guard : getGuards()) { + if (guard.isOnExecution()) { + return true; + } + } + return false; + } + + public ActualParameter getPreviousParam(ActualParameter searchParam) { + ActualParameter prev = null; + for (ActualParameter param : getParameters()) { + if (param == searchParam) { + return prev; + } + prev = param; + } + return prev; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.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/SpecializationGuardData.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,61 @@ +/* + * 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.typesystem.*; + +public class SpecializationGuardData { + + private final String guardMethod; + private final boolean onSpecialization; + private final boolean onExecution; + + private GuardData guardDeclaration; + + public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) { + this.guardMethod = guardMethod; + this.onSpecialization = onSpecialization; + this.onExecution = onExecution; + } + + public String getGuardMethod() { + return guardMethod; + } + + public boolean isOnExecution() { + return onExecution; + } + + public boolean isOnSpecialization() { + return onSpecialization; + } + + public void setGuardDeclaration(GuardData compatibleGuard) { + this.guardDeclaration = compatibleGuard; + } + + public GuardData getGuardDeclaration() { + return guardDeclaration; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.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/SpecializationListenerParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,63 @@ +/* + * 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 java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.template.*; + + +public class SpecializationListenerParser extends MethodParser { + + private final MethodSpec specification; + + public SpecializationListenerParser(ProcessorContext context, NodeData node) { + super(context, node); + this.specification = createDefaultMethodSpec(null); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return specification; + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("void", getContext().getType(void.class), false); + } + + @Override + public TemplateMethod create(TemplateMethod method) { + return method; + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return SpecializationListener.class; + } + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.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/SpecializationMethodParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -0,0 +1,174 @@ +/* + * 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 java.lang.annotation.*; +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.typesystem.*; + + +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; + } + + public MethodSpec getSpecification() { + return specification; + } + + @Override + public SpecializationData create(TemplateMethod method) { + return parseSpecialization(method); + } + + @Override + public Class< ? extends Annotation> getAnnotationType() { + return Specialization.class; + } + + private SpecializationData parseSpecialization(TemplateMethod method) { + int order = Utils.getAnnotationValueInt(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); + + 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)); + return null; + } + } + + Arrays.sort(exceptionData, new Comparator() { + @Override + public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { + return Utils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); + } + }); + SpecializationData specialization = new SpecializationData(method, order, exceptionData); + boolean valid = true; + List guardDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "guards", method.getMethod(), SpecializationGuard.class); + 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"); + + if (!onSpecialization && !onExecution) { + String message = "Either onSpecialization, onExecution or both must be enabled."; + getContext().getLog().error(method.getMethod(), guardMirror, message); + valid = false; + continue; + } + + guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution); + + GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]); + if (compatibleGuard != null) { + guardData[i].setGuardDeclaration(compatibleGuard); + } else { + valid = false; + } + } + + if (!valid) { + return null; + } + + specialization.setGuards(guardData); + + return specialization; + } + + private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) { + List foundGuards = getNode().findGuards(specializationGuard.getGuardMethod()); + + GuardData compatibleGuard = null; + for (GuardData guardData : foundGuards) { + if (isGuardCompatible(specialization, guardData)) { + compatibleGuard = guardData; + break; + } + } + + if (compatibleGuard == null) { + ParameterSpec returnTypeSpec = new ParameterSpec("returnValue", getContext().getType(boolean.class), false); + List expectedParameterSpecs = new ArrayList<>(); + + for (ActualParameter param : specialization.getParameters()) { + ParameterSpec spec = param.getSpecification(); + expectedParameterSpecs.add(new ParameterSpec(spec.getName(), param.getActualType(), false)); + } + String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs); + AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName"); + getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature); + return null; + } + + return compatibleGuard; + } + + private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { + Iterator guardParameters = Arrays.asList(guard.getParameters()).iterator(); + for (ActualParameter param : specialization.getParameters()) { + if (!guardParameters.hasNext()) { + return false; + } + ActualParameter guardParam = guardParameters.next(); + if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType())) { + return false; + } + } + if (guardParameters.hasNext()) { + return false; + } + return true; + } + + +} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.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/SpecializationThrowsData.java Fri Jan 18 13:28:12 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.codegen.processor.node; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class SpecializationThrowsData { + + private final AnnotationMirror annotationMirror; + private final TypeMirror javaClass; + private final String transitionTo; + private SpecializationData specialization; + + public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) { + this.annotationMirror = annotationMirror; + this.javaClass = javaClass; + this.transitionTo = transitionTo; + } + + + void setSpecialization(SpecializationData specialization) { + this.specialization = specialization; + } + + public TypeMirror getJavaClass() { + return javaClass; + } + + public SpecializationData getSpecialization() { + return specialization; + } + + public AnnotationMirror getAnnotationMirror() { + 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; + } +} + diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/GenericParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +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.codegen.processor.operation; - -import java.lang.annotation.*; - -import javax.lang.model.element.*; - -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; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; - -public class GenericParser extends OperationMethodParser { - - public GenericParser(ProcessorContext context, OperationData operation) { - super(context, operation); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(null); - } - - @Override - protected ParameterSpec createValueParameterSpec(String valueName) { - return new ParameterSpec(valueName, getOperation().getTypeSystem().getGenericType(), Kind.EXECUTE, false); - } - - @Override - protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("returnValue", getOperation().getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE); - } - - @Override - public SpecializationData create(TemplateMethod method) { - return new SpecializationData(method, true, false); - } - - @Override - public Class< ? extends Annotation> getAnnotationType() { - return Generic.class; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationCodeGenerator.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,903 +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.codegen.processor.operation; - -import static com.oracle.truffle.codegen.processor.Utils.*; -import static javax.lang.model.element.Modifier.*; - -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.ast.*; -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; -import com.oracle.truffle.codegen.processor.typesystem.*; - -public class OperationCodeGenerator extends CompilationUnitFactory { - - private static final String OPERATION_FIELD_NAME = "operation"; - - public OperationCodeGenerator(ProcessorContext context) { - super(context); - } - - private TypeMirror getUnexpectedValueException() { - return getContext().getTruffleTypes().getUnexpectedValueException(); - } - - private static String operationClassName(OperationData operation) { - return Utils.getSimpleName(operation.getTemplateType().asType()); - } - - private static String factoryClassName(OperationData operation) { - return operationClassName(operation) + "Factory"; - } - - private static String nodeClassName(OperationData operation) { - String name = operationClassName(operation); - if (name.length() > 2 && name.endsWith("Op")) { - name = name.substring(0, name.length() - 2); - } - return name + "Node"; - } - - private static String nodeClassName(SpecializationData specialization) { - String name = ""; - if (specialization.getOperation().getAllMethods().length > 1) { - name = specialization.getMethodName(); - if (name.startsWith("do")) { - name = name.substring(2); - } - } - return name + nodeClassName(specialization.getOperation()); - } - - private static String nodeVariableName(ParameterSpec spec) { - if (spec.getKind() == Kind.EXECUTE) { - return spec.getName() + "Node"; - } - return spec.getName(); - } - - private static String nodeVariableName(ActualParameter param) { - return nodeVariableName(param.getSpecification()); - } - - private static String valueVariableName(ParameterSpec spec) { - if (spec.getKind() == Kind.EXECUTE) { - return spec.getName() + "Value"; - } - return spec.getName(); - } - - private static String valueVariableName(ActualParameter param) { - return valueVariableName(param.getSpecification()); - } - - public static String executeMethodName(TypeData type) { - if (type.isGeneric()) { - return "executeGeneric"; - } - return "execute" + Utils.getSimpleName(type.getBoxedType()); - } - - private static EnumSet kinds(Kind... values) { - EnumSet result = EnumSet.noneOf(Kind.class); - for (Kind value : values) { - result.add(value); - } - return result; - } - - private static void addNodeParameters(CodeExecutableElement method, OperationData operation, EnumSet included) { - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - if (included.contains(spec.getKind())) { - if (spec.getKind() == Kind.EXECUTE) { - method.addParameter(new CodeVariableElement(operation.getTypeSystem().getNodeType(), nodeVariableName(spec))); - } else { - method.addParameter(new CodeVariableElement(spec.getValueType(), nodeVariableName(spec))); - } - } - } - if (included.contains(Kind.CONSTRUCTOR_FIELD)) { - for (OperationFieldData field : operation.getConstructorFields()) { - method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); - } - } - } - - private static void addValueParameters(CodeExecutableElement method, OperationData operation, EnumSet included) { - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - if (included.contains(spec.getKind())) { - method.addParameter(new CodeVariableElement(spec.getValueType(), valueVariableName(spec))); - } - } - if (included.contains(Kind.CONSTRUCTOR_FIELD)) { - for (OperationFieldData field : operation.getConstructorFields()) { - method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); - } - } - } - - private static void addOperationFieldName(CodeTreeBuilder body, OperationData operation) { - if (!operation.isUseSingleton()) { - body.string(OPERATION_FIELD_NAME); - } - } - - private static void addOperationVariable(Set modifiers, Element element, OperationData operation, CodeTypeElement operationGen) { - if (!operation.isUseSingleton()) { - TypeMirror type = findOperationType(operation, operationGen); - if (element instanceof CodeExecutableElement) { - ((CodeExecutableElement) element).addParameter(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); - } else if (element instanceof CodeTypeElement) { - ((CodeTypeElement) element).add(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); - } - } - } - - private static void addNodeNames(CodeTreeBuilder body, OperationData operation, EnumSet included) { - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - if (included.contains(spec.getKind())) { - body.string(nodeVariableName(spec)); - } - } - if (included.contains(Kind.CONSTRUCTOR_FIELD)) { - for (OperationFieldData field : operation.getConstructorFields()) { - body.string(field.getName()); - } - } - } - - private static void addValueNames(CodeTreeBuilder body, OperationData operation, EnumSet included) { - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - if (included.contains(spec.getKind())) { - body.string(valueVariableName(spec)); - } - } - if (included.contains(Kind.CONSTRUCTOR_FIELD)) { - for (OperationFieldData field : operation.getConstructorFields()) { - body.string(field.getName()); - } - } - } - - private static void addValueNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization, EnumSet included) { - for (ActualParameter spec : specialization.getParameters()) { - if (included.contains(spec.getSpecification().getKind())) { - TypeData typeData = spec.getActualTypeData(specialization.getOperation().getTypeSystem()); - if (typeData.isGeneric()) { - body.string(valueVariableName(spec)); - } else { - String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); - startCallTypeSystemMethod(context, body, specialization.getOperation(), methodName); - body.string(valueVariableName(spec)); - body.end().end(); - } - } - } - } - - public static VariableElement findSingleton(ProcessorContext context, OperationData operation) { - TypeMirror type = context.findGeneratedClassBySimpleName(OperationCodeGenerator.genClassName(operation), operation); - return Utils.findDeclaredField(type, OperationCodeGenerator.singletonName(operation)); - } - - private static TypeMirror findOperationType(OperationData operation, CodeTypeElement operationGen) { - if (operation.hasExtensions()) { - // return generated type - return operationGen.asType(); - } else { - // return default type - return operation.getTemplateType().asType(); - } - } - - private static String genClassName(OperationData operation) { - String name = getSimpleName(operation.getTemplateType()); - return name + "Gen"; - } - - private static String singletonName(OperationData operation) { - return createConstantName(getSimpleName(operation.getTemplateType().asType())); - } - - private static void startCallOperationMethod(CodeTreeBuilder body, OperationData operation, TemplateMethod method) { - body.startGroup(); - - if (operation.isUseSingleton()) { - body.string(singletonName(operation)); - body.string(".").startCall(method.getMethodName()); - } else { - body.string(OPERATION_FIELD_NAME); - body.string("."); - body.startCall(method.getMethodName()); - } - } - - private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, OperationData operation, String methodName) { - VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, operation.getTypeSystem()); - assert singleton != null; - - body.startGroup(); - body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); - body.string(".").startCall(methodName); - } - - private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { - // Implict guards based on method signature - String andOperator = prefix; - for (ActualParameter param : specialization.getParameters()) { - if (param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric()) { - body.string(andOperator); - startCallTypeSystemMethod(context, body, specialization.getOperation(), - TypeSystemCodeGenerator.isTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); - body.string(valueVariableName(param)); - body.end().end(); // call - andOperator = " && "; - } - } - - if (specialization.getGuards().length > 0) { - // Explicitly specified guards - for (SpecializationGuardData guard : specialization.getGuards()) { - if ((guard.isOnSpecialization() && onSpecialization) - || (guard.isOnExecution() && !onSpecialization)) { - body.string(andOperator); - - if (guard.getGuardDeclaration().getOrigin() == specialization.getOperation()) { - startCallOperationMethod(body, specialization.getOperation(), guard.getGuardDeclaration()); - } else { - startCallTypeSystemMethod(context, body, specialization.getOperation(), guard.getGuardMethod()); - } - - if (needsCast) { - addValueNamesWithCasts(context, body, specialization, kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); - } else { - addValueNames(body, specialization.getOperation(), kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); - } - body.end().end(); // call - andOperator = " && "; - } - } - } - } - - @Override - protected void createChildren(OperationData m) { - CodeTypeElement operationGen = null; - if (m.hasExtensions()) { - OperationGenFactory factory = new OperationGenFactory(context); - add(factory, m); - operationGen = (CodeTypeElement) factory.getElement(); - } - if (m.generateFactory) { - add(new OperationNodeFactory(context, operationGen), m); - } - } - - protected class OperationGenFactory extends ClassElementFactory { - - public OperationGenFactory(ProcessorContext context) { - super(context); - } - - @Override - protected CodeTypeElement create(OperationData operation) { - CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC), genClassName(operation), operation.getTemplateType().asType(), false); - - clazz.add(createConstructorUsingFields(modifiers(PUBLIC), clazz)); - - if (operation.getExtensionElements() != null) { - clazz.getEnclosedElements().addAll(operation.getExtensionElements()); - } - return clazz; - } - - } - - - - protected class OperationNodeFactory extends ClassElementFactory { - - private final CodeTypeElement operationGen; - - public OperationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { - super(context); - this.operationGen = operationGen; - } - - @Override - protected CodeTypeElement create(OperationData operation) { - CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC, FINAL), factoryClassName(operation), null, false); - - if (operation.isUseSingleton()) { - TypeMirror type = findOperationType(operation, operationGen); - CodeVariableElement singleton = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), type, singletonName(operation)); - clazz.add(singleton); - CodeTreeBuilder singletonInit = singleton.createInitBuilder(); - singletonInit.startNew(type).end(); - } - - clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); - clazz.add(createCreateMethod(operation)); - if (operation.getAllMethods().length > 1) { - clazz.add(createCreateSpecializedMethod(operation)); - } - if (operation.needsRewrites()) { - clazz.add(createSpecializeMethod(operation)); - clazz.add(createGeneratedGenericMethod(operation)); - } - - return clazz; - } - - @Override - protected void createChildren(OperationData operation) { - for (SpecializationData specialization : operation.getAllMethods()) { - add(new SpecializationNodeFactory(context, operationGen), specialization); - } - } - - private CodeExecutableElement createCreateMethod(OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), operation.getNodeType(), "create"); - addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE, Kind.CONSTRUCTOR_FIELD)); - - CodeTreeBuilder body = method.createBuilder(); - body.startReturn(); - if (operation.getAllMethods().length == 0) { - body.null_(); - } else { - body.startNew(nodeClassName(operation.getAllMethods()[0])); - emitNewOperation(body, operation); - addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - body.end(); - } - body.end(); - - return method; - } - - private void emitNewOperation(CodeTreeBuilder body, OperationData operation) { - if (!operation.isUseSingleton()) { - body.startGroup(); - if (operation.hasExtensions()) { - body.startNew(genClassName(operation)); - } else { - body.startNew(operation.getTemplateType().asType()); - } - addNodeNames(body, operation, kinds(Kind.CONSTRUCTOR_FIELD)); - body.end(); - body.end(); - } - } - - private CodeExecutableElement createCreateSpecializedMethod(OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "createSpecialized"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); - addOperationVariable(modifiers(), method, operation, operationGen); - addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - - CodeTreeBuilder body = method.createBuilder(); - - boolean first = true; - for (TypeData type : operation.getTypeSystem().getTypes()) { - SpecializationData specialization = operation.findUniqueSpecialization(type); - if (specialization != null && !type.isGeneric()) { - if (first) { - body.startIf(); - first = false; - } else { - body.startElseIf(); - } - body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeClassName(specialization)); - addOperationFieldName(body, operation); - addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - body.end().end(); - body.end(); - } - } - body.startReturn().startNew(nodeClassName(operation.getGenericSpecialization())); - addOperationFieldName(body, operation); - addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - body.end().end(); - return method; - } - - private CodeExecutableElement createSpecializeMethod(OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "specialize"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addOperationVariable(modifiers(), method, operation, operationGen); - addValueParameters(method, operation, kinds(Kind.EXECUTE)); - addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - - CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(operation.getAllMethods()[0])).string(".class)").end(); - - for (int i = 1; i < operation.getAllMethods().length; i++) { - SpecializationData specialization = operation.getAllMethods()[i]; - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); - - if (specialization.isGeneric()) { - body.startIf().string("allowed").end().startBlock(); - } else { - body.startIf().string("allowed"); - emitGuards(getContext(), body, " && ", specialization, true, true); - body.end().startBlock(); - } - body.startReturn().startNew(nodeClassName(specialization)); - - addOperationFieldName(body, operation); - addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - body.end().end(); - body.end(); // block - } - body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); - - return method; - } - - - private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization) { - if (specialization.getExceptions().length > 0) { - builder.startTryBlock(); - } - - builder.startReturn(); - startCallOperationMethod(builder, specialization.getOperation(), specialization); - for (ActualParameter param : specialization.getParameters()) { - boolean needsCast = param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric(); - if (needsCast) { - startCallTypeSystemMethod(getContext(), builder, specialization.getOperation(), TypeSystemCodeGenerator.asTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); - } - builder.string(valueVariableName(param)); - if (needsCast) { - builder.end().end(); - } - } - builder.end().end(); // start call operation - builder.end(); // return - - if (specialization.getExceptions().length > 0) { - for (SpecializationThrowsData exception : specialization.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - emitInvokeDoMethod(builder, exception.getTransitionTo()); - } - builder.end(); - } - } - - private CodeExecutableElement createGeneratedGenericMethod(OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getGenericSpecialization().getReturnType().getActualType(), "generatedGeneric"); - addOperationVariable(modifiers(), method, operation, operationGen); - addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - - CodeTreeBuilder builder = method.createBuilder(); - boolean ifStarted = false; - for (int i = 0; i < operation.getSpecializations().length; i++) { - SpecializationData specialization = operation.getSpecializations()[i]; - if (specialization.isUninitialized()) { - continue; - } - if (!specialization.isGeneric()) { - if (!ifStarted) { - builder.startIf(); - ifStarted = true; - } else { - builder.startElseIf(); - } - emitGuards(getContext(), builder, "", specialization, false, true); - builder.end().startBlock(); - } else { - builder.startElseBlock(); - } - - emitInvokeDoMethod(builder, specialization); - builder.end(); - } - return method; - } - } - - protected class SpecializationNodeFactory extends ClassElementFactory { - - private CodeTypeElement operationGen; - - public SpecializationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { - super(context); - this.operationGen = operationGen; - } - - @Override - public CodeTypeElement create(SpecializationData specialization) { - OperationData operation = specialization.getOperation(); - CodeTypeElement clazz = createClass(operation, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), operation.getNodeType(), false); - - - CodeExecutableElement constructor = new CodeExecutableElement(modifiers(PROTECTED), null, clazz.getSimpleName().toString()); - clazz.add(constructor); - - CodeTreeBuilder builder = constructor.createBuilder(); - builder.startStatement().startSuperCall(); - addNodeNames(builder, operation, kinds(Kind.SUPER_ATTRIBUTE)); - builder.end().end(); - - if (!operation.isUseSingleton()) { - addOperationVariable(modifiers(), constructor, operation, operationGen); - addOperationVariable(modifiers(PRIVATE, FINAL), clazz, operation, operationGen); - builder.startStatement(); - builder.string("this."); - addOperationFieldName(builder, operation); - builder.string(" = "); - addOperationFieldName(builder, operation); - builder.end(); - } - addNodeParameters(constructor, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - - - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - String name = nodeVariableName(spec); - - boolean isNodeAttribute = spec.getKind() == Kind.ATTRIBUTE && getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNode()); - boolean isNodeArrayAttribute = spec.getKind() == Kind.ATTRIBUTE && - getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNodeArray()); - if (spec.getKind() == Kind.EXECUTE || isNodeAttribute || isNodeArrayAttribute) { - CodeVariableElement field = new CodeVariableElement(modifiers(PRIVATE), operation.getTypeSystem().getNodeType(), name); - clazz.add(field); - field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getStableAnnotation())); - if (isNodeArrayAttribute) { - field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getContentStableAnnotation())); - } - builder.startStatement().string("this.").string(name).string(" = adoptChild(").string(name).string(")").end(); - } else if (spec.getKind() == Kind.ATTRIBUTE) { - clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), spec.getValueType(), name)); - builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); - } - } - - TypeSystemData typeSystem = operation.getTypeSystem(); - for (TypeData type : typeSystem.getTypes()) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), executeMethodName(type)); - clazz.add(method); - addValueParameters(method, operation, kinds(Kind.SIGNATURE)); - if (!type.isGeneric()) { - method.addThrownType(getUnexpectedValueException()); - } - - if (specialization.getReturnType().getActualTypeData(typeSystem) == type) { - buildFunctionalExecuteMethod(method.createBuilder(), operation, specialization); - } else { - buildCastingExecuteMethod(method.createBuilder(), operation, specialization, type); - } - } - - if (typeSystem.getVoidType() != null) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), executeMethodName(typeSystem.getVoidType())); - addValueParameters(method, operation, kinds(Kind.SIGNATURE)); - buildCastingExecuteMethod(method.createBuilder(), operation, specialization, typeSystem.getVoidType()); - clazz.add(method); - } - - if (operation.needsRewrites() && !specialization.isGeneric() && !specialization.isUninitialized()) { - buildSpecializeStateMethod(clazz, operation); - } - buildSpecializeClassMethod(clazz, operation); - - return clazz; - } - - private void buildCastingExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, TypeData type) { - if (!type.isVoid()) { - builder.startStatement().type(specialization.getReturnType().getActualType()).string(" result").end(); - } - - boolean needsTry = !specialization.getReturnType().getActualTypeData(operation.getTypeSystem()).isGeneric(); - if (needsTry) { - builder.startTryBlock(); - } - - builder.startStatement(); - if (!type.isVoid()) { - builder.string("result = "); - } - builder.startCall(executeMethodName(specialization.getReturnType().getActualTypeData(operation.getTypeSystem()))).string("frame").end(); - builder.end(); // statement - - if (needsTry) { - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - - if (!type.isVoid()) { - builder.startReturn(); - if (!type.isGeneric()) { - startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); - } - - builder.string("ex.getResult()"); - - if (!type.isGeneric()) { - builder.end().end(); - } - builder.end(); // return - } else { - builder.string("// ignore").newLine(); - } - } - builder.end(); // try/catch - - if (!type.isVoid()) { - builder.startReturn(); - if (!type.isGeneric()) { - startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); - } - builder.string("result"); - if (!type.isGeneric()) { - builder.end().end(); - } - builder.end(); // return - } - } - - private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization) { - ActualParameter previousShortCircuitParameter = null; - for (ActualParameter param : specialization.getParameters()) { - if (param.getSpecification().getKind() != Kind.EXECUTE) { - // Nothing to do. - } else if (param.getActualTypeData(operation.getTypeSystem()).isGeneric()) { - buildGenericValueExecute(builder, operation, param, null); - } else { - buildSpecializedValueExecute(builder, operation, specialization, param); - } - - assert param.getSpecification().getKind() == Kind.SHORT_CIRCUIT || previousShortCircuitParameter == null; - } - - if (specialization.hasDynamicGuards()) { - builder.startIf(); - emitGuards(getContext(), builder, "", specialization, false, false); - builder.end().startBlock(); - } - if (specialization.getExceptions().length > 0) { - builder.startTryBlock(); - } - - if (specialization.isUninitialized() && operation.needsRewrites()) { - for (TemplateMethod listener : operation.getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, operation, listener); - for (ActualParameter param : listener.getParameters()) { - builder.string(valueVariableName(param)); - } - builder.end().end(); - builder.end(); // statement - } - - builder.startStatement(); - builder.startCall("replace"); - builder.startCall(factoryClassName(operation), "specialize"); - builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); - addOperationFieldName(builder, operation); - addValueNames(builder, operation, kinds(Kind.EXECUTE)); - addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - builder.end().end().end(); - } - - if ((specialization.isUninitialized() || specialization.isGeneric()) && operation.needsRewrites()) { - builder.startReturn().startCall(factoryClassName(specialization.getOperation()), "generatedGeneric"); - addOperationFieldName(builder, operation); - addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - builder.end().end(); - } else { - builder.startReturn(); - - if (specialization.isUninitialized()) { - startCallOperationMethod(builder, specialization.getOperation(), specialization.getOperation().getGenericSpecialization()); - } else { - startCallOperationMethod(builder, specialization.getOperation(), specialization); - } - for (ActualParameter param : specialization.getParameters()) { - builder.string(valueVariableName(param)); - } - builder.end().end(); // operation call - builder.end(); // return - } - - if (specialization.getExceptions().length > 0) { - for (SpecializationThrowsData exception : specialization.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - buildThrowSpecialize(builder, operation, exception.getTransitionTo(), null); - } - builder.end(); - } - if (specialization.hasDynamicGuards()) { - builder.end().startElseBlock(); - buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), null); - builder.end(); - } - } - - private void buildGenericValueExecute(CodeTreeBuilder builder, OperationData operation, ActualParameter param, ParameterSpec exceptionSpec) { - boolean shortCircuit = startShortCircuit(builder, operation.getGenericSpecialization(), - operation.getGenericSpecialization().findParameter(param.getSpecification().getName()), exceptionSpec); - - builder.startStatement(); - if (!shortCircuit) { - builder.type(operation.getTypeSystem().getGenericType()); - builder.string(" "); - } - builder.string(valueVariableName(param)); - builder.string(" = ").startCall(nodeVariableName(param), executeMethodName(operation.getTypeSystem().getGenericTypeData())).string("frame").end(); - builder.end(); - - endShortCircuit(builder, shortCircuit); - } - - private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, - ActualParameter forParam, ParameterSpec exceptionParam) { - ActualParameter shortCircuitParam = specialization.getPreviousParam(forParam); - if (shortCircuitParam == null || shortCircuitParam.getSpecification().getKind() != Kind.SHORT_CIRCUIT) { - return false; - } - - int shortCircuitIndex = 0; - for (ActualParameter parameter : specialization.getParameters()) { - if (parameter.getSpecification().getKind() == Kind.SHORT_CIRCUIT) { - if (parameter == shortCircuitParam) { - break; - } - shortCircuitIndex++; - } - } - - builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(shortCircuitParam.getSpecification().getName()).string(" = "); - ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; - - startCallOperationMethod(builder, specialization.getOperation(), shortCircuitData); - for (ActualParameter callParam : shortCircuitData.getParameters()) { - ParameterSpec spec = callParam.getSpecification(); - if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT || spec.getKind() == Kind.SIGNATURE) { - if (exceptionParam != null && callParam.getSpecification().getName().equals(exceptionParam.getName())) { - builder.string("ex.getResult()"); - } else { - builder.string(valueVariableName(spec)); - } - } - } - builder.end().end(); // call operation - - builder.end(); // statement - - builder.declaration(forParam.getActualType(), valueVariableName(forParam), - CodeTreeBuilder.createBuilder().defaultValue(forParam.getActualType())); - builder.startIf().string(valueVariableName(shortCircuitParam)).end(); - builder.startBlock(); - - return true; - } - - - private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { - if (shortCircuit) { - builder.end(); - } - } - - private void buildSpecializedValueExecute(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, ActualParameter param) { - boolean shortCircuit = startShortCircuit(builder, specialization, param, null); - - if (!shortCircuit) { - builder.startStatement().type(param.getActualType()).string(" ").string(valueVariableName(param)).end(); - } - - builder.startTryBlock(); - builder.startStatement().string(valueVariableName(param)).string(" = "); - builder.startCall(nodeVariableName(param), executeMethodName(param.getActualTypeData(operation.getTypeSystem()))).string("frame").end(); - builder.end(); - - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - boolean execute = false; - for (ActualParameter exParam : specialization.getParameters()) { - if (exParam.getSpecification().getKind() != Kind.EXECUTE) { - // Nothing to do. - } else if (execute) { - buildGenericValueExecute(builder, operation, exParam, param.getSpecification()); - } else if (exParam == param) { - execute = true; - } - } - - buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), param.getSpecification()); - builder.end(); // catch block - - endShortCircuit(builder, shortCircuit); - builder.newLine(); - } - - private void buildThrowSpecialize(CodeTreeBuilder builder, OperationData operation, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { - builder.startThrow().startCall("specialize"); - builder.string(nodeClassName(nextSpecialization) + ".class"); - addValueNames(builder, operation, kinds(Kind.SIGNATURE)); - for (ParameterSpec spec : operation.getSpecification().getParameters()) { - if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT) { - if (spec == exceptionSpec) { - builder.string("ex.getResult()"); - } else { - builder.string(valueVariableName(spec)); - } - } - } - builder.end().end(); - } - - private void buildSpecializeStateMethod(CodeTypeElement clazz, OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getUnexpectedValueException(), "specialize"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT)); - clazz.add(method); - CodeTreeBuilder builder = method.createBuilder(); - - for (TemplateMethod listener : operation.getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, operation, listener); - for (ActualParameter param : listener.getParameters()) { - builder.string(valueVariableName(param)); - } - builder.end().end(); - builder.end(); // statement - } - - builder.startStatement(); - builder.startCall("replace"); - builder.startCall(factoryClassName(operation), "specialize").string("minimumState"); - addOperationFieldName(builder, operation); - addValueNames(builder, operation, kinds(Kind.EXECUTE)); - addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - builder.end().end().end(); - - builder.startReturn().startNew(getUnexpectedValueException()).startCall(factoryClassName(operation), "generatedGeneric"); - addOperationFieldName(builder, operation); - addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - builder.end().end().end(); - } - - private void buildSpecializeClassMethod(CodeTypeElement clazz, OperationData operation) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), "specialize"); - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); - if (!isDeclaredMethodInSuperType(clazz, method.getSimpleName().toString(), method.getParameterTypes())) { - return; - } - clazz.add(method); - CodeTreeBuilder builder = method.createBuilder(); - - builder.startStatement(); - builder.startCall("replace"); - builder.startCall(factoryClassName(operation), "createSpecialized").string("specializationClass"); - addOperationFieldName(builder, operation); - addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); - builder.end().end().end(); - } - } -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +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.codegen.processor.operation; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.typesystem.*; - -public class OperationData extends Template { - - private final TypeSystemData typeSystem; - private final String[] values; - private final String[] shortCircuitValues; - private final OperationFieldData[] operationFields; - private final OperationFieldData[] constructorFields; - private final OperationFieldData[] superFields; - private final TypeMirror nodeType; - - private MethodSpec specification; - private SpecializationData genericSpecialization; - private SpecializationData[] specializations; - private TemplateMethod[] specializationListeners; - private GuardData[] guards; - - boolean generateFactory = true; - - public OperationData(TypeElement templateType, AnnotationMirror templateTypeAnnotation, - TypeSystemData typeSystem, TypeMirror nodeType, - String[] values, String[] shortCircuitValues, - OperationFieldData[] operationFields, - OperationFieldData[] constructorFields, - OperationFieldData[] superFields) { - super(templateType, templateTypeAnnotation); - this.nodeType = nodeType; - this.typeSystem = typeSystem; - this.values = values; - this.shortCircuitValues = shortCircuitValues; - this.operationFields = operationFields; - this.constructorFields = constructorFields; - this.superFields = superFields; - } - - public boolean isUseSingleton() { - return constructorFields.length == 0; - } - - public boolean hasExtensions() { - return !getExtensionElements().isEmpty(); - } - - public List findGuards(String name) { - List foundGuards = new ArrayList<>(); - for (GuardData guardData : guards) { - if (guardData.getMethodName().equals(name)) { - foundGuards.add(guardData); - } - } - for (GuardData guardData : getTypeSystem().getGuards()) { - if (guardData.getMethodName().equals(name)) { - foundGuards.add(guardData); - } - } - return foundGuards; - } - - - void setGuards(GuardData[] guards) { - this.guards = guards; - } - - void setSpecification(MethodSpec specification) { - this.specification = specification; - } - - void setGenericSpecialization(SpecializationData genericSpecialization) { - this.genericSpecialization = genericSpecialization; - } - - void setSpecializations(SpecializationData[] specializations) { - this.specializations = specializations; - for (SpecializationData specialization : specializations) { - specialization.setOperation(this); - } - } - - void setSpecializationListeners(TemplateMethod[] specializationListeners) { - this.specializationListeners = specializationListeners; - } - - public String[] getValues() { - return values; - } - - public OperationFieldData[] getOperationFields() { - return operationFields; - } - - public String[] getShortCircuitValues() { - return shortCircuitValues; - } - - public TypeSystemData getTypeSystem() { - return typeSystem; - } - - public TypeMirror getNodeType() { - return nodeType; - } - - public SpecializationData[] getSpecializations() { - return specializations; - } - - public SpecializationData getGenericSpecialization() { - return genericSpecialization; - } - - public OperationFieldData[] getConstructorFields() { - return constructorFields; - } - - public OperationFieldData[] getSuperFields() { - return superFields; - } - - public MethodSpec getSpecification() { - return specification; - } - - public SpecializationData[] getAllMethods() { - return specializations; - } - - public boolean needsRewrites() { - boolean needsRewrites = getValues().length > 0 || getShortCircuitValues().length > 0; - needsRewrites &= specializations.length >= 2; - return needsRewrites; - } - - public TemplateMethod[] getSpecializationListeners() { - return specializationListeners; - } - - public GuardData[] getGuards() { - return guards; - } - - public SpecializationData findUniqueSpecialization(TypeData type) { - SpecializationData result = null; - for (SpecializationData specialization : specializations) { - if (specialization.getReturnType().getActualTypeData(getTypeSystem()) == type) { - if (result != null) { - // Result not unique; - return null; - } - result = specialization; - } - } - return result; - } -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationFieldData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationFieldData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +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.codegen.processor.operation; - -import javax.lang.model.type.*; - -import com.oracle.truffle.codegen.processor.*; - -public class OperationFieldData { - - private final String name; - private final TypeMirror javaClass; - - public OperationFieldData(String name, TypeMirror javaClass) { - this.name = name; - this.javaClass = javaClass; - } - - public String getName() { - return name; - } - - public TypeMirror getJavaClass() { - return javaClass; - } - - @Override - public String toString() { - return Utils.getSimpleName(javaClass); - } -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationMethodParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +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.codegen.processor.operation; - -import java.util.*; - -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; - - -public abstract class OperationMethodParser extends TemplateMethodParser{ - - private final OperationData operation; - - public OperationMethodParser(ProcessorContext context, OperationData operation) { - super(context); - this.operation = operation; - } - - public OperationData getOperation() { - return operation; - } - - protected ParameterSpec createValueParameterSpec(String valueName) { - return new ParameterSpec(valueName, operation.getTypeSystem(), - Kind.EXECUTE, false, Cardinality.ONE); - } - - protected ParameterSpec createReturnParameterSpec() { - return createValueParameterSpec("operation"); - } - - protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { - List defaultParameters = new ArrayList<>(); - ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), Kind.SIGNATURE, true); - defaultParameters.add(frameSpec); - - for (String valueName : operation.getValues()) { - defaultParameters.add(createValueParameterSpec(valueName)); - } - - for (String valueName : operation.getShortCircuitValues()) { - if (shortCircuitName != null && valueName.equals(shortCircuitName)) { - break; - } - - defaultParameters.add(new ParameterSpec(shortCircuitValueName(valueName), - getContext().getType(boolean.class), Kind.SHORT_CIRCUIT, false)); - - defaultParameters.add(createValueParameterSpec(valueName)); - } - - for (OperationFieldData field : operation.getSuperFields()) { - defaultParameters.add(new ParameterSpec(field.getName(), field.getJavaClass(), Kind.SUPER_ATTRIBUTE, true)); - } - - for (OperationFieldData field : operation.getOperationFields()) { - defaultParameters.add(new ParameterSpec(field.getName(), field.getJavaClass(), Kind.ATTRIBUTE, false)); - } - - return new MethodSpec(createReturnParameterSpec(), defaultParameters); - } - - private static String shortCircuitValueName(String valueName) { - return "has" + Utils.firstLetterUpperCase(valueName) + "Value"; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,569 +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.codegen.processor.operation; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.ast.*; -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; -import com.oracle.truffle.codegen.processor.typesystem.*; - -public class OperationParser extends TemplateParser { - - public OperationParser(ProcessorContext c) { - super(c); - } - - @Override - public Class< ? extends Annotation> getAnnotationType() { - return com.oracle.truffle.api.codegen.Operation.class; - } - - @Override - protected OperationData parse(Element element, AnnotationMirror templateTypeAnnotation) { - TypeElement templateType = (TypeElement) element; - - if (!verifyTemplateType(templateType, templateTypeAnnotation)) { - return null; - } - - TypeMirror typeSystemMirror = Utils.getAnnotationValueType(templateTypeAnnotation, "typeSystem"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemMirror, true); - if (typeSystem == null) { - log.error(templateType, templateTypeAnnotation, "Type system '%s' is invalid.", Utils.getQualifiedName(typeSystemMirror)); - return null; - } - - TypeMirror nodeType = Utils.getAnnotationValueType(templateTypeAnnotation, "baseClass"); - if (Utils.typeEquals(nodeType, context.getTruffleTypes().getNode())) { - nodeType = typeSystem.getNodeType(); - } - - if (!Utils.isAssignable(nodeType, typeSystem.getNodeType())) { - log.error(templateType, templateTypeAnnotation, - Utils.getAnnotationValue(templateTypeAnnotation, "baseClass"), - "The baseClass does not extend the base class of the type system '%s'.", Utils.getQualifiedName(typeSystem.getNodeType())); - return null; - } - - for (VariableElement field : ElementFilter.fieldsIn(templateType.getEnclosedElements())) { - if (!field.getModifiers().contains(Modifier.STATIC) - && !field.getModifiers().contains(Modifier.FINAL)) { - log.error(field, "Field must be final."); - return null; - } - } - - - List valueNames = Utils.getAnnotationValueList(templateTypeAnnotation, "values"); - List shortCircuitNames = Utils.getAnnotationValueList(templateTypeAnnotation, "shortCircuitValues"); - - List names = new ArrayList<>(); - names.addAll(valueNames); - names.addAll(shortCircuitNames); - - List fieldAnnotations = Collections.emptyList(); // call collectionAnnotations instead if you want OperationField support enabled. - List fields = new ArrayList<>(); - for (AnnotationMirror fieldMirror : fieldAnnotations) { - String name = Utils.getAnnotationValueString(fieldMirror, "name"); - TypeMirror javaClass = Utils.getAnnotationValueType(fieldMirror, "javaClass"); - fields.add(new OperationFieldData(name, javaClass)); - names.add(name); - } - - List constructorFields = parseConstructorFields(templateType, true); - if (constructorFields == null) { - return null; - } - - List superConstructorFields = parseConstructorFields(Utils.fromTypeMirror(nodeType), false); - if (superConstructorFields == null) { - return null; - } - - List protectedSuperFields = parseProtectedFields(Utils.fromTypeMirror(nodeType)); - if (protectedSuperFields == null) { - return null; - } - - List matchedSuperFields = matchFields(superConstructorFields, protectedSuperFields); - if (matchedSuperFields == null) { - log.error(templateType, templateTypeAnnotation, Utils.getAnnotationValue(templateTypeAnnotation, "baseClass"), - "The signature of the protected fields (%s) and the first constructor(%s) in %s does not match.", - protectedSuperFields.toString(), - superConstructorFields.toString(), - Utils.getQualifiedName(nodeType)); - return null; - } - - for (OperationFieldData field : constructorFields) { - names.add(field.getName()); - } - - for (OperationFieldData field : matchedSuperFields) { - names.add(field.getName()); - } - - if (!verifyNames(templateType, templateTypeAnnotation, names)) { - return null; - } - - OperationData operationData = new OperationData(templateType, templateTypeAnnotation, typeSystem, nodeType, - valueNames.toArray(new String[valueNames.size()]), - shortCircuitNames.toArray(new String[shortCircuitNames.size()]), - fields.toArray(new OperationFieldData[fields.size()]), - constructorFields.toArray(new OperationFieldData[constructorFields.size()]), - matchedSuperFields.toArray(new OperationFieldData[matchedSuperFields.size()])); - - if (!verifyExclusiveMethodAnnotation(templateType, - Specialization.class, Generic.class, SpecializationListener.class, ShortCircuit.class, GuardCheck.class)) { - return noFactory(operationData); - } - - operationData.setExtensionElements(getExtensionParser().parseAll(templateType)); - - List genericSpecializations = parseMethods(operationData, new GenericParser(context, operationData)); - List guards = parseMethods(operationData, new GuardParser(context, operationData.getTypeSystem(), operationData)); - operationData.setGuards(guards.toArray(new GuardData[guards.size()])); - - SpecializationParser specializationParser = new SpecializationParser(context, operationData); - operationData.setSpecification(specializationParser.getSpecification()); - List specializations = parseMethods(operationData, specializationParser); - List shortCircuits = parseMethods(operationData, new ShortCircuitParser(context, operationData)); - List listeners = parseMethods(operationData, new SpecializationListenerParser(context, operationData)); - - if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) { - return noFactory(operationData); - } - - - SpecializationData genericSpecialization = null; - if (genericSpecializations.size() > 1) { - for (SpecializationData generic : genericSpecializations) { - log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); - } - return noFactory(operationData); - } else if (genericSpecializations.size() == 1) { - genericSpecialization = genericSpecializations.get(0); - } - - if (specializations.size() > 1 && genericSpecialization == null) { - log.error(templateType, "Need a @%s method.", Generic.class.getSimpleName()); - return noFactory(operationData); - } - - Collections.sort(specializations, new Comparator() { - @Override - public int compare(SpecializationData o1, SpecializationData o2) { - return compareSpecialization(typeSystem, o1, o2); - } - }); - - List allSpecializations = new ArrayList<>(specializations); - if (genericSpecialization != null) { - allSpecializations.add(genericSpecialization); - TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getSpecification(), new CodeExecutableElement(context.getType(void.class), "doUninialized"), - genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters()); - allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true)); - } - - // verify order is not ambiguous - verifySpecializationOrder(typeSystem, specializations); - - operationData.setGenericSpecialization(genericSpecialization); - operationData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()])); - operationData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()])); - - if (!assignShortCircuitsToSpecializations(operationData, allSpecializations, shortCircuits)) { - return null; - } - - if (!verifyNamingConvention(specializations, "do")) { - return noFactory(operationData); - } - - if (!verifyNamesUnique(specializations)) { - return noFactory(operationData); - } - - if (!verifyNamingConvention(shortCircuits, "needs")) { - return noFactory(operationData); - } - - if (!verifySpecializationThrows(typeSystem, specializations)) { - return noFactory(operationData); - } - - return operationData; - } - - private static List matchFields(List params, - List fields) { - - if (params.size() != fields.size()) { - return null; - } - - List matchedFields = new ArrayList<>(); - for (int i = 0; i < params.size(); i++) { - OperationFieldData param = params.get(i); - OperationFieldData field = fields.get(i); - if (!Utils.typeEquals(param.getJavaClass(), field.getJavaClass())) { - return null; - } - matchedFields.add(new OperationFieldData(field.getName(), param.getJavaClass())); - } - - return matchedFields; - } - - private static List parseProtectedFields(Element element) { - List opFields = new ArrayList<>(); - List fields = ElementFilter.fieldsIn(element.getEnclosedElements()); - for (VariableElement var : fields) { - if (var.getModifiers().contains(Modifier.STATIC)) { - continue; - } - - if (var.getModifiers().contains(Modifier.PROTECTED)) { - opFields.add(new OperationFieldData(var.getSimpleName().toString(), var.asType())); - } - } - return opFields; - - } - - private List parseConstructorFields(Element element, boolean failOnMultipleConstructors) { - if (element == null) { - return Collections.emptyList(); - } - - List constructors = ElementFilter.constructorsIn(element.getEnclosedElements()); - ExecutableElement constructor = null; - if (constructors.size() > 1) { - if (failOnMultipleConstructors) { - for (ExecutableElement c : constructors) { - log.error(c, "The Operation annotated class must not define multiple constructors."); - } - return null; - } else { - // take first constructor - constructor = constructors.get(0); - } - } else if (constructors.size() == 1) { - constructor = constructors.get(0); - } - - List constructorFields = new ArrayList<>(); - if (constructor != null) { - for (VariableElement var : constructor.getParameters()) { - constructorFields.add(new OperationFieldData(var.getSimpleName().toString(), var.asType())); - } - } - return constructorFields; - } - - private static OperationData noFactory(OperationData data) { - data.generateFactory = false; - return data; - } - - private boolean verifySpecializationThrows(TypeSystemData typeSystem, List specializations) { - Map specializationMap = new HashMap<>(); - for (SpecializationData spec : specializations) { - specializationMap.put(spec.getMethodName(), spec); - } - boolean valid = true; - for (SpecializationData sourceSpecialization : specializations) { - 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()); - valid = false; - } - } - } - } - } - return valid; - } - - - private boolean assignShortCircuitsToSpecializations(OperationData operation, - List specializations, - List shortCircuits) { - - Map> groupedShortCircuits = groupShortCircuits(shortCircuits); - - boolean valid = true; - - for (String valueName : operation.getShortCircuitValues()) { - List availableCircuits = groupedShortCircuits.get(valueName); - - if (availableCircuits == null || availableCircuits.isEmpty()) { - log.error(operation.getTemplateType(), operation.getTemplateTypeAnnotation(), - "@%s method for short cut value '%s' required.", - ShortCircuit.class.getSimpleName(), valueName); - valid = false; - continue; - } - - - boolean sameMethodName = true; - String methodName = availableCircuits.get(0).getMethodName(); - for (ShortCircuitData circuit : availableCircuits) { - if (!circuit.getMethodName().equals(methodName)) { - sameMethodName = false; - } - } - - if (!sameMethodName) { - for (ShortCircuitData circuit : availableCircuits) { - log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName); - } - valid = false; - continue; - } - - ShortCircuitData genericCircuit = null; - for (ShortCircuitData circuit : availableCircuits) { - if (isGenericShortCutMethod(circuit, operation.getTypeSystem().getGenericType())) { - genericCircuit = circuit; - break; - } - } - - if (genericCircuit == null) { - log.error(operation.getTemplateType(), operation.getTemplateTypeAnnotation(), - "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName); - valid = false; - continue; - } - - for (ShortCircuitData circuit : availableCircuits) { - if (circuit != genericCircuit) { - circuit.setGenericShortCircuitMethod(genericCircuit); - } - } - } - - if (!valid) { - return valid; - } - - for (SpecializationData specialization : specializations) { - ShortCircuitData[] assignedShortCuts = new ShortCircuitData[operation.getShortCircuitValues().length]; - - for (int i = 0; i < operation.getShortCircuitValues().length; i++) { - List availableShortCuts = groupedShortCircuits.get(operation.getShortCircuitValues()[i]); - - ShortCircuitData genericShortCircuit = null; - for (ShortCircuitData circuit : availableShortCuts) { - if (circuit.isGeneric()) { - genericShortCircuit = circuit; - } else if (circuit.isCompatibleTo(specialization)) { - assignedShortCuts[i] = circuit; - } - } - - if (assignedShortCuts[i] == null) { - assignedShortCuts[i] = genericShortCircuit; - } - } - specialization.setShortCircuits(assignedShortCuts); - } - return true; - } - - private static boolean isGenericShortCutMethod(TemplateMethod method, TypeMirror genericType) { - for (ActualParameter parameter : method.getParameters()) { - if (parameter.getSpecification().getKind() == Kind.EXECUTE) { - if (!Utils.typeEquals(genericType, parameter.getActualType())) { - return false; - } - } - } - return true; - } - - private static Map> groupShortCircuits(List shortCircuits) { - Map> group = new HashMap<>(); - for (ShortCircuitData shortCircuit : shortCircuits) { - List circuits = group.get(shortCircuit.getValueName()); - if (circuits == null) { - circuits = new ArrayList<>(); - group.put(shortCircuit.getValueName(), circuits); - } - circuits.add(shortCircuit); - } - return group; - } - - private boolean verifyNamingConvention(List methods, String prefix) { - boolean valid = true; - for (int i = 0; i < methods.size(); i++) { - TemplateMethod m1 = methods.get(i); - if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix); - valid = false; - } - } - return valid; - } - - private boolean verifyNamesUnique(List methods) { - boolean valid = true; - for (int i = 0; i < methods.size(); i++) { - TemplateMethod m1 = methods.get(i); - for (int j = i + 1; j < methods.size(); j++) { - TemplateMethod m2 = methods.get(j); - - if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName()); - return false; - } - } - } - return valid; - } - - private boolean verifySpecializationOrder(TypeSystemData typeSystem, List specializations) { - for (int i = 0; i < specializations.size(); i++) { - SpecializationData m1 = specializations.get(i); - for (int j = i + 1; j < specializations.size(); j++) { - SpecializationData m2 = specializations.get(j); - int inferredOrder = compareSpecializationWithoutOrder(typeSystem, m1, m2); - - if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { - int specOrder = m1.getOrder() - m2.getOrder(); - if (specOrder == 0) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder()); - return false; - } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) { - log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder()); - return false; - } - } else if (inferredOrder == 0) { - SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2); - log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this."); - return false; - } - } - } - return true; - } - - private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) { - int result = compareSpecializationWithoutOrder(typeSystem, m1, m2); - if (result == 0) { - if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) { - return m1.getOrder() - m2.getOrder(); - } - } - return result; - } - - 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."); - } - - int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType()); - - for (ParameterSpec spec : m1.getSpecification().getParameters()) { - ActualParameter p1 = m1.findParameter(spec); - ActualParameter p2 = m2.findParameter(spec); - - if (p1 != null && p2 != null && !Utils.typeEquals(p1.getActualType(), p2.getActualType())) { - int typeResult = compareActualParameter(typeSystem, p1, p2); - if (result == 0) { - result = typeResult; - } else if (Math.signum(result) != Math.signum(typeResult)) { - // We cannot define an order. - return 0; - } - } - } - return result; - } - - private static int compareActualParameter(TypeSystemData typeSystem, ActualParameter p1, ActualParameter p2) { - int index1 = typeSystem.findType(p1.getActualType()); - int index2 = typeSystem.findType(p2.getActualType()); - - assert index1 != index2; - assert !(index1 == -1 ^ index2 == -1); - - return index1 - index2; - } - - private boolean verifyNames(TypeElement element, AnnotationMirror mirror, List names) { - boolean valid = true; - - for (int i = 0; i < names.size(); i++) { - String name = names.get(i); - if (!JavaName.isValid(name)) { - log.error(element, mirror, "Name '%s' is not a valid java identifier.", name); - valid = false; - } else if (JavaName.isReserved(name)) { - log.error(element, mirror, "Name '%s' is a reserved java identifier.", name); - valid = false; - } - for (int j = i + 1; j < names.size(); j++) { - String otherName = names.get(j); - if (name.equalsIgnoreCase(otherName)) { - log.error(element, mirror, "Name '%s' is not unique.", name); - valid = false; - } - } - } - return valid; - } -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +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.codegen.processor.operation; - -import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.template.*; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; - - -public class ShortCircuitData extends TemplateMethod { - - private ShortCircuitData genericShortCircuitMethod; - - private final String valueName; - - public ShortCircuitData(TemplateMethod template, String valueName) { - super(template); - this.valueName = valueName; - } - - public String getValueName() { - return valueName; - } - - public void setGenericShortCircuitMethod(ShortCircuitData genericShortCircuitMethod) { - this.genericShortCircuitMethod = genericShortCircuitMethod; - } - - public boolean isGeneric() { - return genericShortCircuitMethod == null; - } - - public ShortCircuitData getGeneric() { - if (isGeneric()) { - return this; - } else { - return genericShortCircuitMethod; - } - } - - public boolean isCompatibleTo(SpecializationData specialization) { - if (isGeneric() && specialization.isGeneric()) { - return true; - } - - for (ActualParameter param : getParameters()) { - ParameterSpec paramSpec = param.getSpecification(); - if (paramSpec.getKind() == Kind.EXECUTE) { - ActualParameter specializationParam = specialization.findParameter(paramSpec.getName()); - if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) { - return false; - } - } - } - return true; - } -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/ShortCircuitParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +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.codegen.processor.operation; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; - -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.Kind; - - -public class ShortCircuitParser extends OperationMethodParser { - - private final Set shortCircuitValues; - - public ShortCircuitParser(ProcessorContext context, OperationData operation) { - super(context, operation); - shortCircuitValues = new HashSet<>(Arrays.asList(operation.getShortCircuitValues())); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value"); - - if (!shortCircuitValues.contains(shortCircuitValue)) { - getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue); - return null; - } - - return createDefaultMethodSpec(shortCircuitValue); - } - - @Override - protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("has", getContext().getType(boolean.class), Kind.SHORT_CIRCUIT, false); - } - - @Override - public ShortCircuitData create(TemplateMethod method) { - String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value"); - assert shortCircuitValue != null; - assert shortCircuitValues.contains(shortCircuitValue); - return new ShortCircuitData(method, shortCircuitValue); - } - - @Override - public Class< ? extends Annotation> getAnnotationType() { - return ShortCircuit.class; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +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.codegen.processor.operation; - -import com.oracle.truffle.api.codegen.*; -import com.oracle.truffle.codegen.processor.template.*; - -public class SpecializationData extends TemplateMethod { - - private final int order; - private final boolean generic; - private final boolean uninitialized; - private final SpecializationThrowsData[] exceptions; - private SpecializationGuardData[] guards; - private ShortCircuitData[] shortCircuits; - - private OperationData operation; - - public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) { - super(template.getSpecification(), template.getMethod(), template.getMarkerAnnotation(), template.getReturnType(), template.getParameters()); - this.order = order; - this.generic = false; - this.uninitialized = false; - this.exceptions = exceptions; - - for (SpecializationThrowsData exception : exceptions) { - exception.setSpecialization(this); - } - } - - public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized) { - super(template.getSpecification(), template.getMethod(), template.getMarkerAnnotation(), template.getReturnType(), template.getParameters()); - this.order = Specialization.DEFAULT_ORDER; - this.generic = generic; - this.uninitialized = uninitialized; - this.exceptions = new SpecializationThrowsData[0]; - this.guards = new SpecializationGuardData[0]; - } - - public void setOperation(OperationData operation) { - this.operation = operation; - } - - void setGuards(SpecializationGuardData[] guards) { - this.guards = guards; - } - - public OperationData getOperation() { - return operation; - } - - public int getOrder() { - return order; - } - - public boolean isGeneric() { - return generic; - } - - public boolean isUninitialized() { - return uninitialized; - } - - public SpecializationThrowsData[] getExceptions() { - return exceptions; - } - - public SpecializationGuardData[] getGuards() { - return guards; - } - - public void setShortCircuits(ShortCircuitData[] shortCircuits) { - this.shortCircuits = shortCircuits; - } - - public ShortCircuitData[] getShortCircuits() { - return shortCircuits; - } - - public SpecializationData findNextSpecialization() { - SpecializationData[] allMethods = operation.getAllMethods(); - for (int i = 0; i < allMethods.length - 1; i++) { - if (allMethods[i] == this) { - return allMethods[i + 1]; - } - } - throw new IllegalArgumentException(); - } - - public boolean hasDynamicGuards() { - for (SpecializationGuardData guard : getGuards()) { - if (guard.isOnExecution()) { - return true; - } - } - return false; - } - - public ActualParameter getPreviousParam(ActualParameter searchParam) { - ActualParameter prev = null; - for (ActualParameter param : getParameters()) { - if (param == searchParam) { - return prev; - } - prev = param; - } - return prev; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationGuardData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationGuardData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +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.codegen.processor.operation; - -import com.oracle.truffle.codegen.processor.typesystem.*; - -public class SpecializationGuardData { - - private final String guardMethod; - private final boolean onSpecialization; - private final boolean onExecution; - - private GuardData guardDeclaration; - - public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) { - this.guardMethod = guardMethod; - this.onSpecialization = onSpecialization; - this.onExecution = onExecution; - } - - public String getGuardMethod() { - return guardMethod; - } - - public boolean isOnExecution() { - return onExecution; - } - - public boolean isOnSpecialization() { - return onSpecialization; - } - - void setGuardDeclaration(GuardData compatibleGuard) { - this.guardDeclaration = compatibleGuard; - } - - public GuardData getGuardDeclaration() { - return guardDeclaration; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationListenerParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationListenerParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +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.codegen.processor.operation; - -import java.lang.annotation.*; - -import javax.lang.model.element.*; - -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.Kind; - - -public class SpecializationListenerParser extends OperationMethodParser { - - private final MethodSpec specification; - - public SpecializationListenerParser(ProcessorContext context, OperationData operation) { - super(context, operation); - this.specification = createDefaultMethodSpec(null); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; - } - - @Override - protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("void", getContext().getType(void.class), Kind.ATTRIBUTE, false); - } - - @Override - public TemplateMethod create(TemplateMethod method) { - return method; - } - - @Override - public Class< ? extends Annotation> getAnnotationType() { - return SpecializationListener.class; - } - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationParser.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +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.codegen.processor.operation; - -import java.lang.annotation.*; -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.Kind; -import com.oracle.truffle.codegen.processor.typesystem.*; - - -public class SpecializationParser extends OperationMethodParser { - - private final MethodSpec specification; - - public SpecializationParser(ProcessorContext context, OperationData operation) { - super(context, operation); - this.specification = createDefaultMethodSpec(null); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; - } - public MethodSpec getSpecification() { - return specification; - } - - @Override - public SpecializationData create(TemplateMethod method) { - return parseSpecialization(method); - } - - @Override - public Class< ? extends Annotation> getAnnotationType() { - return Specialization.class; - } - - private SpecializationData parseSpecialization(TemplateMethod template) { - int order = Utils.getAnnotationValueInt(template.getMarkerAnnotation(), "order"); - if (order < 0 && order != Specialization.DEFAULT_ORDER) { - getContext().getLog().error(template.getMethod(), template.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value."); - return null; - } - - List exceptionDefs = Utils.collectAnnotations(getContext(), template.getMarkerAnnotation(), "exceptions", template.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); - - if (!Utils.canThrowType(template.getMethod().getThrownTypes(), javaClass)) { - getContext().getLog().error(template.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(javaClass)); - return null; - } - } - - Arrays.sort(exceptionData, new Comparator() { - @Override - public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { - return Utils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); - } - }); - SpecializationData specialization = new SpecializationData(template, order, exceptionData); - - boolean valid = true; - List guardDefs = Utils.collectAnnotations(getContext(), template.getMarkerAnnotation(), "guards", template.getMethod(), SpecializationGuard.class); - 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"); - - if (!onSpecialization && !onExecution) { - String message = "Either onSpecialization, onExecution or both must be enabled."; - getContext().getLog().error(template.getMethod(), guardMirror, message); - valid = false; - continue; - } - - guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution); - - GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]); - if (compatibleGuard != null) { - guardData[i].setGuardDeclaration(compatibleGuard); - } else { - valid = false; - } - } - - if (!valid) { - return null; - } - - specialization.setGuards(guardData); - - return specialization; - } - - private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) { - List foundGuards = getOperation().findGuards(specializationGuard.getGuardMethod()); - GuardData compatibleGuard = null; - for (GuardData guardData : foundGuards) { - if (isGuardCompatible(specialization, guardData)) { - compatibleGuard = guardData; - break; - } - } - - if (compatibleGuard == null) { - ParameterSpec returnTypeSpec = new ParameterSpec("returnValue", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); - List expectedParameterSpecs = new ArrayList<>(); - - for (ActualParameter param : filterGuardParameters(specialization)) { - ParameterSpec spec = param.getSpecification(); - expectedParameterSpecs.add(new ParameterSpec(spec.getName(), param.getActualType(), Kind.ATTRIBUTE, false)); - } - String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs); - AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName"); - getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature); - return null; - } - - return compatibleGuard; - } - - private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { - Iterator guardParameters = Arrays.asList(guard.getParameters()).iterator(); - for (ActualParameter param : filterGuardParameters(specialization)) { - if (!guardParameters.hasNext()) { - return false; - } - ActualParameter guardParam = guardParameters.next(); - if (!Utils.typeEquals(guardParam.getActualType(), param.getActualType())) { - return false; - } - } - if (guardParameters.hasNext()) { - return false; - } - return true; - } - - private static List filterGuardParameters(SpecializationData specialization) { - List parameters = new ArrayList<>(); - for (ActualParameter param : specialization.getParameters()) { - if (param.getSpecification().getKind() != Kind.EXECUTE - && param.getSpecification().getKind() != Kind.SHORT_CIRCUIT) { - continue; - } - parameters.add(param); - } - return parameters; - } - - -} diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationThrowsData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/SpecializationThrowsData.java Thu Jan 17 17:21:16 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +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.codegen.processor.operation; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public class SpecializationThrowsData { - - private final AnnotationMirror annotationMirror; - private final TypeMirror javaClass; - private final String transitionTo; - private SpecializationData specialization; - - public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) { - this.annotationMirror = annotationMirror; - this.javaClass = javaClass; - this.transitionTo = transitionTo; - } - - - void setSpecialization(SpecializationData specialization) { - this.specialization = specialization; - } - - public TypeMirror getJavaClass() { - return javaClass; - } - - public SpecializationData getSpecialization() { - return specialization; - } - - public AnnotationMirror getAnnotationMirror() { - return annotationMirror; - } - - public String getTransitionToName() { - return transitionTo; - } - - public SpecializationData getTransitionTo() { - for (SpecializationData s : specialization.getOperation().getAllMethods()) { - if (s.getMethodName().equals(transitionTo)) { - return s; - } - } - throw new IllegalArgumentException(); - } -} - diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Fri Jan 18 13:28:12 2013 +0100 @@ -45,6 +45,6 @@ } public TypeData getActualTypeData(TypeSystemData typeSystem) { - return typeSystem.getTypes()[typeSystem.findType(actualType)]; + return typeSystem.findTypeData(actualType); } } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java Fri Jan 18 13:28:12 2013 +0100 @@ -44,6 +44,12 @@ @Override protected abstract CodeTypeElement create(M m); + + @Override + public CodeTypeElement getElement() { + return (CodeTypeElement) super.getElement(); + } + protected CodeExecutableElement createConstructorUsingFields(Set modifiers, CodeTypeElement clazz) { CodeExecutableElement method = new CodeExecutableElement(modifiers, null, clazz.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); @@ -81,6 +87,7 @@ return method; } + private static ExecutableElement findConstructor(TypeElement clazz) { List constructors = ElementFilter.constructorsIn(clazz.getEnclosedElements()); if (constructors.isEmpty()) { @@ -90,6 +97,27 @@ } } + protected CodeExecutableElement createSuperConstructor(TypeElement type, ExecutableElement element) { + if (element.getModifiers().contains(Modifier.PRIVATE)) { + return null; + } + + CodeExecutableElement executable = CodeExecutableElement.clone(getContext().getEnvironment(), element); + executable.setReturnType(null); + executable.setSimpleName(CodeNames.of(type.getSimpleName().toString())); + CodeTreeBuilder b = executable.createBuilder(); + b.startStatement(); + b.startSuperCall(); + for (VariableElement v : element.getParameters()) { + b.string(v.getSimpleName().toString()); + } + b.end(); + b.end(); + + return executable; + } + + protected CodeTypeElement createClass(Template model, Set modifiers, String simpleName, TypeMirror superType, boolean enumType) { TypeElement templateType = model.getTemplateType(); diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CodeElementFactory.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CodeElementFactory.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CodeElementFactory.java Fri Jan 18 13:28:12 2013 +0100 @@ -44,9 +44,12 @@ protected void createChildren(M m) { } @SuppressWarnings("unchecked") - public final CodeElement process(M m) { + public CodeElement process(CodeElement parent, M m) { model = m; element = (CodeElement) create(model); + if (parent != null) { + parent.add(element); + } if (element != null) { createChildren(model); } @@ -58,7 +61,7 @@ } protected void add(CodeElementFactory factory, MO m) { - this.element.add(factory.process(m)); + factory.process(this.element, m); } public ProcessorContext getContext() { diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CompilationUnitFactory.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CompilationUnitFactory.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/CompilationUnitFactory.java Fri Jan 18 13:28:12 2013 +0100 @@ -37,6 +37,11 @@ } @Override + public CodeCompilationUnit process(CodeElement parent, M m) { + return (CodeCompilationUnit) super.process(parent, m); + } + + @Override protected abstract void createChildren(M m); } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java Fri Jan 18 13:28:12 2013 +0100 @@ -22,17 +22,16 @@ */ package com.oracle.truffle.codegen.processor.template; +import java.util.*; + import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; +import com.oracle.truffle.codegen.processor.node.*; import com.oracle.truffle.codegen.processor.typesystem.*; public class ParameterSpec { - public enum Kind { - EXECUTE, SIGNATURE, SUPER_ATTRIBUTE, ATTRIBUTE, CONSTRUCTOR_FIELD, SHORT_CIRCUIT - } - public enum Cardinality { ONE, MULTIPLE; } @@ -40,35 +39,49 @@ private final String name; private final TypeMirror[] allowedTypes; private final TypeMirror valueType; - private final Kind kind; private final boolean optional; private final Cardinality cardinality; - public ParameterSpec(String name, TypeMirror[] allowedTypes, TypeMirror valueType, Kind kind, boolean optional, Cardinality cardinality) { + public ParameterSpec(String name, TypeMirror[] allowedTypes, TypeMirror valueType, boolean optional, Cardinality cardinality) { this.valueType = valueType; this.allowedTypes = allowedTypes; this.name = name; - this.kind = kind; this.optional = optional; this.cardinality = cardinality; } - public ParameterSpec(String name, TypeMirror singleFixedType, Kind kind, boolean optional) { - this(name, new TypeMirror[]{singleFixedType}, singleFixedType, kind, optional, Cardinality.ONE); + /** Type constructor. */ + public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) { + this(name, new TypeMirror[]{singleFixedType}, singleFixedType, optional, Cardinality.ONE); + } + + /** Type system value constructor. */ + public ParameterSpec(String name, TypeSystemData typeSystem, boolean optional, Cardinality cardinality) { + this(name, typeSystem.getPrimitiveTypeMirrors(), typeSystem.getGenericType(), optional, cardinality); } - public ParameterSpec(String name, TypeSystemData typeSystem, Kind kind, boolean optional, Cardinality cardinality) { - this(name, typeSystem.getPrimitiveTypeMirrors(), typeSystem.getGenericType(), kind, optional, cardinality); + /** Node value constructor. */ + public ParameterSpec(String name, NodeData nodeData, boolean optional, Cardinality cardinality) { + this(name, nodeTypeMirrors(nodeData), nodeData.getTypeSystem().getGenericType(), optional, cardinality); } + private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) { + List typeMirrors = new ArrayList<>(); + + for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { + typeMirrors.add(typeData.getType().getPrimitiveType()); + } + + typeMirrors.add(nodeData.getTypeSystem().getGenericType()); + + return typeMirrors.toArray(new TypeMirror[typeMirrors.size()]); + } + + public final String getName() { return name; } - public Kind getKind() { - return kind; - } - public final boolean isOptional() { return optional; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Fri Jan 18 13:28:12 2013 +0100 @@ -26,13 +26,15 @@ public class TemplateMethod { + private final Template template; private final MethodSpec specification; private final ExecutableElement method; private final AnnotationMirror markerAnnotation; private final ActualParameter returnType; private final ActualParameter[] parameters; - public TemplateMethod(MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + public TemplateMethod(Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + this.template = template; this.specification = specification; this.method = method; this.markerAnnotation = markerAnnotation; @@ -41,6 +43,7 @@ } public TemplateMethod(TemplateMethod method) { + this.template = method.template; this.specification = method.specification; this.method = method.method; this.markerAnnotation = method.markerAnnotation; @@ -48,6 +51,9 @@ this.parameters = method.parameters; } + public Template getTemplate() { + return template; + } public MethodSpec getSpecification() { return specification; diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -29,18 +29,41 @@ import javax.lang.model.element.*; import javax.lang.model.type.*; +import javax.lang.model.util.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -public abstract class TemplateMethodParser { +public abstract class TemplateMethodParser { private final ProcessorContext context; - public TemplateMethodParser(ProcessorContext context) { + protected final T template; + + private boolean emitErrors = true; + private boolean parseNullOnError = true; + + public TemplateMethodParser(ProcessorContext context, T template) { + this.template = template; this.context = context; } + public boolean isEmitErrors() { + return emitErrors; + } + + public void setParseNullOnError(boolean nullOnError) { + this.parseNullOnError = nullOnError; + } + + public boolean isParseNullOnError() { + return parseNullOnError; + } + + public void setEmitErrors(boolean emitErrors) { + this.emitErrors = emitErrors; + } + public ProcessorContext getContext() { return context; } @@ -49,9 +72,49 @@ public abstract E create(TemplateMethod method); - public abstract Class getAnnotationType(); + public abstract boolean isParsable(ExecutableElement method); + + public Class getAnnotationType() { + return null; + } + + public final List parse(List elements) { + List methods = new ArrayList<>(); + methods.addAll(ElementFilter.methodsIn(elements)); + + List parsedMethods = new ArrayList<>(); + boolean valid = true; + for (ExecutableElement method : methods) { + if (!isParsable(method)) { + continue; + } - public final E parse(ExecutableElement method, AnnotationMirror annotation, Template template) { + Class annotationType = getAnnotationType(); + AnnotationMirror mirror = null; + if (annotationType != null) { + mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); + } + + if (method.getModifiers().contains(Modifier.PRIVATE)) { + getContext().getLog().error(method, "Method must not be private."); + valid = false; + continue; + } + + E parsedMethod = parse(method, mirror); + if (parsedMethod != null) { + parsedMethods.add(parsedMethod); + } else { + valid = false; + } + } + if (!valid && parseNullOnError) { + return null; + } + return parsedMethods; + } + + private E parse(ExecutableElement method, AnnotationMirror annotation) { MethodSpec methodSpecification = createSpecification(method, annotation); if (methodSpecification == null) { return null; @@ -63,13 +126,15 @@ ActualParameter returnTypeMirror = resolveTypeMirror(returnTypeSpec, method.getReturnType(), template); if (returnTypeMirror == null) { - String expectedReturnType = createTypeSignature(returnTypeSpec, true); - String actualReturnType = Utils.getSimpleName(method.getReturnType()); + if (isEmitErrors()) { + String expectedReturnType = createTypeSignature(returnTypeSpec, true); + String actualReturnType = Utils.getSimpleName(method.getReturnType()); - String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); - context.getLog().error(method, annotation, message); + context.getLog().error(method, annotation, message); + } return null; } @@ -93,13 +158,15 @@ specification = null; continue; } else if (!specification.isOptional()) { - // non option type specification found -> argument missing - String expectedType = createTypeSignature(specification, false); + if (isEmitErrors()) { + // non option type specification found -> argument missing + String expectedType = createTypeSignature(specification, false); - String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType, - createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); + String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType, + createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs)); - context.getLog().error(method, message); + context.getLog().error(method, message); + } return null; } else { // specification is optional -> continue @@ -116,13 +183,15 @@ continue; } - String expectedReturnType = createTypeSignature(specification, false); - String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName(); + if (isEmitErrors()) { + String expectedReturnType = createTypeSignature(specification, 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)); + 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)); - context.getLog().error(parameter, message); + context.getLog().error(parameter, message); + } return null; } @@ -136,16 +205,18 @@ if (variableIterator.hasNext()) { parameter = variableIterator.next(); - 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)); + 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)); - context.getLog().error(parameter, message); + context.getLog().error(parameter, message); + } return null; } ActualParameter[] paramMirrors = resolvedMirrors.toArray(new ActualParameter[resolvedMirrors.size()]); - return create(new TemplateMethod(methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); + return create(new TemplateMethod(template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); } private ActualParameter resolveTypeMirror(ParameterSpec specification, TypeMirror mirror, Template typeSystem) { diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -28,7 +28,6 @@ import javax.lang.model.util.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.api.element.*; import com.oracle.truffle.codegen.processor.ext.*; public abstract class TemplateParser extends AbstractParser { @@ -92,42 +91,4 @@ return valid; } - protected List parseMethods(Template template, TemplateMethodParser parser) { - TypeElement type = template.getTemplateType(); - - List methods = new ArrayList<>(); - methods.addAll(ElementFilter.methodsIn(type.getEnclosedElements())); - if (template.getExtensionElements() != null) { - for (WritableElement e : template.getExtensionElements()) { - if (e instanceof ExecutableElement) { - methods.add((ExecutableElement) e); - } - } - } - - List parsedMethods = new ArrayList<>(); - boolean valid = true; - for (ExecutableElement method : methods) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, parser.getAnnotationType()); - if (mirror != null) { - if (method.getModifiers().contains(Modifier.PRIVATE)) { - log.error(method, "Methods annotated with @%s must not be private.", parser.getAnnotationType().getSimpleName()); - valid = false; - continue; - } - E parsedMethod = parser.parse(method, mirror, template); - if (parsedMethod != null) { - parsedMethods.add(parsedMethod); - } else { - valid = false; - } - } - } - if (!valid) { - return null; - } - return parsedMethods; - } - - } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -31,30 +31,34 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; -public class GuardParser extends TypeSystemMethodParser { +public class GuardParser extends TemplateMethodParser { - private final Template origin; + private final TypeSystemData typeSystem; - public GuardParser(ProcessorContext context, TypeSystemData typeSystem, Template origin) { - super(context, typeSystem); - this.origin = origin; + public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) { + super(context, template); + this.typeSystem = typeSystem; } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value1", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); - specs.add(new ParameterSpec("valueN", getTypeSystem(), Kind.EXECUTE, false, Cardinality.MULTIPLE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); + specs.add(new ParameterSpec("value1", typeSystem, false, Cardinality.ONE)); + specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE)); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); return new MethodSpec(returnTypeSpec, specs); } @Override + public boolean isParsable(ExecutableElement method) { + return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + } + + @Override public GuardData create(TemplateMethod method) { - return new GuardData(method, origin); + return new GuardData(method, template); } @Override diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -31,7 +31,6 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; class TypeCastParser extends TypeSystemMethodParser { @@ -47,8 +46,8 @@ return null; } List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), Kind.ATTRIBUTE, false); + specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); + ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false); MethodSpec spec = new MethodSpec(returnTypeSpec, specs); return spec; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -31,7 +31,6 @@ import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality; -import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; class TypeCheckParser extends TypeSystemMethodParser { @@ -46,8 +45,8 @@ return null; } List specs = new ArrayList<>(); - specs.add(new ParameterSpec("value", getTypeSystem(), Kind.EXECUTE, false, Cardinality.ONE)); - ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), Kind.ATTRIBUTE, false); + 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); return spec; } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java Fri Jan 18 13:28:12 2013 +0100 @@ -84,5 +84,11 @@ } return Utils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType()); } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + Utils.getSimpleName(primitiveType) + "]"; + } + } diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java Fri Jan 18 13:28:12 2013 +0100 @@ -36,22 +36,17 @@ private final TypeMirror[] primitiveTypeMirrors; private final TypeMirror[] boxedTypeMirrors; - private final TypeMirror nodeType; private final TypeMirror genericType; private final TypeData voidType; - private List guards; - public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, - TypeData[] types, TypeMirror nodeType, TypeMirror genericType, TypeData voidType) { + TypeData[] types, TypeMirror genericType, TypeData voidType) { super(templateType, annotation); - this.voidType = voidType; this.types = types; - this.nodeType = nodeType; this.genericType = genericType; - + this.voidType = voidType; this.primitiveTypeMirrors = new TypeMirror[types.length]; for (int i = 0; i < types.length; i++) { primitiveTypeMirrors[i] = types[i].getPrimitiveType(); @@ -70,16 +65,12 @@ } } - public TypeData getVoidType() { - return voidType; + public boolean isGeneric(TypeMirror type) { + return Utils.typeEquals(getGenericType(), type); } - void setGuards(List guards) { - this.guards = guards; - } - - public List getGuards() { - return guards; + public TypeData getVoidType() { + return voidType; } public TypeData[] getTypes() { @@ -94,10 +85,6 @@ return boxedTypeMirrors; } - public TypeMirror getNodeType() { - return nodeType; - } - public TypeMirror getGenericType() { return genericType; } @@ -116,6 +103,18 @@ } return null; } + public TypeData findTypeData(TypeMirror type) { + if (Utils.typeEquals(voidType.getPrimitiveType(), type)) { + return voidType; + } + + int index = findType(type); + if (index == -1) { + return null; + } + return types[index]; + } + public int findType(TypeMirror type) { for (int i = 0; i < types.length; i++) { @@ -126,4 +125,11 @@ return -1; } + + @Override + public String toString() { + return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + Arrays.toString(types) + "]"; + } + + } diff -r 0f8c6dbf68be -r 6343a09b2ec1 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -29,17 +29,19 @@ import com.oracle.truffle.codegen.processor.template.*; -abstract class TypeSystemMethodParser extends TemplateMethodParser { - - private final TypeSystemData typeSystem; +abstract class TypeSystemMethodParser extends TemplateMethodParser { public TypeSystemMethodParser(ProcessorContext context, TypeSystemData typeSystem) { - super(context); - this.typeSystem = typeSystem; + super(context, typeSystem); } public TypeSystemData getTypeSystem() { - return typeSystem; + return template; + } + + @Override + public final boolean isParsable(ExecutableElement method) { + return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } protected TypeData findTypeByMethodName(ExecutableElement method, AnnotationMirror annotationMirror, String prefix) { @@ -51,7 +53,7 @@ return null; } String typeName = methodName.substring(prefix.length(), methodName.length()); - TypeData type = typeSystem.findType(typeName); + TypeData type = getTypeSystem().findType(typeName); if (type == null) { String annotationName = TypeSystem.class.getSimpleName(); getContext().getLog().error(method, "Type '%s' is not declared in this @%s.", typeName, annotationName); diff -r 0f8c6dbf68be -r 6343a09b2ec1 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 Thu Jan 17 17:21:16 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Fri Jan 18 13:28:12 2013 +0100 @@ -33,7 +33,6 @@ import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; -import com.oracle.truffle.codegen.processor.operation.*; import com.oracle.truffle.codegen.processor.template.*; public class TypeSystemParser extends TemplateParser { @@ -61,31 +60,25 @@ return null; } - TypeMirror nodeType = Utils.getAnnotationValueType(templateTypeAnnotation, "nodeBaseClass"); TypeMirror genericType = context.getType(Object.class); + TypeData voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class)); - TypeData voidType = null; - if (Utils.getAnnotationValueBoolean(templateTypeAnnotation, "hasVoid")) { - voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class)); - } + TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, genericType, voidType); - TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, nodeType, genericType, voidType); - - if (!verifyNodeBaseType(typeSystem)) { + if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class)) { return null; } - if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class, GuardCheck.class)) { - return null; + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); + typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType, elements)); + if (typeSystem.getExtensionElements() != null) { + elements.addAll(typeSystem.getExtensionElements()); } - typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType)); + List casts = new TypeCastParser(context, typeSystem).parse(elements); + List checks = new TypeCheckParser(context, typeSystem).parse(elements); - List casts = parseMethods(typeSystem, new TypeCastParser(context, typeSystem)); - List checks = parseMethods(typeSystem, new TypeCheckParser(context, typeSystem)); - List guards = parseMethods(typeSystem, new GuardParser(context, typeSystem, typeSystem)); - - if (casts == null || checks == null || guards == null) { + if (casts == null || checks == null) { return null; } @@ -97,8 +90,6 @@ cast.getTargetType().addTypeCast(cast); } - typeSystem.setGuards(guards); - if (!verifyGenericTypeChecksAndCasts(types)) { return null; } @@ -155,43 +146,15 @@ return valid; } - private boolean verifyNodeBaseType(TypeSystemData typeSystem) { - List types = new ArrayList<>(Arrays.asList(typeSystem.getTypes())); - if (typeSystem.getVoidType() != null) { - types.add(typeSystem.getVoidType()); - } - - TypeMirror[] args = new TypeMirror[]{context.getTruffleTypes().getFrame()}; - List missingMethods = new ArrayList<>(); - for (TypeData typeData : types) { - String methodName = OperationCodeGenerator.executeMethodName(typeData); - ExecutableElement declared = Utils.getDeclaredMethodRecursive(Utils.fromTypeMirror(typeSystem.getNodeType()), methodName, args); - if (declared == null || declared.getModifiers().contains(Modifier.FINAL)) { - missingMethods.add(String.format("public %s %s(%s)", - Utils.getSimpleName(typeData.getPrimitiveType()), methodName, - Utils.getSimpleName(context.getTruffleTypes().getFrame()))); - } - } - - if (!missingMethods.isEmpty()) { - log.error(typeSystem.getTemplateType(), typeSystem.getTemplateTypeAnnotation(), - Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "nodeBaseClass"), - "The class '%s' does not declare the required non final method(s) %s.", - Utils.getQualifiedName(typeSystem.getNodeType()), missingMethods); - return false; - } - - return true; - } private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) { - List typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "types"); + List typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "value"); if (typeMirrors.size() == 0) { - log.error(templateType, templateTypeAnnotation, "At least one type child must be defined."); + log.error(templateType, templateTypeAnnotation, "At least one type must be defined."); return null; } - final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "types"); + final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "value"); final TypeMirror objectType = context.getType(Object.class); List types = new ArrayList<>();