# HG changeset patch # User Christian Humer # Date 1407765434 -7200 # Node ID 23415229349b16be51f58f3acff9ffcc6e2e25ae # Parent c5f8eeb3cbc848b45dc13612f71bf4300ec7b129 Truffle-DSL: new package structure. diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/AbstractParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/AbstractParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * 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.dsl.processor; - -import java.lang.annotation.*; -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; - -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.template.MessageContainer.*; - -/** - * THIS IS NOT PUBLIC API. - */ -public abstract class AbstractParser { - - protected final ProcessorContext context; - protected final ProcessingEnvironment processingEnv; - protected RoundEnvironment roundEnv; - - protected final Log log; - - public AbstractParser() { - this.context = ProcessorContext.getInstance(); - this.processingEnv = context.getEnvironment(); - this.log = context.getLog(); - } - - public final M parse(RoundEnvironment env, Element element) { - this.roundEnv = env; - M model = null; - try { - AnnotationMirror mirror = null; - if (getAnnotationType() != null) { - mirror = Utils.findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), getAnnotationType()); - } - - if (!context.getTruffleTypes().verify(context, element, mirror)) { - return null; - } - model = parse(element, mirror); - if (model == null) { - return null; - } - - redirectMessages(new HashSet(), model, model); - model.emitMessages(context, log); - return filterErrorElements(model); - } catch (CompileErrorException e) { - log.message(Kind.WARNING, element, null, null, "The truffle processor could not parse class due to error: %s", e.getMessage()); - return null; - } finally { - this.roundEnv = null; - } - } - - private void redirectMessages(Set visitedSinks, MessageContainer model, MessageContainer baseContainer) { - List messages = model.getMessages(); - for (int i = messages.size() - 1; i >= 0; i--) { - Message message = messages.get(i); - if (!Utils.isEnclosedIn(baseContainer.getMessageElement(), message.getOriginalContainer().getMessageElement())) { - // redirect message - MessageContainer original = message.getOriginalContainer(); - String text = wrapText(original.getMessageElement(), original.getMessageAnnotation(), message.getText()); - Message redirectedMessage = new Message(null, baseContainer, text, message.getKind()); - model.getMessages().remove(i); - baseContainer.getMessages().add(redirectedMessage); - } - } - - for (MessageContainer childContainer : model) { - if (visitedSinks.contains(childContainer)) { - continue; - } - visitedSinks.add(childContainer); - - MessageContainer newBase = baseContainer; - if (childContainer.getBaseContainer() != null) { - newBase = childContainer.getBaseContainer(); - } - redirectMessages(visitedSinks, childContainer, newBase); - } - } - - private static String wrapText(Element element, AnnotationMirror mirror, String text) { - StringBuilder b = new StringBuilder(); - if (element != null) { - b.append("Element " + element.toString()); - } - if (mirror != null) { - b.append(" at annotation @" + Utils.getSimpleName(mirror.getAnnotationType())); - } - - if (b.length() > 0) { - b.append(" is erroneous: ").append(text); - return b.toString(); - } else { - return text; - } - } - - protected M filterErrorElements(M model) { - return model.hasErrors() ? null : model; - } - - protected abstract M parse(Element element, AnnotationMirror mirror); - - public abstract Class 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 c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/AnnotationProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/AnnotationProcessor.java Mon Aug 11 15:53:05 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/AnnotationProcessor.java Mon Aug 11 15:57:14 2014 +0200 @@ -30,11 +30,13 @@ import javax.lang.model.type.*; import javax.tools.*; -import com.oracle.truffle.dsl.processor.ast.*; -import com.oracle.truffle.dsl.processor.codewriter.*; -import com.oracle.truffle.dsl.processor.compiler.*; -import com.oracle.truffle.dsl.processor.node.*; -import com.oracle.truffle.dsl.processor.template.*; +import com.oracle.truffle.dsl.processor.generator.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.compiler.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.java.transform.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.parser.*; /** * THIS IS NOT PUBLIC API. @@ -42,11 +44,11 @@ class AnnotationProcessor { private final AbstractParser parser; - private final CompilationUnitFactory factory; + private final AbstractCompilationUnitFactory factory; private final Set processedElements = new HashSet<>(); - public AnnotationProcessor(AbstractParser parser, CompilationUnitFactory factory) { + public AnnotationProcessor(AbstractParser parser, AbstractCompilationUnitFactory factory) { this.parser = parser; this.factory = factory; } @@ -56,11 +58,11 @@ } @SuppressWarnings({"unchecked"}) - public void process(RoundEnvironment env, Element element, boolean callback) { + public void process(Element element, boolean callback) { // since it is not guaranteed to be called only once by the compiler // we check for already processed elements to avoid errors when writing files. if (!callback && element instanceof TypeElement) { - String qualifiedName = Utils.getQualifiedName((TypeElement) element); + String qualifiedName = ElementUtils.getQualifiedName((TypeElement) element); if (processedElements.contains(qualifiedName)) { return; } @@ -75,12 +77,11 @@ if (firstRun || !callback) { context.registerTemplate(type, null); - model = parser.parse(env, element); + model = parser.parse(element); context.registerTemplate(type, model); if (model != null) { CodeCompilationUnit unit = factory.process(null, model); - patchGeneratedTypes(unit); unit.setGeneratorAnnotationMirror(model.getTemplateTypeAnnotation()); unit.setGeneratorElement(model.getTemplateType()); @@ -96,55 +97,6 @@ } } - private static void patchGeneratedTypes(CodeCompilationUnit unit) { - final Map classes = new HashMap<>(); - - unit.accept(new CodeElementScanner() { - @Override - public Void visitType(CodeTypeElement e, Void p) { - classes.put(e.getSimpleName().toString(), e); - return super.visitType(e, p); - } - - }, null); - - unit.accept(new CodeElementScanner() { - @Override - public Void visitExecutable(CodeExecutableElement e, Void p) { - if (e.getReturnType() instanceof GeneratedTypeMirror) { - e.setReturnType(patchType(e.getReturnType())); - } - for (VariableElement element : e.getParameters()) { - if (element instanceof CodeVariableElement) { - CodeVariableElement var = ((CodeVariableElement) element); - if (var.getType() instanceof GeneratedTypeMirror) { - var.setType(patchType(var.getType())); - } - } - } - return super.visitExecutable(e, p); - } - - @Override - public void visitTree(CodeTree e, Void p) { - if (e.getType() instanceof GeneratedTypeMirror) { - e.setType(patchType(e.asType())); - } - } - - private TypeMirror patchType(TypeMirror typeMirror) { - assert typeMirror instanceof GeneratedTypeMirror; - GeneratedTypeMirror type = (GeneratedTypeMirror) typeMirror; - CodeTypeElement generatedType = classes.get(Utils.fromTypeMirror(type).getSimpleName().toString()); - if (generatedType == null) { - return type; - } - return generatedType.asType(); - } - }, null); - - } - private static class CodeWriter extends AbstractCodeWriter { private final Element originalElement; diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java Mon Aug 11 15:53:05 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java Mon Aug 11 15:57:14 2014 +0200 @@ -26,7 +26,7 @@ import javax.lang.model.element.*; import javax.tools.Diagnostic.Kind; -import com.oracle.truffle.dsl.processor.ast.*; +import com.oracle.truffle.dsl.processor.java.model.*; /** * THIS IS NOT PUBLIC API. diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Mon Aug 11 15:53:05 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java Mon Aug 11 15:57:14 2014 +0200 @@ -22,8 +22,6 @@ */ package com.oracle.truffle.dsl.processor; -import static com.oracle.truffle.dsl.processor.Utils.*; - import java.util.*; import javax.annotation.processing.*; @@ -31,9 +29,9 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; -import com.oracle.truffle.dsl.processor.ast.*; -import com.oracle.truffle.dsl.processor.ast.CodeTypeMirror.ArrayCodeTypeMirror; -import com.oracle.truffle.dsl.processor.template.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; /** * THIS IS NOT PUBLIC API. @@ -43,13 +41,12 @@ private final ProcessingEnvironment environment; private final Map models = new HashMap<>(); - private final Map> generatedClasses = new HashMap<>(); private final ProcessCallback callback; private final Log log; private final TruffleTypes truffleTypes; - public ProcessorContext(ProcessingEnvironment env, ProcessCallback callback) { + ProcessorContext(ProcessingEnvironment env, ProcessCallback callback) { this.environment = env; this.callback = callback; this.log = new Log(environment); @@ -69,86 +66,23 @@ } public boolean containsTemplate(TypeElement element) { - return models.containsKey(Utils.getQualifiedName(element)); + return models.containsKey(ElementUtils.getQualifiedName(element)); } public void registerTemplate(TypeElement element, Template model) { - models.put(Utils.getQualifiedName(element), model); - } - - public void registerType(TypeElement templateType, TypeMirror generatedTypeMirror) { - String templateQualifiedName = getQualifiedName(templateType); - Map simpleNameToType = generatedClasses.get(templateQualifiedName); - if (simpleNameToType == null) { - simpleNameToType = new HashMap<>(); - generatedClasses.put(templateQualifiedName, simpleNameToType); - } - String generatedSimpleName = getSimpleName(generatedTypeMirror); - simpleNameToType.put(generatedSimpleName, generatedTypeMirror); + models.put(ElementUtils.getQualifiedName(element), model); } public Template getTemplate(TypeMirror templateTypeMirror, boolean invokeCallback) { - String qualifiedName = Utils.getQualifiedName(templateTypeMirror); + String qualifiedName = ElementUtils.getQualifiedName(templateTypeMirror); Template model = models.get(qualifiedName); if (model == null && invokeCallback) { - callback.callback(Utils.fromTypeMirror(templateTypeMirror)); + callback.callback(ElementUtils.fromTypeMirror(templateTypeMirror)); model = models.get(qualifiedName); } return model; } - public TypeMirror resolveNotYetCompiledType(TypeMirror mirror, Template templateHint) { - TypeMirror resolvedType = null; - if (mirror.getKind() == TypeKind.ARRAY) { - TypeMirror originalComponentType = ((ArrayType) mirror).getComponentType(); - TypeMirror resolvedComponent = resolveNotYetCompiledType(originalComponentType, templateHint); - if (resolvedComponent != originalComponentType) { - return new ArrayCodeTypeMirror(resolvedComponent); - } - } - - if (mirror.getKind() == TypeKind.ERROR) { - Element element = ((ErrorType) mirror).asElement(); - ElementKind kind = element.getKind(); - if (kind == ElementKind.CLASS || kind == ElementKind.PARAMETER || kind == ElementKind.ENUM) { - String simpleName = element.getSimpleName().toString(); - resolvedType = findGeneratedClassBySimpleName(simpleName, templateHint); - } - } else { - resolvedType = mirror; - } - - return resolvedType; - } - - public TypeMirror findGeneratedClassBySimpleName(String simpleName, Template templateHint) { - if (templateHint == null) { - // search all - for (String qualifiedTemplateName : generatedClasses.keySet()) { - Map mirrors = generatedClasses.get(qualifiedTemplateName); - if (mirrors.get(simpleName) != null) { - return mirrors.get(simpleName); - } - } - return null; - } else { - String templateQualifiedName = getQualifiedName(templateHint.getTemplateType()); - Map simpleNameToType = generatedClasses.get(templateQualifiedName); - if (simpleNameToType == null) { - return null; - } - return simpleNameToType.get(simpleName); - } - } - - public TypeMirror getType(String className) { - TypeElement element = environment.getElementUtils().getTypeElement(className); - if (element != null) { - return element.asType(); - } - return null; - } - public TypeMirror getType(Class element) { TypeMirror mirror; if (element.isPrimitive()) { @@ -191,6 +125,14 @@ return getType(type.getQualifiedName().toString()); } + private TypeMirror getType(String className) { + TypeElement element = environment.getElementUtils().getTypeElement(className); + if (element != null) { + return element.asType(); + } + return null; + } + public TypeMirror reloadType(TypeMirror type) { if (type instanceof CodeTypeMirror) { return type; diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java Mon Aug 11 15:53:05 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleProcessor.java Mon Aug 11 15:57:14 2014 +0200 @@ -31,8 +31,9 @@ import javax.tools.Diagnostic.Kind; import com.oracle.truffle.dsl.processor.ProcessorContext.ProcessCallback; -import com.oracle.truffle.dsl.processor.node.*; -import com.oracle.truffle.dsl.processor.typesystem.*; +import com.oracle.truffle.dsl.processor.generator.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.parser.*; /** * THIS IS NOT PUBLIC API. @@ -44,8 +45,6 @@ private List> generators; - private RoundEnvironment round; - @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { @@ -55,7 +54,6 @@ } 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 { @@ -64,7 +62,7 @@ AbstractParser parser = generator.getParser(); if (parser.getAnnotationType() != null) { for (Element e : env.getElementsAnnotatedWith(parser.getAnnotationType())) { - processElement(env, generator, e, false); + processElement(generator, e, false); } } @@ -72,24 +70,23 @@ for (Element e : env.getElementsAnnotatedWith(annotationType)) { TypeElement processedType; if (parser.isDelegateToRootDeclaredType()) { - processedType = Utils.findRootEnclosingType(e); + processedType = ElementUtils.findRootEnclosingType(e); } else { - processedType = Utils.findNearestEnclosingType(e); + processedType = ElementUtils.findNearestEnclosingType(e); } - processElement(env, generator, processedType, false); + processElement(generator, processedType, false); } } } } finally { ProcessorContext.setThreadLocalInstance(null); - this.round = null; } } - private static void processElement(RoundEnvironment env, AnnotationProcessor generator, Element e, boolean callback) { + private static void processElement(AnnotationProcessor generator, Element e, boolean callback) { try { - generator.process(env, e, callback); + generator.process(e, callback); } catch (Throwable e1) { handleThrowable(generator, e1, e); } @@ -97,7 +94,7 @@ private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) { String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e; - ProcessorContext.getInstance().getEnvironment().getMessager().printMessage(Kind.ERROR, message + ": " + Utils.printException(t), e); + ProcessorContext.getInstance().getEnvironment().getMessager().printMessage(Kind.ERROR, message + ": " + ElementUtils.printException(t), e); } @Override @@ -107,7 +104,7 @@ if (annotationType != null) { Annotation annotation = template.getAnnotation(annotationType); if (annotation != null) { - processElement(round, generator, template, true); + processElement(generator, template, true); } } } diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Aug 11 15:53:05 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java Mon Aug 11 15:57:14 2014 +0200 @@ -73,7 +73,7 @@ private final List errors = new ArrayList<>(); - public TruffleTypes(ProcessorContext context) { + TruffleTypes(ProcessorContext context) { node = getRequired(context, Node.class); nodeArray = context.getEnvironment().getTypeUtils().getArrayType(node); unexpectedValueException = getRequired(context, UnexpectedResultException.class); diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Utils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Utils.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1012 +0,0 @@ -/* - * 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.dsl.processor; - -import java.io.*; -import java.lang.annotation.*; -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.ast.*; -import com.oracle.truffle.dsl.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror; -import com.oracle.truffle.dsl.processor.compiler.*; - -/** - * THIS IS NOT PUBLIC API. - */ -public class Utils { - - public static ExecutableElement findExecutableElement(DeclaredType type, String name) { - List elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); - for (ExecutableElement executableElement : elements) { - if (executableElement.getSimpleName().toString().equals(name)) { - return executableElement; - } - } - return null; - } - - public static boolean needsCastTo(TypeMirror sourceType, TypeMirror targetType) { - if (typeEquals(sourceType, targetType)) { - return false; - } else if (isObject(targetType)) { - return false; - } else if (isVoid(targetType)) { - return false; - } else if (isAssignable(sourceType, targetType)) { - return false; - } - return true; - } - - public static VariableElement findVariableElement(DeclaredType type, String name) { - List elements = ElementFilter.fieldsIn(type.asElement().getEnclosedElements()); - for (VariableElement variableElement : elements) { - if (variableElement.getSimpleName().toString().equals(name)) { - return variableElement; - } - } - return null; - } - - public static String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { - if (method instanceof CodeExecutableElement) { - return ((CodeExecutableElement) method).getBody(); - } else { - return CompilerFactory.getCompiler(method).getMethodBody(env, method); - } - } - - public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) { - TypeMirror boxedType = primitiveType; - if (boxedType.getKind().isPrimitive()) { - boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); - } - return boxedType; - } - - public static List asTypeMirrors(List elements) { - List types = new ArrayList<>(elements.size()); - for (Element element : elements) { - types.add(element.asType()); - } - return types; - } - - public static DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { - return new DeclaredCodeTypeMirror(typeElem, Arrays.asList(typeArgs)); - } - - public static List collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, - Class annotationClass) { - List result = new ArrayList<>(); - if (markerAnnotation != null) { - result.addAll(Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName)); - } - AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); - if (explicit != null) { - result.add(explicit); - } - return result; - } - - public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) { - if (types.length == 0) { - return context.getType(Object.class); - } - TypeMirror prev = types[0]; - for (int i = 1; i < types.length; i++) { - prev = getCommonSuperType(context, prev, types[i]); - } - return prev; - } - - private static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror type1, TypeMirror type2) { - if (typeEquals(type1, type2)) { - return type1; - } - TypeElement element1 = fromTypeMirror(type1); - TypeElement element2 = fromTypeMirror(type2); - if (element1 == null || element2 == null) { - return context.getType(Object.class); - } - - List element1Types = getDirectSuperTypes(element1); - element1Types.add(0, element1); - List element2Types = getDirectSuperTypes(element2); - element2Types.add(0, element2); - - for (TypeElement superType1 : element1Types) { - for (TypeElement superType2 : element2Types) { - if (typeEquals(superType1.asType(), superType2.asType())) { - return superType2.asType(); - } - } - } - return context.getType(Object.class); - } - - 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: - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case INT: - case SHORT: - case LONG: - case DECLARED: - case VOID: - case TYPEVAR: - return false; - case ARRAY: - return hasError(((ArrayType) mirror).getComponentType()); - case ERROR: - return true; - default: - throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); - } - } - - public static boolean isSubtype(TypeMirror type1, TypeMirror type2) { - if (type1 instanceof CodeTypeMirror && type2 instanceof CodeTypeMirror) { - throw new UnsupportedOperationException(); - } - return ProcessorContext.getInstance().getEnvironment().getTypeUtils().isSubtype(type1, type2); - } - - public static boolean isAssignable(TypeMirror from, TypeMirror to) { - ProcessorContext context = ProcessorContext.getInstance(); - - if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) { - return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to)); - } else { - return isAssignableImpl(from, to); - } - } - - private static boolean isAssignableImpl(TypeMirror from, TypeMirror to) { - // JLS 5.1.1 identity conversion - if (Utils.typeEquals(from, to)) { - return true; - } - - if (isObject(to)) { - return true; - } - - // JLS 5.1.2 widening primitives - if (Utils.isPrimitive(from) && Utils.isPrimitive(to)) { - TypeKind fromKind = from.getKind(); - TypeKind toKind = to.getKind(); - switch (fromKind) { - case BYTE: - switch (toKind) { - case SHORT: - case INT: - case LONG: - case FLOAT: - case DOUBLE: - return true; - } - break; - case SHORT: - switch (toKind) { - case INT: - case LONG: - case FLOAT: - case DOUBLE: - return true; - } - break; - case CHAR: - switch (toKind) { - case INT: - case LONG: - case FLOAT: - case DOUBLE: - return true; - } - break; - case INT: - switch (toKind) { - case LONG: - case FLOAT: - case DOUBLE: - return true; - } - break; - case LONG: - switch (toKind) { - case FLOAT: - case DOUBLE: - return true; - } - break; - case FLOAT: - switch (toKind) { - case DOUBLE: - return true; - } - break; - - } - return false; - } else if (Utils.isPrimitive(from) || Utils.isPrimitive(to)) { - return false; - } - - if (from instanceof ArrayType && to instanceof ArrayType) { - return isAssignable(((ArrayType) from).getComponentType(), ((ArrayType) to).getComponentType()); - } - - if (from instanceof ArrayType || to instanceof ArrayType) { - return false; - } - - TypeElement fromType = Utils.fromTypeMirror(from); - TypeElement toType = Utils.fromTypeMirror(to); - if (fromType == null || toType == null) { - return false; - } - // JLS 5.1.6 narrowing reference conversion - - List superTypes = Utils.getSuperTypes(fromType); - for (TypeElement superType : superTypes) { - if (Utils.typeEquals(superType.asType(), to)) { - return true; - } - } - - // TODO more spec - return false; - } - - public static Set modifiers(Modifier... modifier) { - return new LinkedHashSet<>(Arrays.asList(modifier)); - } - - public static String getTypeId(TypeMirror mirror) { - switch (mirror.getKind()) { - case BOOLEAN: - return "Boolean"; - case BYTE: - return "Byte"; - case CHAR: - return "Char"; - case DOUBLE: - return "Double"; - case FLOAT: - return "Float"; - case SHORT: - return "Short"; - case INT: - return "Int"; - case LONG: - return "Long"; - case DECLARED: - return fixECJBinaryNameIssue(((DeclaredType) mirror).asElement().getSimpleName().toString()); - case ARRAY: - return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; - case VOID: - return "Void"; - case WILDCARD: - StringBuilder b = new StringBuilder(); - WildcardType type = (WildcardType) mirror; - if (type.getExtendsBound() != null) { - b.append("Extends").append(getTypeId(type.getExtendsBound())); - } else if (type.getSuperBound() != null) { - b.append("Super").append(getTypeId(type.getExtendsBound())); - } - return b.toString(); - case TYPEVAR: - return "Any"; - case ERROR: - throw new CompileErrorException("Type error " + mirror); - default: - throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); - } - } - - public static String getSimpleName(TypeElement element) { - return getSimpleName(element.asType()); - } - - public static String getSimpleName(TypeMirror mirror) { - switch (mirror.getKind()) { - case BOOLEAN: - return "boolean"; - case BYTE: - return "byte"; - case CHAR: - return "char"; - case DOUBLE: - return "double"; - case FLOAT: - return "float"; - case SHORT: - return "short"; - case INT: - return "int"; - case LONG: - return "long"; - case DECLARED: - return getDeclaredName((DeclaredType) mirror); - case ARRAY: - return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; - case VOID: - return "void"; - case WILDCARD: - return getWildcardName((WildcardType) mirror); - case TYPEVAR: - return "?"; - case ERROR: - throw new CompileErrorException("Type error " + mirror); - default: - throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); - } - } - - private static String getWildcardName(WildcardType type) { - StringBuilder b = new StringBuilder(); - if (type.getExtendsBound() != null) { - b.append("? extends ").append(getSimpleName(type.getExtendsBound())); - } else if (type.getSuperBound() != null) { - b.append("? super ").append(getSimpleName(type.getExtendsBound())); - } - return b.toString(); - } - - private static String getDeclaredName(DeclaredType element) { - String simpleName = fixECJBinaryNameIssue(element.asElement().getSimpleName().toString()); - - if (element.getTypeArguments().size() == 0) { - return simpleName; - } - - StringBuilder b = new StringBuilder(simpleName); - b.append("<"); - if (element.getTypeArguments().size() > 0) { - for (int i = 0; i < element.getTypeArguments().size(); i++) { - b.append(getSimpleName(element.getTypeArguments().get(i))); - if (i < element.getTypeArguments().size() - 1) { - b.append(", "); - } - } - } - b.append(">"); - return b.toString(); - } - - public static String fixECJBinaryNameIssue(String name) { - if (name.contains("$")) { - int lastIndex = name.lastIndexOf('$'); - return name.substring(lastIndex + 1, name.length()); - } - return name; - } - - public static String getQualifiedName(TypeElement element) { - String qualifiedName = element.getQualifiedName().toString(); - if (qualifiedName.contains("$")) { - /* - * If a class gets loaded in its binary form by the ECJ compiler it fails to produce the - * proper canonical class name. It leaves the $ in the qualified name of the class. So - * one instance of a TypeElement may be loaded in binary and one in source form. The - * current type comparison in #typeEquals compares by the qualified name so the - * qualified name must match. This is basically a hack to fix the returned qualified - * name of eclipse. - */ - qualifiedName = qualifiedName.replace('$', '.'); - } - return qualifiedName; - } - - public static String getQualifiedName(TypeMirror mirror) { - switch (mirror.getKind()) { - case BOOLEAN: - return "boolean"; - case BYTE: - return "byte"; - case CHAR: - return "char"; - case DOUBLE: - return "double"; - case SHORT: - return "short"; - case FLOAT: - return "float"; - case INT: - return "int"; - case LONG: - return "long"; - case DECLARED: - return getQualifiedName(fromTypeMirror(mirror)); - case ARRAY: - return getQualifiedName(((ArrayType) mirror).getComponentType()); - case VOID: - return "void"; - case TYPEVAR: - return getSimpleName(mirror); - case ERROR: - throw new CompileErrorException("Type error " + mirror); - case EXECUTABLE: - return ((ExecutableType) mirror).toString(); - case NONE: - return "$none"; - default: - throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror); - } - } - - public static boolean isVoid(TypeMirror mirror) { - return mirror != null && mirror.getKind() == TypeKind.VOID; - } - - public static boolean isPrimitive(TypeMirror mirror) { - return mirror != null && mirror.getKind().isPrimitive(); - } - - public static boolean isPrimitiveOrVoid(TypeMirror mirror) { - return isPrimitive(mirror) || isVoid(mirror); - } - - public static List getQualifiedSuperTypeNames(TypeElement element) { - List types = getSuperTypes(element); - List qualifiedNames = new ArrayList<>(); - for (TypeElement type : types) { - qualifiedNames.add(getQualifiedName(type)); - } - return qualifiedNames; - } - - public static List getDeclaredTypes(TypeElement element) { - return ElementFilter.typesIn(element.getEnclosedElements()); - } - - public static VariableElement findDeclaredField(TypeMirror type, String singletonName) { - List elements = ElementFilter.fieldsIn(fromTypeMirror(type).getEnclosedElements()); - for (VariableElement var : elements) { - if (var.getSimpleName().toString().equals(singletonName)) { - return var; - } - } - return null; - } - - public static boolean isEnclosedIn(Element enclosedIn, Element element) { - if (element == null) { - return false; - } else if (enclosedIn.equals(element)) { - return true; - } else { - return isEnclosedIn(enclosedIn, 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 null; - } - - public 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 getDirectSuperTypes(TypeElement element) { - List types = new ArrayList<>(); - if (element.getSuperclass() != null) { - TypeElement superElement = fromTypeMirror(element.getSuperclass()); - if (superElement != null) { - types.add(superElement); - types.addAll(getDirectSuperTypes(superElement)); - } - } - - return types; - } - - public static List getAssignableTypes(ProcessorContext context, TypeMirror type) { - if (isPrimitive(type)) { - return Arrays.asList(type, boxType(context, type), context.getType(Object.class)); - } else if (type.getKind() == TypeKind.ARRAY) { - return Arrays.asList(type, context.getType(Object.class)); - } else if (type.getKind() == TypeKind.DECLARED) { - List types = getSuperTypes(fromTypeMirror(type)); - List mirrors = new ArrayList<>(types.size()); - mirrors.add(type); - for (TypeElement typeElement : types) { - mirrors.add(typeElement.asType()); - } - return mirrors; - } else { - return Collections.emptyList(); - } - } - - public static List getSuperTypes(TypeElement element) { - List types = new ArrayList<>(); - List superTypes = null; - List superInterfaces = null; - if (element.getSuperclass() != null) { - TypeElement superElement = fromTypeMirror(element.getSuperclass()); - if (superElement != null) { - types.add(superElement); - superTypes = getSuperTypes(superElement); - } - } - for (TypeMirror interfaceMirror : element.getInterfaces()) { - TypeElement interfaceElement = fromTypeMirror(interfaceMirror); - if (interfaceElement != null) { - types.add(interfaceElement); - superInterfaces = getSuperTypes(interfaceElement); - } - } - - if (superTypes != null) { - types.addAll(superTypes); - } - - if (superInterfaces != null) { - types.addAll(superInterfaces); - } - - return types; - } - - public static String getPackageName(TypeElement element) { - return findPackageElement(element).getQualifiedName().toString(); - } - - public static String getPackageName(TypeMirror mirror) { - switch (mirror.getKind()) { - case BOOLEAN: - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case SHORT: - case INT: - case LONG: - case VOID: - case TYPEVAR: - return null; - case DECLARED: - PackageElement pack = findPackageElement(fromTypeMirror(mirror)); - if (pack == null) { - throw new IllegalArgumentException("No package element found for declared type " + getSimpleName(mirror)); - } - return pack.getQualifiedName().toString(); - case ARRAY: - return getSimpleName(((ArrayType) mirror).getComponentType()); - default: - throw new RuntimeException("Unknown type specified " + mirror.getKind()); - } - } - - public static String createConstantName(String simpleName) { - // TODO use camel case to produce underscores. - return simpleName.toString().toUpperCase(); - } - - public static TypeElement fromTypeMirror(TypeMirror mirror) { - switch (mirror.getKind()) { - case DECLARED: - return (TypeElement) ((DeclaredType) mirror).asElement(); - case ARRAY: - return fromTypeMirror(((ArrayType) mirror).getComponentType()); - default: - return null; - } - } - - @SuppressWarnings("unchecked") - public static List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { - List values = getAnnotationValue(List.class, mirror, name); - List result = new ArrayList<>(); - - if (values != null) { - for (AnnotationValue value : values) { - T annotationValue = resolveAnnotationValue(expectedListType, value); - if (annotationValue != null) { - result.add(annotationValue); - } - } - } - return result; - } - - public static T getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { - return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); - } - - @SuppressWarnings({"unchecked"}) - private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { - if (value == null) { - return null; - } - - Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); - if (unboxedValue != null) { - if (expectedType == TypeMirror.class && unboxedValue instanceof String) { - return null; - } - if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { - throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); - } - } - return (T) unboxedValue; - } - - public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { - ExecutableElement valueMethod = null; - for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) { - if (method.getSimpleName().toString().equals(name)) { - valueMethod = method; - break; - } - } - - if (valueMethod == null) { - return null; - } - - AnnotationValue value = mirror.getElementValues().get(valueMethod); - if (value == null) { - value = valueMethod.getDefaultValue(); - } - - return value; - } - - private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7 { - - @Override - public Object visitBoolean(boolean b, Void p) { - return Boolean.valueOf(b); - } - - @Override - public Object visitByte(byte b, Void p) { - return Byte.valueOf(b); - } - - @Override - public Object visitChar(char c, Void p) { - return c; - } - - @Override - public Object visitDouble(double d, Void p) { - return d; - } - - @Override - public Object visitFloat(float f, Void p) { - return f; - } - - @Override - public Object visitInt(int i, Void p) { - return i; - } - - @Override - public Object visitLong(long i, Void p) { - return i; - } - - @Override - public Object visitShort(short s, Void p) { - return s; - } - - @Override - public Object visitString(String s, Void p) { - return s; - } - - @Override - public Object visitType(TypeMirror t, Void p) { - return t; - } - - @Override - public Object visitEnumConstant(VariableElement c, Void p) { - return c; - } - - @Override - public Object visitAnnotation(AnnotationMirror a, Void p) { - return a; - } - - @Override - public Object visitArray(List vals, Void p) { - return vals; - } - - } - - public static String printException(Throwable e) { - StringWriter string = new StringWriter(); - PrintWriter writer = new PrintWriter(string); - e.printStackTrace(writer); - writer.flush(); - return e.getMessage() + "\r\n" + string.toString(); - } - - public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, Element element, Class annotationClass) { - return findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), annotationClass); - } - - public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List mirrors, Class annotationClass) { - TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName()); - return findAnnotationMirror(mirrors, expectedAnnotationType); - } - - public static AnnotationMirror findAnnotationMirror(List mirrors, TypeElement expectedAnnotationType) { - for (AnnotationMirror mirror : mirrors) { - DeclaredType annotationType = mirror.getAnnotationType(); - TypeElement actualAnnotationType = (TypeElement) annotationType.asElement(); - if (actualAnnotationType.equals(expectedAnnotationType)) { - return mirror; - } - } - return null; - } - - private static PackageElement findPackageElement(Element type) { - List hierarchy = getElementHierarchy(type); - for (Element element : hierarchy) { - if (element.getKind() == ElementKind.PACKAGE) { - return (PackageElement) element; - } - } - return null; - } - - public static String firstLetterUpperCase(String name) { - if (name == null || name.isEmpty()) { - return name; - } - return Character.toUpperCase(name.charAt(0)) + name.substring(1, name.length()); - } - - public static String firstLetterLowerCase(String name) { - if (name == null || name.isEmpty()) { - return name; - } - return Character.toLowerCase(name.charAt(0)) + name.substring(1, name.length()); - } - - private static ExecutableElement getDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { - List methods = ElementFilter.methodsIn(element.getEnclosedElements()); - method: for (ExecutableElement method : methods) { - if (!method.getSimpleName().toString().equals(name)) { - continue; - } - if (method.getParameters().size() != params.length) { - continue; - } - for (int i = 0; i < params.length; i++) { - TypeMirror param1 = params[i]; - TypeMirror param2 = method.getParameters().get(i).asType(); - if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) { - if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { - continue method; - } - } - } - return method; - } - return null; - } - - private static boolean isDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { - return getDeclaredMethod(element, name, params) != null; - } - - public static boolean isDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { - List superElements = getSuperTypes(element); - - for (TypeElement typeElement : superElements) { - if (isDeclaredMethod(typeElement, name, params)) { - return true; - } - } - return false; - } - - private static ExecutableElement getDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { - List superElements = getSuperTypes(element); - - for (TypeElement typeElement : superElements) { - ExecutableElement declared = getDeclaredMethod(typeElement, name, params); - if (declared != null) { - return declared; - } - } - return null; - } - - public static ExecutableElement getDeclaredMethodRecursive(TypeElement element, String name, TypeMirror[] params) { - ExecutableElement declared = getDeclaredMethod(element, name, params); - if (declared != null) { - return declared; - } - return getDeclaredMethodInSuperType(element, name, params); - } - - public static boolean typeEquals(TypeMirror type1, TypeMirror type2) { - if (type1 == null && type2 == null) { - return true; - } else if (type1 == null || type2 == null) { - return false; - } else if (type1 == type2) { - return true; - } - String qualified1 = getQualifiedName(type1); - String qualified2 = getQualifiedName(type2); - - if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) { - if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) { - return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType()); - } else { - return false; - } - } - return qualified1.equals(qualified2); - } - - public static int compareByTypeHierarchy(TypeMirror t1, TypeMirror t2) { - if (typeEquals(t1, t2)) { - return 0; - } - Set t1SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t1))); - if (t1SuperSet.contains(getQualifiedName(t2))) { - return -1; - } - - Set t2SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t2))); - if (t2SuperSet.contains(getQualifiedName(t1))) { - return 1; - } - return 0; - } - - public static boolean canThrowType(List thrownTypes, TypeMirror exceptionType) { - if (Utils.containsType(thrownTypes, exceptionType)) { - return true; - } - - if (isRuntimeException(exceptionType)) { - return true; - } - - // search for any super types - TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); - List superTypes = getSuperTypes(exceptionTypeElement); - for (TypeElement typeElement : superTypes) { - if (Utils.containsType(thrownTypes, typeElement.asType())) { - return true; - } - } - - return false; - } - - public static Modifier getVisibility(Set modifier) { - for (Modifier mod : modifier) { - if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) { - return mod; - } - } - return null; - } - - private static boolean isRuntimeException(TypeMirror type) { - Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); - String typeName = getQualifiedName(type); - if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { - throw new IllegalArgumentException("Given type does not extend Throwable."); - } - return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); - } - - private static boolean containsType(Collection collection, TypeMirror type) { - for (TypeMirror otherTypeMirror : collection) { - if (typeEquals(otherTypeMirror, type)) { - return true; - } - } - 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; - } - - public static boolean isObject(TypeMirror actualType) { - return actualType.getKind() == TypeKind.DECLARED && getQualifiedName(actualType).equals("java.lang.Object"); - } - - public static boolean isFieldAccessible(Element element, VariableElement variable) { - TypeElement type = Utils.findNearestEnclosingType(element); - TypeElement varType = Utils.findNearestEnclosingType(variable); - - while (type != null) { - if (typeEquals(type.asType(), varType.asType())) { - return true; - } - if (type.getSuperclass() != null) { - type = Utils.fromTypeMirror(type.getSuperclass()); - } else { - type = null; - } - } - return false; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeAnnotationMirror.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeAnnotationMirror.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public class CodeAnnotationMirror implements AnnotationMirror { - - private final DeclaredType annotationType; - private final Map values = new LinkedHashMap<>(); - - public CodeAnnotationMirror(DeclaredType annotationType) { - this.annotationType = annotationType; - } - - @Override - public DeclaredType getAnnotationType() { - return annotationType; - } - - @Override - public Map getElementValues() { - return values; - } - - public AnnotationValue getElementValue(ExecutableElement method) { - return values.get(method); - } - - public void setElementValue(ExecutableElement method, AnnotationValue value) { - values.put(method, value); - } - - public ExecutableElement findExecutableElement(String name) { - return Utils.findExecutableElement(annotationType, name); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeAnnotationValue.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeAnnotationValue.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public class CodeAnnotationValue implements AnnotationValue { - - private final Object value; - - public CodeAnnotationValue(Object value) { - Objects.requireNonNull(value); - if ((value instanceof AnnotationMirror) || (value instanceof List) || (value instanceof Boolean) || (value instanceof Byte) || (value instanceof Character) || (value instanceof Double) || - (value instanceof VariableElement) || (value instanceof Float) || (value instanceof Integer) || (value instanceof Long) || (value instanceof Short) || - (value instanceof String) || (value instanceof TypeMirror)) { - this.value = value; - } else { - throw new IllegalArgumentException("Invalid annotation value type " + value.getClass().getName()); - } - } - - @Override - public Object getValue() { - return value; - } - - @SuppressWarnings("unchecked") - @Override - public R accept(AnnotationValueVisitor v, P p) { - if (value instanceof AnnotationMirror) { - return v.visitAnnotation((AnnotationMirror) value, p); - } else if (value instanceof List) { - return v.visitArray((List) value, p); - } else if (value instanceof Boolean) { - return v.visitBoolean((boolean) value, p); - } else if (value instanceof Byte) { - return v.visitByte((byte) value, p); - } else if (value instanceof Character) { - return v.visitChar((char) value, p); - } else if (value instanceof Double) { - return v.visitDouble((double) value, p); - } else if (value instanceof VariableElement) { - return v.visitEnumConstant((VariableElement) value, p); - } else if (value instanceof Float) { - return v.visitFloat((float) value, p); - } else if (value instanceof Integer) { - return v.visitInt((int) value, p); - } else if (value instanceof Long) { - return v.visitLong((long) value, p); - } else if (value instanceof Short) { - return v.visitShort((short) value, p); - } else if (value instanceof String) { - return v.visitString((String) value, p); - } else if (value instanceof TypeMirror) { - return v.visitType((TypeMirror) value, p); - } else { - return v.visitUnknown(this, p); - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeCompilationUnit.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeCompilationUnit.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public class CodeCompilationUnit extends CodeElement { - - public CodeCompilationUnit() { - super(Collections. emptySet()); - } - - @Override - public TypeMirror asType() { - throw new UnsupportedOperationException(); - } - - @Override - public ElementKind getKind() { - return ElementKind.OTHER; - } - - @Override - public Name getSimpleName() { - throw new UnsupportedOperationException(); - } - - @Override - public R accept(ElementVisitor v, P p) { - for (Element type : getEnclosedElements()) { - if (type.getKind().isClass()) { - type.accept(v, p); - } else { - throw new ClassCastException(type.getClass().getName()); - } - } - return null; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,365 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.io.*; -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.codewriter.*; - -public abstract class CodeElement implements Element, GeneratedElement { - - private final Set modifiers; - private List annotations; - private List enclosedElements; - - private Element enclosingElement; - - private Element generatorElement; - private AnnotationMirror generatorAnnotationMirror; - - public CodeElement() { - this.modifiers = new LinkedHashSet<>(); - } - - public CodeElement(Set modifiers) { - this.modifiers = new LinkedHashSet<>(modifiers); - } - - @Override - public void setGeneratorAnnotationMirror(AnnotationMirror mirror) { - this.generatorAnnotationMirror = mirror; - } - - @Override - public void setGeneratorElement(Element element) { - this.generatorElement = element; - } - - @Override - public AnnotationMirror getGeneratorAnnotationMirror() { - return generatorAnnotationMirror; - } - - @Override - public Element getGeneratorElement() { - return generatorElement; - } - - public E add(E element) { - if (element == null) { - throw new NullPointerException(); - } - getEnclosedElements().add(element); - return element; - } - - public E addOptional(E element) { - if (element != null) { - add(element); - } - return element; - } - - public void remove(E element) { - getEnclosedElements().remove(element); - } - - @Override - public Set getModifiers() { - return modifiers; - } - - @Override - public List getEnclosedElements() { - if (enclosedElements == null) { - enclosedElements = parentableList(this, new ArrayList()); - } - return enclosedElements; - } - - @Override - public List getAnnotationMirrors() { - if (annotations == null) { - annotations = parentableList(this, new ArrayList()); - } - return annotations; - } - - /** - * Support JDK8 langtools. - * - * @param annotationType - */ - public A[] getAnnotationsByType(Class annotationType) { - throw new UnsupportedOperationException(); - } - - /** - * Support for some JDK8 builds. (remove after jdk8 is released) - * - * @param annotationType - */ - public A[] getAnnotations(Class annotationType) { - throw new UnsupportedOperationException(); - } - - /** - * Support for some JDK8 builds. (remove after jdk8 is released) - * - * @param annotationType - */ - public A getAnnotation(Class annotationType) { - throw new UnsupportedOperationException(); - } - - public void addAnnotationMirror(AnnotationMirror annotationMirror) { - getAnnotationMirrors().add(annotationMirror); - } - - public void removeAnnotationMirror(AnnotationMirror annotationMirror) { - getAnnotationMirrors().remove(annotationMirror); - } - - protected void setEnclosingElement(Element parent) { - this.enclosingElement = parent; - } - - public Element getEnclosingElement() { - return enclosingElement; - } - - public CodeTypeElement getEnclosingClass() { - Element p = enclosingElement; - while (p != null && p.getKind() != ElementKind.CLASS && p.getKind() != ElementKind.ENUM) { - p = p.getEnclosingElement(); - } - return (CodeTypeElement) p; - } - - List parentableList(Element parent, List list) { - return new ParentableList<>(parent, list); - } - - @Override - public String toString() { - StringBuilderCodeWriter codeWriter = new StringBuilderCodeWriter(); - accept(codeWriter, null); - return codeWriter.getString(); - } - - private static class StringBuilderCodeWriter extends AbstractCodeWriter { - - public StringBuilderCodeWriter() { - this.writer = new CharArrayWriter(); - } - - @Override - protected Writer createWriter(CodeTypeElement clazz) throws IOException { - return writer; - } - - public String getString() { - return new String(((CharArrayWriter) writer).toCharArray()).trim(); - } - - } - - private static class ParentableList implements List { - - private final Element parent; - private final List delegate; - - public ParentableList(Element parent, List delegate) { - this.parent = parent; - this.delegate = delegate; - } - - private void addImpl(T element) { - if (element != null) { - if (element instanceof CodeElement) { - ((CodeElement) element).setEnclosingElement(parent); - } - } - } - - private static void removeImpl(Object element) { - if (element instanceof CodeElement) { - ((CodeElement) element).setEnclosingElement(null); - } - } - - @Override - public int size() { - return delegate.size(); - } - - @Override - public boolean isEmpty() { - return delegate.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return delegate.contains(o); - } - - @Override - public Iterator iterator() { - return delegate.iterator(); - } - - @Override - public Object[] toArray() { - return delegate.toArray(); - } - - @Override - public E[] toArray(E[] a) { - return delegate.toArray(a); - } - - @Override - public boolean add(T e) { - addImpl(e); - return delegate.add(e); - } - - @Override - public boolean remove(Object o) { - boolean removed = delegate.remove(o); - if (removed) { - removeImpl(o); - } - return removed; - } - - @Override - public boolean containsAll(Collection c) { - return delegate.containsAll(c); - } - - @Override - public boolean addAll(Collection c) { - if (c != null) { - for (T t : c) { - addImpl(t); - } - } - return delegate.addAll(c); - } - - @Override - public boolean addAll(int index, Collection c) { - if (c != null) { - for (T t : c) { - addImpl(t); - } - } - return delegate.addAll(index, c); - } - - @Override - public boolean removeAll(Collection c) { - if (c != null) { - for (Object t : c) { - removeImpl(t); - } - } - return delegate.removeAll(c); - } - - @Override - public String toString() { - return delegate.toString(); - } - - @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException("Not supported by parentable list"); - } - - @Override - public void clear() { - for (Object e : this) { - removeImpl(e); - } - delegate.clear(); - } - - @Override - public T get(int index) { - return delegate.get(index); - } - - @Override - public T set(int index, T element) { - removeImpl(delegate.get(index)); - addImpl(element); - return delegate.set(index, element); - } - - @Override - public void add(int index, T element) { - addImpl(element); - delegate.add(index, element); - } - - @Override - public T remove(int index) { - T element = delegate.remove(index); - removeImpl(element); - return element; - } - - @Override - public int indexOf(Object o) { - return delegate.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return delegate.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return delegate.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return delegate.listIterator(index); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return new ParentableList<>(parent, delegate.subList(fromIndex, toIndex)); - } - - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElementScanner.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeElementScanner.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import javax.lang.model.element.*; -import javax.lang.model.util.*; - -public abstract class CodeElementScanner extends ElementScanner7 { - - @Override - public final R visitExecutable(ExecutableElement e, P p) { - return visitExecutable(cast(e, CodeExecutableElement.class), p); - } - - public R visitExecutable(CodeExecutableElement e, P p) { - R ret = super.visitExecutable(e, p); - if (e.getBodyTree() != null) { - visitTree(e.getBodyTree(), p); - } - return ret; - } - - @Override - public R visitPackage(PackageElement e, P p) { - return super.visitPackage(e, p); - } - - @Override - public final R visitType(TypeElement e, P p) { - return visitType(cast(e, CodeTypeElement.class), p); - } - - public R visitType(CodeTypeElement e, P p) { - return super.visitType(e, p); - } - - @Override - public R visitTypeParameter(TypeParameterElement e, P p) { - return super.visitTypeParameter(e, p); - } - - private static E cast(Element element, Class clazz) { - return clazz.cast(element); - } - - public void visitTree(CodeTree e, P p) { - for (CodeTree tree : e.getEnclosedElements()) { - tree.acceptCodeElementScanner(this, p); - } - } - - @SuppressWarnings("unused") - public void visitImport(CodeImport e, P p) { - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public class CodeExecutableElement extends CodeElement implements ExecutableElement { - - private final List throwables = new ArrayList<>(); - private final List parameters = parentableList(this, new ArrayList()); - - private TypeMirror returnType; - private Name name; - - private CodeTree bodyTree; - private String body; - private AnnotationValue defaultValue; - private boolean varArgs; - - public CodeExecutableElement(TypeMirror returnType, String name) { - super(Utils.modifiers()); - this.returnType = returnType; - this.name = CodeNames.of(name); - } - - public CodeExecutableElement(Set modifiers, TypeMirror returnType, String name, CodeVariableElement... parameters) { - super(modifiers); - this.returnType = returnType; - this.name = CodeNames.of(name); - for (CodeVariableElement codeParameter : parameters) { - addParameter(codeParameter); - } - } - - /* Support JDK8 langtools. */ - public boolean isDefault() { - return false; - } - - @Override - public List getThrownTypes() { - return throwables; - } - - @Override - public TypeMirror asType() { - return returnType; - } - - @Override - public ElementKind getKind() { - if (getReturnType() == null) { - return ElementKind.CONSTRUCTOR; - } else { - return ElementKind.METHOD; - } - } - - @Override - public List getTypeParameters() { - return Collections.emptyList(); - } - - public void setVarArgs(boolean varargs) { - this.varArgs = varargs; - } - - @Override - public boolean isVarArgs() { - return varArgs; - } - - public void setDefaultValue(AnnotationValue defaultValue) { - this.defaultValue = defaultValue; - } - - @Override - public AnnotationValue getDefaultValue() { - return defaultValue; - } - - @Override - public Name getSimpleName() { - return name; - } - - public CodeTreeBuilder getBuilder() { - CodeTree tree = this.bodyTree; - return createBuilder().tree(tree); - } - - public CodeTreeBuilder createBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(null); - this.bodyTree = builder.getTree(); - this.bodyTree.setEnclosingElement(this); - this.body = null; - return builder; - } - - public void setBodyTree(CodeTree body) { - this.bodyTree = body; - } - - public CodeTree getBodyTree() { - return bodyTree; - } - - public TypeMirror getReturnType() { - return returnType; - } - - @Override - public List getParameters() { - return parameters; - } - - public TypeMirror[] getParameterTypes() { - TypeMirror[] types = new TypeMirror[getParameters().size()]; - for (int i = 0; i < types.length; i++) { - types[i] = parameters.get(i).asType(); - } - return types; - } - - public void setReturnType(TypeMirror type) { - returnType = type; - } - - public void addParameter(VariableElement parameter) { - parameters.add(parameter); - } - - public void removeParameter(VariableElement parameter) { - parameters.remove(parameter); - } - - public void addThrownType(TypeMirror thrownType) { - throwables.add(thrownType); - } - - public void removeThrownType(TypeMirror thrownType) { - throwables.remove(thrownType); - } - - public void setSimpleName(Name name) { - this.name = name; - } - - public void setBody(String body) { - this.body = body; - } - - public String getBody() { - return body; - } - - @Override - public R accept(ElementVisitor v, P p) { - return v.visitExecutable(this, p); - } - - public static CodeExecutableElement clone(@SuppressWarnings("unused") ProcessingEnvironment env, ExecutableElement method) { - CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); - for (TypeMirror thrownType : method.getThrownTypes()) { - copy.addThrownType(thrownType); - } - copy.setDefaultValue(method.getDefaultValue()); - - for (AnnotationMirror mirror : method.getAnnotationMirrors()) { - copy.addAnnotationMirror(mirror); - } - for (VariableElement var : method.getParameters()) { - copy.addParameter(CodeVariableElement.clone(var)); - } - for (Element element : method.getEnclosedElements()) { - copy.add(element); - } - copy.getModifiers().addAll(method.getModifiers()); - copy.setVarArgs(method.isVarArgs()); - return copy; - } - - public TypeMirror getReceiverType() { - throw new UnsupportedOperationException(); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeImport.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeImport.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import javax.lang.model.type.*; - -public class CodeImport implements Comparable { - - private final TypeMirror importType; - private final String importString; - private final boolean staticImport; - - public CodeImport(TypeMirror importedType, String importString, boolean staticImport) { - this.importType = importedType; - this.importString = importString; - this.staticImport = staticImport; - } - - public TypeMirror getImportType() { - return importType; - } - - public boolean isStaticImport() { - return staticImport; - } - - public String getImportString() { - return importString; - } - - @Override - public int compareTo(CodeImport o) { - if (staticImport && !o.staticImport) { - return 1; - } else if (!staticImport && o.staticImport) { - return -1; - } else { - return importString.compareTo(o.getImportString()); - } - } - - public

void accept(CodeElementScanner s, P p) { - s.visitImport(this, p); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((importString == null) ? 0 : importString.hashCode()); - result = prime * result + (staticImport ? 1231 : 1237); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - CodeImport other = (CodeImport) obj; - if (importString == null) { - if (other.importString != null) { - return false; - } - } else if (!importString.equals(other.importString)) { - return false; - } - if (staticImport != other.staticImport) { - return false; - } - return true; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeNames.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeNames.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,90 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; - -public abstract class CodeNames { - - private static Map names = new HashMap<>(); - - public static Name of(String value) { - Name name = names.get(value); - if (name == null) { - name = new NameImpl(value); - names.put(value, name); - } - return name; - } - - private static class NameImpl implements Name { - - private final String name; - - public NameImpl(String name) { - this.name = name; - } - - @Override - public int length() { - return name.length(); - } - - @Override - public char charAt(int index) { - return name.charAt(index); - } - - @Override - public CharSequence subSequence(int start, int end) { - return name.subSequence(start, end); - } - - @Override - public boolean contentEquals(CharSequence cs) { - return name.contentEquals(cs); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof Name) { - return ((Name) obj).contentEquals(name); - } - return super.equals(obj); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - @Override - public String toString() { - return name; - } - - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTree.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTree.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public class CodeTree extends CodeElement { - - private final CodeTreeKind kind; - - private TypeMirror type; - private final String string; - - CodeTree(CodeTreeKind kind, TypeMirror type, String string) { - this.kind = kind; - this.type = type; - this.string = string; - } - - public TypeMirror getType() { - return type; - } - - public CodeTreeKind getCodeKind() { - return kind; - } - - public String getString() { - return string; - } - - public

void acceptCodeElementScanner(CodeElementScanner s, P p) { - s.visitTree(this, p); - } - - public void setType(TypeMirror type) { - this.type = type; - } - - @Override - public TypeMirror asType() { - return type; - } - - @Override - public ElementKind getKind() { - return ElementKind.OTHER; - } - - @Override - public Name getSimpleName() { - return CodeNames.of(getString()); - } - - @Override - public R accept(ElementVisitor v, P p) { - if (v instanceof CodeElementScanner) { - acceptCodeElementScanner((CodeElementScanner) v, p); - return null; - } else { - throw new UnsupportedOperationException(); - } - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeBuilder.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,888 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import static com.oracle.truffle.dsl.processor.ast.CodeTreeKind.*; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public class CodeTreeBuilder { - - private final CodeTreeBuilder parent; - - private BuilderCodeTree currentElement; - private final BuilderCodeTree root; - - private int treeCount; - - public CodeTreeBuilder(CodeTreeBuilder parent) { - this.root = new BuilderCodeTree(GROUP, null, null); - this.currentElement = root; - this.parent = parent; - } - - @Override - public String toString() { - return root.toString(); - } - - public int getTreeCount() { - return treeCount; - } - - public boolean isEmpty() { - return treeCount == 0; - } - - public CodeTreeBuilder statement(String statement) { - return startStatement().string(statement).end(); - } - - public CodeTreeBuilder statement(CodeTree statement) { - return startStatement().tree(statement).end(); - } - - public static CodeTreeBuilder createBuilder() { - return new CodeTreeBuilder(null); - } - - public static CodeTree singleString(String s) { - return new CodeTreeBuilder(null).string(s).getTree(); - } - - public static CodeTree singleType(TypeMirror s) { - return new CodeTreeBuilder(null).type(s).getTree(); - } - - private CodeTreeBuilder push(CodeTreeKind kind) { - return push(new BuilderCodeTree(kind, null, null)); - } - - private CodeTreeBuilder push(String string) { - return push(new BuilderCodeTree(CodeTreeKind.STRING, null, string)); - } - - private CodeTreeBuilder push(TypeMirror type) { - return push(new BuilderCodeTree(CodeTreeKind.TYPE, type, null)); - } - - private CodeTreeBuilder push(CodeTreeKind kind, TypeMirror type, String string) { - return push(new BuilderCodeTree(kind, type, string)); - } - - private CodeTreeBuilder push(BuilderCodeTree tree) { - if (currentElement != null) { - if (!removeLastIfEnqueued(tree)) { - return this; - } - currentElement.add(tree); - } - switch (tree.getCodeKind()) { - case COMMA_GROUP: - case GROUP: - case INDENT: - currentElement = tree; - break; - } - treeCount++; - return this; - } - - private boolean removeLastIfEnqueued(BuilderCodeTree tree) { - if (tree.getCodeKind() == REMOVE_LAST) { - return !clearLastRec(tree.removeLast, currentElement.getEnclosedElements()); - } - List childTree = tree.getEnclosedElements(); - if (!childTree.isEmpty()) { - CodeTree last = childTree.get(0); - if (last instanceof BuilderCodeTree) { - if (!removeLastIfEnqueued((BuilderCodeTree) last)) { - childTree.remove(0); - } - } - } - return true; - } - - private void clearLast(CodeTreeKind kind) { - if (clearLastRec(kind, currentElement.getEnclosedElements())) { - treeCount--; - } else { - // delay clearing the last - BuilderCodeTree tree = new BuilderCodeTree(REMOVE_LAST, null, null); - tree.removeLast = kind; - push(tree); - } - } - - public CodeTreeBuilder startStatement() { - startGroup(); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - string(";").newLine(); - } - - @Override - public void afterEnd() { - } - }); - return this; - } - - public CodeTreeBuilder startGroup() { - return push(CodeTreeKind.GROUP); - } - - public CodeTreeBuilder startCommaGroup() { - return push(CodeTreeKind.COMMA_GROUP); - } - - public CodeTreeBuilder startCall(String callSite) { - return startCall((CodeTree) null, callSite); - } - - public CodeTreeBuilder startCall(String receiver, String callSite) { - return startCall(singleString(receiver), callSite); - } - - public CodeTreeBuilder startCall(CodeTree receiver, String callSite) { - if (receiver == null) { - return startGroup().string(callSite).startParanthesesCommaGroup().endAfter(); - } else { - return startGroup().tree(receiver).string(".").string(callSite).startParanthesesCommaGroup().endAfter(); - } - } - - public CodeTreeBuilder startStaticCall(TypeMirror type, String methodName) { - return startGroup().push(CodeTreeKind.STATIC_METHOD_REFERENCE, type, methodName).startParanthesesCommaGroup().endAfter(); - } - - public CodeTreeBuilder startStaticCall(ExecutableElement method) { - return startStaticCall(Utils.findNearestEnclosingType(method).asType(), method.getSimpleName().toString()); - } - - public CodeTreeBuilder staticReference(TypeMirror type, String fieldName) { - return push(CodeTreeKind.STATIC_FIELD_REFERENCE, type, fieldName); - } - - private CodeTreeBuilder endAndWhitespaceAfter() { - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - string(" "); - end(); - } - }); - return this; - } - - private CodeTreeBuilder endAfter() { - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - end(); - } - }); - return this; - } - - private CodeTreeBuilder startParanthesesCommaGroup() { - startGroup(); - string("(").startCommaGroup(); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - string(")"); - } - }); - endAfter(); - return this; - } - - private CodeTreeBuilder startCurlyBracesCommaGroup() { - startGroup(); - string("{").startCommaGroup(); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - string("}"); - } - }); - endAfter(); - return this; - } - - public CodeTreeBuilder startParantheses() { - startGroup(); - string("(").startGroup(); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - string(")"); - } - }); - endAfter(); - return this; - } - - public CodeTreeBuilder doubleQuote(String s) { - return startGroup().string("\"" + s + "\"").end(); - } - - public CodeTreeBuilder string(String chunk1) { - return push(chunk1); - } - - public CodeTreeBuilder string(String chunk1, String chunk2) { - return push(GROUP).string(chunk1).string(chunk2).end(); - } - - public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3) { - return push(GROUP).string(chunk1).string(chunk2).string(chunk3).end(); - } - - public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4) { - return push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4).end(); - } - - public CodeTreeBuilder tree(CodeTree treeToAdd) { - if (treeToAdd instanceof BuilderCodeTree) { - return push((BuilderCodeTree) treeToAdd).end(); - } else { - BuilderCodeTree tree = new BuilderCodeTree(GROUP, null, null); - tree.add(treeToAdd); - return push(tree).end(); - } - } - - public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) { - push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4); - for (int i = 0; i < chunks.length; i++) { - string(chunks[i]); - } - return end(); - } - - public CodeTreeBuilder dot() { - return string("."); - } - - public CodeTreeBuilder newLine() { - return push(NEW_LINE); - } - - public CodeTreeBuilder startWhile() { - return startGroup().string("while ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); - } - - public CodeTreeBuilder startDoBlock() { - return startGroup().string("do ").startBlock(); - } - - public CodeTreeBuilder startDoWhile() { - clearLast(CodeTreeKind.NEW_LINE); - return startStatement().string(" while ").startParanthesesCommaGroup().endAfter().startGroup().endAfter(); - } - - public CodeTreeBuilder startIf() { - return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); - } - - public CodeTreeBuilder startFor() { - return startGroup().string("for ").startParantheses().endAndWhitespaceAfter().startGroup().endAfter(); - } - - public boolean startIf(boolean elseIf) { - if (elseIf) { - startElseIf(); - } else { - startIf(); - } - return true; - } - - public CodeTreeBuilder startElseIf() { - clearLast(CodeTreeKind.NEW_LINE); - return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); - } - - public CodeTreeBuilder startElseBlock() { - clearLast(CodeTreeKind.NEW_LINE); - return startGroup().string(" else ").startBlock().endAfter(); - } - - private boolean clearLastRec(CodeTreeKind kind, List children) { - for (int i = children.size() - 1; i >= 0; i--) { - CodeTree child = children.get(i); - if (child.getCodeKind() == kind) { - children.remove(children.get(i)); - return true; - } else { - if (clearLastRec(kind, child.getEnclosedElements())) { - return true; - } - } - } - return false; - } - - public CodeTreeBuilder startCase() { - startGroup().string("case "); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - string(" :").newLine(); - } - - @Override - public void afterEnd() { - } - }); - return this; - } - - public CodeTreeBuilder caseDefault() { - return startGroup().string("default :").newLine().end(); - } - - public CodeTreeBuilder startSwitch() { - return startGroup().string("switch ").startParanthesesCommaGroup().endAndWhitespaceAfter(); - } - - public CodeTreeBuilder startReturn() { - ExecutableElement method = findMethod(); - if (method != null && Utils.isVoid(method.getReturnType())) { - 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 "); - } - } - - public CodeTreeBuilder startAssert() { - return startStatement().string("assert "); - } - - public CodeTreeBuilder startNewArray(ArrayType arrayType, CodeTree size) { - startGroup().string("new ").type(arrayType.getComponentType()).string("["); - if (size != null) { - tree(size); - } - string("]"); - if (size == null) { - string(" "); - startCurlyBracesCommaGroup().endAfter(); - } - return this; - } - - public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) { - return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter(); - } - - public CodeTreeBuilder startNew(String typeName) { - return startGroup().string("new ").string(typeName).startParanthesesCommaGroup().endAfter(); - } - - public CodeTreeBuilder startIndention() { - return push(CodeTreeKind.INDENT); - } - - public CodeTreeBuilder end(int times) { - for (int i = 0; i < times; i++) { - end(); - } - return this; - } - - public CodeTreeBuilder end() { - BuilderCodeTree tree = currentElement; - EndCallback callback = tree.getAtEndListener(); - if (callback != null) { - callback.beforeEnd(); - toParent(); - callback.afterEnd(); - } else { - toParent(); - } - return this; - } - - private void toParent() { - Element parentElement = currentElement.getEnclosingElement(); - if (currentElement != root) { - this.currentElement = (BuilderCodeTree) parentElement; - } else { - this.currentElement = root; - } - } - - public CodeTreeBuilder startBlock() { - startGroup(); - string("{").newLine().startIndention(); - registerCallBack(new EndCallback() { - - @Override - public void beforeEnd() { - } - - @Override - public void afterEnd() { - string("}").newLine(); - } - }); - endAfter(); - return this; - } - - private void registerCallBack(EndCallback callback) { - currentElement.registerAtEnd(callback); - } - - public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) { - if (!Utils.isVoid(type)) { - startStatement(); - type(type); - string(" "); - string(name); - string(" = "); - defaultValue(type); - end(); // statement - } - return this; - } - - public CodeTreeBuilder declaration(TypeMirror type, String name, String init) { - return declaration(type, name, singleString(init)); - } - - public CodeTreeBuilder declaration(String type, String name, CodeTree init) { - startStatement(); - string(type); - string(" "); - string(name); - if (init != null) { - string(" = "); - tree(init); - } - end(); // statement - return this; - } - - public CodeTreeBuilder declaration(String type, String name, String init) { - return declaration(type, name, singleString(init)); - } - - public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { - if (Utils.isVoid(type)) { - startStatement(); - tree(init); - end(); - } else { - startStatement(); - type(type); - string(" "); - string(name); - if (init != null) { - string(" = "); - tree(init); - } - end(); // statement - } - return this; - } - - public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTreeBuilder init) { - if (init == this) { - throw new IllegalArgumentException("Recursive builder usage."); - } - return declaration(type, name, init.getTree()); - } - - public CodeTreeBuilder declaration(String type, String name, CodeTreeBuilder init) { - if (init == this) { - throw new IllegalArgumentException("Recursive builder usage."); - } - return declaration(type, name, init.getTree()); - } - - public CodeTreeBuilder declaration(TypeMirror type, String name) { - return declaration(type, name, (CodeTree) null); - } - - public CodeTreeBuilder create() { - return new CodeTreeBuilder(this); - } - - public CodeTreeBuilder type(TypeMirror type) { - return push(type); - } - - public CodeTreeBuilder typeLiteral(TypeMirror type) { - return startGroup().type(type).string(".class").end(); - } - - private void assertRoot() { - if (currentElement != root) { - throw new IllegalStateException("CodeTreeBuilder was not ended properly."); - } - } - - public CodeTreeBuilder startCaseBlock() { - return startIndention(); - } - - public CodeTreeBuilder startThrow() { - return startStatement().string("throw "); - } - - public CodeTree getTree() { - assertRoot(); - return root; - } - - public CodeTree getRoot() { - return root; - } - - public CodeTreeBuilder cast(String baseClassName) { - string("(").string(baseClassName).string(") "); - return this; - } - - public CodeTreeBuilder cast(TypeMirror type, CodeTree content) { - if (Utils.isVoid(type)) { - tree(content); - return this; - } else if (type.getKind() == TypeKind.DECLARED && Utils.getQualifiedName(type).equals("java.lang.Object")) { - tree(content); - return this; - } else { - return startGroup().string("(").type(type).string(")").string(" ").tree(content).end(); - } - } - - public CodeTreeBuilder startSuperCall() { - return string("super").startParanthesesCommaGroup(); - } - - public CodeTreeBuilder returnFalse() { - return startReturn().string("false").end(); - } - - public CodeTreeBuilder returnStatement() { - return statement("return"); - } - - public ExecutableElement findMethod() { - Element element = currentElement; - while (element != null && (element.getKind() != ElementKind.METHOD && (element.getKind() != ElementKind.CONSTRUCTOR))) { - element = element.getEnclosingElement(); - } - ExecutableElement found = element != null ? (ExecutableElement) element : null; - if (found == null && parent != null) { - found = parent.findMethod(); - } - return found; - } - - public CodeTreeBuilder returnNull() { - return startReturn().string("null").end(); - } - - public CodeTreeBuilder returnTrue() { - return startReturn().string("true").end(); - } - - public CodeTreeBuilder instanceOf(CodeTree var, CodeTree type) { - tree(var).string(" instanceof ").tree(type); - return this; - } - - public CodeTreeBuilder instanceOf(String var, String type) { - return instanceOf(singleString(var), singleString(type)); - } - - public CodeTreeBuilder instanceOf(String var, TypeMirror type) { - TypeElement element = Utils.fromTypeMirror(type); - if (element == null) { - throw new IllegalArgumentException("Cannot call instanceof for a non supported type: " + type.getKind()); - } - return instanceOf(singleString(var), singleType(type)); - } - - public CodeTreeBuilder defaultValue(TypeMirror mirror) { - switch (mirror.getKind()) { - case VOID: - return string(""); - case ARRAY: - case DECLARED: - case PACKAGE: - case NULL: - return string("null"); - case BOOLEAN: - return string("false"); - case BYTE: - return string("(byte) 0"); - case CHAR: - return string("(char) 0"); - case DOUBLE: - return string("0.0D"); - case LONG: - return string("0L"); - case INT: - return string("0"); - case FLOAT: - return string("0.0F"); - case SHORT: - return string("(short) 0"); - default: - throw new AssertionError(); - } - } - - public CodeTreeBuilder assertFalse() { - return startAssert().string("false").end(); - } - - public CodeTreeBuilder breakStatement() { - return statement("break"); - } - - public CodeTreeBuilder isNull() { - return string(" == null"); - } - - public CodeTreeBuilder isNotNull() { - return string(" != null"); - } - - public CodeTreeBuilder is(CodeTree tree) { - return string(" == ").tree(tree); - } - - public CodeTreeBuilder startTryBlock() { - return string("try ").startBlock(); - } - - public CodeTreeBuilder startCatchBlock(TypeMirror exceptionType, String localVarName) { - clearLast(CodeTreeKind.NEW_LINE); - string(" catch (").type(exceptionType).string(" ").string(localVarName).string(") "); - return startBlock(); - } - - public CodeTreeBuilder startFinallyBlock() { - clearLast(CodeTreeKind.NEW_LINE); - string(" finally "); - return startBlock(); - } - - public CodeTreeBuilder nullLiteral() { - return string("null"); - } - - private static class BuilderCodeTree extends CodeTree { - - private EndCallback atEndListener; - private CodeTreeKind removeLast; - - public BuilderCodeTree(CodeTreeKind kind, TypeMirror type, String string) { - super(kind, type, string); - } - - public void registerAtEnd(EndCallback atEnd) { - if (this.atEndListener != null) { - this.atEndListener = new CompoundCallback(this.atEndListener, atEnd); - } else { - this.atEndListener = atEnd; - } - } - - public EndCallback getAtEndListener() { - return atEndListener; - } - - @Override - public String toString() { - final StringBuilder b = new StringBuilder(); - acceptCodeElementScanner(new Printer(b), null); - return b.toString(); - } - - private static class CompoundCallback implements EndCallback { - - private final EndCallback callback1; - private final EndCallback callback2; - - public CompoundCallback(EndCallback callback1, EndCallback callback2) { - this.callback1 = callback1; - this.callback2 = callback2; - } - - @Override - public void afterEnd() { - callback1.afterEnd(); - callback2.afterEnd(); - } - - @Override - public void beforeEnd() { - callback1.beforeEnd(); - callback1.beforeEnd(); - } - } - - } - - private interface EndCallback { - - void beforeEnd(); - - void afterEnd(); - } - - private static class Printer extends CodeElementScanner { - - private int indent; - private boolean newLine; - private final String ln = "\n"; - - private final StringBuilder b; - - Printer(StringBuilder b) { - this.b = b; - } - - @Override - public void visitTree(CodeTree e, Void p) { - switch (e.getCodeKind()) { - case COMMA_GROUP: - List children = e.getEnclosedElements(); - for (int i = 0; i < children.size(); i++) { - children.get(i).acceptCodeElementScanner(this, p); - if (i < e.getEnclosedElements().size() - 1) { - b.append(", "); - } - } - break; - case GROUP: - super.visitTree(e, p); - break; - case INDENT: - indent(); - super.visitTree(e, p); - dedent(); - break; - case NEW_LINE: - writeLn(); - break; - case STRING: - if (e.getString() != null) { - write(e.getString()); - } else { - write("null"); - } - break; - case TYPE: - write(Utils.getSimpleName(e.getType())); - break; - default: - assert false; - return; - } - } - - private void indent() { - indent++; - } - - private void dedent() { - indent--; - } - - private void writeLn() { - write(ln); - newLine = true; - } - - private void write(String m) { - if (newLine && m != ln) { - writeIndent(); - newLine = false; - } - b.append(m); - } - - private void writeIndent() { - for (int i = 0; i < indent; i++) { - b.append(" "); - } - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeKind.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTreeKind.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* - * 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.dsl.processor.ast; - -public enum CodeTreeKind { - STATIC_FIELD_REFERENCE, - STATIC_METHOD_REFERENCE, - GROUP, - COMMA_GROUP, - REMOVE_LAST, - INDENT, - STRING, - NEW_LINE, - TYPE; -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTypeElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTypeElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror; - -public class CodeTypeElement extends CodeElement implements TypeElement { - - private final List imports = parentableList(this, new ArrayList()); - - private final PackageElement packageElement; - - private final Name simpleName; - private final Name packageName; - private Name qualifiedName; - - private final List implementsInterfaces = new ArrayList<>(); - private final ElementKind kind; - private TypeMirror superClass; - - private final DeclaredCodeTypeMirror mirror = new DeclaredCodeTypeMirror(this); - - public CodeTypeElement(Set modifiers, ElementKind kind, PackageElement packageElement, String simpleName) { - super(modifiers); - this.kind = kind; - this.packageElement = packageElement; - this.simpleName = CodeNames.of(simpleName); - if (this.packageElement != null) { - this.packageName = packageElement.getQualifiedName(); - } else { - this.packageName = CodeNames.of("default"); - } - this.qualifiedName = createQualifiedName(); - } - - @Override - public TypeMirror asType() { - return mirror; - } - - @Override - public ElementKind getKind() { - return kind; - } - - public boolean containsField(String name) { - for (VariableElement field : getFields()) { - if (field.getSimpleName().toString().equals(name)) { - return true; - } - } - return false; - } - - @Override - public NestingKind getNestingKind() { - return isTopLevelClass() ? NestingKind.TOP_LEVEL : NestingKind.LOCAL; - } - - @Override - public Element getEnclosingElement() { - if (isTopLevelClass()) { - return packageElement; - } else { - return super.getEnclosingElement(); - } - } - - @Override - public TypeMirror getSuperclass() { - return superClass; - } - - @Override - public List getInterfaces() { - return implementsInterfaces; - } - - @Override - public List getTypeParameters() { - return Collections.emptyList(); - } - - public boolean isTopLevelClass() { - return super.getEnclosingElement() instanceof CodeCompilationUnit; - } - - private Name createQualifiedName() { - TypeElement enclosingType = getEnclosingClass(); - if (enclosingType == null) { - return CodeNames.of(packageName + "." + simpleName); - } else { - return CodeNames.of(enclosingType.getQualifiedName() + "." + simpleName); - } - } - - @Override - protected void setEnclosingElement(Element element) { - super.setEnclosingElement(element); - - // update qualified name on container change - this.qualifiedName = createQualifiedName(); - } - - public Name getPackageName() { - return packageName; - } - - @Override - public Name getQualifiedName() { - return qualifiedName; - } - - @Override - public Name getSimpleName() { - return simpleName; - } - - public void setSuperClass(TypeMirror superType) { - this.superClass = superType; - } - - public List getImports() { - return imports; - } - - public List getImplements() { - return implementsInterfaces; - } - - @Override - public int hashCode() { - return getQualifiedName().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } else if (obj instanceof TypeElement) { - return getQualifiedName().equals(((TypeElement) obj).getQualifiedName()); - } - return false; - } - - public List getFields() { - 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()); - } - - public List getInnerClasses() { - return ElementFilter.typesIn(getEnclosedElements()); - } - - @Override - public String toString() { - return getQualifiedName().toString(); - } - - @Override - public R accept(ElementVisitor v, P p) { - return v.visitType(this, p); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTypeMirror.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeTypeMirror.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,119 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public class CodeTypeMirror implements TypeMirror { - - private final TypeKind kind; - - public CodeTypeMirror(TypeKind kind) { - this.kind = kind; - } - - @Override - public TypeKind getKind() { - return kind; - } - - @Override - public R accept(TypeVisitor v, P p) { - throw new UnsupportedOperationException(); - } - - public static class ArrayCodeTypeMirror extends CodeTypeMirror implements ArrayType { - - private final TypeMirror component; - - public ArrayCodeTypeMirror(TypeMirror component) { - super(TypeKind.ARRAY); - this.component = component; - } - - @Override - public TypeMirror getComponentType() { - return component; - } - - } - - public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType { - - private final TypeElement clazz; - private final List typeArguments; - - public DeclaredCodeTypeMirror(TypeElement clazz) { - this(clazz, Collections. emptyList()); - } - - public DeclaredCodeTypeMirror(TypeElement clazz, List typeArguments) { - super(TypeKind.DECLARED); - this.clazz = clazz; - this.typeArguments = typeArguments; - } - - @Override - public Element asElement() { - return clazz; - } - - @Override - public TypeMirror getEnclosingType() { - return clazz.getEnclosingElement().asType(); - } - - @Override - public List getTypeArguments() { - return typeArguments; - } - - @Override - public String toString() { - return clazz.getQualifiedName().toString(); - } - - } - - public List getAnnotationMirrors() { - throw new UnsupportedOperationException(); - } - - /** - * @param annotationType - */ - public A getAnnotation(Class annotationType) { - throw new UnsupportedOperationException(); - } - - /** - * @param annotationType - */ - public A[] getAnnotationsByType(Class annotationType) { - throw new UnsupportedOperationException(); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeVariableElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeVariableElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public final class CodeVariableElement extends CodeElement implements VariableElement { - - private Name name; - private TypeMirror type; - private Object constantValue; - - private CodeTree init; - - public CodeVariableElement(TypeMirror type, String name) { - super(Utils.modifiers()); - this.type = type; - this.name = CodeNames.of(name); - } - - public CodeVariableElement(Set modifiers, TypeMirror type, String name) { - super(modifiers); - this.type = type; - this.name = CodeNames.of(name); - } - - public CodeVariableElement(Set modifiers, TypeMirror type, String name, String init) { - this(modifiers, type, name); - if (init != null) { - this.init = new CodeTree(CodeTreeKind.STRING, null, init); - } - } - - public CodeTreeBuilder createInitBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(null); - init = builder.getTree(); - init.setEnclosingElement(this); - return builder; - } - - public void setInit(CodeTree init) { - this.init = init; - } - - public CodeTree getInit() { - return init; - } - - public Name getSimpleName() { - return name; - } - - public TypeMirror getType() { - return type; - } - - @Override - public TypeMirror asType() { - return type; - } - - @Override - public ElementKind getKind() { - if (getEnclosingElement() instanceof ExecutableElement) { - return ElementKind.PARAMETER; - } else if (getEnclosingElement() instanceof TypeElement) { - return ElementKind.FIELD; - } else { - return ElementKind.PARAMETER; - } - } - - public void setConstantValue(Object constantValue) { - this.constantValue = constantValue; - } - - @Override - public Object getConstantValue() { - return constantValue; - } - - public String getName() { - return getSimpleName().toString(); - } - - public void setSimpleName(Name name) { - this.name = name; - } - - public void setName(String name) { - this.name = CodeNames.of(name); - } - - public void setType(TypeMirror type) { - this.type = type; - } - - @Override - public R accept(ElementVisitor v, P p) { - return v.visitVariable(this, p); - } - - public static CodeVariableElement clone(VariableElement var) { - CodeVariableElement copy = new CodeVariableElement(var.getModifiers(), var.asType(), var.getSimpleName().toString()); - copy.setConstantValue(var.getConstantValue()); - for (AnnotationMirror mirror : var.getAnnotationMirrors()) { - copy.addAnnotationMirror(mirror); - } - for (Element element : var.getEnclosedElements()) { - copy.add(element); - } - return copy; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import javax.lang.model.element.*; - -public interface GeneratedElement { - - AnnotationMirror getGeneratorAnnotationMirror(); - - void setGeneratorAnnotationMirror(AnnotationMirror mirror); - - Element getGeneratorElement(); - - void setGeneratorElement(Element element); - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedPackageElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedPackageElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -public final class GeneratedPackageElement extends CodeElement implements PackageElement { - - private final Name qualifiedName; - private final Name simpleName; - - public GeneratedPackageElement(String qualifiedName) { - this.qualifiedName = CodeNames.of(qualifiedName); - int lastIndex = qualifiedName.lastIndexOf('.'); - if (lastIndex == -1) { - simpleName = CodeNames.of(""); - } else { - simpleName = CodeNames.of(qualifiedName.substring(lastIndex, qualifiedName.length())); - } - } - - public TypeMirror asType() { - throw new UnsupportedOperationException(); - } - - public ElementKind getKind() { - return ElementKind.PACKAGE; - } - - public R accept(ElementVisitor v, P p) { - return v.visitPackage(this, p); - } - - public Name getQualifiedName() { - return qualifiedName; - } - - public Name getSimpleName() { - return simpleName; - } - - public boolean isUnnamed() { - return simpleName.toString().equals(""); - } - - @Override - public int hashCode() { - return qualifiedName.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PackageElement) { - return qualifiedName.equals(((PackageElement) obj).getQualifiedName()); - } - return super.equals(obj); - } -} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedTypeElement.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedTypeElement.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; - -public final class GeneratedTypeElement extends CodeTypeElement { - - public GeneratedTypeElement(Set modifiers, ElementKind kind, PackageElement packageElement, String simpleName) { - super(modifiers, kind, packageElement, simpleName); - setEnclosingElement(packageElement); - } - -} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedTypeMirror.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/GeneratedTypeMirror.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - * 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.dsl.processor.ast; - -import java.util.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror; - -public final class GeneratedTypeMirror extends DeclaredCodeTypeMirror { - - public GeneratedTypeMirror(String packageName, String name) { - super(new GeneratedTypeElement(Collections. emptySet(), ElementKind.CLASS, new GeneratedPackageElement(packageName), name)); - } - -} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,764 +0,0 @@ -/* - * 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.dsl.processor.codewriter; - -import static com.oracle.truffle.dsl.processor.Utils.*; - -import java.io.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public abstract class AbstractCodeWriter extends CodeElementScanner { - - private static final int MAX_LINE_LENGTH = 200; - private static final int LINE_WRAP_INDENTS = 3; - private static final String IDENT_STRING = " "; - private static final String LN = "\n"; /* unix style */ - - protected Writer writer; - private int indent; - private boolean newLine; - private int lineLength; - private boolean lineWrapping = false; - - private OrganizedImports imports; - - public void visitCompilationUnit(CodeCompilationUnit e) { - for (TypeElement clazz : e.getEnclosedElements()) { - clazz.accept(this, null); - } - } - - protected abstract Writer createWriter(CodeTypeElement clazz) throws IOException; - - @Override - public Void visitType(CodeTypeElement e, Void p) { - if (e.isTopLevelClass()) { - Writer w = null; - try { - imports = OrganizedImports.organize(e); - w = new TrimTrailingSpaceWriter(createWriter(e)); - writer = w; - writeRootClass(e); - } catch (IOException ex) { - throw new RuntimeException(ex); - } finally { - if (w != null) { - try { - w.close(); - } catch (Throwable e1) { - // see eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=361378 - // TODO temporary suppress errors on close. - } - } - writer = null; - } - } else { - writeClassImpl(e); - } - return null; - } - - private void writeRootClass(CodeTypeElement e) { - writeHeader(); - write("package ").write(e.getPackageName()).write(";").writeLn(); - writeEmptyLn(); - - Set generateImports = imports.generateImports(); - List typeImports = new ArrayList<>(); - List staticImports = new ArrayList<>(); - - for (CodeImport codeImport : generateImports) { - if (codeImport.isStaticImport()) { - staticImports.add(codeImport); - } else { - typeImports.add(codeImport); - } - } - Collections.sort(typeImports); - Collections.sort(staticImports); - - for (CodeImport imp : staticImports) { - imp.accept(this, null); - writeLn(); - } - if (!staticImports.isEmpty()) { - writeEmptyLn(); - } - - for (CodeImport imp : typeImports) { - imp.accept(this, null); - writeLn(); - } - if (!typeImports.isEmpty()) { - writeEmptyLn(); - } - - writeClassImpl(e); - } - - private String useImport(Element enclosedType, TypeMirror type) { - if (imports != null) { - return imports.createTypeReference(enclosedType, type); - } else { - return Utils.getSimpleName(type); - } - } - - private void writeClassImpl(CodeTypeElement e) { - for (AnnotationMirror annotation : e.getAnnotationMirrors()) { - visitAnnotation(e, annotation); - writeLn(); - } - - writeModifiers(e.getModifiers()); - if (e.getKind() == ElementKind.ENUM) { - write("enum "); - } else { - write("class "); - } - write(e.getSimpleName()); - if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) { - write(" extends ").write(useImport(e, e.getSuperclass())); - } - if (e.getImplements().size() > 0) { - write(" implements "); - for (int i = 0; i < e.getImplements().size(); i++) { - write(useImport(e, e.getImplements().get(i))); - if (i < e.getImplements().size() - 1) { - write(", "); - } - } - } - - write(" {").writeLn(); - writeEmptyLn(); - indent(1); - - List staticFields = getStaticFields(e); - List instanceFields = getInstanceFields(e); - - for (int i = 0; i < staticFields.size(); i++) { - VariableElement field = staticFields.get(i); - field.accept(this, null); - if (e.getKind() == ElementKind.ENUM && i < staticFields.size() - 1) { - write(","); - writeLn(); - } else { - write(";"); - writeLn(); - } - } - - if (staticFields.size() > 0) { - writeEmptyLn(); - } - - for (VariableElement field : instanceFields) { - field.accept(this, null); - write(";"); - writeLn(); - } - if (instanceFields.size() > 0) { - writeEmptyLn(); - } - - for (ExecutableElement method : ElementFilter.constructorsIn(e.getEnclosedElements())) { - method.accept(this, null); - } - - for (ExecutableElement method : getInstanceMethods(e)) { - method.accept(this, null); - } - - for (ExecutableElement method : getStaticMethods(e)) { - method.accept(this, null); - } - - for (TypeElement clazz : e.getInnerClasses()) { - clazz.accept(this, null); - } - - dedent(1); - write("}"); - writeEmptyLn(); - } - - private static List getStaticFields(CodeTypeElement clazz) { - List staticFields = new ArrayList<>(); - for (VariableElement field : clazz.getFields()) { - if (field.getModifiers().contains(Modifier.STATIC)) { - staticFields.add(field); - } - } - return staticFields; - } - - private static List getInstanceFields(CodeTypeElement clazz) { - List instanceFields = new ArrayList<>(); - for (VariableElement field : clazz.getFields()) { - if (!field.getModifiers().contains(Modifier.STATIC)) { - instanceFields.add(field); - } - } - return instanceFields; - } - - private static List getStaticMethods(CodeTypeElement clazz) { - List staticMethods = new ArrayList<>(); - for (ExecutableElement method : clazz.getMethods()) { - if (method.getModifiers().contains(Modifier.STATIC)) { - staticMethods.add(method); - } - } - return staticMethods; - } - - private static List getInstanceMethods(CodeTypeElement clazz) { - List instanceMethods = new ArrayList<>(); - for (ExecutableElement method : clazz.getMethods()) { - if (!method.getModifiers().contains(Modifier.STATIC)) { - instanceMethods.add(method); - } - } - return instanceMethods; - } - - @Override - public Void visitVariable(VariableElement f, Void p) { - Element parent = f.getEnclosingElement(); - - for (AnnotationMirror annotation : f.getAnnotationMirrors()) { - visitAnnotation(f, annotation); - write(" "); - } - - CodeTree init = null; - if (f instanceof CodeVariableElement) { - init = ((CodeVariableElement) f).getInit(); - } - - if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) { - write(f.getSimpleName()); - if (init != null) { - write("("); - init.acceptCodeElementScanner(this, p); - write(")"); - } - } else { - Element enclosing = f.getEnclosingElement(); - writeModifiers(f.getModifiers()); - - boolean varArgs = false; - if (enclosing.getKind() == ElementKind.METHOD) { - ExecutableElement method = (ExecutableElement) enclosing; - if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { - varArgs = true; - } - } - - TypeMirror varType = f.asType(); - if (varArgs) { - if (varType.getKind() == TypeKind.ARRAY) { - varType = ((ArrayType) varType).getComponentType(); - } - write(useImport(f, varType)); - write("..."); - } else { - write(useImport(f, varType)); - } - - write(" "); - write(f.getSimpleName()); - if (init != null) { - write(" = "); - init.acceptCodeElementScanner(this, p); - } - } - return null; - } - - public void visitAnnotation(Element enclosedElement, AnnotationMirror e) { - write("@").write(useImport(enclosedElement, e.getAnnotationType())); - - if (!e.getElementValues().isEmpty()) { - write("("); - final ExecutableElement defaultElement = findExecutableElement(e.getAnnotationType(), "value"); - - Map values = e.getElementValues(); - if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) { - visitAnnotationValue(enclosedElement, values.get(defaultElement)); - } else { - Set methodsSet = values.keySet(); - List methodsList = new ArrayList<>(); - for (ExecutableElement method : methodsSet) { - if (values.get(method) == null) { - continue; - } - methodsList.add(method); - } - - Collections.sort(methodsList, new Comparator() { - - @Override - public int compare(ExecutableElement o1, ExecutableElement o2) { - return o1.getSimpleName().toString().compareTo(o2.getSimpleName().toString()); - } - }); - - for (int i = 0; i < methodsList.size(); i++) { - ExecutableElement method = methodsList.get(i); - AnnotationValue value = values.get(method); - write(method.getSimpleName().toString()); - write(" = "); - visitAnnotationValue(enclosedElement, value); - - if (i < methodsList.size() - 1) { - write(", "); - } - } - } - - write(")"); - } - } - - public void visitAnnotationValue(Element enclosedElement, AnnotationValue e) { - e.accept(new AnnotationValueWriterVisitor(enclosedElement), null); - } - - private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7 { - - private final Element enclosedElement; - - public AnnotationValueWriterVisitor(Element enclosedElement) { - this.enclosedElement = enclosedElement; - } - - @Override - public Void visitBoolean(boolean b, Void p) { - write(Boolean.toString(b)); - return null; - } - - @Override - public Void visitByte(byte b, Void p) { - write(Byte.toString(b)); - return null; - } - - @Override - public Void visitChar(char c, Void p) { - write(Character.toString(c)); - return null; - } - - @Override - public Void visitDouble(double d, Void p) { - write(Double.toString(d)); - return null; - } - - @Override - public Void visitFloat(float f, Void p) { - write(Float.toString(f)); - return null; - } - - @Override - public Void visitInt(int i, Void p) { - write(Integer.toString(i)); - return null; - } - - @Override - public Void visitLong(long i, Void p) { - write(Long.toString(i)); - return null; - } - - @Override - public Void visitShort(short s, Void p) { - write(Short.toString(s)); - return null; - } - - @Override - public Void visitString(String s, Void p) { - write("\""); - write(s); - write("\""); - return null; - } - - @Override - public Void visitType(TypeMirror t, Void p) { - write(useImport(enclosedElement, t)); - write(".class"); - return null; - } - - @Override - public Void visitEnumConstant(VariableElement c, Void p) { - write(useImport(enclosedElement, c.asType())); - write("."); - write(c.getSimpleName().toString()); - return null; - } - - @Override - public Void visitAnnotation(AnnotationMirror a, Void p) { - AbstractCodeWriter.this.visitAnnotation(enclosedElement, a); - return null; - } - - @Override - public Void visitArray(List vals, Void p) { - write("{"); - for (int i = 0; i < vals.size(); i++) { - AnnotationValue value = vals.get(i); - AbstractCodeWriter.this.visitAnnotationValue(enclosedElement, value); - if (i < vals.size() - 1) { - write(", "); - } - } - write("}"); - return null; - } - } - - public ExecutableElement findExecutableElement(DeclaredType type, String name) { - List elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); - for (ExecutableElement executableElement : elements) { - if (executableElement.getSimpleName().toString().equals(name)) { - return executableElement; - } - } - return null; - } - - @Override - public void visitImport(CodeImport e, Void p) { - if (e.isStaticImport()) { - write("import static ").write(e.getImportString()).write(";"); - } else { - write("import ").write(e.getImportString()).write(";"); - } - } - - @Override - public Void visitExecutable(CodeExecutableElement e, Void p) { - for (AnnotationMirror annotation : e.getAnnotationMirrors()) { - visitAnnotation(e, annotation); - writeLn(); - } - - writeModifiers(e.getModifiers()); - - if (e.getReturnType() != null) { - write(useImport(e, e.getReturnType())); - write(" "); - } - write(e.getSimpleName()); - write("("); - - for (int i = 0; i < e.getParameters().size(); i++) { - VariableElement param = e.getParameters().get(i); - param.accept(this, p); - if (i < e.getParameters().size() - 1) { - write(", "); - } - } - write(")"); - - List throwables = e.getThrownTypes(); - if (throwables.size() > 0) { - write(" throws "); - for (int i = 0; i < throwables.size(); i++) { - write(useImport(e, throwables.get(i))); - if (i < throwables.size() - 1) { - write(", "); - } - } - } - - if (e.getModifiers().contains(Modifier.ABSTRACT)) { - writeLn(";"); - } else if (e.getBodyTree() != null) { - writeLn(" {"); - indent(1); - e.getBodyTree().acceptCodeElementScanner(this, p); - dedent(1); - writeLn("}"); - } else if (e.getBody() != null) { - write(" {"); - write(e.getBody()); - writeLn("}"); - } else { - writeLn("{ }"); - } - writeEmptyLn(); - return null; - } - - @Override - public void visitTree(CodeTree e, Void p) { - CodeTreeKind kind = e.getCodeKind(); - - switch (kind) { - case COMMA_GROUP: - List children = e.getEnclosedElements(); - for (int i = 0; i < children.size(); i++) { - children.get(i).acceptCodeElementScanner(this, p); - if (i < e.getEnclosedElements().size() - 1) { - write(", "); - } - } - break; - case GROUP: - for (CodeTree tree : e.getEnclosedElements()) { - tree.acceptCodeElementScanner(this, p); - } - break; - case INDENT: - indent(1); - for (CodeTree tree : e.getEnclosedElements()) { - tree.acceptCodeElementScanner(this, p); - } - dedent(1); - break; - case NEW_LINE: - writeLn(); - break; - case STRING: - if (e.getString() != null) { - write(e.getString()); - } else { - write("null"); - } - break; - case STATIC_FIELD_REFERENCE: - if (e.getString() != null) { - write(imports.createStaticFieldReference(e, e.getType(), e.getString())); - } else { - write("null"); - } - break; - case STATIC_METHOD_REFERENCE: - if (e.getString() != null) { - write(imports.createStaticMethodReference(e, e.getType(), e.getString())); - } else { - write("null"); - } - break; - case TYPE: - write(useImport(e, e.getType())); - break; - default: - assert false; - return; - } - } - - protected void writeHeader() { - // default implementation does nothing - } - - private void writeModifiers(Set modifiers) { - if (modifiers != null) { - for (Modifier modifier : modifiers) { - write(modifier.toString()); - write(" "); - } - } - } - - protected void indent(int count) { - indent += count; - } - - protected void dedent(int count) { - indent -= count; - } - - protected void writeLn() { - writeLn(""); - } - - protected void writeLn(String text) { - write(text); - write(LN); - lineLength = 0; - newLine = true; - if (lineWrapping) { - dedent(LINE_WRAP_INDENTS); - lineWrapping = false; - } - lineWrapping = false; - } - - protected void writeEmptyLn() { - writeLn(); - } - - private AbstractCodeWriter write(Name name) { - return write(name.toString()); - } - - private AbstractCodeWriter write(String m) { - if (m.isEmpty()) { - return this; - } - try { - String s = m; - lineLength += s.length(); - if (newLine && s != LN) { - writeIndent(); - newLine = false; - } - if (lineLength > MAX_LINE_LENGTH) { - s = wrapLine(s); - } - writer.write(s); - } catch (IOException e) { - throw new RuntimeException(e); - } - return this; - } - - private String wrapLine(String m) throws IOException { - assert !m.isEmpty(); - - char firstCharacter = m.charAt(0); - char lastCharacter = m.charAt(m.length() - 1); - if (firstCharacter == '\"' && lastCharacter == '\"') { - // string line wrapping - String string = m.substring(1, m.length() - 1); - if (string.isEmpty()) { - return m; - } - - // restore original line length - lineLength = lineLength - m.length(); - int size = 0; - for (int i = 0; i < string.length(); i += size) { - if (i != 0) { - write("+ "); - } - - int nextSize = MAX_LINE_LENGTH - lineLength - 2; - if (nextSize <= 0) { - writeLn(); - nextSize = MAX_LINE_LENGTH - lineLength - 2; - } - - int end = Math.min(i + nextSize, string.length()); - - // TODO(CH): fails in normal usage - output ok though - // assert lineLength + (end - i) + 2 < MAX_LINE_LENGTH; - - write("\"" + string.substring(i, end) + "\""); - size = nextSize; - } - - return ""; - } else if (!Character.isAlphabetic(firstCharacter) && firstCharacter != '+') { - return m; - } - - if (!lineWrapping) { - indent(LINE_WRAP_INDENTS); - } - lineWrapping = true; - lineLength = 0; - write(LN); - writeIndent(); - return m; - } - - private void writeIndent() throws IOException { - lineLength += indentSize(); - for (int i = 0; i < indent; i++) { - writer.write(IDENT_STRING); - } - } - - private int indentSize() { - return IDENT_STRING.length() * indent; - } - - private static class TrimTrailingSpaceWriter extends Writer { - - private final Writer delegate; - private final StringBuilder buffer = new StringBuilder(); - - public TrimTrailingSpaceWriter(Writer delegate) { - this.delegate = delegate; - } - - @Override - public void close() throws IOException { - this.delegate.close(); - } - - @Override - public void flush() throws IOException { - this.delegate.flush(); - } - - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - buffer.append(cbuf, off, len); - int newLinePoint = buffer.indexOf(LN); - - if (newLinePoint != -1) { - String lhs = trimTrailing(buffer.substring(0, newLinePoint)); - delegate.write(lhs); - delegate.write(LN); - buffer.delete(0, newLinePoint + 1); - } - } - - private static String trimTrailing(String s) { - int cut = 0; - for (int i = s.length() - 1; i >= 0; i--) { - if (Character.isWhitespace(s.charAt(i))) { - cut++; - } else { - break; - } - } - if (cut > 0) { - return s.substring(0, s.length() - cut); - } - return s; - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/FixWarningsVisitor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/FixWarningsVisitor.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * 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.dsl.processor.codewriter; - -import static com.oracle.truffle.dsl.processor.Utils.*; -import static javax.lang.model.element.Modifier.*; - -import java.io.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public class FixWarningsVisitor extends CodeElementScanner { - - private final Set symbolsUsed = new HashSet<>(); - - private final ProcessorContext context; - private final DeclaredType unusedAnnotation; - private final DeclaredType overrideType; - - public FixWarningsVisitor(ProcessorContext context, DeclaredType unusedAnnotation, DeclaredType overrideType) { - this.context = context; - this.unusedAnnotation = unusedAnnotation; - this.overrideType = overrideType; - } - - @Override - public Void visitType(CodeTypeElement e, Void p) { - List superTypes = Utils.getSuperTypes(e); - for (TypeElement type : superTypes) { - String qualifiedName = Utils.getQualifiedName(type); - if (qualifiedName.equals(Serializable.class.getCanonicalName())) { - if (!e.containsField("serialVersionUID")) { - e.add(new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getType(long.class), "serialVersionUID", "1L")); - } - break; - } - } - - return super.visitType(e, p); - } - - @Override - public Void visitExecutable(CodeExecutableElement e, Void p) { - if (e.getParameters().isEmpty()) { - return null; - } else if (e.getModifiers().contains(Modifier.ABSTRACT)) { - return null; - } else if (containsOverride(e)) { - return null; - } - - symbolsUsed.clear(); - super.visitExecutable(e, p); - - for (VariableElement parameter : e.getParameters()) { - if (!symbolsUsed.contains(parameter.getSimpleName().toString())) { - e.getAnnotationMirrors().add(createUnusedAnnotationMirror()); - break; - } - } - return null; - } - - private boolean containsOverride(CodeExecutableElement e) { - for (AnnotationMirror mirror : e.getAnnotationMirrors()) { - if (Utils.typeEquals(overrideType, mirror.getAnnotationType())) { - return true; - } - } - return false; - } - - private CodeAnnotationMirror createUnusedAnnotationMirror() { - CodeAnnotationMirror mirror = new CodeAnnotationMirror(unusedAnnotation); - mirror.setElementValue(mirror.findExecutableElement("value"), new CodeAnnotationValue("unused")); - return mirror; - } - - @Override - public void visitTree(CodeTree e, Void p) { - if (e.getString() != null) { - computeSymbols(e.getString()); - } - super.visitTree(e, p); - } - - private void computeSymbols(String s) { - // TODO there should not be any need for a StringTokenizer if we have a real AST for - // method bodies. Also the current solution is not perfect. What if one token - // is spread across multiple CodeTree instances? But for now that works. - StringTokenizer tokenizer = new StringTokenizer(s, ".= :,()[];{}\"\"'' ", false); - while (tokenizer.hasMoreElements()) { - String token = tokenizer.nextToken().trim(); - if (token.length() > 0) { - symbolsUsed.add(token); - } - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/GenerateOverrideVisitor.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/GenerateOverrideVisitor.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * 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.dsl.processor.codewriter; - -import static com.oracle.truffle.dsl.processor.Utils.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public class GenerateOverrideVisitor extends CodeElementScanner { - - private final DeclaredType overrideType; - - public GenerateOverrideVisitor(DeclaredType overrideType) { - this.overrideType = overrideType; - } - - @Override - public Void visitExecutable(CodeExecutableElement e, Void p) { - if (!e.getModifiers().contains(Modifier.STATIC) && !e.getModifiers().contains(Modifier.PRIVATE)) { - String name = e.getSimpleName().toString(); - TypeMirror[] params = e.getParameterTypes(); - - for (AnnotationMirror mirror : e.getAnnotationMirrors()) { - if (Utils.typeEquals(overrideType, mirror.getAnnotationType())) { - // already declared (may happen if method copied from super class) - return super.visitExecutable(e, p); - } - } - - if (isDeclaredMethodInSuperType(e.getEnclosingClass(), name, params)) { - e.addAnnotationMirror(new CodeAnnotationMirror(overrideType)); - } - } - return super.visitExecutable(e, p); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/OrganizedImports.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/OrganizedImports.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,489 +0,0 @@ -/* - * 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.dsl.processor.codewriter; - -import static com.oracle.truffle.dsl.processor.Utils.*; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public final class OrganizedImports { - - private final Set staticImportUsage = new HashSet<>(); - - private final Map simpleNamesUsed = new HashMap<>(); - - private final Set declaredStaticMethods = new HashSet<>(); - private final Set declaredStaticFields = new HashSet<>(); - private final Set ambiguousStaticMethods = new HashSet<>(); - private final Set ambiguousStaticFields = new HashSet<>(); - - private final CodeTypeElement topLevelClass; - - private OrganizedImports(CodeTypeElement topLevelClass) { - this.topLevelClass = topLevelClass; - } - - public static OrganizedImports organize(CodeTypeElement topLevelClass) { - OrganizedImports organized = new OrganizedImports(topLevelClass); - organized.organizeImpl(); - return organized; - } - - private void organizeImpl() { - ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor(); - topLevelClass.accept(reference, null); - - processStaticImports(topLevelClass); - List types = Utils.getSuperTypes(topLevelClass); - for (TypeElement typeElement : types) { - processStaticImports(typeElement); - } - - for (TypeMirror type : staticImportUsage) { - TypeElement element = fromTypeMirror(type); - if (element != null) { - // already processed by supertype - if (types.contains(element)) { - continue; - } - processStaticImports(element); - } - } - } - - public String createTypeReference(Element enclosedElement, TypeMirror type) { - switch (type.getKind()) { - case BOOLEAN: - case BYTE: - case CHAR: - case DOUBLE: - case FLOAT: - case SHORT: - case INT: - case LONG: - case VOID: - return Utils.getSimpleName(type); - case DECLARED: - return createDeclaredTypeName(enclosedElement, (DeclaredType) type); - case ARRAY: - return createTypeReference(enclosedElement, ((ArrayType) type).getComponentType()) + "[]"; - case WILDCARD: - return createWildcardName(enclosedElement, (WildcardType) type); - case TYPEVAR: - return "?"; - default: - throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type); - } - } - - public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) { - return createStaticReference(enclosedElement, type, fieldName, ambiguousStaticFields); - } - - public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) { - return createStaticReference(enclosedElement, type, methodName, ambiguousStaticMethods); - } - - private String createStaticReference(Element enclosedElement, TypeMirror type, String name, Set ambiguousSymbols) { - if (ambiguousSymbols.contains(name)) { - // ambiguous import - return createTypeReference(enclosedElement, type) + "." + name; - } else { - // import declared and not ambiguous - return name; - } - } - - private String createWildcardName(Element enclosedElement, WildcardType type) { - StringBuilder b = new StringBuilder(); - if (type.getExtendsBound() != null) { - b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound())); - } else if (type.getSuperBound() != null) { - b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound())); - } - return b.toString(); - } - - private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) { - String name; - name = Utils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString()); - - if (needsImport(enclosedElement, type)) { - TypeMirror usedByType = simpleNamesUsed.get(name); - if (usedByType == null) { - simpleNamesUsed.put(name, type); - usedByType = type; - } - - if (!typeEquals(type, usedByType)) { - name = getQualifiedName(type); - } - } - - if (type.getTypeArguments().size() == 0) { - return name; - } - - StringBuilder b = new StringBuilder(name); - b.append("<"); - if (type.getTypeArguments().size() > 0) { - for (int i = 0; i < type.getTypeArguments().size(); i++) { - b.append(createTypeReference(enclosedElement, type.getTypeArguments().get(i))); - if (i < type.getTypeArguments().size() - 1) { - b.append(", "); - } - } - } - b.append(">"); - return b.toString(); - } - - public Set generateImports() { - Set imports = new HashSet<>(); - - imports.addAll(generateImports(simpleNamesUsed.values())); - imports.addAll(generateStaticImports(staticImportUsage)); - - return imports; - } - - boolean processStaticImports(TypeElement element) { - Set importedMethods = new HashSet<>(); - List methods = ElementFilter.methodsIn(element.getEnclosedElements()); - for (ExecutableElement method : methods) { - if (method.getModifiers().contains(Modifier.STATIC)) { - importedMethods.add(method.getSimpleName().toString()); - } - } - - boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods); - - Set importedFields = new HashSet<>(); - List fields = ElementFilter.fieldsIn(element.getEnclosedElements()); - for (VariableElement field : fields) { - if (field.getModifiers().contains(Modifier.STATIC)) { - importedFields.add(field.getSimpleName().toString()); - } - } - - boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields); - - return allMethodsAmbiguous && allFieldsAmbiguous; - } - - private static boolean processStaticImportElements(Set newElements, Set ambiguousElements, Set declaredElements) { - boolean allAmbiguous = false; - if (declaredElements.containsAll(newElements)) { - // all types already declared -> we can remove the import completely -> they will all - // get ambiguous - allAmbiguous = true; - } - Set newAmbiguous = new HashSet<>(); - Set newDeclared = new HashSet<>(); - - for (String newElement : newElements) { - if (declaredElements.contains(newElement)) { - newAmbiguous.add(newElement); - } else if (ambiguousElements.contains(newElement)) { - // nothing to do - } else { - newDeclared.add(newElement); - } - } - - ambiguousElements.addAll(newAmbiguous); - declaredElements.addAll(newDeclared); - return allAmbiguous; - } - - private boolean needsImport(Element enclosedElement, TypeMirror importType) { - String importPackagName = getPackageName(importType); - if (importPackagName == null) { - return false; - } else if (importPackagName.equals("java.lang")) { - return false; - } else if (importPackagName.equals(getPackageName(topLevelClass)) && Utils.isTopLevelClass(importType)) { - return false; // same package name -> no import - } - - List elements = Utils.getElementHierarchy(enclosedElement); - - Set autoImportedTypes = new HashSet<>(); - for (Element element : elements) { - if (element.getKind().isClass()) { - collectSuperTypeImports((TypeElement) element, autoImportedTypes); - collectInnerTypeImports((TypeElement) element, autoImportedTypes); - } - } - - String qualifiedName = getQualifiedName(importType); - if (autoImportedTypes.contains(qualifiedName)) { - return false; - } - - return true; - } - - private static Set generateImports(Collection toGenerate) { - TreeSet importObjects = new TreeSet<>(); - for (TypeMirror importType : toGenerate) { - importObjects.add(new CodeImport(importType, getQualifiedName(importType), false)); - } - return importObjects; - } - - private static void collectInnerTypeImports(TypeElement e, Set autoImportedTypes) { - autoImportedTypes.add(getQualifiedName(e)); - for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) { - collectInnerTypeImports(innerClass, autoImportedTypes); - } - } - - private static void collectSuperTypeImports(TypeElement e, Set autoImportedTypes) { - List superTypes = getSuperTypes(e); - for (TypeElement superType : superTypes) { - List declaredTypes = getDeclaredTypes(superType); - for (TypeElement declaredType : declaredTypes) { - autoImportedTypes.add(getQualifiedName(declaredType)); - } - } - } - - private Set generateStaticImports(Set toGenerate) { - Set autoImportedStaticTypes = new HashSet<>(); - - // if type is declared inside a super type of this class -> no import - autoImportedStaticTypes.add(getQualifiedName(topLevelClass)); - autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(topLevelClass)); - - TreeSet importObjects = new TreeSet<>(); - for (TypeMirror importType : toGenerate) { - if (getPackageName(importType) == null) { - continue; // no package name -> no import - } - - String qualifiedName = getQualifiedName(importType); - if (autoImportedStaticTypes.contains(qualifiedName)) { - continue; - } - - importObjects.add(new CodeImport(importType, qualifiedName + ".*", true)); - } - - return importObjects; - } - - private abstract static class TypeReferenceVisitor extends CodeElementScanner { - - @Override - public void visitTree(CodeTree e, Void p) { - if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { - visitStaticFieldReference(e, e.getType(), e.getString()); - } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { - visitStaticMethodReference(e, e.getType(), e.getString()); - } else if (e.getType() != null) { - visitTypeReference(e, e.getType()); - } - super.visitTree(e, p); - } - - @Override - public Void visitExecutable(CodeExecutableElement e, Void p) { - visitAnnotations(e, e.getAnnotationMirrors()); - if (e.getReturnType() != null) { - visitTypeReference(e, e.getReturnType()); - } - for (TypeMirror type : e.getThrownTypes()) { - visitTypeReference(e, type); - } - return super.visitExecutable(e, p); - } - - @Override - public Void visitType(CodeTypeElement e, Void p) { - visitAnnotations(e, e.getAnnotationMirrors()); - - visitTypeReference(e, e.getSuperclass()); - for (TypeMirror type : e.getImplements()) { - visitTypeReference(e, type); - } - - return super.visitType(e, p); - } - - private void visitAnnotations(Element enclosingElement, List mirrors) { - for (AnnotationMirror mirror : mirrors) { - visitAnnotation(enclosingElement, mirror); - } - } - - public void visitAnnotation(Element enclosingElement, AnnotationMirror e) { - visitTypeReference(enclosingElement, e.getAnnotationType()); - if (!e.getElementValues().isEmpty()) { - Map values = e.getElementValues(); - Set methodsSet = values.keySet(); - List methodsList = new ArrayList<>(); - for (ExecutableElement method : methodsSet) { - if (values.get(method) == null) { - continue; - } - methodsList.add(method); - } - - for (int i = 0; i < methodsList.size(); i++) { - AnnotationValue value = values.get(methodsList.get(i)); - visitAnnotationValue(enclosingElement, value); - } - } - } - - public void visitAnnotationValue(Element enclosingElement, AnnotationValue e) { - e.accept(new AnnotationValueReferenceVisitor(enclosingElement), null); - } - - private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7 { - - private final Element enclosingElement; - - public AnnotationValueReferenceVisitor(Element enclosedElement) { - this.enclosingElement = enclosedElement; - } - - @Override - public Void visitBoolean(boolean b, Void p) { - return null; - } - - @Override - public Void visitByte(byte b, Void p) { - return null; - } - - @Override - public Void visitChar(char c, Void p) { - return null; - } - - @Override - public Void visitDouble(double d, Void p) { - return null; - } - - @Override - public Void visitFloat(float f, Void p) { - return null; - } - - @Override - public Void visitInt(int i, Void p) { - return null; - } - - @Override - public Void visitLong(long i, Void p) { - return null; - } - - @Override - public Void visitShort(short s, Void p) { - return null; - } - - @Override - public Void visitString(String s, Void p) { - return null; - } - - @Override - public Void visitType(TypeMirror t, Void p) { - visitTypeReference(enclosingElement, t); - return null; - } - - @Override - public Void visitEnumConstant(VariableElement c, Void p) { - visitTypeReference(enclosingElement, c.asType()); - return null; - } - - @Override - public Void visitAnnotation(AnnotationMirror a, Void p) { - TypeReferenceVisitor.this.visitAnnotation(enclosingElement, a); - return null; - } - - @Override - public Void visitArray(List vals, Void p) { - for (int i = 0; i < vals.size(); i++) { - TypeReferenceVisitor.this.visitAnnotationValue(enclosingElement, vals.get(i)); - } - return null; - } - } - - @Override - public Void visitVariable(VariableElement f, Void p) { - visitAnnotations(f, f.getAnnotationMirrors()); - visitTypeReference(f, f.asType()); - return super.visitVariable(f, p); - } - - @Override - public void visitImport(CodeImport e, Void p) { - } - - public abstract void visitTypeReference(Element enclosedType, TypeMirror type); - - public abstract void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName); - - public abstract void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName); - - } - - private class ImportTypeReferenceVisitor extends TypeReferenceVisitor { - - @Override - public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) { - staticImportUsage.add(type); - } - - @Override - public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) { - staticImportUsage.add(type); - } - - @Override - public void visitTypeReference(Element enclosedType, TypeMirror type) { - createTypeReference(enclosedType, type); - } - - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/AbstractCompiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/AbstractCompiler.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * 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.dsl.processor.compiler; - -import java.lang.reflect.*; - -public abstract class AbstractCompiler implements Compiler { - - protected static Object method(Object o, String methodName) throws Exception { - Method method = o.getClass().getMethod(methodName); - method.setAccessible(true); - return method.invoke(o); - } - - protected static Object method(Object o, String methodName, Class[] paramTypes, Object... values) throws Exception { - Method method = o.getClass().getMethod(methodName, paramTypes); - method.setAccessible(true); - return method.invoke(o, values); - } - - protected static Object field(Object o, String fieldName) throws Exception { - if (o == null) { - return null; - } - Class clazz = o.getClass(); - Field field = null; - try { - field = clazz.getField(fieldName); - } catch (NoSuchFieldException e) { - while (clazz != null) { - try { - field = clazz.getDeclaredField(fieldName); - break; - } catch (NoSuchFieldException e1) { - clazz = clazz.getSuperclass(); - } - } - if (field == null) { - throw e; - } - } - field.setAccessible(true); - return field.get(o); - } - - protected static String parseHeader(String content) { - int index = content.indexOf("/*"); - if (index == -1) { - return null; - } - if (!content.substring(0, index).trim().equals("")) { - // just whitespace before - return null; - } - - int endIndex = content.indexOf("*/", index); - if (endIndex == -1) { - return null; - } - return content.substring(index, endIndex + 2); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/Compiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/Compiler.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * 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.dsl.processor.compiler; - -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; - -public interface Compiler { - - String getMethodBody(ProcessingEnvironment env, ExecutableElement method); - - String getHeaderComment(ProcessingEnvironment env, Element type); - - List getEnclosedElementsInDeclarationOrder(TypeElement type); - - List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type); - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/CompilerFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/CompilerFactory.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * 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.dsl.processor.compiler; - -import javax.lang.model.element.*; - -public class CompilerFactory { - - private static Compiler javac; - private static Compiler jdt; - - public static Compiler getCompiler(Element currentElement) { - if (JavaCCompiler.isValidElement(currentElement)) { - if (javac == null) { - javac = new JavaCCompiler(); - } - return javac; - } else if (JDTCompiler.isValidElement(currentElement)) { - if (jdt == null) { - jdt = new JDTCompiler(); - } - return jdt; - } else { - throw new UnsupportedOperationException("Unsupported compiler for element " + currentElement.getClass().getName() + "."); - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JDTCompiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JDTCompiler.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,283 +0,0 @@ -/* - * 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.dsl.processor.compiler; - -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public class JDTCompiler extends AbstractCompiler { - - public static boolean isValidElement(Element currentElement) { - try { - Class elementClass = Class.forName("org.eclipse.jdt.internal.compiler.apt.model.ElementImpl"); - return elementClass.isAssignableFrom(currentElement.getClass()); - } catch (ClassNotFoundException e) { - return false; - } - } - - public List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type) { - return sortBySourceOrder(new ArrayList<>(environment.getElementUtils().getAllMembers(type))); - } - - public List getEnclosedElementsInDeclarationOrder(TypeElement type) { - return sortBySourceOrder(new ArrayList<>(type.getEnclosedElements())); - } - - private static List sortBySourceOrder(List elements) { - final Map> declarationOrders = new HashMap<>(); - - Collections.sort(elements, new Comparator() { - public int compare(Element o1, Element o2) { - try { - TypeMirror enclosing1 = o1.getEnclosingElement().asType(); - TypeMirror enclosing2 = o2.getEnclosingElement().asType(); - - if (Utils.typeEquals(enclosing1, enclosing2)) { - List declarationOrder = lookupDeclarationOrder(declarationOrders, (TypeElement) o1.getEnclosingElement()); - if (declarationOrder == null) { - return 0; - } - Object o1Binding = field(o1, "_binding"); - Object o2Binding = field(o2, "_binding"); - - int i1 = declarationOrder.indexOf(o1Binding); - int i2 = declarationOrder.indexOf(o2Binding); - - return i1 - i2; - } else { - if (Utils.isSubtype(enclosing1, enclosing2)) { - return 1; - } else if (Utils.isSubtype(enclosing2, enclosing1)) { - return -1; - } else { - return 0; - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - return elements; - } - - private static List lookupDeclarationOrder(Map> declarationOrders, TypeElement type) throws Exception, ClassNotFoundException { - if (declarationOrders.containsKey(type)) { - return declarationOrders.get(type); - } - - Object binding = field(type, "_binding"); - Class sourceTypeBinding = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); - Class binaryTypeBinding = Class.forName("org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding"); - - List declarationOrder = null; - if (sourceTypeBinding.isAssignableFrom(binding.getClass())) { - declarationOrder = findSourceTypeOrder(binding); - } else if (binaryTypeBinding.isAssignableFrom(binding.getClass())) { - declarationOrder = findBinaryTypeOrder(binding); - } - - declarationOrders.put(type, declarationOrder); - - return declarationOrder; - } - - private static List findBinaryTypeOrder(Object binding) throws Exception { - Object binaryType = lookupBinaryType(binding); - final Object[] sortedMethods = (Object[]) method(binaryType, "getMethods"); - - List sortedElements = new ArrayList<>(); - if (sortedMethods != null) { - sortedElements.addAll(Arrays.asList(sortedMethods)); - } - final Object[] sortedFields = (Object[]) method(binaryType, "getFields"); - if (sortedFields != null) { - sortedElements.addAll(Arrays.asList(sortedFields)); - } - final Object[] sortedTypes = (Object[]) method(binaryType, "getMemberTypes", new Class[0]); - if (sortedTypes != null) { - sortedElements.addAll(Arrays.asList(sortedTypes)); - } - - Collections.sort(sortedElements, new Comparator() { - public int compare(Object o1, Object o2) { - try { - int structOffset1 = (int) field(o1, "structOffset"); - int structOffset2 = (int) field(o2, "structOffset"); - return structOffset1 - structOffset2; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - - Class binaryMethod = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryMethod"); - Class binaryField = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryField"); - Class nestedType = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryNestedType"); - - List bindings = new ArrayList<>(); - for (Object sortedElement : sortedElements) { - Class elementClass = sortedElement.getClass(); - if (binaryMethod.isAssignableFrom(elementClass)) { - char[] selector = (char[]) method(sortedElement, "getSelector"); - Object[] foundBindings = (Object[]) method(binding, "getMethods", new Class[]{char[].class}, selector); - if (foundBindings == null || foundBindings.length == 0) { - continue; - } else if (foundBindings.length == 1) { - bindings.add(foundBindings[0]); - } else { - char[] idescriptor = (char[]) method(sortedElement, "getMethodDescriptor"); - for (Object foundBinding : foundBindings) { - char[] descriptor = (char[]) method(foundBinding, "signature"); - if (descriptor == null && idescriptor == null || Arrays.equals(descriptor, idescriptor)) { - bindings.add(foundBinding); - break; - } - } - } - } else if (binaryField.isAssignableFrom(elementClass)) { - char[] selector = (char[]) method(sortedElement, "getName"); - Object foundField = method(binding, "getField", new Class[]{char[].class, boolean.class}, selector, true); - if (foundField != null) { - bindings.add(foundField); - } - } else if (nestedType.isAssignableFrom(elementClass)) { - char[] selector = (char[]) method(sortedElement, "getSourceName"); - Object foundType = method(binding, "getMemberType", new Class[]{char[].class}, selector); - if (foundType != null) { - bindings.add(foundType); - } - } else { - throw new AssertionError("Unexpected encountered type " + elementClass); - } - } - - return bindings; - } - - private static Object lookupBinaryType(Object binding) throws Exception { - Object lookupEnvironment = field(binding, "environment"); - Object compoundClassName = field(binding, "compoundName"); - Object nameEnvironment = field(lookupEnvironment, "nameEnvironment"); - Object nameEnvironmentAnswer = method(nameEnvironment, "findType", new Class[]{char[][].class}, compoundClassName); - Object binaryType = method(nameEnvironmentAnswer, "getBinaryType", new Class[0]); - return binaryType; - } - - private static List findSourceTypeOrder(Object binding) throws Exception { - Object referenceContext = field(field(binding, "scope"), "referenceContext"); - - TreeMap orderedBindings = new TreeMap<>(); - - collectSourceOrder(orderedBindings, referenceContext, "methods"); - collectSourceOrder(orderedBindings, referenceContext, "fields"); - collectSourceOrder(orderedBindings, referenceContext, "memberTypes"); - - return new ArrayList<>(orderedBindings.values()); - } - - private static void collectSourceOrder(TreeMap orderedBindings, Object referenceContext, String fieldName) throws Exception { - Object[] declarations = (Object[]) field(referenceContext, fieldName); - if (declarations != null) { - for (int i = 0; i < declarations.length; i++) { - Integer declarationSourceStart = (Integer) field(declarations[i], "declarationSourceStart"); - orderedBindings.put(declarationSourceStart, field(declarations[i], "binding")); - } - } - } - - @Override - public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { - try { - - char[] source = getSource(method); - if (source == null) { - return null; - } - - /* - * 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"); - - int length = bodyEnd - bodyStart; - char[] target = new char[length]; - System.arraycopy(source, bodyStart, target, 0, length); - - return new String(target); - } catch (Exception e) { - return Utils.printException(e); - } - } - - 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; - */ - - 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"); - - char[] source = null; - if (methodBindingClass.isAssignableFrom(binding.getClass())) { - Object sourceMethod = method(binding, "sourceMethod"); - if (sourceMethod == null) { - return null; - } - source = (char[]) method(method(field(sourceMethod, "compilationResult"), "getCompilationUnit"), "getContents"); - } else if (referenceBindingClass.isAssignableFrom(binding.getClass())) { - source = (char[]) method(field(field(field(field(binding, "scope"), "referenceContext"), "compilationResult"), "compilationUnit"), "getContents"); - } - return source; - } - - @Override - public String getHeaderComment(ProcessingEnvironment env, Element type) { - try { - char[] source = getSource(type); - if (source == null) { - return null; - } - return parseHeader(new String(source)); - } catch (Exception e) { - return Utils.printException(e); - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JavaCCompiler.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/compiler/JavaCCompiler.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/* - * 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.dsl.processor.compiler; - -import java.util.*; - -import javax.annotation.processing.*; -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.*; - -public class JavaCCompiler extends AbstractCompiler { - - public static boolean isValidElement(Element currentElement) { - try { - Class elementClass = Class.forName("com.sun.tools.javac.code.Symbol"); - return elementClass.isAssignableFrom(currentElement.getClass()); - } catch (ClassNotFoundException e) { - return false; - } - } - - public List getEnclosedElementsInDeclarationOrder(TypeElement type) { - return type.getEnclosedElements(); - } - - public List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type) { - return environment.getElementUtils().getAllMembers(type); - } - - private static final Class[] getTreeAndTopLevelSignature = new Class[]{Element.class, AnnotationMirror.class, AnnotationValue.class}; - private static final Class[] getCharContentSignature = new Class[]{boolean.class}; - - @Override - public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { - try { - /* - * if (false) { Pair treeAndTopLevel = ((JavacElements) - * env.getElementUtils()).getTreeAndTopLevel(method, null, null); JCBlock block = - * ((JCMethodDecl) treeAndTopLevel.fst).getBody(); int startPos = block.pos; int endPos - * = block.endpos; String methodBody = - * treeAndTopLevel.snd.getSourceFile().getCharContent(true).subSequence(startPos + 1, - * endPos).toString(); return methodBody; } - */ - - Object treeAndTopLevel = getTreeAndTopLevel(env, method); - Object block = method(field(treeAndTopLevel, "fst"), "getBody"); - int startPos = (int) field(block, "pos"); - int endPos = (int) field(block, "endpos"); - return getContent(treeAndTopLevel).subSequence(startPos + 1, endPos).toString(); - } catch (Exception e) { - return Utils.printException(e); - } - } - - private static CharSequence getContent(Object treeAndTopLevel) throws Exception { - /* - * CharSequence content = treeAndTopLevel.snd.getSourceFile().getCharContent(true); - */ - return (CharSequence) method(method(field(treeAndTopLevel, "snd"), "getSourceFile"), "getCharContent", getCharContentSignature, true); - } - - private static Object getTreeAndTopLevel(ProcessingEnvironment env, Element element) throws Exception { - /* - * Pair treeAndTopLevel = ((JavacElements) - * env.getElementUtils()).getTreeAndTopLevel(method, null, null); - */ - return method(method(env, "getElementUtils"), "getTreeAndTopLevel", getTreeAndTopLevelSignature, element, null, null); - } - - @Override - public String getHeaderComment(ProcessingEnvironment env, Element type) { - try { - String content = getContent(getTreeAndTopLevel(env, type)).toString(); - return parseHeader(content); - } catch (Exception e) { - return Utils.printException(e); - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractClassElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractClassElementFactory.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,134 @@ +/* + * 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.dsl.processor.generator; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +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.api.dsl.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; + +public abstract class AbstractClassElementFactory extends AbstractCodeElementFactory { + + @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(); + TypeElement superClass = fromTypeMirror(clazz.getSuperclass()); + ExecutableElement constructor = findConstructor(superClass); + if (constructor != null && constructor.getParameters().size() > 0) { + builder.startStatement(); + builder.startSuperCall(); + for (VariableElement parameter : constructor.getParameters()) { + method.addParameter(new CodeVariableElement(parameter.asType(), parameter.getSimpleName().toString())); + builder.string(parameter.getSimpleName().toString()); + } + builder.end(); // super + builder.end(); // statement + } + + for (VariableElement field : clazz.getFields()) { + if (field.getModifiers().contains(STATIC)) { + continue; + } + String fieldName = field.getSimpleName().toString(); + method.addParameter(new CodeVariableElement(field.asType(), fieldName)); + builder.startStatement(); + builder.string("this."); + builder.string(fieldName); + builder.string(" = "); + if (isAssignable(field.asType(), getContext().getTruffleTypes().getNode())) { + builder.string("adoptChild(").string(fieldName).string(")"); + } else { + builder.string(fieldName); + } + builder.end(); // statement + } + + return method; + } + + private static ExecutableElement findConstructor(TypeElement clazz) { + List constructors = ElementFilter.constructorsIn(clazz.getEnclosedElements()); + if (constructors.isEmpty()) { + return null; + } else { + return constructors.get(0); + } + } + + 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(); + + PackageElement pack = getContext().getEnvironment().getElementUtils().getPackageOf(templateType); + CodeTypeElement clazz = new CodeTypeElement(modifiers, enumType ? ElementKind.ENUM : ElementKind.CLASS, pack, simpleName); + TypeMirror resolvedSuperType = superType; + if (resolvedSuperType == null) { + resolvedSuperType = getContext().getType(Object.class); + } + clazz.setSuperClass(resolvedSuperType); + + CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class)); + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); + if (model.getTemplateMethodName() != null) { + generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName())); + } + + clazz.addAnnotationMirror(generatedByAnnotation); + + return clazz; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractCodeElementFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractCodeElementFactory.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,77 @@ +/* + * 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.dsl.processor.generator; + +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.model.*; + +public abstract class AbstractCodeElementFactory { + + protected final ProcessorContext context; + private M model; + + private CodeElement element; + + public AbstractCodeElementFactory() { + this.context = ProcessorContext.getInstance(); + } + + protected abstract CodeElement create(M m); + + @SuppressWarnings("unused") + protected void createChildren(M m) { + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public CodeElement process(CodeElement parent, M m) { + model = m; + element = (CodeElement) create(model); + if (parent != null) { + parent.add(element); + } + if (element != null) { + createChildren(model); + } + return element; + } + + @SuppressWarnings("rawtypes") + public CodeElement getElement() { + return element; + } + + protected void add(AbstractCodeElementFactory factory, MO m) { + factory.process(this.element, m); + } + + public ProcessorContext getContext() { + return context; + } + + public M getModel() { + return model; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractCompilationUnitFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/AbstractCompilationUnitFactory.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,43 @@ +/* + * 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.dsl.processor.generator; + +import com.oracle.truffle.dsl.processor.java.model.*; + +public abstract class AbstractCompilationUnitFactory extends AbstractCodeElementFactory { + + @Override + public final CodeCompilationUnit create(M m) { + return new CodeCompilationUnit(); + } + + @SuppressWarnings("rawtypes") + @Override + public CodeCompilationUnit process(CodeElement parent, M m) { + return (CodeCompilationUnit) super.process(parent, m); + } + + @Override + protected abstract void createChildren(M m); + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,2935 @@ +/* + * 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.dsl.processor.generator; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +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.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; +import com.oracle.truffle.dsl.processor.parser.*; +import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard; + +public class NodeCodeGenerator extends AbstractCompilationUnitFactory { + + private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; + + private static final String EXECUTE_CHAINED = "executeChained0"; + private static final String SPECIALIZE = "specialize0"; + private static final String DSLSHARE_REWRITE = "rewrite"; + private static final String DSLSHARE_FIND_ROOT = "findRoot"; + private static final String DSLSHARE_REWRITE_TO_POLYMORHPIC = "rewriteToPolymorphic"; + private static final String EXECUTE_UNINITIALIZED = "executeUninitialized0"; + private static final String REWRITE = "rewrite0"; + private static final String CREATE_INFO = "createInfo0"; + private static final String CONTAINS_FALLBACK = "containsFallback"; + + private static final String FACTORY_METHOD_NAME = "create0"; + private static final String EMPTY_CLASS_ARRAY = "EMPTY_CLASS_ARRAY"; + + private static final String METADATA_FIELD_NAME = "METADATA"; + + private TypeMirror getUnexpectedValueException() { + return getContext().getTruffleTypes().getUnexpectedValueException(); + } + + private static String factoryClassName(NodeData node) { + return node.getNodeId() + "Factory"; + } + + private static String nodeSpecializationClassName(SpecializationData specialization) { + String nodeid = resolveNodeId(specialization.getNode()); + String name = ElementUtils.firstLetterUpperCase(nodeid); + name += ElementUtils.firstLetterUpperCase(specialization.getId()); + name += "Node"; + return name; + } + + private static String nodePolymorphicClassName(NodeData node) { + return ElementUtils.firstLetterUpperCase(resolveNodeId(node)) + "PolymorphicNode"; + } + + private static String resolveNodeId(NodeData node) { + String nodeid = node.getNodeId(); + if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { + nodeid = nodeid.substring(0, nodeid.length() - 4); + } + return nodeid; + } + + private static String valueNameEvaluated(Parameter targetParameter) { + return valueName(targetParameter) + "Evaluated"; + } + + private static String implicitTypeName(Parameter param) { + return param.getLocalName() + "ImplicitType"; + } + + private static String polymorphicTypeName(NodeExecutionData param) { + return param.getName() + "PolymorphicType"; + } + + private static String valueName(Parameter param) { + return param.getLocalName(); + } + + private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) { + String reference = thisReference; + if (reference == null) { + reference = "this"; + } + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + Element accessElement = targetExecution.getChild().getAccessElement(); + if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { + builder.string(reference).string(".").string(targetExecution.getChild().getName()); + } else if (accessElement.getKind() == ElementKind.FIELD) { + builder.string(reference).string(".").string(accessElement.getSimpleName().toString()); + } else { + throw new AssertionError(); + } + if (targetExecution.isIndexed()) { + builder.string("[" + targetExecution.getIndex() + "]"); + } + return builder.getRoot(); + } + + private static String castValueName(Parameter parameter) { + return valueName(parameter) + "Cast"; + } + + private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); + } + for (Parameter parameter : specialization.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (forceFrame && spec.getName().equals("frame")) { + continue; + } + if (spec.isLocal()) { + continue; + } + + String name = valueName(parameter); + if (evaluated && spec.isSignature()) { + name = valueNameEvaluated(parameter); + } + + method.addParameter(new CodeVariableElement(parameter.getType(), name)); + } + } + + private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, + Map customNames) { + if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { + builder.string("frameValue"); + } + for (Parameter parameter : specialization.getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (forceFrame && spec.getName().equals("frame")) { + continue; + } + + if (parameter.getSpecification().isLocal()) { + continue; + } + + Parameter sourceParameter = source.findParameter(parameter.getLocalName()); + + if (customNames != null && customNames.containsKey(parameter.getLocalName())) { + builder.string(customNames.get(parameter.getLocalName())); + } else if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { + builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); + } else if (sourceParameter != null) { + builder.string(valueName(sourceParameter, parameter)); + } else { + builder.string(valueName(parameter)); + } + } + } + + private static String valueName(Parameter sourceParameter, Parameter targetParameter) { + if (!sourceParameter.getSpecification().isSignature()) { + return valueName(targetParameter); + } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { + if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) { + return castValueName(targetParameter); + } + } + return valueName(targetParameter); + } + + private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName, + String... customSignatureValueNames) { + CodeTreeBuilder builder = parent.create(); + + boolean castedValues = sourceMethod != targetMethod; + + builder.startGroup(); + ExecutableElement method = targetMethod.getMethod(); + if (method == null) { + throw new UnsupportedOperationException(); + } + TypeElement targetClass = ElementUtils.findNearestEnclosingType(method.getEnclosingElement()); + NodeData node = (NodeData) targetMethod.getTemplate(); + + if (target == null) { + boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType()); + if (accessible) { + if (builder.findMethod().getModifiers().contains(STATIC)) { + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); + } else { + builder.string(THIS_NODE_LOCAL_VAR_NAME); + } + } else { + if (targetMethod instanceof ExecutableTypeData) { + builder.string("this"); + } else { + builder.string("super"); + } + } + } else { + if (method.getModifiers().contains(STATIC)) { + builder.type(targetClass.asType()); + } else { + Parameter firstParameter = null; + for (Parameter searchParameter : targetMethod.getParameters()) { + if (searchParameter.getSpecification().isSignature()) { + firstParameter = searchParameter; + break; + } + } + if (firstParameter == null) { + throw new AssertionError(); + } + + Parameter sourceParameter = sourceMethod.findParameter(firstParameter.getLocalName()); + + if (castedValues && sourceParameter != null) { + builder.string(valueName(sourceParameter, firstParameter)); + } else { + builder.string(valueName(firstParameter)); + } + } + } + builder.string("."); + } else { + builder.tree(target); + } + builder.startCall(method.getSimpleName().toString()); + + int signatureIndex = 0; + + for (Parameter targetParameter : targetMethod.getParameters()) { + Parameter valueParameter = null; + if (sourceMethod != null) { + valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); + } + if (valueParameter == null) { + valueParameter = targetParameter; + } + TypeMirror targetType = targetParameter.getType(); + TypeMirror valueType = null; + if (valueParameter != null) { + valueType = valueParameter.getType(); + } + + if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) { + builder.string(customSignatureValueNames[signatureIndex]); + signatureIndex++; + } else if (targetParameter.getSpecification().isLocal()) { + builder.startGroup(); + if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { + builder.string(THIS_NODE_LOCAL_VAR_NAME).string("."); + } else { + builder.string("this."); + } + builder.string(targetParameter.getSpecification().getName()); + builder.end(); + } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { + builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); + } else if (!ElementUtils.needsCastTo(valueType, targetType)) { + builder.startGroup(); + builder.string(valueName(targetParameter)); + builder.end(); + } else { + builder.string(castValueName(targetParameter)); + } + } + + builder.end().end(); + + return builder.getRoot(); + } + + private static String baseClassName(NodeData node) { + String nodeid = resolveNodeId(node); + String name = ElementUtils.firstLetterUpperCase(nodeid); + name += "BaseNode"; + return name; + } + + private static CodeTree createCallTypeSystemMethod(CodeTreeBuilder parent, NodeData node, String methodName, CodeTree... args) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + startCallTypeSystemMethod(builder, node.getTypeSystem(), methodName); + for (CodeTree arg : args) { + builder.tree(arg); + } + builder.end().end(); + return builder.getRoot(); + } + + private static void startCallTypeSystemMethod(CodeTreeBuilder body, TypeSystemData typeSystem, String methodName) { + GeneratedTypeMirror typeMirror = new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()), TypeSystemCodeGenerator.typeName(typeSystem)); + body.startGroup(); + body.staticReference(typeMirror, TypeSystemCodeGenerator.singletonName(typeSystem)); + body.string(".").startCall(methodName); + } + + /** + *
+     * variant1 $condition != null
+     * 
+     * $type $name = defaultValue($type);
+     * if ($condition) {
+     *     $name = $value;
+     * }
+     * 
+     * variant2 $condition != null
+     * $type $name = $value;
+     * 
+ * + * . + */ + private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (condition == null) { + builder.declaration(type, name, value); + } else { + builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot()); + + builder.startIf().tree(condition).end(); + builder.startBlock(); + builder.startStatement(); + builder.string(name); + builder.string(" = "); + builder.tree(value); + builder.end(); // statement + builder.end(); // block + } + return builder.getRoot(); + } + + private void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { + CodeTreeBuilder nodes = builder.create(); + CodeTreeBuilder arguments = builder.create(); + nodes.startCommaGroup(); + arguments.startCommaGroup(); + boolean empty = true; + for (Parameter parameter : current.getParameters()) { + NodeExecutionData executionData = parameter.getSpecification().getExecution(); + if (executionData != null) { + if (executionData.isShortCircuit()) { + nodes.nullLiteral(); + arguments.string(valueName(parameter.getPreviousParameter())); + } + nodes.tree(createAccessChild(executionData, "rootNode")); + arguments.string(valueName(parameter)); + empty = false; + } + } + nodes.end(); + arguments.end(); + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); + + builder.declaration(baseClassName(getModel()), "rootNode", builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_FIND_ROOT).string("this").end()); + builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class)); + builder.string("rootNode"); + builder.startNewArray(getContext().getTruffleTypes().getNodeArray(), null); + builder.tree(nodes.getRoot()); + builder.end(); + if (!empty) { + builder.tree(arguments.getRoot()); + } + builder.end().end(); + } + + private static List findUserConstructors(TypeMirror nodeType) { + List constructors = new ArrayList<>(); + for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(nodeType).getEnclosedElements())) { + if (constructor.getModifiers().contains(PRIVATE)) { + continue; + } + if (isCopyConstructor(constructor)) { + continue; + } + constructors.add(constructor); + } + + if (constructors.isEmpty()) { + constructors.add(new CodeExecutableElement(null, ElementUtils.getSimpleName(nodeType))); + } + + return constructors; + } + + private static ExecutableElement findCopyConstructor(TypeMirror type) { + for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(type).getEnclosedElements())) { + if (constructor.getModifiers().contains(PRIVATE)) { + continue; + } + if (isCopyConstructor(constructor)) { + return constructor; + } + } + + return null; + } + + private static boolean isCopyConstructor(ExecutableElement element) { + if (element.getParameters().size() != 1) { + return false; + } + VariableElement var = element.getParameters().get(0); + TypeElement enclosingType = ElementUtils.findNearestEnclosingType(var); + if (ElementUtils.typeEquals(var.asType(), enclosingType.asType())) { + return true; + } + List types = ElementUtils.getDirectSuperTypes(enclosingType); + for (TypeElement type : types) { + if (!(type instanceof CodeTypeElement)) { + // no copy constructors which are not generated types + return false; + } + + if (ElementUtils.typeEquals(var.asType(), type.asType())) { + return true; + } + } + return false; + } + + @Override + @SuppressWarnings("unchecked") + protected void createChildren(NodeData node) { + List casts = new ArrayList<>(getElement().getEnclosedElements()); + getElement().getEnclosedElements().clear(); + + Map> childTypes = new LinkedHashMap<>(); + for (NodeData nodeChild : node.getEnclosingNodes()) { + NodeCodeGenerator generator = new NodeCodeGenerator(); + childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements()); + } + + if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { + NodeFactoryFactory factory = new NodeFactoryFactory(childTypes); + add(factory, node); + factory.getElement().getEnclosedElements().addAll(casts); + } + } + + private static CodeTree createCastType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { + if (targetType == null) { + return value; + } else if (sourceType != null && !sourceType.needsCastTo(targetType)) { + return value; + } + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String targetMethodName; + if (expect) { + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); + } else { + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); + } + startCallTypeSystemMethod(builder, typeSystem, targetMethodName); + builder.tree(value); + builder.end().end(); + return builder.getRoot(); + } + + private static CodeTree createExpectType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, CodeTree expression) { + return createCastType(typeSystem, sourceType, targetType, true, expression); + } + + private CodeTree createDeoptimize(CodeTreeBuilder parent) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end(); + builder.end(); + return builder.getRoot(); + } + + private class NodeFactoryFactory extends AbstractClassElementFactory { + + private final Map> childTypes; + private CodeTypeElement generatedNode; + + public NodeFactoryFactory(Map> childElements) { + this.childTypes = childElements; + } + + @Override + protected CodeTypeElement create(NodeData node) { + Modifier visibility = ElementUtils.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); + return clazz; + } + + @Override + protected void createChildren(NodeData node) { + CodeTypeElement clazz = getElement(); + + Modifier createVisibility = ElementUtils.getVisibility(clazz.getModifiers()); + + if (node.needsFactory()) { + NodeBaseFactory factory = new NodeBaseFactory(); + add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); + generatedNode = factory.getElement(); + + createFactoryMethods(node, clazz, createVisibility); + + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isReachable() || specialization.isGeneric()) { + continue; + } + + if (specialization.isPolymorphic() && node.isPolymorphic(context)) { + PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(generatedNode); + add(polymorphicFactory, specialization); + continue; + } + + add(new SpecializedNodeFactory(generatedNode), specialization); + } + + TypeMirror nodeFactory = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getTruffleTypes().getNodeFactoryBase()), node.getNodeType()); + clazz.setSuperClass(nodeFactory); + clazz.add(createNodeFactoryConstructor(node)); + clazz.add(createCreateNodeMethod(node)); +// clazz.add(createGetNodeClassMethod(node)); +// clazz.add(createGetNodeSignaturesMethod()); +// clazz.add(createGetChildrenSignatureMethod(node)); + clazz.add(createGetInstanceMethod(node, createVisibility)); + clazz.add(createInstanceConstant(node, clazz.asType())); + } + + 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 = ElementUtils.getVisibility(type.getModifiers()); + typeModifiers.clear(); + if (visibility != null) { + typeModifiers.add(visibility); + } + + typeModifiers.add(Modifier.STATIC); + typeModifiers.add(Modifier.FINAL); + clazz.add(type); + } + } + + List children = node.getNodeDeclaringChildren(); + if (node.getDeclaringNode() == null && children.size() > 0) { + clazz.add(createGetFactories(node)); + } + + } + + private Element createNodeFactoryConstructor(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), null, factoryClassName(node)); + CodeTreeBuilder builder = method.createBuilder(); + builder.startStatement(); + builder.startCall("super"); + + // node type + builder.typeLiteral(node.getNodeType()); + + // execution signature + builder.startGroup(); + if (node.getChildExecutions().isEmpty()) { + builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); + } else { + builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); + for (NodeExecutionData execution : node.getChildExecutions()) { + builder.typeLiteral(execution.getNodeType()); + } + builder.end(); + } + builder.end(); + + // node signatures + builder.startGroup(); + builder.startNewArray(new ArrayCodeTypeMirror(new ArrayCodeTypeMirror(context.getType(Class.class))), null); + List constructors = findUserConstructors(generatedNode.asType()); + for (ExecutableElement constructor : constructors) { + builder.startGroup(); + if (constructor.getParameters().isEmpty()) { + builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); + } else { + builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); + for (VariableElement var : constructor.getParameters()) { + builder.typeLiteral(var.asType()); + } + builder.end(); + } + builder.end(); + } + builder.end(); + builder.end(); + + builder.end().end().end(); + return method; + } + + private CodeExecutableElement createCreateNodeMethod(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); + method.setVarArgs(true); + method.addParameter(arguments); + + CodeTreeBuilder builder = method.createBuilder(); + List signatures = findUserConstructors(generatedNode.asType()); + boolean ifStarted = false; + + for (ExecutableElement element : signatures) { + ifStarted = builder.startIf(ifStarted); + builder.string("arguments.length == " + element.getParameters().size()); + + int index = 0; + for (VariableElement param : element.getParameters()) { + if (ElementUtils.isObject(param.asType())) { + continue; + } + builder.string(" && "); + if (!param.asType().getKind().isPrimitive()) { + builder.string("(arguments[" + index + "] == null || "); + } + builder.string("arguments[" + index + "] instanceof "); + builder.type(ElementUtils.boxType(getContext(), param.asType())); + if (!param.asType().getKind().isPrimitive()) { + builder.string(")"); + } + index++; + } + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("create"); + index = 0; + for (VariableElement param : element.getParameters()) { + builder.startGroup(); + if (!ElementUtils.isObject(param.asType())) { + builder.string("(").type(param.asType()).string(") "); + } + builder.string("arguments[").string(String.valueOf(index)).string("]"); + builder.end(); + index++; + } + builder.end().end(); + + builder.end(); // block + } + + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid create signature."); + builder.end().end(); + builder.end(); // else block + return method; + } + + private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { + TypeElement nodeFactoryType = ElementUtils.fromTypeMirror(getContext().getType(NodeFactory.class)); + TypeMirror returnType = ElementUtils.getDeclaredType(nodeFactoryType, node.getNodeType()); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance"); + if (visibility != null) { + method.getModifiers().add(visibility); + } + method.getModifiers().add(Modifier.STATIC); + + String varName = instanceVarName(node); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startIf(); + builder.string(varName).string(" == null"); + builder.end().startBlock(); + + builder.startStatement(); + builder.string(varName); + builder.string(" = "); + builder.startNew(factoryClassName(node)).end(); + builder.end(); + + builder.end(); + builder.startReturn().string(varName).end(); + return method; + } + + private String instanceVarName(NodeData node) { + if (node.getDeclaringNode() != null) { + return ElementUtils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; + } else { + return "instance"; + } + } + + private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { + String varName = instanceVarName(node); + CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); + var.getModifiers().add(Modifier.PRIVATE); + var.getModifiers().add(Modifier.STATIC); + return var; + } + + private ExecutableElement createGetFactories(NodeData node) { + List children = node.getNodeDeclaringChildren(); + if (node.needsFactory()) { + children.add(node); + } + + List nodeTypesList = new ArrayList<>(); + TypeMirror prev = null; + boolean allSame = true; + for (NodeData child : children) { + nodeTypesList.add(child.getNodeType()); + if (prev != null && !ElementUtils.typeEquals(child.getNodeType(), prev)) { + allSame = false; + } + prev = child.getNodeType(); + } + TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); + + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror factoryType = getContext().getType(NodeFactory.class); + TypeMirror baseType; + if (allSame) { + baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), commonNodeSuperType); + } else { + baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); + } + TypeMirror listType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getType(List.class)), baseType); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); + + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + + for (NodeData child : children) { + builder.startGroup(); + NodeData childNode = child; + List factories = new ArrayList<>(); + while (childNode.getDeclaringNode() != null) { + factories.add(childNode); + childNode = childNode.getDeclaringNode(); + } + Collections.reverse(factories); + for (NodeData nodeData : factories) { + builder.string(factoryClassName(nodeData)).string("."); + } + builder.string("getInstance()"); + builder.end(); + } + builder.end(); + builder.end(); + return method; + } + + private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { + List constructors = findUserConstructors(generatedNode.asType()); + for (ExecutableElement constructor : constructors) { + 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().isEmpty()) { + body.nullLiteral(); + } else { + body.startCall(nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME); + for (VariableElement var : method.getParameters()) { + body.string(var.getSimpleName().toString()); + } + body.end(); + } + body.end(); + return method; + } + + } + + private class NodeBaseFactory extends AbstractClassElementFactory { + + @Override + protected CodeTypeElement create(SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); + clazz.getImplements().add(context.getTruffleTypes().getDslNode()); + + for (NodeChildData child : node.getChildren()) { + clazz.add(createChildField(child)); + + if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { + ExecutableElement getter = (ExecutableElement) child.getAccessElement(); + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); + method.getModifiers().remove(Modifier.ABSTRACT); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().string("this.").string(child.getName()).end(); + clazz.add(method); + } + } + + for (NodeFieldData field : node.getFields()) { + if (!field.isGenerated()) { + continue; + } + + clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), field.getType(), field.getName())); + if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), field.getGetter()); + method.getModifiers().remove(Modifier.ABSTRACT); + method.createBuilder().startReturn().string("this.").string(field.getName()).end(); + clazz.add(method); + } + } + + for (String assumption : node.getAssumptions()) { + clazz.add(createAssumptionField(assumption)); + } + + createConstructors(node, clazz); + + return clazz; + } + + @Override + protected void createChildren(SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTypeElement clazz = getElement(); + + SpecializationGroup rootGroup = createSpecializationGroups(node); + + if (node.needsRewrites(context)) { + if (node.isPolymorphic(context)) { + + CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0"); + var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); + clazz.add(var); + + CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getPolymorphicSpecialization()); + clazz.add(genericCachedExecute); + + } + + for (CodeExecutableElement method : createImplicitChildrenAccessors()) { + clazz.add(method); + } + clazz.add(createInfoMessage(node)); + clazz.add(createMonomorphicRewrite()); + clazz.add(createCreateSpecializationMethod(node, rootGroup)); + } + + clazz.add(createAdoptChildren0()); + clazz.add(createGetMetadata0(true)); + clazz.add(createUpdateTypes0()); + clazz.add(createGetNext()); + } + + private Element createGetNext() { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(Node.class), "getNext0"); + CodeTreeBuilder builder = method.createBuilder(); + NodeData node = getModel().getNode(); + + if (node.isPolymorphic(context)) { + builder.startReturn().string("next0").end(); + } else { + builder.returnNull(); + } + + return method; + } + + protected final CodeExecutableElement createUpdateTypes0() { + ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(void.class), "updateTypes0"); + method.getParameters().add(new CodeVariableElement(classArray, "types")); + + if (getModel().isPolymorphic()) { + CodeTreeBuilder builder = method.createBuilder(); + + int index = 0; + for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) { + String fieldName = polymorphicTypeName(execution); + + builder.startStatement(); + builder.string(fieldName).string(" = ").string("types[").string(String.valueOf(index)).string("]"); + builder.end(); + index++; + } + } + + return method; + } + + protected final CodeExecutableElement createGetMetadata0(boolean empty) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getDslMetadata(), "getMetadata0"); + if (empty) { + method.createBuilder().startReturn().staticReference(context.getTruffleTypes().getDslMetadata(), "NONE").end(); + } else { + method.createBuilder().startReturn().string(METADATA_FIELD_NAME).end(); + } + return method; + } + + private CodeExecutableElement createAdoptChildren0() { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(void.class), "adoptChildren0"); + method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "other")); + method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "newNext")); + NodeData node = getModel().getNode(); + CodeTreeBuilder builder = method.createBuilder(); + List executions = node.getChildExecutions(); + + if (executions.size() > 0) { + builder.startIf().string("other == null").end().startBlock(); + for (NodeExecutionData execution : executions) { + builder.startStatement().tree(createAccessChild(execution, "this")).string(" = null").end(); + } + builder.end().startElseBlock(); + + String access; + if (executions.size() > 1) { + builder.declaration(baseClassName(node), "otherCast", builder.create().cast(baseClassName(node)).string("other")); + access = "otherCast"; + } else { + assert executions.size() == 1; + access = "((" + baseClassName(node) + ") other)"; + } + for (NodeExecutionData execution : executions) { + builder.startStatement().tree(createAccessChild(execution, "this")).string(" = ").tree(createAccessChild(execution, access)).end(); + } + + builder.end(); + } + + if (getModel().getNode().isPolymorphic(context)) { + builder.startIf().string("newNext == null").end().startBlock(); + builder.statement("this.next0 = null"); + builder.end().startElseBlock(); + builder.statement("this.next0 = (" + baseClassName(getModel().getNode()) + ") newNext"); + builder.end(); + } + + return method; + } + + private List createImplicitChildrenAccessors() { + NodeData node = getModel().getNode(); + List> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null); + List> expectTypes = new ArrayList<>(prototype); + + for (ExecutableTypeData executableType : node.getExecutableTypes()) { + for (int i = 0; i < executableType.getEvaluatedCount(); i++) { + Parameter parameter = executableType.getSignatureParameter(i); + if (i >= expectTypes.size()) { + break; + } + Set types = expectTypes.get(i); + if (types == null) { + types = new TreeSet<>(); + expectTypes.set(i, types); + } + types.add(parameter.getTypeSystemType()); + } + } + + List methods = new ArrayList<>(); + List> visitedList = new ArrayList<>(prototype); + for (SpecializationData spec : node.getSpecializations()) { + int signatureIndex = -1; + for (Parameter param : spec.getParameters()) { + if (!param.getSpecification().isSignature()) { + continue; + } + signatureIndex++; + Set visitedTypeData = visitedList.get(signatureIndex); + if (visitedTypeData == null) { + visitedTypeData = new TreeSet<>(); + visitedList.set(signatureIndex, visitedTypeData); + } + + if (visitedTypeData.contains(param.getTypeSystemType())) { + continue; + } + visitedTypeData.add(param.getTypeSystemType()); + + Set expect = expectTypes.get(signatureIndex); + if (expect == null) { + expect = Collections.emptySet(); + } + + methods.addAll(createExecuteChilds(param, expect)); + } + } + return methods; + } + + private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) { + CodeTreeBuilder builder = parent.create(); + builder.staticReference(getContext().getTruffleTypes().getTruffleOptions(), name); + return builder.getRoot(); + } + + private Element createInfoMessage(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), CREATE_INFO); + method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message")); + addInternalValueParameters(method, node.getGenericSpecialization(), false, false); + + CodeTreeBuilder builder = method.createBuilder(); + + builder.startIf().tree(truffleBooleanOption(builder, TruffleTypes.OPTION_DETAILED_REWRITE_REASONS)).end(); + builder.startBlock(); + + builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end(); + builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end(); + + String sep = null; + for (Parameter parameter : node.getGenericSpecialization().getSignatureParameters()) { + builder.startStatement(); + builder.string("builder"); + if (sep != null) { + builder.startCall(".append").doubleQuote(sep).end(); + } + builder.startCall(".append").doubleQuote(parameter.getLocalName()).end(); + builder.startCall(".append").doubleQuote(" = ").end(); + builder.startCall(".append").string(parameter.getLocalName()).end(); + builder.end(); + + if (!ElementUtils.isPrimitive(parameter.getType())) { + builder.startIf().string(parameter.getLocalName() + " != null").end(); + builder.startBlock(); + } + builder.startStatement(); + if (ElementUtils.isPrimitive(parameter.getType())) { + builder.startCall("builder.append").doubleQuote(" (" + ElementUtils.getSimpleName(parameter.getType()) + ")").end(); + } else { + builder.startCall("builder.append").doubleQuote(" (").end(); + builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end(); + builder.startCall(".append").doubleQuote(")").end(); + } + builder.end(); + if (!ElementUtils.isPrimitive(parameter.getType())) { + builder.end(); + } + + sep = ", "; + } + + builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end(); + builder.startReturn().string("builder.toString()").end(); + + builder.end(); + builder.startElseBlock(); + builder.startReturn().string("message").end(); + builder.end(); + + return method; + } + + private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) { + CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), EXECUTE_CHAINED); + addInternalValueParameters(cachedExecute, polymorph, true, false); + + ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); + boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); + if (sourceThrowsUnexpected && sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) { + sourceThrowsUnexpected = false; + } + if (sourceThrowsUnexpected) { + cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); + } + return cachedExecute; + + } + + private void createConstructors(NodeData node, CodeTypeElement clazz) { + List constructors = findUserConstructors(node.getNodeType()); + ExecutableElement sourceSectionConstructor = null; + if (constructors.isEmpty()) { + clazz.add(createUserConstructor(clazz, null)); + } else { + for (ExecutableElement constructor : constructors) { + clazz.add(createUserConstructor(clazz, constructor)); + if (NodeParser.isSourceSectionConstructor(context, constructor)) { + sourceSectionConstructor = constructor; + } + } + } + if (node.needsRewrites(getContext())) { + ExecutableElement copyConstructor = findCopyConstructor(node.getNodeType()); + clazz.add(createCopyConstructor(clazz, copyConstructor, sourceSectionConstructor)); + } + } + + private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { + CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + + NodeData node = getModel().getNode(); + + if (superConstructor != null) { + for (VariableElement param : superConstructor.getParameters()) { + method.getParameters().add(CodeVariableElement.clone(param)); + } + } + + if (superConstructor != null) { + builder.startStatement().startSuperCall(); + for (VariableElement param : superConstructor.getParameters()) { + builder.string(param.getSimpleName().toString()); + } + builder.end().end(); + } + + for (VariableElement var : type.getFields()) { + if (var.getModifiers().contains(STATIC)) { + continue; + } + NodeChildData child = node.findChild(var.getSimpleName().toString()); + + if (child != null) { + method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); + } else { + method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); + } + + builder.startStatement(); + String fieldName = var.getSimpleName().toString(); + + CodeTree init = createStaticCast(builder, child, fieldName); + + builder.string("this.").string(fieldName).string(" = ").tree(init); + builder.end(); + } + return method; + } + + private CodeTree createStaticCast(CodeTreeBuilder parent, NodeChildData child, String fieldName) { + NodeData parentNode = getModel().getNode(); + if (child != null) { + CreateCastData createCast = parentNode.findCast(child.getName()); + if (createCast != null) { + return createTemplateMethodCall(parent, null, parentNode.getGenericSpecialization(), createCast, null, fieldName); + } + } + return CodeTreeBuilder.singleString(fieldName); + } + + private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) { + CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); + CodeTreeBuilder builder = method.createBuilder(); + method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); + + if (superConstructor != null) { + builder.startStatement().startSuperCall().string("copy").end().end(); + } else if (sourceSectionConstructor != null) { + builder.startStatement().startSuperCall().string("copy.getSourceSection()").end().end(); + } + + for (VariableElement var : type.getFields()) { + if (var.getModifiers().contains(STATIC) || !var.getModifiers().contains(FINAL)) { + continue; + } + final String varName = var.getSimpleName().toString(); + final TypeMirror varType = var.asType(); + if (ElementUtils.isAssignable(varType, getContext().getTruffleTypes().getNodeArray())) { + CodeTree size = builder.create().string("copy.", varName, ".length").getRoot(); + builder.startStatement().string("this.").string(varName).string(" = ").startNewArray((ArrayType) varType, size).end().end(); + } else { + builder.startStatement().string("this.", varName, " = copy.", varName).end(); + } + } + + return method; + } + + private CodeVariableElement createAssumptionField(String assumption) { + CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); + var.getModifiers().add(Modifier.FINAL); + return var; + } + + private CodeVariableElement createChildField(NodeChildData child) { + TypeMirror type = child.getNodeType(); + CodeVariableElement var = new CodeVariableElement(type, child.getName()); + var.getModifiers().add(Modifier.PROTECTED); + + DeclaredType annotationType; + if (child.getCardinality() == Cardinality.MANY) { + var.getModifiers().add(Modifier.FINAL); + annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); + } else { + annotationType = getContext().getTruffleTypes().getChildAnnotation(); + } + + var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); + return var; + } + + private SpecializationGroup createSpecializationGroups(final NodeData node) { + List specializations = node.getSpecializations(); + List filteredSpecializations = new ArrayList<>(); + for (SpecializationData current : specializations) { + if (current.isUninitialized() || current.isPolymorphic() || !current.isReachable()) { + continue; + } + filteredSpecializations.add(current); + } + + return SpecializationGroup.create(filteredSpecializations); + } + + protected final CodeExecutableElement createExecuteUninitialized() { + NodeData node = getModel().getNode(); + SpecializationData generic = node.getGenericSpecialization(); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), generic.getReturnType().getType(), EXECUTE_UNINITIALIZED); + addInternalValueParameters(method, generic, true, false); + CodeTreeBuilder builder = method.createBuilder(); + + CodeTreeBuilder createSpecializationCall = builder.create(); + createSpecializationCall.startCall(SPECIALIZE); + addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null); + createSpecializationCall.end(); + builder.declaration(baseClassName(node), "newNode", createSpecializationCall); + + if (generic.isReachable()) { + builder.startIf().string("newNode == null").end().startBlock(); + + builder.startIf().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "inInterpreter").end().end().startBlock(); + builder.statement("containsFallback = true"); + builder.end(); + builder.tree(createGenericInvoke(builder, generic, generic)); + builder.end(); + builder.startElseBlock(); + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + } + + builder.startReturn(); + builder.startStaticCall(context.getTruffleTypes().getDslShare(), "rewriteUninitialized").string("this").string("newNode").end(); + builder.string(".").startCall(EXECUTE_CHAINED); + addInternalValueParameterNames(builder, generic, generic, null, true, null); + builder.end(); + builder.end(); + + if (generic.isReachable()) { + builder.end(); + } + + return method; + } + + private CodeTree createInfoCall(CodeTreeBuilder parent, SpecializationData specialization, String reason) { + CodeTreeBuilder builder = parent.create(); + builder.startCall(CREATE_INFO).string(reason); + addInternalValueParameterNames(builder, specialization, specialization, null, false, null); + builder.end(); + return builder.getRoot(); + } + + private CodeExecutableElement createMonomorphicRewrite() { + NodeData node = getModel().getNode(); + + SpecializationData generic = node.getGenericSpecialization(); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), generic.getReturnType().getType(), REWRITE); + addInternalValueParameters(method, generic, true, false); + method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); + + CodeTreeBuilder builder = method.createBuilder(); + + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end(); + String baseClassName = baseClassName(getModel().getNode()); + CodeTreeBuilder createSpecializationCall = builder.create(); + createSpecializationCall.startCall(SPECIALIZE); + addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null); + createSpecializationCall.end(); + builder.declaration(baseClassName, "newNode", createSpecializationCall); + + builder.startIf().string("newNode == null").end().startBlock(); + builder.startStatement(); + String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization()); + builder.string("newNode = ").startNew(uninitializedName).string("this").end(); + builder.end(); + if (node.isFallbackReachable()) { + builder.startStatement().string("((", uninitializedName, ") newNode).containsFallback = true").end(); + } + builder.end(); + + builder.startStatement(); + builder.type(getContext().getType(String.class)).string(" message = ").tree(createInfoCall(builder, generic, "reason")); + builder.end(); + + builder.declaration(baseClassName, "returnNode", + builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().getRoot()); + builder.startIf().string("returnNode == null").end().startBlock(); + builder.tree(createRewritePolymorphic(builder, node, "this")); + builder.end(); + + builder.startReturn(); + builder.startCall("returnNode", EXECUTE_CHAINED); + addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, null); + builder.end(); + builder.end(); + + return method; + } + + private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node, String currentNode) { + String polyClassName = nodePolymorphicClassName(node); + CodeTreeBuilder builder = parent.create(); + + builder.startStatement().string("returnNode = "); + builder.startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE_TO_POLYMORHPIC); + builder.string("this"); + builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().getRoot()); + builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().getRoot()); + builder.startGroup().cast(baseClassName(node)).startCall("copy").end().end(); + builder.string("newNode"); + builder.string("message"); + builder.end(); + builder.end(); + + return builder.getRoot(); + } + + private CodeExecutableElement createCreateSpecializationMethod(NodeData node, SpecializationGroup group) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), baseClassName(node)), + SPECIALIZE); + if (!node.needsFrame(getContext())) { + method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); + } + + addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(getContext()), false); + final CodeTreeBuilder builder = method.createBuilder(); + builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createCreateSpecializationMethodBody0(builder, current); + } + }, null, false, true, false, true)); + + emitUnreachableSpecializations(builder, node); + + return method; + } + + protected CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (current.isGeneric()) { + builder.startReturn().nullLiteral().end(); + } else { + String className = nodeSpecializationClassName(current); + if (!current.getExcludedBy().isEmpty()) { + builder.startIf().string("!").startStaticCall(context.getTruffleTypes().getDslShare(), "isExcluded"); + builder.string("this").string(nodeSpecializationClassName(current), ".", METADATA_FIELD_NAME).end().end(); + builder.startBlock(); + } + + if (current.getNode().getGenericSpecialization().isReachable()) { + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + } + builder.startReturn(); + builder.cast(baseClassName(getModel().getNode())); + builder.startGroup().startCall(className, FACTORY_METHOD_NAME).string("this"); + for (Parameter param : current.getSignatureParameters()) { + NodeChildData child = param.getSpecification().getExecution().getChild(); + List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (types.size() > 1) { + builder.string(implicitTypeName(param)); + } + } + builder.end().end(); + builder.end(); + + if (!current.getExcludedBy().isEmpty()) { + builder.end(); + } + } + return builder.getRoot(); + + } + + private void emitUnreachableSpecializations(final CodeTreeBuilder builder, NodeData node) { + for (SpecializationData current : node.getSpecializations()) { + if (current.isReachable()) { + continue; + } + builder.string("// unreachable ").string(current.getId()).newLine(); + } + } + + protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final CodeBlock guardedblock, + final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts, final boolean castForGuardsOnly) { + return guard(outerParent, source, group, new CodeBlock() { + + public CodeTree create(CodeTreeBuilder parent, Integer ifCount) { + CodeTreeBuilder builder = parent.create(); + + if (group.getSpecialization() != null) { + builder.tree(guardedblock.create(builder, group.getSpecialization())); + + assert group.getChildren().isEmpty() : "missed a specialization"; + + } else { + for (SpecializationGroup childGroup : group.getChildren()) { + builder.tree(createExecuteTree(builder, source, childGroup, guardedblock, null, false, emitAssumptions, typedCasts, castForGuardsOnly)); + } + } + + return builder.getRoot(); + } + }, elseBlock, forceElse, emitAssumptions, typedCasts, castForGuardsOnly); + } + + private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, CodeBlock bodyBlock, CodeTree elseBlock, boolean forceElse, + boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) { + CodeTreeBuilder builder = parent.create(); + + int ifCount = emitGuards(builder, source, group, emitAssumptions, typedCasts, castForGuardsOnly); + + if (isReachableGroup(group, ifCount)) { + builder.tree(bodyBlock.create(builder, ifCount)); + } + + builder.end(ifCount); + + if (elseBlock != null) { + if (ifCount > 0 || forceElse) { + builder.tree(elseBlock); + } + } + + return builder.getRoot(); + } + + private boolean isReachableGroup(SpecializationGroup group, int ifCount) { + if (ifCount != 0) { + return true; + } + SpecializationGroup previous = group.getPreviousGroup(); + if (previous == null || previous.findElseConnectableGuards().isEmpty()) { + return true; + } + + /* + * Hacky else case. In this case the specialization is not reachable due to previous + * else branch. This is only true if the minimum state is not checked. + */ + if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && + (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { + return false; + } + + return true; + } + + private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) { + NodeData node = source.getNode(); + + CodeTreeBuilder guardsBuilder = builder.create(); + CodeTreeBuilder castBuilder = builder.create(); + CodeTreeBuilder guardsCastBuilder = builder.create(); + + String guardsAnd = ""; + String guardsCastAnd = ""; + + if (emitAssumptions) { + for (String assumption : group.getAssumptions()) { + guardsBuilder.string(guardsAnd); + guardsBuilder.string("this"); + guardsBuilder.string(".").string(assumption).string(".isValid()"); + guardsAnd = " && "; + } + } + + for (TypeGuard typeGuard : group.getTypeGuards()) { + Parameter valueParam = source.getSignatureParameter(typeGuard.getSignatureIndex()); + + if (valueParam == null) { + /* + * If used inside a execute evaluated method then the value param may not exist. + * In that case we assume that the value is executed generic or of the current + * specialization. + */ + if (group.getSpecialization() != null) { + valueParam = group.getSpecialization().getSignatureParameter(typeGuard.getSignatureIndex()); + } else { + valueParam = node.getGenericSpecialization().getSignatureParameter(typeGuard.getSignatureIndex()); + } + } + + NodeExecutionData execution = valueParam.getSpecification().getExecution(); + CodeTree implicitGuard = createTypeGuard(guardsBuilder, execution, valueParam, typeGuard.getType(), typedCasts); + if (implicitGuard != null) { + guardsBuilder.string(guardsAnd); + guardsBuilder.tree(implicitGuard); + guardsAnd = " && "; + } + + CodeTree implicitGetType = null; + if (castForGuardsOnly) { + implicitGetType = createGetImplicitType(builder, execution, valueParam, typeGuard.getType()); + } + + boolean performCast = true; + if (castForGuardsOnly) { + // if cast for guards we just cast if the type guard is used inside a guard. + performCast = group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard); + } + + if (performCast) { + CodeTree cast = createCast(castBuilder, execution, valueParam, typeGuard.getType(), typedCasts); + if (cast != null) { + castBuilder.tree(cast); + } + } + if (implicitGetType != null) { + castBuilder.tree(implicitGetType); + } + } + List elseGuards = group.findElseConnectableGuards(); + + for (GuardExpression guard : group.getGuards()) { + if (elseGuards.contains(guard)) { + continue; + } + + if (needsTypeGuard(source, group, guard)) { + guardsCastBuilder.tree(createMethodGuard(builder, guardsCastAnd, source, guard)); + guardsCastAnd = " && "; + } else { + guardsBuilder.tree(createMethodGuard(builder, guardsAnd, source, guard)); + guardsAnd = " && "; + } + } + + int ifCount = startGuardIf(builder, guardsBuilder, 0, elseGuards); + builder.tree(castBuilder.getRoot()); + ifCount = startGuardIf(builder, guardsCastBuilder, ifCount, elseGuards); + return ifCount; + } + + private int startGuardIf(CodeTreeBuilder builder, CodeTreeBuilder conditionBuilder, int ifCount, List elseGuard) { + int newIfCount = ifCount; + + if (!conditionBuilder.isEmpty()) { + if (ifCount == 0 && !elseGuard.isEmpty()) { + builder.startElseIf(); + } else { + builder.startIf(); + } + builder.tree(conditionBuilder.getRoot()); + builder.end().startBlock(); + newIfCount++; + } else if (ifCount == 0 && !elseGuard.isEmpty()) { + builder.startElseBlock(); + newIfCount++; + } + return newIfCount; + } + + private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) { + int signatureIndex = 0; + for (Parameter parameter : guard.getResolvedGuard().getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + + TypeGuard typeGuard = group.findTypeGuard(signatureIndex); + if (typeGuard != null) { + TypeData requiredType = typeGuard.getType(); + + Parameter sourceParameter = source.findParameter(parameter.getLocalName()); + if (sourceParameter == null) { + sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName()); + } + + if (ElementUtils.needsCastTo(sourceParameter.getType(), requiredType.getPrimitiveType())) { + return true; + } + } + + signatureIndex++; + } + return false; + } + + private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) { + NodeData node = execution.getChild().getNodeData(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + TypeData sourceType = source.getTypeSystemType(); + + if (!sourceType.needsCastTo(targetType)) { + return null; + } + + builder.startGroup(); + + if (execution.isShortCircuit()) { + Parameter shortCircuit = source.getPreviousParameter(); + assert shortCircuit != null; + builder.string("("); + builder.string("!").string(valueName(shortCircuit)); + builder.string(" || "); + } + + String castMethodName; + String castTypeName = null; + List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + if (types.size() > 1) { + castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType); + if (typedCasts) { + castTypeName = implicitTypeName(source); + } + } else { + castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType); + } + + startCallTypeSystemMethod(builder, node.getTypeSystem(), castMethodName); + builder.string(valueName(source)); + if (castTypeName != null) { + builder.string(castTypeName); + } + builder.end().end(); // call + + if (execution.isShortCircuit()) { + builder.string(")"); + } + + builder.end(); // group + + return builder.getRoot(); + } + + // TODO merge redundancies with #createTypeGuard + private CodeTree createCast(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) { + NodeData node = execution.getChild().getNodeData(); + TypeData sourceType = source.getTypeSystemType(); + + if (!sourceType.needsCastTo(targetType)) { + return null; + } + + CodeTree condition = null; + if (execution.isShortCircuit()) { + Parameter shortCircuit = source.getPreviousParameter(); + assert shortCircuit != null; + condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); + } + + String castMethodName; + String castTypeName = null; + List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + if (types.size() > 1) { + castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType); + if (typedCasts) { + castTypeName = implicitTypeName(source); + } + } else { + castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); + } + + List args = new ArrayList<>(); + args.add(CodeTreeBuilder.singleString(valueName(source))); + if (castTypeName != null) { + args.add(CodeTreeBuilder.singleString(castTypeName)); + } + + CodeTree cast = createCallTypeSystemMethod(parent, node, castMethodName, args.toArray(new CodeTree[0])); + + CodeTreeBuilder builder = parent.create(); + builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, cast)); + + return builder.getRoot(); + } + + private CodeTree createGetImplicitType(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType) { + CodeTree condition = null; + if (execution.isShortCircuit()) { + Parameter shortCircuit = source.getPreviousParameter(); + assert shortCircuit != null; + condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); + } + + CodeTreeBuilder builder = parent.create(); + List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + if (types.size() > 1) { + CodeTree castType = createCallTypeSystemMethod(parent, execution.getChild().getNodeData(), TypeSystemCodeGenerator.getImplicitClass(targetType), + CodeTreeBuilder.singleString(valueName(source))); + builder.tree(createLazyAssignment(builder, implicitTypeName(source), getContext().getType(Class.class), condition, castType)); + } + return builder.getRoot(); + } + + private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardExpression guard) { + CodeTreeBuilder builder = parent.create(); + builder.string(prefix); + if (guard.isNegated()) { + builder.string("!"); + } + builder.tree(createTemplateMethodCall(builder, null, source, guard.getResolvedGuard(), null)); + return builder.getRoot(); + } + + protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + if (current.getMethod() == null) { + emitEncounteredSynthetic(builder, current); + } else { + builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); + } + + return encloseThrowsWithFallThrough(current, builder.getRoot()); + } + + private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { + if (current.getExceptions().isEmpty()) { + return tree; + } + CodeTreeBuilder builder = new CodeTreeBuilder(null); + + builder.startTryBlock(); + builder.tree(tree); + for (SpecializationThrowsData exception : current.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); + builder.tree(createDeoptimize(builder)); + builder.tree(createCallRewriteMonomorphic(builder, false, current.getNode().getGenericSpecialization().getReturnType().getTypeSystemType(), current, null, + "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass()))); + } + builder.end(); + + return builder.getRoot(); + } + + protected CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) { + TypeData type = executable.getType(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + NodeData node = specialization.getNode(); + + TypeData primaryType = castExecutable.getType(); + + boolean needsTry = castExecutable.hasUnexpectedValue(getContext()); + boolean returnVoid = type.isVoid(); + + List executeParameters = new ArrayList<>(); + for (Parameter sourceParameter : executable.getSignatureParameters()) { + Parameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName()); + if (targetParameter != null) { + executeParameters.add(targetParameter); + } + } + + // execute names are enforced no cast + String[] executeParameterNames = new String[executeParameters.size()]; + for (int i = 0; i < executeParameterNames.length; i++) { + executeParameterNames[i] = valueName(executeParameters.get(i)); + } + + builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null)); + boolean hasUnexpected = executable.hasUnexpectedValue(getContext()); + + CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null, executeParameterNames); + if (needsTry) { + if (!returnVoid) { + builder.declaration(primaryType.getPrimitiveType(), "value"); + } + builder.startTryBlock(); + + if (returnVoid) { + builder.statement(primaryExecuteCall); + } else { + builder.startStatement(); + builder.string("value = "); + builder.tree(primaryExecuteCall); + builder.end(); + } + + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + if (returnVoid) { + builder.string("// ignore").newLine(); + } else { + builder.startReturn(); + builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), hasUnexpected, executable.getType(), + CodeTreeBuilder.singleString("ex.getResult()"))); + builder.end(); + } + builder.end(); + + if (!returnVoid) { + builder.startReturn(); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), CodeTreeBuilder.singleString("value"))); + builder.end(); + } + } else { + if (returnVoid) { + builder.statement(primaryExecuteCall); + } else { + builder.startReturn(); + builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), primaryExecuteCall)); + builder.end(); + } + } + + return builder.getRoot(); + } + + protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, boolean hasUnexpected, TypeData exepctedType, CodeTree value) { + return createCastType(node.getTypeSystem(), sourceType, exepctedType, hasUnexpected, value); + } + + protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List targetParameters, + Parameter unexpectedParameter) { + CodeTreeBuilder builder = parent.create(); + for (Parameter targetParameter : targetParameters) { + if (!targetParameter.getSpecification().isSignature()) { + continue; + } + NodeExecutionData execution = targetParameter.getSpecification().getExecution(); + CodeTree executionExpressions = createExecuteChild(builder, execution, sourceExecutable, targetParameter, unexpectedParameter); + CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, specialization, sourceExecutable, targetParameter, execution.isShortCircuit(), unexpectedParameter); + CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, specialization, targetParameter, unexpectedParameter); + + if (shortCircuitTree == executionExpressions) { + if (containsNewLine(executionExpressions)) { + builder.declaration(targetParameter.getType(), valueName(targetParameter)); + builder.tree(shortCircuitTree); + } else { + builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end(); + } + } else { + builder.tree(shortCircuitTree); + } + + } + return builder.getRoot(); + } + + private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) { + ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(getContext(), type); + if (targetExecutable == null) { + targetExecutable = execution.getChild().findAnyGenericExecutableType(getContext()); + } + return targetExecutable; + } + + private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter targetParameter, Parameter unexpectedParameter) { + SpecializationData specialization = getModel(); + TreeSet possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter); + if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null && possiblePolymorphicTypes.size() > 1) { + + CodeTreeBuilder builder = parent.create(); + + boolean elseIf = false; + for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) { + if (possiblePolymoprhicType.isGeneric()) { + continue; + } + elseIf = builder.startIf(elseIf); + + Parameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); + TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; + builder.string(polymorphicTypeName(targetParameter.getSpecification().getExecution())).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType()); + builder.end().startBlock(); + builder.startStatement(); + builder.tree(createExecuteChildExpression(parent, execution, sourceType, new Parameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null)); + builder.end(); + builder.end(); + } + + builder.startElseBlock(); + builder.startStatement().tree(createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter)).end(); + builder.end(); + + return builder.getRoot(); + } else { + return createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter); + } + } + + protected final List getImplicitTypeParameters(SpecializationData model) { + List parameter = new ArrayList<>(); + for (Parameter param : model.getSignatureParameters()) { + NodeChildData child = param.getSpecification().getExecution().getChild(); + List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (types.size() > 1) { + parameter.add(param); + } + } + return parameter; + } + + protected final TreeSet lookupPolymorphicTargetTypes(Parameter param) { + SpecializationData specialization = getModel(); + TreeSet possiblePolymorphicTypes = new TreeSet<>(); + for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) { + if (!otherSpecialization.isSpecialized()) { + continue; + } + Parameter otherParameter = otherSpecialization.findParameter(param.getLocalName()); + if (otherParameter != null) { + possiblePolymorphicTypes.add(otherParameter.getTypeSystemType()); + } + } + return possiblePolymorphicTypes; + } + + private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter param, Parameter unexpectedParameter) { + CodeTreeBuilder builder = parent.create(); + Parameter sourceParameter = sourceExecutable.findParameter(param.getLocalName()); + String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null); + if (childExecuteName != null) { + builder.string(valueName(param)); + builder.string(" = "); + builder.startCall(childExecuteName); + + for (Parameter parameters : sourceExecutable.getParameters()) { + if (parameters.getSpecification().isSignature()) { + continue; + } + builder.string(parameters.getLocalName()); + } + + if (sourceParameter != null) { + builder.string(valueNameEvaluated(sourceParameter)); + } + + builder.string(implicitTypeName(param)); + + builder.end(); + } else { + List sourceTypes = execution.getChild().getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; + if (sourceTypes.size() > 1) { + builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType)); + } else { + builder.tree(createExecuteChildExpression(parent, execution, expectType, param, unexpectedParameter, null)); + } + } + return builder.getRoot(); + } + + private String createExecuteChildMethodName(Parameter param, boolean expect) { + NodeExecutionData execution = param.getSpecification().getExecution(); + NodeChildData child = execution.getChild(); + if (child.getExecuteWith().size() > 0) { + return null; + } + List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (sourceTypes.size() <= 1) { + return null; + } + String prefix = expect ? "expect" : "execute"; + String suffix = execution.getIndex() > -1 ? String.valueOf(execution.getIndex()) : ""; + return prefix + ElementUtils.firstLetterUpperCase(child.getName()) + ElementUtils.firstLetterUpperCase(ElementUtils.getSimpleName(param.getType())) + suffix; + } + + private List createExecuteChilds(Parameter param, Set expectTypes) { + CodeExecutableElement executeMethod = createExecuteChild(param, null); + if (executeMethod == null) { + return Collections.emptyList(); + } + List childs = new ArrayList<>(); + childs.add(executeMethod); + + for (TypeData expectType : expectTypes) { + CodeExecutableElement method = createExecuteChild(param, expectType); + if (method != null) { + childs.add(method); + } + } + return childs; + } + + private CodeExecutableElement createExecuteChild(Parameter param, TypeData expectType) { + String childExecuteName = createExecuteChildMethodName(param, expectType != null); + if (childExecuteName == null) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName); + method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException()); + method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); + if (expectType != null) { + method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param))); + } + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param))); + + CodeTreeBuilder builder = method.createBuilder(); + builder.declaration(param.getType(), valueName(param)); + builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType)); + builder.startReturn().string(valueName(param)).end(); + + return method; + } + + private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, Parameter targetParameter, TypeData expectType) { + CodeTreeBuilder builder = parent.create(); + NodeData node = getModel().getNode(); + NodeExecutionData execution = targetParameter.getSpecification().getExecution(); + List sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType()); + boolean elseIf = false; + int index = 0; + for (TypeData sourceType : sourceTypes) { + if (index < sourceTypes.size() - 1) { + elseIf = builder.startIf(elseIf); + builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType()); + builder.end(); + builder.startBlock(); + } else { + builder.startElseBlock(); + } + + ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(getContext(), sourceType); + if (implictExecutableTypeData == null) { + /* + * For children with executeWith.size() > 0 an executable type may not exist so + * use the generic executable type which is guaranteed to exist. An expect call + * is inserted automatically by #createExecuteExpression. + */ + implictExecutableTypeData = execution.getChild().getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), execution.getChild().getExecuteWith().size()); + } + + ImplicitCastData cast = execution.getChild().getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType()); + CodeTree execute = createExecuteChildExpression(builder, execution, expectType, targetParameter, null, cast); + builder.statement(execute); + builder.end(); + index++; + } + return builder.getRoot(); + } + + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData execution, TypeData sourceParameterType, Parameter targetParameter, Parameter unexpectedParameter, + ImplicitCastData cast) { + // assignments: targetType <- castTargetType <- castSourceType <- sourceType + TypeData sourceType = sourceParameterType; + TypeData targetType = targetParameter.getTypeSystemType(); + TypeData castSourceType = targetType; + TypeData castTargetType = targetType; + + if (cast != null) { + castSourceType = cast.getSourceType(); + castTargetType = cast.getTargetType(); + } + + CodeTree expression; + if (sourceType == null) { + ExecutableTypeData targetExecutable = resolveExecutableType(execution, castSourceType); + expression = createExecuteChildExpression(parent, execution, targetExecutable, unexpectedParameter); + sourceType = targetExecutable.getType(); + } else { + expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); + } + + // target = expectTargetType(implicitCast(expectCastSourceType(source))) + TypeSystemData typeSystem = execution.getChild().getNodeData().getTypeSystem(); + expression = createExpectType(typeSystem, sourceType, castSourceType, expression); + expression = createImplicitCast(parent, typeSystem, cast, expression); + expression = createExpectType(typeSystem, castTargetType, targetType, expression); + + CodeTreeBuilder builder = parent.create(); + builder.string(valueName(targetParameter)); + builder.string(" = "); + builder.tree(expression); + return builder.getRoot(); + } + + private CodeTree createImplicitCast(CodeTreeBuilder parent, TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) { + if (cast == null) { + return expression; + } + CodeTreeBuilder builder = parent.create(); + startCallTypeSystemMethod(builder, typeSystem, cast.getMethodName()); + builder.tree(expression); + builder.end().end(); + return builder.getRoot(); + } + + private boolean containsNewLine(CodeTree tree) { + if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) { + return true; + } + + for (CodeTree codeTree : tree.getEnclosedElements()) { + if (containsNewLine(codeTree)) { + return true; + } + } + return false; + } + + private boolean hasUnexpected(Parameter sourceParameter, Parameter targetParameter, Parameter unexpectedParameter) { + NodeExecutionData execution = targetParameter.getSpecification().getExecution(); + + if (getModel().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) { + // check for other polymorphic types + TreeSet polymorphicTargetTypes = lookupPolymorphicTargetTypes(targetParameter); + if (polymorphicTargetTypes.size() > 1) { + for (TypeData polymorphicTargetType : polymorphicTargetTypes) { + if (hasUnexpectedType(execution, sourceParameter, polymorphicTargetType)) { + return true; + } + } + } + } + + if (hasUnexpectedType(execution, sourceParameter, targetParameter.getTypeSystemType())) { + return true; + } + return false; + } + + private boolean hasUnexpectedType(NodeExecutionData execution, Parameter sourceParameter, TypeData targetType) { + List implicitSourceTypes = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + + for (TypeData implicitSourceType : implicitSourceTypes) { + TypeData sourceType; + ExecutableTypeData targetExecutable = resolveExecutableType(execution, implicitSourceType); + if (sourceParameter != null) { + sourceType = sourceParameter.getTypeSystemType(); + } else { + if (targetExecutable.hasUnexpectedValue(getContext())) { + return true; + } + sourceType = targetExecutable.getType(); + } + + ImplicitCastData cast = getModel().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType); + if (cast != null) { + if (cast.getSourceType().needsCastTo(targetType)) { + return true; + } + } + + if (sourceType.needsCastTo(targetType)) { + return true; + } + } + return false; + } + + private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ExecutableTypeData currentExecutable, Parameter param, + boolean shortCircuit, Parameter unexpectedParameter) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + Parameter sourceParameter = currentExecutable.findParameter(param.getLocalName()); + boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter); + if (!unexpected) { + return body; + } + + if (!shortCircuit) { + builder.declaration(param.getType(), valueName(param)); + } + builder.startTryBlock(); + + if (containsNewLine(body)) { + builder.tree(body); + } else { + builder.statement(body); + } + + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + SpecializationData generic = specialization.getNode().getGenericSpecialization(); + Parameter genericParameter = generic.findParameter(param.getLocalName()); + + List genericParameters = generic.getParametersAfter(genericParameter); + builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter)); + if (specialization.isPolymorphic()) { + builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); + } else { + builder.tree(createCallRewriteMonomorphic(builder, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), specialization, param, + "Expected " + param.getLocalName() + " instanceof " + ElementUtils.getSimpleName(param.getType()))); + } + builder.end(); // catch block + + return builder.getRoot(); + } + + private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, Parameter param) { + NodeData node = specialization.getNode(); + SpecializationData polymorphic = node.getPolymorphicSpecialization(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement().string(polymorphicTypeName(param.getSpecification().getExecution())).string(" = ").typeLiteral(getContext().getType(Object.class)).end(); + + builder.startReturn(); + + CodeTreeBuilder execute = new CodeTreeBuilder(builder); + execute.startCall("next0", EXECUTE_CHAINED); + addInternalValueParameterNames(execute, specialization, polymorphic, param.getLocalName(), true, null); + execute.end(); + + TypeData sourceType = polymorphic.getReturnType().getTypeSystemType(); + + builder.tree(createExpectExecutableType(node, sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.getRoot())); + + builder.end(); + return builder.getRoot(); + } + + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, Parameter unexpectedParameter) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (targetExecution != null) { + builder.tree(createAccessChild(targetExecution, null)); + builder.string("."); + } + + builder.startCall(targetExecutable.getMethodName()); + + // TODO this should be merged with #createTemplateMethodCall + int index = 0; + for (Parameter parameter : targetExecutable.getParameters()) { + + if (!parameter.getSpecification().isSignature()) { + builder.string(parameter.getLocalName()); + } else { + + if (index < targetExecution.getChild().getExecuteWith().size()) { + NodeChildData child = targetExecution.getChild().getExecuteWith().get(index); + + ParameterSpec spec = getModel().getSpecification().findParameterSpec(child.getName()); + List specializationParams = getModel().findParameters(spec); + + if (specializationParams.isEmpty()) { + builder.defaultValue(parameter.getType()); + continue; + } + + Parameter specializationParam = specializationParams.get(0); + + TypeData targetType = parameter.getTypeSystemType(); + TypeData sourceType = specializationParam.getTypeSystemType(); + String localName = specializationParam.getLocalName(); + + if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) { + localName = "ex.getResult()"; + sourceType = getModel().getNode().getTypeSystem().getGenericTypeData(); + } + + CodeTree value = CodeTreeBuilder.singleString(localName); + + if (sourceType.needsCastTo(targetType)) { + value = createCallTypeSystemMethod(builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value); + } + builder.tree(value); + } else { + builder.defaultValue(parameter.getType()); + } + index++; + } + } + + builder.end(); + + return builder.getRoot(); + } + + private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, Parameter parameter, Parameter exceptionParam) { + NodeExecutionData execution = parameter.getSpecification().getExecution(); + if (execution == null || !execution.isShortCircuit()) { + return body; + } + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + Parameter shortCircuitParam = specialization.getPreviousParam(parameter); + builder.tree(createShortCircuitValue(builder, specialization, execution, shortCircuitParam, exceptionParam)); + builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); + builder.startIf().string(shortCircuitParam.getLocalName()).end(); + builder.startBlock(); + + if (containsNewLine(body)) { + builder.tree(body); + } else { + builder.statement(body); + } + builder.end(); + + return builder.getRoot(); + } + + private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeExecutionData execution, Parameter shortCircuitParam, Parameter exceptionParam) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + int shortCircuitIndex = 0; + for (NodeExecutionData otherExectuion : specialization.getNode().getChildExecutions()) { + if (otherExectuion.isShortCircuit()) { + if (otherExectuion == execution) { + break; + } + shortCircuitIndex++; + } + } + + builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); + ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); + builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); + builder.end(); // statement + + return builder.getRoot(); + } + + protected CodeTree createCallRewriteMonomorphic(CodeTreeBuilder parent, boolean hasUnexpected, TypeData returnType, SpecializationData current, Parameter exceptionParam, String reason) { + NodeData node = current.getNode(); + SpecializationData generic = node.getGenericSpecialization(); + CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); + specializeCall.startCall(REWRITE); + addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, null); + specializeCall.doubleQuote(reason); + specializeCall.end().end(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + builder.startReturn(); + builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.getRoot())); + builder.end(); + + return builder.getRoot(); + } + + } + + private class PolymorphicNodeFactory extends SpecializedNodeFactory { + + public PolymorphicNodeFactory(CodeTypeElement nodeGen) { + super(nodeGen); + } + + @Override + public CodeTypeElement create(SpecializationData polymorph) { + NodeData node = polymorph.getNode(); + TypeMirror baseType = node.getNodeType(); + if (nodeGen != null) { + baseType = nodeGen.asType(); + } + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false); + + clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.POLYMORPHIC)); + + for (Parameter polymorphParameter : polymorph.getSignatureParameters()) { + if (!polymorphParameter.getTypeSystemType().isGeneric()) { + continue; + } + Set types = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + Parameter parameter = specialization.findParameter(polymorphParameter.getLocalName()); + assert parameter != null; + types.add(parameter.getTypeSystemType()); + } + + } + + for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) { + String fieldName = polymorphicTypeName(execution); + CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), getContext().getType(Class.class), fieldName); + var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getCompilationFinal())); + clazz.add(var); + } + + return clazz; + } + + @Override + protected void createChildren(SpecializationData specialization) { + CodeTypeElement clazz = getElement(); + + createConstructors(clazz); + createExecuteMethods(specialization); + + clazz.add(createUpdateTypes0()); + createCachedExecuteMethods(specialization); + } + + } + + private class SpecializedNodeFactory extends NodeBaseFactory { + + protected final CodeTypeElement nodeGen; + + public SpecializedNodeFactory(CodeTypeElement nodeGen) { + this.nodeGen = nodeGen; + } + + @Override + public CodeTypeElement create(SpecializationData specialization) { + NodeData node = specialization.getNode(); + TypeMirror baseType = node.getNodeType(); + if (nodeGen != null) { + baseType = nodeGen.asType(); + } + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); + + if (specialization.isSpecialized() || specialization.isUninitialized()) { + clazz.add(createGetMetadata0(false)); + clazz.add(createMetadataLiteral()); + } + + NodeCost cost; + if (specialization.isGeneric()) { + cost = NodeCost.MEGAMORPHIC; + } else if (specialization.isUninitialized()) { + cost = NodeCost.UNINITIALIZED; + } else if (specialization.isPolymorphic()) { + cost = NodeCost.POLYMORPHIC; + } else if (specialization.isSpecialized()) { + cost = NodeCost.MONOMORPHIC; + } else { + throw new AssertionError(); + } + clazz.getAnnotationMirrors().add(createNodeInfo(node, cost)); + + if (specialization.isUninitialized() && node.getGenericSpecialization().isReachable()) { + clazz.add(createUninitializedGetCostOverride()); + } + + return clazz; + } + + private Element createUninitializedGetCostOverride() { + TypeMirror returnType = context.getTruffleTypes().getNodeCost(); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startIf().string(CONTAINS_FALLBACK).end().startBlock(); + builder.startReturn().staticReference(returnType, "MONOMORPHIC").end(); + builder.end(); + builder.startReturn().string("super.getCost()").end(); + return method; + } + + private CodeVariableElement createMetadataLiteral() { + CodeVariableElement includes = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getTruffleTypes().getDslMetadata(), METADATA_FIELD_NAME); + + CodeTreeBuilder builder = includes.createInitBuilder(); + + SpecializationData specialization = getModel(); + NodeData node = specialization.getNode(); + + Set contains = specialization.getContains(); + if (specialization.isUninitialized()) { + contains = new HashSet<>(); + + SpecializationData polymorphic = node.getPolymorphicSpecialization(); + if (polymorphic != null) { + contains.addAll(polymorphic.getContains()); + } + SpecializationData generic = node.getGenericSpecialization(); + if (generic != null) { + contains.addAll(generic.getContains()); + } + } + + builder.startNew(context.getTruffleTypes().getDslMetadata()); + builder.startGroup().string(nodeSpecializationClassName(getModel()), ".class").end(); + builder.tree(createSpecializationListLiteral(builder, contains)); + builder.tree(createSpecializationListLiteral(builder, getModel().getExcludedBy())); + builder.tree(createSpecializationTypeLiteral(builder, SpecializationData.getSignatureTypes(getModel()))); + builder.string("0").string("0"); + builder.end(); + return includes; + } + + private CodeTree createSpecializationTypeLiteral(CodeTreeBuilder parent, List list) { + ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); + CodeTreeBuilder builder = parent.create(); + + if (list.isEmpty()) { + builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); + } else { + builder.startNewArray(classArray, null); + for (TypeMirror type : list) { + builder.typeLiteral(type); + } + builder.end(); + } + + return builder.getRoot(); + } + + private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set list) { + ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); + CodeTreeBuilder builder = parent.create(); + + if (list.isEmpty()) { + builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); + } else { + builder.startNewArray(classArray, null); + for (SpecializationData specialization : list) { + if (specialization.isGeneric() || specialization.isPolymorphic()) { + specialization = getModel().getNode().getUninitializedSpecialization(); + } + builder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); + } + builder.end(); + } + + return builder.getRoot(); + } + + protected CodeAnnotationMirror createNodeInfo(NodeData node, NodeCost cost) { + String shortName = node.getShortName(); + CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); + if (shortName != null) { + nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); + } + + DeclaredType nodeinfoCost = getContext().getTruffleTypes().getNodeCost(); + VariableElement varKind = ElementUtils.findVariableElement(nodeinfoCost, cost.name()); + + nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind)); + return nodeInfoMirror; + } + + @Override + protected void createChildren(SpecializationData specialization) { + CodeTypeElement clazz = getElement(); + createConstructors(clazz); + + createExecuteMethods(specialization); + createCachedExecuteMethods(specialization); + + if (specialization.isUninitialized()) { + if (specialization.getNode().isFallbackReachable()) { + CodeVariableElement var = new CodeVariableElement(modifiers(Modifier.PRIVATE), context.getType(boolean.class), CONTAINS_FALLBACK); + var.addAnnotationMirror(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal())); + clazz.add(var); + } + clazz.add(createExecuteUninitialized()); + } + + if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) { + clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization)); + } else { + for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { + if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) { + // skip copy constructor - not used + continue; + } + clazz.add(createConstructorFactoryMethod(specialization, constructor)); + } + } + } + + protected void createConstructors(CodeTypeElement clazz) { + TypeElement superTypeElement = ElementUtils.fromTypeMirror(clazz.getSuperclass()); + SpecializationData specialization = getModel(); + NodeData node = specialization.getNode(); + for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { + if (specialization.isUninitialized()) { + // ignore copy constructors for uninitialized if not polymorphic + if (isCopyConstructor(constructor) && !node.isPolymorphic(context)) { + continue; + } + } else if (node.getUninitializedSpecialization() != null) { + // ignore others than copy constructors for specialized nodes + if (!isCopyConstructor(constructor)) { + continue; + } + } + + CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); + if (superConstructor == null) { + continue; + } + CodeTree body = superConstructor.getBodyTree(); + CodeTreeBuilder builder = superConstructor.createBuilder(); + builder.tree(body); + + if (superConstructor != null) { + for (Parameter param : getImplicitTypeParameters(getModel())) { + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param))); + superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param))); + + builder.startStatement(); + builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param)); + builder.end(); + } + + clazz.add(superConstructor); + } + } + } + + protected void createExecuteMethods(SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTypeElement clazz = getElement(); + + for (ExecutableTypeData execType : node.getExecutableTypes()) { + if (execType.isFinal()) { + continue; + } + CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true); + clazz.add(executeMethod); + CodeTreeBuilder builder = executeMethod.getBuilder(); + CodeTree result = createExecuteBody(builder, specialization, execType); + if (result != null) { + builder.tree(result); + } else { + clazz.remove(executeMethod); + } + } + } + + protected void createCachedExecuteMethods(SpecializationData specialization) { + NodeData node = specialization.getNode(); + if (!node.isPolymorphic(context)) { + return; + } + + CodeTypeElement clazz = getElement(); + + final SpecializationData polymorphic = node.getPolymorphicSpecialization(); + ExecutableElement executeCached = nodeGen.getMethod(EXECUTE_CHAINED); + CodeExecutableElement executeMethod = CodeExecutableElement.clone(getContext().getEnvironment(), executeCached); + executeMethod.getModifiers().remove(Modifier.ABSTRACT); + CodeTreeBuilder builder = executeMethod.createBuilder(); + + if (specialization.isPolymorphic()) { + builder.startReturn().startCall("this.next0", EXECUTE_CHAINED); + addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null); + builder.end().end(); + } else if (specialization.isUninitialized()) { + if (node.getGenericSpecialization().isReachable()) { + builder.startIf().string("!containsFallback").end().startBlock(); + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + builder.end(); + } else { + builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + } + builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED); + addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null); + builder.end().end(); + } else { + CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); + elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED); + addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, null); + elseBuilder.end().end(); + + builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createGenericInvoke(b, polymorphic, current); + } + }, elseBuilder.getRoot(), false, true, true, false)); + } + clazz.add(executeMethod); + } + + private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + List primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount()); + + if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) { + builder.tree(createFunctionalExecute(builder, specialization, execType)); + } else if (needsCastingExecuteMethod(execType)) { + assert !primaryExecutes.isEmpty(); + builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0))); + } else { + return null; + } + + return builder.getRoot(); + } + + private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); + + method.getAnnotationMirrors().clear(); + for (VariableElement variable : method.getParameters()) { + variable.getAnnotationMirrors().clear(); + } + + CodeTreeBuilder builder = method.createBuilder(); + int i = 0; + int signatureIndex = -1; + for (VariableElement param : method.getParameters()) { + CodeVariableElement var = CodeVariableElement.clone(param); + Parameter actualParameter = i < execType.getParameters().size() ? execType.getParameters().get(i) : null; + String name; + if (actualParameter != null) { + if (actualParameter.getSpecification().isSignature()) { + signatureIndex++; + } + + if (evaluated && actualParameter.getSpecification().isSignature()) { + name = valueNameEvaluated(actualParameter); + } else { + name = valueName(actualParameter); + } + + int varArgCount = getModel().getSignatureSize() - signatureIndex; + if (evaluated && actualParameter.isTypeVarArgs()) { + Parameter baseVarArgs = actualParameter; + name = valueName(baseVarArgs) + "Args"; + + builder.startAssert().string(name).string(" != null").end(); + builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end(); + if (varArgCount > 0) { + List varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size()); + for (Parameter varArg : varArgsParameter) { + if (varArgCount <= 0) { + break; + } + TypeMirror type = baseVarArgs.getType(); + if (type.getKind() == TypeKind.ARRAY) { + type = ((ArrayType) type).getComponentType(); + } + builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getTypeVarArgsIndex() + "]"); + varArgCount--; + } + } + } + } else { + name = "arg" + i; + } + var.setName(name); + method.getParameters().set(i, var); + i++; + } + + method.getAnnotationMirrors().clear(); + method.getModifiers().remove(Modifier.ABSTRACT); + return method; + } + + private boolean needsCastingExecuteMethod(ExecutableTypeData execType) { + if (execType.isAbstract()) { + return true; + } + if (execType.getType().isGeneric()) { + return true; + } + return false; + } + + private List findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) { + TypeData primaryType = specialization.getReturnType().getTypeSystemType(); + List otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount); + + List filteredTypes = new ArrayList<>(); + for (ExecutableTypeData compareType : otherTypes) { + if (!ElementUtils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) { + continue; + } + filteredTypes.add(compareType); + } + + // no direct matches found use generic where the type is Object + if (filteredTypes.isEmpty()) { + for (ExecutableTypeData compareType : otherTypes) { + if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) { + filteredTypes.add(compareType); + } + } + } + + if (filteredTypes.isEmpty()) { + for (ExecutableTypeData compareType : otherTypes) { + if (compareType.getType().isGeneric()) { + filteredTypes.add(compareType); + } + } + } + + return filteredTypes; + } + + private CodeTree createFunctionalExecute(CodeTreeBuilder parent, final SpecializationData specialization, final ExecutableTypeData executable) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (specialization.isUninitialized()) { + builder.tree(createDeoptimize(builder)); + } + + builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null)); + + CodeTree returnSpecialized = null; + + if (specialization.findNextSpecialization() != null) { + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); + returnBuilder.tree(createDeoptimize(builder)); + returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, + "One of guards " + specialization.getGuards() + " failed")); + returnSpecialized = returnBuilder.getRoot(); + } + + builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock() { + + public CodeTree create(CodeTreeBuilder b, SpecializationData current) { + return createExecute(b, executable, specialization); + } + }, returnSpecialized, false, false, false, false)); + + return builder.getRoot(); + } + + private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { + builder.startTryBlock(); + } + + for (String assumption : specialization.getAssumptions()) { + builder.startStatement(); + builder.string("this.").string(assumption).string(".check()"); + builder.end(); + } + + CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); + if (specialization.isPolymorphic()) { + returnBuilder.startCall("next0", EXECUTE_CHAINED); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null); + returnBuilder.end(); + } else if (specialization.isUninitialized()) { + returnBuilder.startCall(EXECUTE_UNINITIALIZED); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null); + returnBuilder.end(); + } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { + emitEncounteredSynthetic(builder, specialization); + } else { + returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); + } + + if (!returnBuilder.isEmpty()) { + TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); + TypeData sourceType = specialization.getReturnType().getTypeSystemType(); + + builder.startReturn(); + if (targetType == null || sourceType == null) { + builder.tree(returnBuilder.getRoot()); + } else if (sourceType.needsCastTo(targetType)) { + String castMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); + if (!executable.hasUnexpectedValue(context)) { + castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); + } + builder.tree(createCallTypeSystemMethod(parent, node, castMethodName, returnBuilder.getRoot())); + } else { + builder.tree(returnBuilder.getRoot()); + } + builder.end(); + } + + if (!specialization.getExceptions().isEmpty()) { + for (SpecializationThrowsData exception : specialization.getExceptions()) { + builder.end().startCatchBlock(exception.getJavaClass(), "ex"); + builder.tree(createDeoptimize(builder)); + builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, + "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass()))); + } + builder.end(); + } + if (!specialization.getAssumptions().isEmpty()) { + builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); + builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, "Assumption failed")); + builder.end(); + } + + return builder.getRoot(); + } + + protected CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) { + List implicitTypeParams = getImplicitTypeParameters(specialization); + String baseName = "current"; + CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME); + method.addParameter(new CodeVariableElement(specialization.getNode().getNodeType(), baseName)); + for (Parameter implicitTypeParam : implicitTypeParams) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam))); + } + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startNew(getElement().asType()); + builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end(); + for (Parameter param : implicitTypeParams) { + builder.string(implicitTypeName(param)); + } + builder.end().end(); + return method; + } + + protected CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) { + List parameters = constructor.getParameters(); + CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME, + parameters.toArray(new CodeVariableElement[parameters.size()])); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startNew(getElement().asType()); + for (VariableElement param : parameters) { + builder.string(((CodeVariableElement) param).getName()); + } + builder.end().end(); + return method; + } + } + + private interface CodeBlock { + + CodeTree create(CodeTreeBuilder parent, T value); + + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,290 @@ +/* + * 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.dsl.processor.generator; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + +import java.util.*; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class TypeSystemCodeGenerator extends AbstractCompilationUnitFactory { + + public static String isTypeMethodName(TypeData type) { + return "is" + ElementUtils.getTypeId(type.getBoxedType()); + } + + public static String isImplicitTypeMethodName(TypeData type) { + return "isImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + } + + public static String asTypeMethodName(TypeData type) { + return "as" + ElementUtils.getTypeId(type.getBoxedType()); + } + + public static String asImplicitTypeMethodName(TypeData type) { + return "asImplicit" + ElementUtils.getTypeId(type.getBoxedType()); + } + + public static String getImplicitClass(TypeData type) { + return "getImplicit" + ElementUtils.getTypeId(type.getBoxedType()) + "Class"; + } + + public static String expectTypeMethodName(TypeData type) { + return "expect" + ElementUtils.getTypeId(type.getBoxedType()); + } + + public static String typeName(TypeSystemData typeSystem) { + String name = getSimpleName(typeSystem.getTemplateType()); + return name + "Gen"; + } + + public static String singletonName(TypeSystemData type) { + return createConstantName(getSimpleName(type.getTemplateType().asType())); + } + + @Override + protected void createChildren(TypeSystemData m) { + add(new TypeClassFactory(), m); + } + + private static class TypeClassFactory extends AbstractClassElementFactory { + + private static final String LOCAL_VALUE = "value"; + + @Override + public CodeTypeElement create(TypeSystemData typeSystem) { + String name = typeName(typeSystem); + CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC, FINAL), name, typeSystem.getTemplateType().asType(), false); + + clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz)); + CodeVariableElement singleton = createSingleton(clazz); + clazz.add(singleton); + + for (TypeData type : typeSystem.getTypes()) { + if (!type.isGeneric()) { + clazz.addOptional(createIsTypeMethod(type)); + clazz.addOptional(createAsTypeMethod(type)); + + for (TypeData sourceType : collectExpectSourceTypes(type)) { + clazz.addOptional(createExpectTypeMethod(type, sourceType)); + } + + clazz.addOptional(createAsImplicitTypeMethod(type, true)); + clazz.addOptional(createAsImplicitTypeMethod(type, false)); + clazz.addOptional(createIsImplicitTypeMethod(type, true)); + clazz.addOptional(createIsImplicitTypeMethod(type, false)); + clazz.addOptional(createGetTypeIndex(type)); + } + } + + return clazz; + } + + private static List collectExpectSourceTypes(TypeData type) { + Set sourceTypes = new HashSet<>(); + sourceTypes.add(type.getTypeSystem().getGenericTypeData()); + for (TypeCastData cast : type.getTypeCasts()) { + sourceTypes.add(cast.getSourceType()); + } + for (TypeCheckData cast : type.getTypeChecks()) { + sourceTypes.add(cast.getCheckedType()); + } + return new ArrayList<>(sourceTypes); + } + + private CodeVariableElement createSingleton(CodeTypeElement clazz) { + CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(getModel())); + field.createInitBuilder().startNew(clazz.asType()).end(); + return field; + } + + private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) { + TypeSystemData typeSystem = getModel(); + List casts = typeSystem.lookupByTargetType(type); + if (casts.isEmpty()) { + return null; + } + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + if (typed) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); + } + CodeTreeBuilder builder = method.createBuilder(); + + List sourceTypes = typeSystem.lookupSourceTypes(type); + + builder.startReturn(); + String sep = ""; + for (TypeData sourceType : sourceTypes) { + builder.string(sep); + if (typed) { + builder.string("(typeHint == ").typeLiteral(sourceType.getPrimitiveType()).string(" && "); + } + builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + if (typed) { + builder.string(")"); + } + if (sourceTypes.lastIndexOf(sourceType) != sourceTypes.size() - 1) { + builder.newLine(); + } + if (sep.equals("")) { + builder.startIndention(); + } + sep = " || "; + } + builder.end(); + builder.end(); + return method; + } + + private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean typed) { + TypeSystemData typeSystem = getModel(); + List casts = typeSystem.lookupByTargetType(type); + if (casts.isEmpty()) { + return null; + } + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asImplicitTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + if (typed) { + method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); + } + + List sourceTypes = typeSystem.lookupSourceTypes(type); + + CodeTreeBuilder builder = method.createBuilder(); + boolean elseIf = false; + for (TypeData sourceType : sourceTypes) { + elseIf = builder.startIf(elseIf); + if (typed) { + builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); + } else { + builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + } + + builder.end().startBlock(); + + builder.startReturn(); + ImplicitCastData cast = typeSystem.lookupCast(sourceType, type); + if (cast != null) { + builder.startCall(cast.getMethodName()); + } + builder.startCall(asTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + if (cast != null) { + builder.end(); + } + builder.end(); + builder.end(); + } + + builder.startElseBlock(); + builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); + builder.end(); + return method; + } + + private CodeExecutableElement createGetTypeIndex(TypeData type) { + TypeSystemData typeSystem = getModel(); + List casts = typeSystem.lookupByTargetType(type); + if (casts.isEmpty()) { + return null; + } + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + + List sourceTypes = typeSystem.lookupSourceTypes(type); + CodeTreeBuilder builder = method.createBuilder(); + boolean elseIf = false; + for (TypeData sourceType : sourceTypes) { + elseIf = builder.startIf(elseIf); + builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); + builder.end().startBlock(); + builder.startReturn().typeLiteral(sourceType.getPrimitiveType()).end(); + builder.end(); + } + + builder.startElseBlock(); + builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); + builder.end(); + + return method; + } + + private CodeExecutableElement createIsTypeMethod(TypeData type) { + if (!type.getTypeChecks().isEmpty()) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + + DeclaredType suppressWarnings = (DeclaredType) getContext().getType(SuppressWarnings.class); + CodeAnnotationMirror annotationMirror = new CodeAnnotationMirror(suppressWarnings); + annotationMirror.setElementValue(annotationMirror.findExecutableElement("value"), new CodeAnnotationValue("static-method")); + method.getAnnotationMirrors().add(annotationMirror); + + CodeTreeBuilder body = method.createBuilder(); + body.startReturn().instanceOf(LOCAL_VALUE, type.getBoxedType()).end(); + + return method; + } + + private CodeExecutableElement createAsTypeMethod(TypeData type) { + if (!type.getTypeCasts().isEmpty()) { + return null; + } + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asTypeMethodName(type)); + method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); + + CodeTreeBuilder body = method.createBuilder(); + String assertMessage = typeName(getModel()) + "." + asTypeMethodName(type) + ": " + ElementUtils.getSimpleName(type.getBoxedType()) + " expected"; + body.startAssert().startCall(isTypeMethodName(type)).string(LOCAL_VALUE).end().string(" : ").doubleQuote(assertMessage).end(); + body.startReturn().cast(type.getPrimitiveType(), body.create().string(LOCAL_VALUE).getTree()).end(); + + return method; + } + + private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); + method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE)); + method.addThrownType(getContext().getTruffleTypes().getUnexpectedValueException()); + + CodeTreeBuilder body = method.createBuilder(); + body.startIf().startCall(TypeSystemCodeGenerator.isTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end().startBlock(); + body.startReturn().startCall(TypeSystemCodeGenerator.asTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end(); + body.end(); // if-block + body.startThrow().startNew(getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end(); + + return method; + } + + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,946 @@ +/* + * 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.dsl.processor.java; + +import java.io.*; +import java.lang.annotation.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.model.*; +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror; + +/** + * THIS IS NOT PUBLIC API. + */ +public class ElementUtils { + + public static ExecutableElement findExecutableElement(DeclaredType type, String name) { + List elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); + for (ExecutableElement executableElement : elements) { + if (executableElement.getSimpleName().toString().equals(name)) { + return executableElement; + } + } + return null; + } + + public static boolean needsCastTo(TypeMirror sourceType, TypeMirror targetType) { + if (typeEquals(sourceType, targetType)) { + return false; + } else if (isObject(targetType)) { + return false; + } else if (isVoid(targetType)) { + return false; + } else if (isAssignable(sourceType, targetType)) { + return false; + } + return true; + } + + public static VariableElement findVariableElement(DeclaredType type, String name) { + List elements = ElementFilter.fieldsIn(type.asElement().getEnclosedElements()); + for (VariableElement variableElement : elements) { + if (variableElement.getSimpleName().toString().equals(name)) { + return variableElement; + } + } + return null; + } + + public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) { + TypeMirror boxedType = primitiveType; + if (boxedType.getKind().isPrimitive()) { + boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); + } + return boxedType; + } + + public static DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { + return new DeclaredCodeTypeMirror(typeElem, Arrays.asList(typeArgs)); + } + + public static List collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, + Class annotationClass) { + List result = new ArrayList<>(); + if (markerAnnotation != null) { + result.addAll(ElementUtils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName)); + } + AnnotationMirror explicit = ElementUtils.findAnnotationMirror(context.getEnvironment(), element, annotationClass); + if (explicit != null) { + result.add(explicit); + } + return result; + } + + public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) { + if (types.length == 0) { + return context.getType(Object.class); + } + TypeMirror prev = types[0]; + for (int i = 1; i < types.length; i++) { + prev = getCommonSuperType(context, prev, types[i]); + } + return prev; + } + + private static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror type1, TypeMirror type2) { + if (typeEquals(type1, type2)) { + return type1; + } + TypeElement element1 = fromTypeMirror(type1); + TypeElement element2 = fromTypeMirror(type2); + if (element1 == null || element2 == null) { + return context.getType(Object.class); + } + + List element1Types = getDirectSuperTypes(element1); + element1Types.add(0, element1); + List element2Types = getDirectSuperTypes(element2); + element2Types.add(0, element2); + + for (TypeElement superType1 : element1Types) { + for (TypeElement superType2 : element2Types) { + if (typeEquals(superType1.asType(), superType2.asType())) { + return superType2.asType(); + } + } + } + return context.getType(Object.class); + } + + 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: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case INT: + case SHORT: + case LONG: + case DECLARED: + case VOID: + case TYPEVAR: + return false; + case ARRAY: + return hasError(((ArrayType) mirror).getComponentType()); + case ERROR: + return true; + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + + public static boolean isSubtype(TypeMirror type1, TypeMirror type2) { + if (type1 instanceof CodeTypeMirror && type2 instanceof CodeTypeMirror) { + throw new UnsupportedOperationException(); + } + return ProcessorContext.getInstance().getEnvironment().getTypeUtils().isSubtype(type1, type2); + } + + public static boolean isAssignable(TypeMirror from, TypeMirror to) { + ProcessorContext context = ProcessorContext.getInstance(); + + if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) { + return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to)); + } else { + return isAssignableImpl(from, to); + } + } + + private static boolean isAssignableImpl(TypeMirror from, TypeMirror to) { + // JLS 5.1.1 identity conversion + if (ElementUtils.typeEquals(from, to)) { + return true; + } + + if (isObject(to)) { + return true; + } + + // JLS 5.1.2 widening primitives + if (ElementUtils.isPrimitive(from) && ElementUtils.isPrimitive(to)) { + TypeKind fromKind = from.getKind(); + TypeKind toKind = to.getKind(); + switch (fromKind) { + case BYTE: + switch (toKind) { + case SHORT: + case INT: + case LONG: + case FLOAT: + case DOUBLE: + return true; + } + break; + case SHORT: + switch (toKind) { + case INT: + case LONG: + case FLOAT: + case DOUBLE: + return true; + } + break; + case CHAR: + switch (toKind) { + case INT: + case LONG: + case FLOAT: + case DOUBLE: + return true; + } + break; + case INT: + switch (toKind) { + case LONG: + case FLOAT: + case DOUBLE: + return true; + } + break; + case LONG: + switch (toKind) { + case FLOAT: + case DOUBLE: + return true; + } + break; + case FLOAT: + switch (toKind) { + case DOUBLE: + return true; + } + break; + + } + return false; + } else if (ElementUtils.isPrimitive(from) || ElementUtils.isPrimitive(to)) { + return false; + } + + if (from instanceof ArrayType && to instanceof ArrayType) { + return isAssignable(((ArrayType) from).getComponentType(), ((ArrayType) to).getComponentType()); + } + + if (from instanceof ArrayType || to instanceof ArrayType) { + return false; + } + + TypeElement fromType = ElementUtils.fromTypeMirror(from); + TypeElement toType = ElementUtils.fromTypeMirror(to); + if (fromType == null || toType == null) { + return false; + } + // JLS 5.1.6 narrowing reference conversion + + List superTypes = ElementUtils.getSuperTypes(fromType); + for (TypeElement superType : superTypes) { + if (ElementUtils.typeEquals(superType.asType(), to)) { + return true; + } + } + + // TODO more spec + return false; + } + + public static Set modifiers(Modifier... modifier) { + return new LinkedHashSet<>(Arrays.asList(modifier)); + } + + public static String getTypeId(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "Boolean"; + case BYTE: + return "Byte"; + case CHAR: + return "Char"; + case DOUBLE: + return "Double"; + case FLOAT: + return "Float"; + case SHORT: + return "Short"; + case INT: + return "Int"; + case LONG: + return "Long"; + case DECLARED: + return fixECJBinaryNameIssue(((DeclaredType) mirror).asElement().getSimpleName().toString()); + case ARRAY: + return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; + case VOID: + return "Void"; + case WILDCARD: + StringBuilder b = new StringBuilder(); + WildcardType type = (WildcardType) mirror; + if (type.getExtendsBound() != null) { + b.append("Extends").append(getTypeId(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("Super").append(getTypeId(type.getExtendsBound())); + } + return b.toString(); + case TYPEVAR: + return "Any"; + case ERROR: + throw new CompileErrorException("Type error " + mirror); + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + + public static String getSimpleName(TypeElement element) { + return getSimpleName(element.asType()); + } + + public static String getSimpleName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case CHAR: + return "char"; + case DOUBLE: + return "double"; + case FLOAT: + return "float"; + case SHORT: + return "short"; + case INT: + return "int"; + case LONG: + return "long"; + case DECLARED: + return getDeclaredName((DeclaredType) mirror); + case ARRAY: + return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; + case VOID: + return "void"; + case WILDCARD: + return getWildcardName((WildcardType) mirror); + case TYPEVAR: + return "?"; + case ERROR: + throw new CompileErrorException("Type error " + mirror); + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + + private static String getWildcardName(WildcardType type) { + StringBuilder b = new StringBuilder(); + if (type.getExtendsBound() != null) { + b.append("? extends ").append(getSimpleName(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("? super ").append(getSimpleName(type.getExtendsBound())); + } + return b.toString(); + } + + private static String getDeclaredName(DeclaredType element) { + String simpleName = fixECJBinaryNameIssue(element.asElement().getSimpleName().toString()); + + if (element.getTypeArguments().size() == 0) { + return simpleName; + } + + StringBuilder b = new StringBuilder(simpleName); + b.append("<"); + if (element.getTypeArguments().size() > 0) { + for (int i = 0; i < element.getTypeArguments().size(); i++) { + b.append(getSimpleName(element.getTypeArguments().get(i))); + if (i < element.getTypeArguments().size() - 1) { + b.append(", "); + } + } + } + b.append(">"); + return b.toString(); + } + + public static String fixECJBinaryNameIssue(String name) { + if (name.contains("$")) { + int lastIndex = name.lastIndexOf('$'); + return name.substring(lastIndex + 1, name.length()); + } + return name; + } + + public static String getQualifiedName(TypeElement element) { + String qualifiedName = element.getQualifiedName().toString(); + if (qualifiedName.contains("$")) { + /* + * If a class gets loaded in its binary form by the ECJ compiler it fails to produce the + * proper canonical class name. It leaves the $ in the qualified name of the class. So + * one instance of a TypeElement may be loaded in binary and one in source form. The + * current type comparison in #typeEquals compares by the qualified name so the + * qualified name must match. This is basically a hack to fix the returned qualified + * name of eclipse. + */ + qualifiedName = qualifiedName.replace('$', '.'); + } + return qualifiedName; + } + + public static String getQualifiedName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case CHAR: + return "char"; + case DOUBLE: + return "double"; + case SHORT: + return "short"; + case FLOAT: + return "float"; + case INT: + return "int"; + case LONG: + return "long"; + case DECLARED: + return getQualifiedName(fromTypeMirror(mirror)); + case ARRAY: + return getQualifiedName(((ArrayType) mirror).getComponentType()); + case VOID: + return "void"; + case TYPEVAR: + return getSimpleName(mirror); + case ERROR: + throw new CompileErrorException("Type error " + mirror); + case EXECUTABLE: + return ((ExecutableType) mirror).toString(); + case NONE: + return "$none"; + default: + throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror); + } + } + + public static boolean isVoid(TypeMirror mirror) { + return mirror != null && mirror.getKind() == TypeKind.VOID; + } + + public static boolean isPrimitive(TypeMirror mirror) { + return mirror != null && mirror.getKind().isPrimitive(); + } + + public static List getQualifiedSuperTypeNames(TypeElement element) { + List types = getSuperTypes(element); + List qualifiedNames = new ArrayList<>(); + for (TypeElement type : types) { + qualifiedNames.add(getQualifiedName(type)); + } + return qualifiedNames; + } + + public static List getDeclaredTypes(TypeElement element) { + return ElementFilter.typesIn(element.getEnclosedElements()); + } + + public static boolean isEnclosedIn(Element enclosedIn, Element element) { + if (element == null) { + return false; + } else if (enclosedIn.equals(element)) { + return true; + } else { + return isEnclosedIn(enclosedIn, 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 null; + } + + public 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 getDirectSuperTypes(TypeElement element) { + List types = new ArrayList<>(); + if (element.getSuperclass() != null) { + TypeElement superElement = fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + types.add(superElement); + types.addAll(getDirectSuperTypes(superElement)); + } + } + + return types; + } + + public static List getAssignableTypes(ProcessorContext context, TypeMirror type) { + if (isPrimitive(type)) { + return Arrays.asList(type, boxType(context, type), context.getType(Object.class)); + } else if (type.getKind() == TypeKind.ARRAY) { + return Arrays.asList(type, context.getType(Object.class)); + } else if (type.getKind() == TypeKind.DECLARED) { + List types = getSuperTypes(fromTypeMirror(type)); + List mirrors = new ArrayList<>(types.size()); + mirrors.add(type); + for (TypeElement typeElement : types) { + mirrors.add(typeElement.asType()); + } + return mirrors; + } else { + return Collections.emptyList(); + } + } + + public static List getSuperTypes(TypeElement element) { + List types = new ArrayList<>(); + List superTypes = null; + List superInterfaces = null; + if (element.getSuperclass() != null) { + TypeElement superElement = fromTypeMirror(element.getSuperclass()); + if (superElement != null) { + types.add(superElement); + superTypes = getSuperTypes(superElement); + } + } + for (TypeMirror interfaceMirror : element.getInterfaces()) { + TypeElement interfaceElement = fromTypeMirror(interfaceMirror); + if (interfaceElement != null) { + types.add(interfaceElement); + superInterfaces = getSuperTypes(interfaceElement); + } + } + + if (superTypes != null) { + types.addAll(superTypes); + } + + if (superInterfaces != null) { + types.addAll(superInterfaces); + } + + return types; + } + + public static String getPackageName(TypeElement element) { + return findPackageElement(element).getQualifiedName().toString(); + } + + public static String getPackageName(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case SHORT: + case INT: + case LONG: + case VOID: + case TYPEVAR: + return null; + case DECLARED: + PackageElement pack = findPackageElement(fromTypeMirror(mirror)); + if (pack == null) { + throw new IllegalArgumentException("No package element found for declared type " + getSimpleName(mirror)); + } + return pack.getQualifiedName().toString(); + case ARRAY: + return getSimpleName(((ArrayType) mirror).getComponentType()); + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind()); + } + } + + public static String createConstantName(String simpleName) { + // TODO use camel case to produce underscores. + return simpleName.toString().toUpperCase(); + } + + public static TypeElement fromTypeMirror(TypeMirror mirror) { + switch (mirror.getKind()) { + case DECLARED: + return (TypeElement) ((DeclaredType) mirror).asElement(); + case ARRAY: + return fromTypeMirror(((ArrayType) mirror).getComponentType()); + default: + return null; + } + } + + @SuppressWarnings("unchecked") + public static List getAnnotationValueList(Class expectedListType, AnnotationMirror mirror, String name) { + List values = getAnnotationValue(List.class, mirror, name); + List result = new ArrayList<>(); + + if (values != null) { + for (AnnotationValue value : values) { + T annotationValue = resolveAnnotationValue(expectedListType, value); + if (annotationValue != null) { + result.add(annotationValue); + } + } + } + return result; + } + + public static T getAnnotationValue(Class expectedType, AnnotationMirror mirror, String name) { + return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name)); + } + + @SuppressWarnings({"unchecked"}) + private static T resolveAnnotationValue(Class expectedType, AnnotationValue value) { + if (value == null) { + return null; + } + + Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null); + if (unboxedValue != null) { + if (expectedType == TypeMirror.class && unboxedValue instanceof String) { + return null; + } + if (!expectedType.isAssignableFrom(unboxedValue.getClass())) { + throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName()); + } + } + return (T) unboxedValue; + } + + public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) { + ExecutableElement valueMethod = null; + for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) { + if (method.getSimpleName().toString().equals(name)) { + valueMethod = method; + break; + } + } + + if (valueMethod == null) { + return null; + } + + AnnotationValue value = mirror.getElementValues().get(valueMethod); + if (value == null) { + value = valueMethod.getDefaultValue(); + } + + return value; + } + + private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7 { + + @Override + public Object visitBoolean(boolean b, Void p) { + return Boolean.valueOf(b); + } + + @Override + public Object visitByte(byte b, Void p) { + return Byte.valueOf(b); + } + + @Override + public Object visitChar(char c, Void p) { + return c; + } + + @Override + public Object visitDouble(double d, Void p) { + return d; + } + + @Override + public Object visitFloat(float f, Void p) { + return f; + } + + @Override + public Object visitInt(int i, Void p) { + return i; + } + + @Override + public Object visitLong(long i, Void p) { + return i; + } + + @Override + public Object visitShort(short s, Void p) { + return s; + } + + @Override + public Object visitString(String s, Void p) { + return s; + } + + @Override + public Object visitType(TypeMirror t, Void p) { + return t; + } + + @Override + public Object visitEnumConstant(VariableElement c, Void p) { + return c; + } + + @Override + public Object visitAnnotation(AnnotationMirror a, Void p) { + return a; + } + + @Override + public Object visitArray(List vals, Void p) { + return vals; + } + + } + + public static String printException(Throwable e) { + StringWriter string = new StringWriter(); + PrintWriter writer = new PrintWriter(string); + e.printStackTrace(writer); + writer.flush(); + return e.getMessage() + "\r\n" + string.toString(); + } + + public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, Element element, Class annotationClass) { + return findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), annotationClass); + } + + public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List mirrors, Class annotationClass) { + TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName()); + return findAnnotationMirror(mirrors, expectedAnnotationType); + } + + public static AnnotationMirror findAnnotationMirror(List mirrors, TypeElement expectedAnnotationType) { + for (AnnotationMirror mirror : mirrors) { + DeclaredType annotationType = mirror.getAnnotationType(); + TypeElement actualAnnotationType = (TypeElement) annotationType.asElement(); + if (actualAnnotationType.equals(expectedAnnotationType)) { + return mirror; + } + } + return null; + } + + private static PackageElement findPackageElement(Element type) { + List hierarchy = getElementHierarchy(type); + for (Element element : hierarchy) { + if (element.getKind() == ElementKind.PACKAGE) { + return (PackageElement) element; + } + } + return null; + } + + public static String firstLetterUpperCase(String name) { + if (name == null || name.isEmpty()) { + return name; + } + return Character.toUpperCase(name.charAt(0)) + name.substring(1, name.length()); + } + + public static String firstLetterLowerCase(String name) { + if (name == null || name.isEmpty()) { + return name; + } + return Character.toLowerCase(name.charAt(0)) + name.substring(1, name.length()); + } + + private static ExecutableElement getDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { + List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + method: for (ExecutableElement method : methods) { + if (!method.getSimpleName().toString().equals(name)) { + continue; + } + if (method.getParameters().size() != params.length) { + continue; + } + for (int i = 0; i < params.length; i++) { + TypeMirror param1 = params[i]; + TypeMirror param2 = method.getParameters().get(i).asType(); + if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) { + if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { + continue method; + } + } + } + return method; + } + return null; + } + + private static boolean isDeclaredMethod(TypeElement element, String name, TypeMirror[] params) { + return getDeclaredMethod(element, name, params) != null; + } + + public static boolean isDeclaredMethodInSuperType(TypeElement element, String name, TypeMirror[] params) { + List superElements = getSuperTypes(element); + + for (TypeElement typeElement : superElements) { + if (isDeclaredMethod(typeElement, name, params)) { + return true; + } + } + return false; + } + + public static boolean typeEquals(TypeMirror type1, TypeMirror type2) { + if (type1 == null && type2 == null) { + return true; + } else if (type1 == null || type2 == null) { + return false; + } else if (type1 == type2) { + return true; + } + String qualified1 = getQualifiedName(type1); + String qualified2 = getQualifiedName(type2); + + if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) { + if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) { + return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType()); + } else { + return false; + } + } + return qualified1.equals(qualified2); + } + + public static int compareByTypeHierarchy(TypeMirror t1, TypeMirror t2) { + if (typeEquals(t1, t2)) { + return 0; + } + Set t1SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t1))); + if (t1SuperSet.contains(getQualifiedName(t2))) { + return -1; + } + + Set t2SuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(t2))); + if (t2SuperSet.contains(getQualifiedName(t1))) { + return 1; + } + return 0; + } + + public static boolean canThrowType(List thrownTypes, TypeMirror exceptionType) { + if (ElementUtils.containsType(thrownTypes, exceptionType)) { + return true; + } + + if (isRuntimeException(exceptionType)) { + return true; + } + + // search for any super types + TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); + List superTypes = getSuperTypes(exceptionTypeElement); + for (TypeElement typeElement : superTypes) { + if (ElementUtils.containsType(thrownTypes, typeElement.asType())) { + return true; + } + } + + return false; + } + + public static Modifier getVisibility(Set modifier) { + for (Modifier mod : modifier) { + if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) { + return mod; + } + } + return null; + } + + private static boolean isRuntimeException(TypeMirror type) { + Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); + String typeName = getQualifiedName(type); + if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { + throw new IllegalArgumentException("Given type does not extend Throwable."); + } + return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); + } + + private static boolean containsType(Collection collection, TypeMirror type) { + for (TypeMirror otherTypeMirror : collection) { + if (typeEquals(otherTypeMirror, type)) { + return true; + } + } + 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; + } + + public static boolean isObject(TypeMirror actualType) { + return actualType.getKind() == TypeKind.DECLARED && getQualifiedName(actualType).equals("java.lang.Object"); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/AbstractCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/AbstractCompiler.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,83 @@ +/* + * 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.dsl.processor.java.compiler; + +import java.lang.reflect.*; + +public abstract class AbstractCompiler implements Compiler { + + protected static Object method(Object o, String methodName) throws Exception { + Method method = o.getClass().getMethod(methodName); + method.setAccessible(true); + return method.invoke(o); + } + + protected static Object method(Object o, String methodName, Class[] paramTypes, Object... values) throws Exception { + Method method = o.getClass().getMethod(methodName, paramTypes); + method.setAccessible(true); + return method.invoke(o, values); + } + + protected static Object field(Object o, String fieldName) throws Exception { + if (o == null) { + return null; + } + Class clazz = o.getClass(); + Field field = null; + try { + field = clazz.getField(fieldName); + } catch (NoSuchFieldException e) { + while (clazz != null) { + try { + field = clazz.getDeclaredField(fieldName); + break; + } catch (NoSuchFieldException e1) { + clazz = clazz.getSuperclass(); + } + } + if (field == null) { + throw e; + } + } + field.setAccessible(true); + return field.get(o); + } + + protected static String parseHeader(String content) { + int index = content.indexOf("/*"); + if (index == -1) { + return null; + } + if (!content.substring(0, index).trim().equals("")) { + // just whitespace before + return null; + } + + int endIndex = content.indexOf("*/", index); + if (endIndex == -1) { + return null; + } + return content.substring(index, endIndex + 2); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/Compiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/Compiler.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,40 @@ +/* + * 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.dsl.processor.java.compiler; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +public interface Compiler { + + String getMethodBody(ProcessingEnvironment env, ExecutableElement method); + + String getHeaderComment(ProcessingEnvironment env, Element type); + + List getEnclosedElementsInDeclarationOrder(TypeElement type); + + List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type); + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/CompilerFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/CompilerFactory.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,48 @@ +/* + * 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.dsl.processor.java.compiler; + +import javax.lang.model.element.*; + +public class CompilerFactory { + + private static Compiler javac; + private static Compiler jdt; + + public static Compiler getCompiler(Element currentElement) { + if (JavaCCompiler.isValidElement(currentElement)) { + if (javac == null) { + javac = new JavaCCompiler(); + } + return javac; + } else if (JDTCompiler.isValidElement(currentElement)) { + if (jdt == null) { + jdt = new JDTCompiler(); + } + return jdt; + } else { + throw new UnsupportedOperationException("Unsupported compiler for element " + currentElement.getClass().getName() + "."); + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JDTCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JDTCompiler.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,283 @@ +/* + * 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.dsl.processor.java.compiler; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class JDTCompiler extends AbstractCompiler { + + public static boolean isValidElement(Element currentElement) { + try { + Class elementClass = Class.forName("org.eclipse.jdt.internal.compiler.apt.model.ElementImpl"); + return elementClass.isAssignableFrom(currentElement.getClass()); + } catch (ClassNotFoundException e) { + return false; + } + } + + public List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type) { + return sortBySourceOrder(new ArrayList<>(environment.getElementUtils().getAllMembers(type))); + } + + public List getEnclosedElementsInDeclarationOrder(TypeElement type) { + return sortBySourceOrder(new ArrayList<>(type.getEnclosedElements())); + } + + private static List sortBySourceOrder(List elements) { + final Map> declarationOrders = new HashMap<>(); + + Collections.sort(elements, new Comparator() { + public int compare(Element o1, Element o2) { + try { + TypeMirror enclosing1 = o1.getEnclosingElement().asType(); + TypeMirror enclosing2 = o2.getEnclosingElement().asType(); + + if (ElementUtils.typeEquals(enclosing1, enclosing2)) { + List declarationOrder = lookupDeclarationOrder(declarationOrders, (TypeElement) o1.getEnclosingElement()); + if (declarationOrder == null) { + return 0; + } + Object o1Binding = field(o1, "_binding"); + Object o2Binding = field(o2, "_binding"); + + int i1 = declarationOrder.indexOf(o1Binding); + int i2 = declarationOrder.indexOf(o2Binding); + + return i1 - i2; + } else { + if (ElementUtils.isSubtype(enclosing1, enclosing2)) { + return 1; + } else if (ElementUtils.isSubtype(enclosing2, enclosing1)) { + return -1; + } else { + return 0; + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + return elements; + } + + private static List lookupDeclarationOrder(Map> declarationOrders, TypeElement type) throws Exception, ClassNotFoundException { + if (declarationOrders.containsKey(type)) { + return declarationOrders.get(type); + } + + Object binding = field(type, "_binding"); + Class sourceTypeBinding = Class.forName("org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding"); + Class binaryTypeBinding = Class.forName("org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding"); + + List declarationOrder = null; + if (sourceTypeBinding.isAssignableFrom(binding.getClass())) { + declarationOrder = findSourceTypeOrder(binding); + } else if (binaryTypeBinding.isAssignableFrom(binding.getClass())) { + declarationOrder = findBinaryTypeOrder(binding); + } + + declarationOrders.put(type, declarationOrder); + + return declarationOrder; + } + + private static List findBinaryTypeOrder(Object binding) throws Exception { + Object binaryType = lookupBinaryType(binding); + final Object[] sortedMethods = (Object[]) method(binaryType, "getMethods"); + + List sortedElements = new ArrayList<>(); + if (sortedMethods != null) { + sortedElements.addAll(Arrays.asList(sortedMethods)); + } + final Object[] sortedFields = (Object[]) method(binaryType, "getFields"); + if (sortedFields != null) { + sortedElements.addAll(Arrays.asList(sortedFields)); + } + final Object[] sortedTypes = (Object[]) method(binaryType, "getMemberTypes", new Class[0]); + if (sortedTypes != null) { + sortedElements.addAll(Arrays.asList(sortedTypes)); + } + + Collections.sort(sortedElements, new Comparator() { + public int compare(Object o1, Object o2) { + try { + int structOffset1 = (int) field(o1, "structOffset"); + int structOffset2 = (int) field(o2, "structOffset"); + return structOffset1 - structOffset2; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + + Class binaryMethod = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryMethod"); + Class binaryField = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryField"); + Class nestedType = Class.forName("org.eclipse.jdt.internal.compiler.env.IBinaryNestedType"); + + List bindings = new ArrayList<>(); + for (Object sortedElement : sortedElements) { + Class elementClass = sortedElement.getClass(); + if (binaryMethod.isAssignableFrom(elementClass)) { + char[] selector = (char[]) method(sortedElement, "getSelector"); + Object[] foundBindings = (Object[]) method(binding, "getMethods", new Class[]{char[].class}, selector); + if (foundBindings == null || foundBindings.length == 0) { + continue; + } else if (foundBindings.length == 1) { + bindings.add(foundBindings[0]); + } else { + char[] idescriptor = (char[]) method(sortedElement, "getMethodDescriptor"); + for (Object foundBinding : foundBindings) { + char[] descriptor = (char[]) method(foundBinding, "signature"); + if (descriptor == null && idescriptor == null || Arrays.equals(descriptor, idescriptor)) { + bindings.add(foundBinding); + break; + } + } + } + } else if (binaryField.isAssignableFrom(elementClass)) { + char[] selector = (char[]) method(sortedElement, "getName"); + Object foundField = method(binding, "getField", new Class[]{char[].class, boolean.class}, selector, true); + if (foundField != null) { + bindings.add(foundField); + } + } else if (nestedType.isAssignableFrom(elementClass)) { + char[] selector = (char[]) method(sortedElement, "getSourceName"); + Object foundType = method(binding, "getMemberType", new Class[]{char[].class}, selector); + if (foundType != null) { + bindings.add(foundType); + } + } else { + throw new AssertionError("Unexpected encountered type " + elementClass); + } + } + + return bindings; + } + + private static Object lookupBinaryType(Object binding) throws Exception { + Object lookupEnvironment = field(binding, "environment"); + Object compoundClassName = field(binding, "compoundName"); + Object nameEnvironment = field(lookupEnvironment, "nameEnvironment"); + Object nameEnvironmentAnswer = method(nameEnvironment, "findType", new Class[]{char[][].class}, compoundClassName); + Object binaryType = method(nameEnvironmentAnswer, "getBinaryType", new Class[0]); + return binaryType; + } + + private static List findSourceTypeOrder(Object binding) throws Exception { + Object referenceContext = field(field(binding, "scope"), "referenceContext"); + + TreeMap orderedBindings = new TreeMap<>(); + + collectSourceOrder(orderedBindings, referenceContext, "methods"); + collectSourceOrder(orderedBindings, referenceContext, "fields"); + collectSourceOrder(orderedBindings, referenceContext, "memberTypes"); + + return new ArrayList<>(orderedBindings.values()); + } + + private static void collectSourceOrder(TreeMap orderedBindings, Object referenceContext, String fieldName) throws Exception { + Object[] declarations = (Object[]) field(referenceContext, fieldName); + if (declarations != null) { + for (int i = 0; i < declarations.length; i++) { + Integer declarationSourceStart = (Integer) field(declarations[i], "declarationSourceStart"); + orderedBindings.put(declarationSourceStart, field(declarations[i], "binding")); + } + } + } + + @Override + public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { + try { + + char[] source = getSource(method); + if (source == null) { + return null; + } + + /* + * 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"); + + int length = bodyEnd - bodyStart; + char[] target = new char[length]; + System.arraycopy(source, bodyStart, target, 0, length); + + return new String(target); + } catch (Exception e) { + return ElementUtils.printException(e); + } + } + + 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; + */ + + 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"); + + char[] source = null; + if (methodBindingClass.isAssignableFrom(binding.getClass())) { + Object sourceMethod = method(binding, "sourceMethod"); + if (sourceMethod == null) { + return null; + } + source = (char[]) method(method(field(sourceMethod, "compilationResult"), "getCompilationUnit"), "getContents"); + } else if (referenceBindingClass.isAssignableFrom(binding.getClass())) { + source = (char[]) method(field(field(field(field(binding, "scope"), "referenceContext"), "compilationResult"), "compilationUnit"), "getContents"); + } + return source; + } + + @Override + public String getHeaderComment(ProcessingEnvironment env, Element type) { + try { + char[] source = getSource(type); + if (source == null) { + return null; + } + return parseHeader(new String(source)); + } catch (Exception e) { + return ElementUtils.printException(e); + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JavaCCompiler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JavaCCompiler.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,101 @@ +/* + * 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.dsl.processor.java.compiler; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class JavaCCompiler extends AbstractCompiler { + + public static boolean isValidElement(Element currentElement) { + try { + Class elementClass = Class.forName("com.sun.tools.javac.code.Symbol"); + return elementClass.isAssignableFrom(currentElement.getClass()); + } catch (ClassNotFoundException e) { + return false; + } + } + + public List getEnclosedElementsInDeclarationOrder(TypeElement type) { + return type.getEnclosedElements(); + } + + public List getAllMembersInDeclarationOrder(ProcessingEnvironment environment, TypeElement type) { + return environment.getElementUtils().getAllMembers(type); + } + + private static final Class[] getTreeAndTopLevelSignature = new Class[]{Element.class, AnnotationMirror.class, AnnotationValue.class}; + private static final Class[] getCharContentSignature = new Class[]{boolean.class}; + + @Override + public String getMethodBody(ProcessingEnvironment env, ExecutableElement method) { + try { + /* + * if (false) { Pair treeAndTopLevel = ((JavacElements) + * env.getElementUtils()).getTreeAndTopLevel(method, null, null); JCBlock block = + * ((JCMethodDecl) treeAndTopLevel.fst).getBody(); int startPos = block.pos; int endPos + * = block.endpos; String methodBody = + * treeAndTopLevel.snd.getSourceFile().getCharContent(true).subSequence(startPos + 1, + * endPos).toString(); return methodBody; } + */ + + Object treeAndTopLevel = getTreeAndTopLevel(env, method); + Object block = method(field(treeAndTopLevel, "fst"), "getBody"); + int startPos = (int) field(block, "pos"); + int endPos = (int) field(block, "endpos"); + return getContent(treeAndTopLevel).subSequence(startPos + 1, endPos).toString(); + } catch (Exception e) { + return ElementUtils.printException(e); + } + } + + private static CharSequence getContent(Object treeAndTopLevel) throws Exception { + /* + * CharSequence content = treeAndTopLevel.snd.getSourceFile().getCharContent(true); + */ + return (CharSequence) method(method(field(treeAndTopLevel, "snd"), "getSourceFile"), "getCharContent", getCharContentSignature, true); + } + + private static Object getTreeAndTopLevel(ProcessingEnvironment env, Element element) throws Exception { + /* + * Pair treeAndTopLevel = ((JavacElements) + * env.getElementUtils()).getTreeAndTopLevel(method, null, null); + */ + return method(method(env, "getElementUtils"), "getTreeAndTopLevel", getTreeAndTopLevelSignature, element, null, null); + } + + @Override + public String getHeaderComment(ProcessingEnvironment env, Element type) { + try { + String content = getContent(getTreeAndTopLevel(env, type)).toString(); + return parseHeader(content); + } catch (Exception e) { + return ElementUtils.printException(e); + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeAnnotationMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeAnnotationMirror.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,59 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class CodeAnnotationMirror implements AnnotationMirror { + + private final DeclaredType annotationType; + private final Map values = new LinkedHashMap<>(); + + public CodeAnnotationMirror(DeclaredType annotationType) { + this.annotationType = annotationType; + } + + @Override + public DeclaredType getAnnotationType() { + return annotationType; + } + + @Override + public Map getElementValues() { + return values; + } + + public void setElementValue(ExecutableElement method, AnnotationValue value) { + values.put(method, value); + } + + public ExecutableElement findExecutableElement(String name) { + return ElementUtils.findExecutableElement(annotationType, name); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeAnnotationValue.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeAnnotationValue.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,84 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeAnnotationValue implements AnnotationValue { + + private final Object value; + + public CodeAnnotationValue(Object value) { + Objects.requireNonNull(value); + if ((value instanceof AnnotationMirror) || (value instanceof List) || (value instanceof Boolean) || (value instanceof Byte) || (value instanceof Character) || (value instanceof Double) || + (value instanceof VariableElement) || (value instanceof Float) || (value instanceof Integer) || (value instanceof Long) || (value instanceof Short) || + (value instanceof String) || (value instanceof TypeMirror)) { + this.value = value; + } else { + throw new IllegalArgumentException("Invalid annotation value type " + value.getClass().getName()); + } + } + + @Override + public Object getValue() { + return value; + } + + @SuppressWarnings("unchecked") + @Override + public R accept(AnnotationValueVisitor v, P p) { + if (value instanceof AnnotationMirror) { + return v.visitAnnotation((AnnotationMirror) value, p); + } else if (value instanceof List) { + return v.visitArray((List) value, p); + } else if (value instanceof Boolean) { + return v.visitBoolean((boolean) value, p); + } else if (value instanceof Byte) { + return v.visitByte((byte) value, p); + } else if (value instanceof Character) { + return v.visitChar((char) value, p); + } else if (value instanceof Double) { + return v.visitDouble((double) value, p); + } else if (value instanceof VariableElement) { + return v.visitEnumConstant((VariableElement) value, p); + } else if (value instanceof Float) { + return v.visitFloat((float) value, p); + } else if (value instanceof Integer) { + return v.visitInt((int) value, p); + } else if (value instanceof Long) { + return v.visitLong((long) value, p); + } else if (value instanceof Short) { + return v.visitShort((short) value, p); + } else if (value instanceof String) { + return v.visitString((String) value, p); + } else if (value instanceof TypeMirror) { + return v.visitType((TypeMirror) value, p); + } else { + return v.visitUnknown(this, p); + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeCompilationUnit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeCompilationUnit.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,63 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeCompilationUnit extends CodeElement { + + public CodeCompilationUnit() { + super(Collections. emptySet()); + } + + @Override + public TypeMirror asType() { + throw new UnsupportedOperationException(); + } + + @Override + public ElementKind getKind() { + return ElementKind.OTHER; + } + + @Override + public Name getSimpleName() { + throw new UnsupportedOperationException(); + } + + @Override + public R accept(ElementVisitor v, P p) { + for (Element type : getEnclosedElements()) { + if (type.getKind().isClass()) { + type.accept(v, p); + } else { + throw new ClassCastException(type.getClass().getName()); + } + } + return null; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,361 @@ +/* + * 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.dsl.processor.java.model; + +import java.io.*; +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.java.transform.*; + +public abstract class CodeElement implements Element, GeneratedElement { + + private final Set modifiers; + private List annotations; + private List enclosedElements; + + private Element enclosingElement; + + private Element generatorElement; + private AnnotationMirror generatorAnnotationMirror; + + public CodeElement() { + this.modifiers = new LinkedHashSet<>(); + } + + public CodeElement(Set modifiers) { + this.modifiers = new LinkedHashSet<>(modifiers); + } + + @Override + public void setGeneratorAnnotationMirror(AnnotationMirror mirror) { + this.generatorAnnotationMirror = mirror; + } + + @Override + public void setGeneratorElement(Element element) { + this.generatorElement = element; + } + + @Override + public AnnotationMirror getGeneratorAnnotationMirror() { + return generatorAnnotationMirror; + } + + @Override + public Element getGeneratorElement() { + return generatorElement; + } + + public E add(E element) { + if (element == null) { + throw new NullPointerException(); + } + getEnclosedElements().add(element); + return element; + } + + public E addOptional(E element) { + if (element != null) { + add(element); + } + return element; + } + + public void remove(E element) { + getEnclosedElements().remove(element); + } + + @Override + public Set getModifiers() { + return modifiers; + } + + @Override + public List getEnclosedElements() { + if (enclosedElements == null) { + enclosedElements = parentableList(this, new ArrayList()); + } + return enclosedElements; + } + + @Override + public List getAnnotationMirrors() { + if (annotations == null) { + annotations = parentableList(this, new ArrayList()); + } + return annotations; + } + + /** + * Support JDK8 langtools. + * + * @param annotationType + */ + public A[] getAnnotationsByType(Class annotationType) { + throw new UnsupportedOperationException(); + } + + /** + * Support for some JDK8 builds. (remove after jdk8 is released) + * + * @param annotationType + */ + public A[] getAnnotations(Class annotationType) { + throw new UnsupportedOperationException(); + } + + /** + * Support for some JDK8 builds. (remove after jdk8 is released) + * + * @param annotationType + */ + public A getAnnotation(Class annotationType) { + throw new UnsupportedOperationException(); + } + + public void addAnnotationMirror(AnnotationMirror annotationMirror) { + getAnnotationMirrors().add(annotationMirror); + } + + protected void setEnclosingElement(Element parent) { + this.enclosingElement = parent; + } + + public Element getEnclosingElement() { + return enclosingElement; + } + + public CodeTypeElement getEnclosingClass() { + Element p = enclosingElement; + while (p != null && p.getKind() != ElementKind.CLASS && p.getKind() != ElementKind.ENUM) { + p = p.getEnclosingElement(); + } + return (CodeTypeElement) p; + } + + List parentableList(Element parent, List list) { + return new ParentableList<>(parent, list); + } + + @Override + public String toString() { + StringBuilderCodeWriter codeWriter = new StringBuilderCodeWriter(); + accept(codeWriter, null); + return codeWriter.getString(); + } + + private static class StringBuilderCodeWriter extends AbstractCodeWriter { + + public StringBuilderCodeWriter() { + this.writer = new CharArrayWriter(); + } + + @Override + protected Writer createWriter(CodeTypeElement clazz) throws IOException { + return writer; + } + + public String getString() { + return new String(((CharArrayWriter) writer).toCharArray()).trim(); + } + + } + + private static class ParentableList implements List { + + private final Element parent; + private final List delegate; + + public ParentableList(Element parent, List delegate) { + this.parent = parent; + this.delegate = delegate; + } + + private void addImpl(T element) { + if (element != null) { + if (element instanceof CodeElement) { + ((CodeElement) element).setEnclosingElement(parent); + } + } + } + + private static void removeImpl(Object element) { + if (element instanceof CodeElement) { + ((CodeElement) element).setEnclosingElement(null); + } + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public E[] toArray(E[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(T e) { + addImpl(e); + return delegate.add(e); + } + + @Override + public boolean remove(Object o) { + boolean removed = delegate.remove(o); + if (removed) { + removeImpl(o); + } + return removed; + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + if (c != null) { + for (T t : c) { + addImpl(t); + } + } + return delegate.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + if (c != null) { + for (T t : c) { + addImpl(t); + } + } + return delegate.addAll(index, c); + } + + @Override + public boolean removeAll(Collection c) { + if (c != null) { + for (Object t : c) { + removeImpl(t); + } + } + return delegate.removeAll(c); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException("Not supported by parentable list"); + } + + @Override + public void clear() { + for (Object e : this) { + removeImpl(e); + } + delegate.clear(); + } + + @Override + public T get(int index) { + return delegate.get(index); + } + + @Override + public T set(int index, T element) { + removeImpl(delegate.get(index)); + addImpl(element); + return delegate.set(index, element); + } + + @Override + public void add(int index, T element) { + addImpl(element); + delegate.add(index, element); + } + + @Override + public T remove(int index) { + T element = delegate.remove(index); + removeImpl(element); + return element; + } + + @Override + public int indexOf(Object o) { + return delegate.indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return delegate.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return delegate.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return delegate.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return new ParentableList<>(parent, delegate.subList(fromIndex, toIndex)); + } + + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElementScanner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeElementScanner.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,76 @@ +/* + * 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.dsl.processor.java.model; + +import javax.lang.model.element.*; +import javax.lang.model.util.*; + +public abstract class CodeElementScanner extends ElementScanner7 { + + @Override + public final R visitExecutable(ExecutableElement e, P p) { + return visitExecutable(cast(e, CodeExecutableElement.class), p); + } + + public R visitExecutable(CodeExecutableElement e, P p) { + R ret = super.visitExecutable(e, p); + if (e.getBodyTree() != null) { + visitTree(e.getBodyTree(), p); + } + return ret; + } + + @Override + public R visitPackage(PackageElement e, P p) { + return super.visitPackage(e, p); + } + + @Override + public final R visitType(TypeElement e, P p) { + return visitType(cast(e, CodeTypeElement.class), p); + } + + public R visitType(CodeTypeElement e, P p) { + return super.visitType(e, p); + } + + @Override + public R visitTypeParameter(TypeParameterElement e, P p) { + return super.visitTypeParameter(e, p); + } + + private static E cast(Element element, Class clazz) { + return clazz.cast(element); + } + + public void visitTree(CodeTree e, P p) { + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + } + + @SuppressWarnings("unused") + public void visitImport(CodeImport e, P p) { + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,204 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class CodeExecutableElement extends CodeElement implements ExecutableElement { + + private final List throwables = new ArrayList<>(); + private final List parameters = parentableList(this, new ArrayList()); + + private TypeMirror returnType; + private Name name; + + private CodeTree bodyTree; + private String body; + private AnnotationValue defaultValue; + private boolean varArgs; + + public CodeExecutableElement(TypeMirror returnType, String name) { + super(ElementUtils.modifiers()); + this.returnType = returnType; + this.name = CodeNames.of(name); + } + + public CodeExecutableElement(Set modifiers, TypeMirror returnType, String name, CodeVariableElement... parameters) { + super(modifiers); + this.returnType = returnType; + this.name = CodeNames.of(name); + for (CodeVariableElement codeParameter : parameters) { + addParameter(codeParameter); + } + } + + /* Support JDK8 langtools. */ + public boolean isDefault() { + return false; + } + + @Override + public List getThrownTypes() { + return throwables; + } + + @Override + public TypeMirror asType() { + return returnType; + } + + @Override + public ElementKind getKind() { + if (getReturnType() == null) { + return ElementKind.CONSTRUCTOR; + } else { + return ElementKind.METHOD; + } + } + + @Override + public List getTypeParameters() { + return Collections.emptyList(); + } + + public void setVarArgs(boolean varargs) { + this.varArgs = varargs; + } + + @Override + public boolean isVarArgs() { + return varArgs; + } + + public void setDefaultValue(AnnotationValue defaultValue) { + this.defaultValue = defaultValue; + } + + @Override + public AnnotationValue getDefaultValue() { + return defaultValue; + } + + @Override + public Name getSimpleName() { + return name; + } + + public CodeTreeBuilder getBuilder() { + CodeTree tree = this.bodyTree; + return createBuilder().tree(tree); + } + + public CodeTreeBuilder createBuilder() { + CodeTreeBuilder builder = new CodeTreeBuilder(null); + this.bodyTree = builder.getTree(); + this.bodyTree.setEnclosingElement(this); + this.body = null; + return builder; + } + + public void setBodyTree(CodeTree body) { + this.bodyTree = body; + } + + public CodeTree getBodyTree() { + return bodyTree; + } + + public TypeMirror getReturnType() { + return returnType; + } + + @Override + public List getParameters() { + return parameters; + } + + public TypeMirror[] getParameterTypes() { + TypeMirror[] types = new TypeMirror[getParameters().size()]; + for (int i = 0; i < types.length; i++) { + types[i] = parameters.get(i).asType(); + } + return types; + } + + public void setReturnType(TypeMirror type) { + returnType = type; + } + + public void addParameter(VariableElement parameter) { + parameters.add(parameter); + } + + public void addThrownType(TypeMirror thrownType) { + throwables.add(thrownType); + } + + public void setSimpleName(Name name) { + this.name = name; + } + + public void setBody(String body) { + this.body = body; + } + + public String getBody() { + return body; + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitExecutable(this, p); + } + + public static CodeExecutableElement clone(@SuppressWarnings("unused") ProcessingEnvironment env, ExecutableElement method) { + CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString()); + for (TypeMirror thrownType : method.getThrownTypes()) { + copy.addThrownType(thrownType); + } + copy.setDefaultValue(method.getDefaultValue()); + + for (AnnotationMirror mirror : method.getAnnotationMirrors()) { + copy.addAnnotationMirror(mirror); + } + for (VariableElement var : method.getParameters()) { + copy.addParameter(CodeVariableElement.clone(var)); + } + for (Element element : method.getEnclosedElements()) { + copy.add(element); + } + copy.getModifiers().addAll(method.getModifiers()); + copy.setVarArgs(method.isVarArgs()); + return copy; + } + + public TypeMirror getReceiverType() { + throw new UnsupportedOperationException(); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeImport.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeImport.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,100 @@ +/* + * 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.dsl.processor.java.model; + +import javax.lang.model.type.*; + +public class CodeImport implements Comparable { + + private final TypeMirror importType; + private final String importString; + private final boolean staticImport; + + public CodeImport(TypeMirror importedType, String importString, boolean staticImport) { + this.importType = importedType; + this.importString = importString; + this.staticImport = staticImport; + } + + public TypeMirror getImportType() { + return importType; + } + + public boolean isStaticImport() { + return staticImport; + } + + public String getImportString() { + return importString; + } + + @Override + public int compareTo(CodeImport o) { + if (staticImport && !o.staticImport) { + return 1; + } else if (!staticImport && o.staticImport) { + return -1; + } else { + return importString.compareTo(o.getImportString()); + } + } + + public

void accept(CodeElementScanner s, P p) { + s.visitImport(this, p); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((importString == null) ? 0 : importString.hashCode()); + result = prime * result + (staticImport ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + CodeImport other = (CodeImport) obj; + if (importString == null) { + if (other.importString != null) { + return false; + } + } else if (!importString.equals(other.importString)) { + return false; + } + if (staticImport != other.staticImport) { + return false; + } + return true; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeNames.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeNames.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,90 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; + +public abstract class CodeNames { + + private static Map names = new HashMap<>(); + + public static Name of(String value) { + Name name = names.get(value); + if (name == null) { + name = new NameImpl(value); + names.put(value, name); + } + return name; + } + + private static class NameImpl implements Name { + + private final String name; + + public NameImpl(String name) { + this.name = name; + } + + @Override + public int length() { + return name.length(); + } + + @Override + public char charAt(int index) { + return name.charAt(index); + } + + @Override + public CharSequence subSequence(int start, int end) { + return name.subSequence(start, end); + } + + @Override + public boolean contentEquals(CharSequence cs) { + return name.contentEquals(cs); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Name) { + return ((Name) obj).contentEquals(name); + } + return super.equals(obj); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return name; + } + + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTree.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,85 @@ +/* + * 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.dsl.processor.java.model; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeTree extends CodeElement { + + private final CodeTreeKind kind; + + private TypeMirror type; + private final String string; + + CodeTree(CodeTreeKind kind, TypeMirror type, String string) { + this.kind = kind; + this.type = type; + this.string = string; + } + + public TypeMirror getType() { + return type; + } + + public CodeTreeKind getCodeKind() { + return kind; + } + + public String getString() { + return string; + } + + public

void acceptCodeElementScanner(CodeElementScanner s, P p) { + s.visitTree(this, p); + } + + public void setType(TypeMirror type) { + this.type = type; + } + + @Override + public TypeMirror asType() { + return type; + } + + @Override + public ElementKind getKind() { + return ElementKind.OTHER; + } + + @Override + public Name getSimpleName() { + return CodeNames.of(getString()); + } + + @Override + public R accept(ElementVisitor v, P p) { + if (v instanceof CodeElementScanner) { + acceptCodeElementScanner((CodeElementScanner) v, p); + return null; + } else { + throw new UnsupportedOperationException(); + } + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,888 @@ +/* + * 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.dsl.processor.java.model; + +import static com.oracle.truffle.dsl.processor.java.model.CodeTreeKind.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class CodeTreeBuilder { + + private final CodeTreeBuilder parent; + + private BuilderCodeTree currentElement; + private final BuilderCodeTree root; + + private int treeCount; + + public CodeTreeBuilder(CodeTreeBuilder parent) { + this.root = new BuilderCodeTree(GROUP, null, null); + this.currentElement = root; + this.parent = parent; + } + + @Override + public String toString() { + return root.toString(); + } + + public int getTreeCount() { + return treeCount; + } + + public boolean isEmpty() { + return treeCount == 0; + } + + public CodeTreeBuilder statement(String statement) { + return startStatement().string(statement).end(); + } + + public CodeTreeBuilder statement(CodeTree statement) { + return startStatement().tree(statement).end(); + } + + public static CodeTreeBuilder createBuilder() { + return new CodeTreeBuilder(null); + } + + public static CodeTree singleString(String s) { + return new CodeTreeBuilder(null).string(s).getTree(); + } + + public static CodeTree singleType(TypeMirror s) { + return new CodeTreeBuilder(null).type(s).getTree(); + } + + private CodeTreeBuilder push(CodeTreeKind kind) { + return push(new BuilderCodeTree(kind, null, null)); + } + + private CodeTreeBuilder push(String string) { + return push(new BuilderCodeTree(CodeTreeKind.STRING, null, string)); + } + + private CodeTreeBuilder push(TypeMirror type) { + return push(new BuilderCodeTree(CodeTreeKind.TYPE, type, null)); + } + + private CodeTreeBuilder push(CodeTreeKind kind, TypeMirror type, String string) { + return push(new BuilderCodeTree(kind, type, string)); + } + + private CodeTreeBuilder push(BuilderCodeTree tree) { + if (currentElement != null) { + if (!removeLastIfEnqueued(tree)) { + return this; + } + currentElement.add(tree); + } + switch (tree.getCodeKind()) { + case COMMA_GROUP: + case GROUP: + case INDENT: + currentElement = tree; + break; + } + treeCount++; + return this; + } + + private boolean removeLastIfEnqueued(BuilderCodeTree tree) { + if (tree.getCodeKind() == REMOVE_LAST) { + return !clearLastRec(tree.removeLast, currentElement.getEnclosedElements()); + } + List childTree = tree.getEnclosedElements(); + if (!childTree.isEmpty()) { + CodeTree last = childTree.get(0); + if (last instanceof BuilderCodeTree) { + if (!removeLastIfEnqueued((BuilderCodeTree) last)) { + childTree.remove(0); + } + } + } + return true; + } + + private void clearLast(CodeTreeKind kind) { + if (clearLastRec(kind, currentElement.getEnclosedElements())) { + treeCount--; + } else { + // delay clearing the last + BuilderCodeTree tree = new BuilderCodeTree(REMOVE_LAST, null, null); + tree.removeLast = kind; + push(tree); + } + } + + public CodeTreeBuilder startStatement() { + startGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + string(";").newLine(); + } + + @Override + public void afterEnd() { + } + }); + return this; + } + + public CodeTreeBuilder startGroup() { + return push(CodeTreeKind.GROUP); + } + + public CodeTreeBuilder startCommaGroup() { + return push(CodeTreeKind.COMMA_GROUP); + } + + public CodeTreeBuilder startCall(String callSite) { + return startCall((CodeTree) null, callSite); + } + + public CodeTreeBuilder startCall(String receiver, String callSite) { + return startCall(singleString(receiver), callSite); + } + + public CodeTreeBuilder startCall(CodeTree receiver, String callSite) { + if (receiver == null) { + return startGroup().string(callSite).startParanthesesCommaGroup().endAfter(); + } else { + return startGroup().tree(receiver).string(".").string(callSite).startParanthesesCommaGroup().endAfter(); + } + } + + public CodeTreeBuilder startStaticCall(TypeMirror type, String methodName) { + return startGroup().push(CodeTreeKind.STATIC_METHOD_REFERENCE, type, methodName).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startStaticCall(ExecutableElement method) { + return startStaticCall(ElementUtils.findNearestEnclosingType(method).asType(), method.getSimpleName().toString()); + } + + public CodeTreeBuilder staticReference(TypeMirror type, String fieldName) { + return push(CodeTreeKind.STATIC_FIELD_REFERENCE, type, fieldName); + } + + private CodeTreeBuilder endAndWhitespaceAfter() { + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string(" "); + end(); + } + }); + return this; + } + + private CodeTreeBuilder endAfter() { + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + end(); + } + }); + return this; + } + + private CodeTreeBuilder startParanthesesCommaGroup() { + startGroup(); + string("(").startCommaGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string(")"); + } + }); + endAfter(); + return this; + } + + private CodeTreeBuilder startCurlyBracesCommaGroup() { + startGroup(); + string("{").startCommaGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string("}"); + } + }); + endAfter(); + return this; + } + + public CodeTreeBuilder startParantheses() { + startGroup(); + string("(").startGroup(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string(")"); + } + }); + endAfter(); + return this; + } + + public CodeTreeBuilder doubleQuote(String s) { + return startGroup().string("\"" + s + "\"").end(); + } + + public CodeTreeBuilder string(String chunk1) { + return push(chunk1); + } + + public CodeTreeBuilder string(String chunk1, String chunk2) { + return push(GROUP).string(chunk1).string(chunk2).end(); + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3) { + return push(GROUP).string(chunk1).string(chunk2).string(chunk3).end(); + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4) { + return push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4).end(); + } + + public CodeTreeBuilder tree(CodeTree treeToAdd) { + if (treeToAdd instanceof BuilderCodeTree) { + return push((BuilderCodeTree) treeToAdd).end(); + } else { + BuilderCodeTree tree = new BuilderCodeTree(GROUP, null, null); + tree.add(treeToAdd); + return push(tree).end(); + } + } + + public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) { + push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4); + for (int i = 0; i < chunks.length; i++) { + string(chunks[i]); + } + return end(); + } + + public CodeTreeBuilder dot() { + return string("."); + } + + public CodeTreeBuilder newLine() { + return push(NEW_LINE); + } + + public CodeTreeBuilder startWhile() { + return startGroup().string("while ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startDoBlock() { + return startGroup().string("do ").startBlock(); + } + + public CodeTreeBuilder startDoWhile() { + clearLast(CodeTreeKind.NEW_LINE); + return startStatement().string(" while ").startParanthesesCommaGroup().endAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startIf() { + return startGroup().string("if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startFor() { + return startGroup().string("for ").startParantheses().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public boolean startIf(boolean elseIf) { + if (elseIf) { + startElseIf(); + } else { + startIf(); + } + return true; + } + + public CodeTreeBuilder startElseIf() { + clearLast(CodeTreeKind.NEW_LINE); + return startGroup().string(" else if ").startParanthesesCommaGroup().endAndWhitespaceAfter().startGroup().endAfter(); + } + + public CodeTreeBuilder startElseBlock() { + clearLast(CodeTreeKind.NEW_LINE); + return startGroup().string(" else ").startBlock().endAfter(); + } + + private boolean clearLastRec(CodeTreeKind kind, List children) { + for (int i = children.size() - 1; i >= 0; i--) { + CodeTree child = children.get(i); + if (child.getCodeKind() == kind) { + children.remove(children.get(i)); + return true; + } else { + if (clearLastRec(kind, child.getEnclosedElements())) { + return true; + } + } + } + return false; + } + + public CodeTreeBuilder startCase() { + startGroup().string("case "); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + string(" :").newLine(); + } + + @Override + public void afterEnd() { + } + }); + return this; + } + + public CodeTreeBuilder caseDefault() { + return startGroup().string("default :").newLine().end(); + } + + public CodeTreeBuilder startSwitch() { + return startGroup().string("switch ").startParanthesesCommaGroup().endAndWhitespaceAfter(); + } + + public CodeTreeBuilder startReturn() { + ExecutableElement method = findMethod(); + if (method != null && ElementUtils.isVoid(method.getReturnType())) { + 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 "); + } + } + + public CodeTreeBuilder startAssert() { + return startStatement().string("assert "); + } + + public CodeTreeBuilder startNewArray(ArrayType arrayType, CodeTree size) { + startGroup().string("new ").type(arrayType.getComponentType()).string("["); + if (size != null) { + tree(size); + } + string("]"); + if (size == null) { + string(" "); + startCurlyBracesCommaGroup().endAfter(); + } + return this; + } + + public CodeTreeBuilder startNew(TypeMirror uninializedNodeClass) { + return startGroup().string("new ").type(uninializedNodeClass).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startNew(String typeName) { + return startGroup().string("new ").string(typeName).startParanthesesCommaGroup().endAfter(); + } + + public CodeTreeBuilder startIndention() { + return push(CodeTreeKind.INDENT); + } + + public CodeTreeBuilder end(int times) { + for (int i = 0; i < times; i++) { + end(); + } + return this; + } + + public CodeTreeBuilder end() { + BuilderCodeTree tree = currentElement; + EndCallback callback = tree.getAtEndListener(); + if (callback != null) { + callback.beforeEnd(); + toParent(); + callback.afterEnd(); + } else { + toParent(); + } + return this; + } + + private void toParent() { + Element parentElement = currentElement.getEnclosingElement(); + if (currentElement != root) { + this.currentElement = (BuilderCodeTree) parentElement; + } else { + this.currentElement = root; + } + } + + public CodeTreeBuilder startBlock() { + startGroup(); + string("{").newLine().startIndention(); + registerCallBack(new EndCallback() { + + @Override + public void beforeEnd() { + } + + @Override + public void afterEnd() { + string("}").newLine(); + } + }); + endAfter(); + return this; + } + + private void registerCallBack(EndCallback callback) { + currentElement.registerAtEnd(callback); + } + + public CodeTreeBuilder defaultDeclaration(TypeMirror type, String name) { + if (!ElementUtils.isVoid(type)) { + startStatement(); + type(type); + string(" "); + string(name); + string(" = "); + defaultValue(type); + end(); // statement + } + return this; + } + + public CodeTreeBuilder declaration(TypeMirror type, String name, String init) { + return declaration(type, name, singleString(init)); + } + + public CodeTreeBuilder declaration(String type, String name, CodeTree init) { + startStatement(); + string(type); + string(" "); + string(name); + if (init != null) { + string(" = "); + tree(init); + } + end(); // statement + return this; + } + + public CodeTreeBuilder declaration(String type, String name, String init) { + return declaration(type, name, singleString(init)); + } + + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTree init) { + if (ElementUtils.isVoid(type)) { + startStatement(); + tree(init); + end(); + } else { + startStatement(); + type(type); + string(" "); + string(name); + if (init != null) { + string(" = "); + tree(init); + } + end(); // statement + } + return this; + } + + public CodeTreeBuilder declaration(TypeMirror type, String name, CodeTreeBuilder init) { + if (init == this) { + throw new IllegalArgumentException("Recursive builder usage."); + } + return declaration(type, name, init.getTree()); + } + + public CodeTreeBuilder declaration(String type, String name, CodeTreeBuilder init) { + if (init == this) { + throw new IllegalArgumentException("Recursive builder usage."); + } + return declaration(type, name, init.getTree()); + } + + public CodeTreeBuilder declaration(TypeMirror type, String name) { + return declaration(type, name, (CodeTree) null); + } + + public CodeTreeBuilder create() { + return new CodeTreeBuilder(this); + } + + public CodeTreeBuilder type(TypeMirror type) { + return push(type); + } + + public CodeTreeBuilder typeLiteral(TypeMirror type) { + return startGroup().type(type).string(".class").end(); + } + + private void assertRoot() { + if (currentElement != root) { + throw new IllegalStateException("CodeTreeBuilder was not ended properly."); + } + } + + public CodeTreeBuilder startCaseBlock() { + return startIndention(); + } + + public CodeTreeBuilder startThrow() { + return startStatement().string("throw "); + } + + public CodeTree getTree() { + assertRoot(); + return root; + } + + public CodeTree getRoot() { + return root; + } + + public CodeTreeBuilder cast(String baseClassName) { + string("(").string(baseClassName).string(") "); + return this; + } + + public CodeTreeBuilder cast(TypeMirror type, CodeTree content) { + if (ElementUtils.isVoid(type)) { + tree(content); + return this; + } else if (type.getKind() == TypeKind.DECLARED && ElementUtils.getQualifiedName(type).equals("java.lang.Object")) { + tree(content); + return this; + } else { + return startGroup().string("(").type(type).string(")").string(" ").tree(content).end(); + } + } + + public CodeTreeBuilder startSuperCall() { + return string("super").startParanthesesCommaGroup(); + } + + public CodeTreeBuilder returnFalse() { + return startReturn().string("false").end(); + } + + public CodeTreeBuilder returnStatement() { + return statement("return"); + } + + public ExecutableElement findMethod() { + Element element = currentElement; + while (element != null && (element.getKind() != ElementKind.METHOD && (element.getKind() != ElementKind.CONSTRUCTOR))) { + element = element.getEnclosingElement(); + } + ExecutableElement found = element != null ? (ExecutableElement) element : null; + if (found == null && parent != null) { + found = parent.findMethod(); + } + return found; + } + + public CodeTreeBuilder returnNull() { + return startReturn().string("null").end(); + } + + public CodeTreeBuilder returnTrue() { + return startReturn().string("true").end(); + } + + public CodeTreeBuilder instanceOf(CodeTree var, CodeTree type) { + tree(var).string(" instanceof ").tree(type); + return this; + } + + public CodeTreeBuilder instanceOf(String var, String type) { + return instanceOf(singleString(var), singleString(type)); + } + + public CodeTreeBuilder instanceOf(String var, TypeMirror type) { + TypeElement element = ElementUtils.fromTypeMirror(type); + if (element == null) { + throw new IllegalArgumentException("Cannot call instanceof for a non supported type: " + type.getKind()); + } + return instanceOf(singleString(var), singleType(type)); + } + + public CodeTreeBuilder defaultValue(TypeMirror mirror) { + switch (mirror.getKind()) { + case VOID: + return string(""); + case ARRAY: + case DECLARED: + case PACKAGE: + case NULL: + return string("null"); + case BOOLEAN: + return string("false"); + case BYTE: + return string("(byte) 0"); + case CHAR: + return string("(char) 0"); + case DOUBLE: + return string("0.0D"); + case LONG: + return string("0L"); + case INT: + return string("0"); + case FLOAT: + return string("0.0F"); + case SHORT: + return string("(short) 0"); + default: + throw new AssertionError(); + } + } + + public CodeTreeBuilder assertFalse() { + return startAssert().string("false").end(); + } + + public CodeTreeBuilder breakStatement() { + return statement("break"); + } + + public CodeTreeBuilder isNull() { + return string(" == null"); + } + + public CodeTreeBuilder isNotNull() { + return string(" != null"); + } + + public CodeTreeBuilder is(CodeTree tree) { + return string(" == ").tree(tree); + } + + public CodeTreeBuilder startTryBlock() { + return string("try ").startBlock(); + } + + public CodeTreeBuilder startCatchBlock(TypeMirror exceptionType, String localVarName) { + clearLast(CodeTreeKind.NEW_LINE); + string(" catch (").type(exceptionType).string(" ").string(localVarName).string(") "); + return startBlock(); + } + + public CodeTreeBuilder startFinallyBlock() { + clearLast(CodeTreeKind.NEW_LINE); + string(" finally "); + return startBlock(); + } + + public CodeTreeBuilder nullLiteral() { + return string("null"); + } + + private static class BuilderCodeTree extends CodeTree { + + private EndCallback atEndListener; + private CodeTreeKind removeLast; + + public BuilderCodeTree(CodeTreeKind kind, TypeMirror type, String string) { + super(kind, type, string); + } + + public void registerAtEnd(EndCallback atEnd) { + if (this.atEndListener != null) { + this.atEndListener = new CompoundCallback(this.atEndListener, atEnd); + } else { + this.atEndListener = atEnd; + } + } + + public EndCallback getAtEndListener() { + return atEndListener; + } + + @Override + public String toString() { + final StringBuilder b = new StringBuilder(); + acceptCodeElementScanner(new Printer(b), null); + return b.toString(); + } + + private static class CompoundCallback implements EndCallback { + + private final EndCallback callback1; + private final EndCallback callback2; + + public CompoundCallback(EndCallback callback1, EndCallback callback2) { + this.callback1 = callback1; + this.callback2 = callback2; + } + + @Override + public void afterEnd() { + callback1.afterEnd(); + callback2.afterEnd(); + } + + @Override + public void beforeEnd() { + callback1.beforeEnd(); + callback1.beforeEnd(); + } + } + + } + + private interface EndCallback { + + void beforeEnd(); + + void afterEnd(); + } + + private static class Printer extends CodeElementScanner { + + private int indent; + private boolean newLine; + private final String ln = "\n"; + + private final StringBuilder b; + + Printer(StringBuilder b) { + this.b = b; + } + + @Override + public void visitTree(CodeTree e, Void p) { + switch (e.getCodeKind()) { + case COMMA_GROUP: + List children = e.getEnclosedElements(); + for (int i = 0; i < children.size(); i++) { + children.get(i).acceptCodeElementScanner(this, p); + if (i < e.getEnclosedElements().size() - 1) { + b.append(", "); + } + } + break; + case GROUP: + super.visitTree(e, p); + break; + case INDENT: + indent(); + super.visitTree(e, p); + dedent(); + break; + case NEW_LINE: + writeLn(); + break; + case STRING: + if (e.getString() != null) { + write(e.getString()); + } else { + write("null"); + } + break; + case TYPE: + write(ElementUtils.getSimpleName(e.getType())); + break; + default: + assert false; + return; + } + } + + private void indent() { + indent++; + } + + private void dedent() { + indent--; + } + + private void writeLn() { + write(ln); + newLine = true; + } + + private void write(String m) { + if (newLine && m != ln) { + writeIndent(); + newLine = false; + } + b.append(m); + } + + private void writeIndent() { + for (int i = 0; i < indent; i++) { + b.append(" "); + } + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeKind.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeKind.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,35 @@ +/* + * 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.dsl.processor.java.model; + +public enum CodeTreeKind { + STATIC_FIELD_REFERENCE, + STATIC_METHOD_REFERENCE, + GROUP, + COMMA_GROUP, + REMOVE_LAST, + INDENT, + STRING, + NEW_LINE, + TYPE; +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,203 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror; + +public class CodeTypeElement extends CodeElement implements TypeElement { + + private final List imports = parentableList(this, new ArrayList()); + + private final PackageElement packageElement; + + private final Name simpleName; + private final Name packageName; + private Name qualifiedName; + + private final List implementsInterfaces = new ArrayList<>(); + private final ElementKind kind; + private TypeMirror superClass; + + private final DeclaredCodeTypeMirror mirror = new DeclaredCodeTypeMirror(this); + + public CodeTypeElement(Set modifiers, ElementKind kind, PackageElement packageElement, String simpleName) { + super(modifiers); + this.kind = kind; + this.packageElement = packageElement; + this.simpleName = CodeNames.of(simpleName); + if (this.packageElement != null) { + this.packageName = packageElement.getQualifiedName(); + } else { + this.packageName = CodeNames.of("default"); + } + this.qualifiedName = createQualifiedName(); + } + + @Override + public TypeMirror asType() { + return mirror; + } + + @Override + public ElementKind getKind() { + return kind; + } + + public boolean containsField(String name) { + for (VariableElement field : getFields()) { + if (field.getSimpleName().toString().equals(name)) { + return true; + } + } + return false; + } + + @Override + public NestingKind getNestingKind() { + return isTopLevelClass() ? NestingKind.TOP_LEVEL : NestingKind.LOCAL; + } + + @Override + public Element getEnclosingElement() { + if (isTopLevelClass()) { + return packageElement; + } else { + return super.getEnclosingElement(); + } + } + + @Override + public TypeMirror getSuperclass() { + return superClass; + } + + @Override + public List getInterfaces() { + return implementsInterfaces; + } + + @Override + public List getTypeParameters() { + return Collections.emptyList(); + } + + public boolean isTopLevelClass() { + return super.getEnclosingElement() instanceof CodeCompilationUnit; + } + + private Name createQualifiedName() { + TypeElement enclosingType = getEnclosingClass(); + if (enclosingType == null) { + return CodeNames.of(packageName + "." + simpleName); + } else { + return CodeNames.of(enclosingType.getQualifiedName() + "." + simpleName); + } + } + + @Override + protected void setEnclosingElement(Element element) { + super.setEnclosingElement(element); + + // update qualified name on container change + this.qualifiedName = createQualifiedName(); + } + + public Name getPackageName() { + return packageName; + } + + @Override + public Name getQualifiedName() { + return qualifiedName; + } + + @Override + public Name getSimpleName() { + return simpleName; + } + + public void setSuperClass(TypeMirror superType) { + this.superClass = superType; + } + + public List getImports() { + return imports; + } + + public List getImplements() { + return implementsInterfaces; + } + + @Override + public int hashCode() { + return getQualifiedName().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof TypeElement) { + return getQualifiedName().equals(((TypeElement) obj).getQualifiedName()); + } + return false; + } + + public List getFields() { + 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()); + } + + public List getInnerClasses() { + return ElementFilter.typesIn(getEnclosedElements()); + } + + @Override + public String toString() { + return getQualifiedName().toString(); + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitType(this, p); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeMirror.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,119 @@ +/* + * 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.dsl.processor.java.model; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class CodeTypeMirror implements TypeMirror { + + private final TypeKind kind; + + public CodeTypeMirror(TypeKind kind) { + this.kind = kind; + } + + @Override + public TypeKind getKind() { + return kind; + } + + @Override + public R accept(TypeVisitor v, P p) { + throw new UnsupportedOperationException(); + } + + public static class ArrayCodeTypeMirror extends CodeTypeMirror implements ArrayType { + + private final TypeMirror component; + + public ArrayCodeTypeMirror(TypeMirror component) { + super(TypeKind.ARRAY); + this.component = component; + } + + @Override + public TypeMirror getComponentType() { + return component; + } + + } + + public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType { + + private final TypeElement clazz; + private final List typeArguments; + + public DeclaredCodeTypeMirror(TypeElement clazz) { + this(clazz, Collections. emptyList()); + } + + public DeclaredCodeTypeMirror(TypeElement clazz, List typeArguments) { + super(TypeKind.DECLARED); + this.clazz = clazz; + this.typeArguments = typeArguments; + } + + @Override + public Element asElement() { + return clazz; + } + + @Override + public TypeMirror getEnclosingType() { + return clazz.getEnclosingElement().asType(); + } + + @Override + public List getTypeArguments() { + return typeArguments; + } + + @Override + public String toString() { + return clazz.getQualifiedName().toString(); + } + + } + + public List getAnnotationMirrors() { + throw new UnsupportedOperationException(); + } + + /** + * @param annotationType + */ + public A getAnnotation(Class annotationType) { + throw new UnsupportedOperationException(); + } + + /** + * @param annotationType + */ + public A[] getAnnotationsByType(Class annotationType) { + throw new UnsupportedOperationException(); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,140 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public final class CodeVariableElement extends CodeElement implements VariableElement { + + private Name name; + private TypeMirror type; + private Object constantValue; + + private CodeTree init; + + public CodeVariableElement(TypeMirror type, String name) { + super(ElementUtils.modifiers()); + this.type = type; + this.name = CodeNames.of(name); + } + + public CodeVariableElement(Set modifiers, TypeMirror type, String name) { + super(modifiers); + this.type = type; + this.name = CodeNames.of(name); + } + + public CodeVariableElement(Set modifiers, TypeMirror type, String name, String init) { + this(modifiers, type, name); + if (init != null) { + this.init = new CodeTree(CodeTreeKind.STRING, null, init); + } + } + + public CodeTreeBuilder createInitBuilder() { + CodeTreeBuilder builder = new CodeTreeBuilder(null); + init = builder.getTree(); + init.setEnclosingElement(this); + return builder; + } + + public void setInit(CodeTree init) { + this.init = init; + } + + public CodeTree getInit() { + return init; + } + + public Name getSimpleName() { + return name; + } + + public TypeMirror getType() { + return type; + } + + @Override + public TypeMirror asType() { + return type; + } + + @Override + public ElementKind getKind() { + if (getEnclosingElement() instanceof ExecutableElement) { + return ElementKind.PARAMETER; + } else if (getEnclosingElement() instanceof TypeElement) { + return ElementKind.FIELD; + } else { + return ElementKind.PARAMETER; + } + } + + public void setConstantValue(Object constantValue) { + this.constantValue = constantValue; + } + + @Override + public Object getConstantValue() { + return constantValue; + } + + public String getName() { + return getSimpleName().toString(); + } + + public void setSimpleName(Name name) { + this.name = name; + } + + public void setName(String name) { + this.name = CodeNames.of(name); + } + + public void setType(TypeMirror type) { + this.type = type; + } + + @Override + public R accept(ElementVisitor v, P p) { + return v.visitVariable(this, p); + } + + public static CodeVariableElement clone(VariableElement var) { + CodeVariableElement copy = new CodeVariableElement(var.getModifiers(), var.asType(), var.getSimpleName().toString()); + copy.setConstantValue(var.getConstantValue()); + for (AnnotationMirror mirror : var.getAnnotationMirrors()) { + copy.addAnnotationMirror(mirror); + } + for (Element element : var.getEnclosedElements()) { + copy.add(element); + } + return copy; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,37 @@ +/* + * 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.dsl.processor.java.model; + +import javax.lang.model.element.*; + +public interface GeneratedElement { + + AnnotationMirror getGeneratorAnnotationMirror(); + + void setGeneratorAnnotationMirror(AnnotationMirror mirror); + + Element getGeneratorElement(); + + void setGeneratorElement(Element element); + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedPackageElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedPackageElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,79 @@ +/* + * 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.dsl.processor.java.model; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public final class GeneratedPackageElement extends CodeElement implements PackageElement { + + private final Name qualifiedName; + private final Name simpleName; + + public GeneratedPackageElement(String qualifiedName) { + this.qualifiedName = CodeNames.of(qualifiedName); + int lastIndex = qualifiedName.lastIndexOf('.'); + if (lastIndex == -1) { + simpleName = CodeNames.of(""); + } else { + simpleName = CodeNames.of(qualifiedName.substring(lastIndex, qualifiedName.length())); + } + } + + public TypeMirror asType() { + throw new UnsupportedOperationException(); + } + + public ElementKind getKind() { + return ElementKind.PACKAGE; + } + + public R accept(ElementVisitor v, P p) { + return v.visitPackage(this, p); + } + + public Name getQualifiedName() { + return qualifiedName; + } + + public Name getSimpleName() { + return simpleName; + } + + public boolean isUnnamed() { + return simpleName.toString().equals(""); + } + + @Override + public int hashCode() { + return qualifiedName.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof PackageElement) { + return qualifiedName.equals(((PackageElement) obj).getQualifiedName()); + } + return super.equals(obj); + } +} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedTypeElement.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedTypeElement.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,36 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; + +public final class GeneratedTypeElement extends CodeTypeElement { + + public GeneratedTypeElement(Set modifiers, ElementKind kind, PackageElement packageElement, String simpleName) { + super(modifiers, kind, packageElement, simpleName); + setEnclosingElement(packageElement); + } + +} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedTypeMirror.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/GeneratedTypeMirror.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,37 @@ +/* + * 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.dsl.processor.java.model; + +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror; + +public final class GeneratedTypeMirror extends DeclaredCodeTypeMirror { + + public GeneratedTypeMirror(String packageName, String name) { + super(new GeneratedTypeElement(Collections. emptySet(), ElementKind.CLASS, new GeneratedPackageElement(packageName), name)); + } + +} \ No newline at end of file diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,758 @@ +/* + * 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.dsl.processor.java.transform; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; + +public abstract class AbstractCodeWriter extends CodeElementScanner { + + private static final int MAX_LINE_LENGTH = 200; + private static final int LINE_WRAP_INDENTS = 3; + private static final String IDENT_STRING = " "; + private static final String LN = "\n"; /* unix style */ + + protected Writer writer; + private int indent; + private boolean newLine; + private int lineLength; + private boolean lineWrapping = false; + + private OrganizedImports imports; + + protected abstract Writer createWriter(CodeTypeElement clazz) throws IOException; + + @Override + public Void visitType(CodeTypeElement e, Void p) { + if (e.isTopLevelClass()) { + Writer w = null; + try { + imports = OrganizedImports.organize(e); + w = new TrimTrailingSpaceWriter(createWriter(e)); + writer = w; + writeRootClass(e); + } catch (IOException ex) { + throw new RuntimeException(ex); + } finally { + if (w != null) { + try { + w.close(); + } catch (Throwable e1) { + // see eclipse bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=361378 + // TODO temporary suppress errors on close. + } + } + writer = null; + } + } else { + writeClassImpl(e); + } + return null; + } + + private void writeRootClass(CodeTypeElement e) { + writeHeader(); + write("package ").write(e.getPackageName()).write(";").writeLn(); + writeEmptyLn(); + + Set generateImports = imports.generateImports(); + List typeImports = new ArrayList<>(); + List staticImports = new ArrayList<>(); + + for (CodeImport codeImport : generateImports) { + if (codeImport.isStaticImport()) { + staticImports.add(codeImport); + } else { + typeImports.add(codeImport); + } + } + Collections.sort(typeImports); + Collections.sort(staticImports); + + for (CodeImport imp : staticImports) { + imp.accept(this, null); + writeLn(); + } + if (!staticImports.isEmpty()) { + writeEmptyLn(); + } + + for (CodeImport imp : typeImports) { + imp.accept(this, null); + writeLn(); + } + if (!typeImports.isEmpty()) { + writeEmptyLn(); + } + + writeClassImpl(e); + } + + private String useImport(Element enclosedType, TypeMirror type) { + if (imports != null) { + return imports.createTypeReference(enclosedType, type); + } else { + return ElementUtils.getSimpleName(type); + } + } + + private void writeClassImpl(CodeTypeElement e) { + for (AnnotationMirror annotation : e.getAnnotationMirrors()) { + visitAnnotation(e, annotation); + writeLn(); + } + + writeModifiers(e.getModifiers()); + if (e.getKind() == ElementKind.ENUM) { + write("enum "); + } else { + write("class "); + } + write(e.getSimpleName()); + if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) { + write(" extends ").write(useImport(e, e.getSuperclass())); + } + if (e.getImplements().size() > 0) { + write(" implements "); + for (int i = 0; i < e.getImplements().size(); i++) { + write(useImport(e, e.getImplements().get(i))); + if (i < e.getImplements().size() - 1) { + write(", "); + } + } + } + + write(" {").writeLn(); + writeEmptyLn(); + indent(1); + + List staticFields = getStaticFields(e); + List instanceFields = getInstanceFields(e); + + for (int i = 0; i < staticFields.size(); i++) { + VariableElement field = staticFields.get(i); + field.accept(this, null); + if (e.getKind() == ElementKind.ENUM && i < staticFields.size() - 1) { + write(","); + writeLn(); + } else { + write(";"); + writeLn(); + } + } + + if (staticFields.size() > 0) { + writeEmptyLn(); + } + + for (VariableElement field : instanceFields) { + field.accept(this, null); + write(";"); + writeLn(); + } + if (instanceFields.size() > 0) { + writeEmptyLn(); + } + + for (ExecutableElement method : ElementFilter.constructorsIn(e.getEnclosedElements())) { + method.accept(this, null); + } + + for (ExecutableElement method : getInstanceMethods(e)) { + method.accept(this, null); + } + + for (ExecutableElement method : getStaticMethods(e)) { + method.accept(this, null); + } + + for (TypeElement clazz : e.getInnerClasses()) { + clazz.accept(this, null); + } + + dedent(1); + write("}"); + writeEmptyLn(); + } + + private static List getStaticFields(CodeTypeElement clazz) { + List staticFields = new ArrayList<>(); + for (VariableElement field : clazz.getFields()) { + if (field.getModifiers().contains(Modifier.STATIC)) { + staticFields.add(field); + } + } + return staticFields; + } + + private static List getInstanceFields(CodeTypeElement clazz) { + List instanceFields = new ArrayList<>(); + for (VariableElement field : clazz.getFields()) { + if (!field.getModifiers().contains(Modifier.STATIC)) { + instanceFields.add(field); + } + } + return instanceFields; + } + + private static List getStaticMethods(CodeTypeElement clazz) { + List staticMethods = new ArrayList<>(); + for (ExecutableElement method : clazz.getMethods()) { + if (method.getModifiers().contains(Modifier.STATIC)) { + staticMethods.add(method); + } + } + return staticMethods; + } + + private static List getInstanceMethods(CodeTypeElement clazz) { + List instanceMethods = new ArrayList<>(); + for (ExecutableElement method : clazz.getMethods()) { + if (!method.getModifiers().contains(Modifier.STATIC)) { + instanceMethods.add(method); + } + } + return instanceMethods; + } + + @Override + public Void visitVariable(VariableElement f, Void p) { + Element parent = f.getEnclosingElement(); + + for (AnnotationMirror annotation : f.getAnnotationMirrors()) { + visitAnnotation(f, annotation); + write(" "); + } + + CodeTree init = null; + if (f instanceof CodeVariableElement) { + init = ((CodeVariableElement) f).getInit(); + } + + if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) { + write(f.getSimpleName()); + if (init != null) { + write("("); + init.acceptCodeElementScanner(this, p); + write(")"); + } + } else { + Element enclosing = f.getEnclosingElement(); + writeModifiers(f.getModifiers()); + + boolean varArgs = false; + if (enclosing.getKind() == ElementKind.METHOD) { + ExecutableElement method = (ExecutableElement) enclosing; + if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { + varArgs = true; + } + } + + TypeMirror varType = f.asType(); + if (varArgs) { + if (varType.getKind() == TypeKind.ARRAY) { + varType = ((ArrayType) varType).getComponentType(); + } + write(useImport(f, varType)); + write("..."); + } else { + write(useImport(f, varType)); + } + + write(" "); + write(f.getSimpleName()); + if (init != null) { + write(" = "); + init.acceptCodeElementScanner(this, p); + } + } + return null; + } + + private void visitAnnotation(Element enclosedElement, AnnotationMirror e) { + write("@").write(useImport(enclosedElement, e.getAnnotationType())); + + if (!e.getElementValues().isEmpty()) { + write("("); + final ExecutableElement defaultElement = findExecutableElement(e.getAnnotationType(), "value"); + + Map values = e.getElementValues(); + if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) { + visitAnnotationValue(enclosedElement, values.get(defaultElement)); + } else { + Set methodsSet = values.keySet(); + List methodsList = new ArrayList<>(); + for (ExecutableElement method : methodsSet) { + if (values.get(method) == null) { + continue; + } + methodsList.add(method); + } + + Collections.sort(methodsList, new Comparator() { + + @Override + public int compare(ExecutableElement o1, ExecutableElement o2) { + return o1.getSimpleName().toString().compareTo(o2.getSimpleName().toString()); + } + }); + + for (int i = 0; i < methodsList.size(); i++) { + ExecutableElement method = methodsList.get(i); + AnnotationValue value = values.get(method); + write(method.getSimpleName().toString()); + write(" = "); + visitAnnotationValue(enclosedElement, value); + + if (i < methodsList.size() - 1) { + write(", "); + } + } + } + + write(")"); + } + } + + private void visitAnnotationValue(Element enclosedElement, AnnotationValue e) { + e.accept(new AnnotationValueWriterVisitor(enclosedElement), null); + } + + private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7 { + + private final Element enclosedElement; + + public AnnotationValueWriterVisitor(Element enclosedElement) { + this.enclosedElement = enclosedElement; + } + + @Override + public Void visitBoolean(boolean b, Void p) { + write(Boolean.toString(b)); + return null; + } + + @Override + public Void visitByte(byte b, Void p) { + write(Byte.toString(b)); + return null; + } + + @Override + public Void visitChar(char c, Void p) { + write(Character.toString(c)); + return null; + } + + @Override + public Void visitDouble(double d, Void p) { + write(Double.toString(d)); + return null; + } + + @Override + public Void visitFloat(float f, Void p) { + write(Float.toString(f)); + return null; + } + + @Override + public Void visitInt(int i, Void p) { + write(Integer.toString(i)); + return null; + } + + @Override + public Void visitLong(long i, Void p) { + write(Long.toString(i)); + return null; + } + + @Override + public Void visitShort(short s, Void p) { + write(Short.toString(s)); + return null; + } + + @Override + public Void visitString(String s, Void p) { + write("\""); + write(s); + write("\""); + return null; + } + + @Override + public Void visitType(TypeMirror t, Void p) { + write(useImport(enclosedElement, t)); + write(".class"); + return null; + } + + @Override + public Void visitEnumConstant(VariableElement c, Void p) { + write(useImport(enclosedElement, c.asType())); + write("."); + write(c.getSimpleName().toString()); + return null; + } + + @Override + public Void visitAnnotation(AnnotationMirror a, Void p) { + AbstractCodeWriter.this.visitAnnotation(enclosedElement, a); + return null; + } + + @Override + public Void visitArray(List vals, Void p) { + write("{"); + for (int i = 0; i < vals.size(); i++) { + AnnotationValue value = vals.get(i); + AbstractCodeWriter.this.visitAnnotationValue(enclosedElement, value); + if (i < vals.size() - 1) { + write(", "); + } + } + write("}"); + return null; + } + } + + private static ExecutableElement findExecutableElement(DeclaredType type, String name) { + List elements = ElementFilter.methodsIn(type.asElement().getEnclosedElements()); + for (ExecutableElement executableElement : elements) { + if (executableElement.getSimpleName().toString().equals(name)) { + return executableElement; + } + } + return null; + } + + @Override + public void visitImport(CodeImport e, Void p) { + if (e.isStaticImport()) { + write("import static ").write(e.getImportString()).write(";"); + } else { + write("import ").write(e.getImportString()).write(";"); + } + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + for (AnnotationMirror annotation : e.getAnnotationMirrors()) { + visitAnnotation(e, annotation); + writeLn(); + } + + writeModifiers(e.getModifiers()); + + if (e.getReturnType() != null) { + write(useImport(e, e.getReturnType())); + write(" "); + } + write(e.getSimpleName()); + write("("); + + for (int i = 0; i < e.getParameters().size(); i++) { + VariableElement param = e.getParameters().get(i); + param.accept(this, p); + if (i < e.getParameters().size() - 1) { + write(", "); + } + } + write(")"); + + List throwables = e.getThrownTypes(); + if (throwables.size() > 0) { + write(" throws "); + for (int i = 0; i < throwables.size(); i++) { + write(useImport(e, throwables.get(i))); + if (i < throwables.size() - 1) { + write(", "); + } + } + } + + if (e.getModifiers().contains(Modifier.ABSTRACT)) { + writeLn(";"); + } else if (e.getBodyTree() != null) { + writeLn(" {"); + indent(1); + e.getBodyTree().acceptCodeElementScanner(this, p); + dedent(1); + writeLn("}"); + } else if (e.getBody() != null) { + write(" {"); + write(e.getBody()); + writeLn("}"); + } else { + writeLn("{ }"); + } + writeEmptyLn(); + return null; + } + + @Override + public void visitTree(CodeTree e, Void p) { + CodeTreeKind kind = e.getCodeKind(); + + switch (kind) { + case COMMA_GROUP: + List children = e.getEnclosedElements(); + for (int i = 0; i < children.size(); i++) { + children.get(i).acceptCodeElementScanner(this, p); + if (i < e.getEnclosedElements().size() - 1) { + write(", "); + } + } + break; + case GROUP: + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + break; + case INDENT: + indent(1); + for (CodeTree tree : e.getEnclosedElements()) { + tree.acceptCodeElementScanner(this, p); + } + dedent(1); + break; + case NEW_LINE: + writeLn(); + break; + case STRING: + if (e.getString() != null) { + write(e.getString()); + } else { + write("null"); + } + break; + case STATIC_FIELD_REFERENCE: + if (e.getString() != null) { + write(imports.createStaticFieldReference(e, e.getType(), e.getString())); + } else { + write("null"); + } + break; + case STATIC_METHOD_REFERENCE: + if (e.getString() != null) { + write(imports.createStaticMethodReference(e, e.getType(), e.getString())); + } else { + write("null"); + } + break; + case TYPE: + write(useImport(e, e.getType())); + break; + default: + assert false; + return; + } + } + + protected void writeHeader() { + // default implementation does nothing + } + + private void writeModifiers(Set modifiers) { + if (modifiers != null) { + for (Modifier modifier : modifiers) { + write(modifier.toString()); + write(" "); + } + } + } + + private void indent(int count) { + indent += count; + } + + private void dedent(int count) { + indent -= count; + } + + private void writeLn() { + writeLn(""); + } + + protected void writeLn(String text) { + write(text); + write(LN); + lineLength = 0; + newLine = true; + if (lineWrapping) { + dedent(LINE_WRAP_INDENTS); + lineWrapping = false; + } + lineWrapping = false; + } + + private void writeEmptyLn() { + writeLn(); + } + + private AbstractCodeWriter write(Name name) { + return write(name.toString()); + } + + private AbstractCodeWriter write(String m) { + if (m.isEmpty()) { + return this; + } + try { + String s = m; + lineLength += s.length(); + if (newLine && s != LN) { + writeIndent(); + newLine = false; + } + if (lineLength > MAX_LINE_LENGTH) { + s = wrapLine(s); + } + writer.write(s); + } catch (IOException e) { + throw new RuntimeException(e); + } + return this; + } + + private String wrapLine(String m) throws IOException { + assert !m.isEmpty(); + + char firstCharacter = m.charAt(0); + char lastCharacter = m.charAt(m.length() - 1); + if (firstCharacter == '\"' && lastCharacter == '\"') { + // string line wrapping + String string = m.substring(1, m.length() - 1); + if (string.isEmpty()) { + return m; + } + + // restore original line length + lineLength = lineLength - m.length(); + int size = 0; + for (int i = 0; i < string.length(); i += size) { + if (i != 0) { + write("+ "); + } + + int nextSize = MAX_LINE_LENGTH - lineLength - 2; + if (nextSize <= 0) { + writeLn(); + nextSize = MAX_LINE_LENGTH - lineLength - 2; + } + + int end = Math.min(i + nextSize, string.length()); + + // TODO(CH): fails in normal usage - output ok though + // assert lineLength + (end - i) + 2 < MAX_LINE_LENGTH; + + write("\"" + string.substring(i, end) + "\""); + size = nextSize; + } + + return ""; + } else if (!Character.isAlphabetic(firstCharacter) && firstCharacter != '+') { + return m; + } + + if (!lineWrapping) { + indent(LINE_WRAP_INDENTS); + } + lineWrapping = true; + lineLength = 0; + write(LN); + writeIndent(); + return m; + } + + private void writeIndent() throws IOException { + lineLength += indentSize(); + for (int i = 0; i < indent; i++) { + writer.write(IDENT_STRING); + } + } + + private int indentSize() { + return IDENT_STRING.length() * indent; + } + + private static class TrimTrailingSpaceWriter extends Writer { + + private final Writer delegate; + private final StringBuilder buffer = new StringBuilder(); + + public TrimTrailingSpaceWriter(Writer delegate) { + this.delegate = delegate; + } + + @Override + public void close() throws IOException { + this.delegate.close(); + } + + @Override + public void flush() throws IOException { + this.delegate.flush(); + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + buffer.append(cbuf, off, len); + int newLinePoint = buffer.indexOf(LN); + + if (newLinePoint != -1) { + String lhs = trimTrailing(buffer.substring(0, newLinePoint)); + delegate.write(lhs); + delegate.write(LN); + buffer.delete(0, newLinePoint + 1); + } + } + + private static String trimTrailing(String s) { + int cut = 0; + for (int i = s.length() - 1; i >= 0; i--) { + if (Character.isWhitespace(s.charAt(i))) { + cut++; + } else { + break; + } + } + if (cut > 0) { + return s.substring(0, s.length() - cut); + } + return s; + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/FixWarningsVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/FixWarningsVisitor.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,126 @@ +/* + * 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.dsl.processor.java.transform; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; +import static javax.lang.model.element.Modifier.*; + +import java.io.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; + +public class FixWarningsVisitor extends CodeElementScanner { + + private final Set symbolsUsed = new HashSet<>(); + + private final ProcessorContext context; + private final DeclaredType unusedAnnotation; + private final DeclaredType overrideType; + + public FixWarningsVisitor(ProcessorContext context, DeclaredType unusedAnnotation, DeclaredType overrideType) { + this.context = context; + this.unusedAnnotation = unusedAnnotation; + this.overrideType = overrideType; + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + List superTypes = ElementUtils.getSuperTypes(e); + for (TypeElement type : superTypes) { + String qualifiedName = ElementUtils.getQualifiedName(type); + if (qualifiedName.equals(Serializable.class.getCanonicalName())) { + if (!e.containsField("serialVersionUID")) { + e.add(new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getType(long.class), "serialVersionUID", "1L")); + } + break; + } + } + + return super.visitType(e, p); + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + if (e.getParameters().isEmpty()) { + return null; + } else if (e.getModifiers().contains(Modifier.ABSTRACT)) { + return null; + } else if (containsOverride(e)) { + return null; + } + + symbolsUsed.clear(); + super.visitExecutable(e, p); + + for (VariableElement parameter : e.getParameters()) { + if (!symbolsUsed.contains(parameter.getSimpleName().toString())) { + e.getAnnotationMirrors().add(createUnusedAnnotationMirror()); + break; + } + } + return null; + } + + private boolean containsOverride(CodeExecutableElement e) { + for (AnnotationMirror mirror : e.getAnnotationMirrors()) { + if (ElementUtils.typeEquals(overrideType, mirror.getAnnotationType())) { + return true; + } + } + return false; + } + + private CodeAnnotationMirror createUnusedAnnotationMirror() { + CodeAnnotationMirror mirror = new CodeAnnotationMirror(unusedAnnotation); + mirror.setElementValue(mirror.findExecutableElement("value"), new CodeAnnotationValue("unused")); + return mirror; + } + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getString() != null) { + computeSymbols(e.getString()); + } + super.visitTree(e, p); + } + + private void computeSymbols(String s) { + // TODO there should not be any need for a StringTokenizer if we have a real AST for + // method bodies. Also the current solution is not perfect. What if one token + // is spread across multiple CodeTree instances? But for now that works. + StringTokenizer tokenizer = new StringTokenizer(s, ".= :,()[];{}\"\"'' ", false); + while (tokenizer.hasMoreElements()) { + String token = tokenizer.nextToken().trim(); + if (token.length() > 0) { + symbolsUsed.add(token); + } + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/GenerateOverrideVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/GenerateOverrideVisitor.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,61 @@ +/* + * 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.dsl.processor.java.transform; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; + +public class GenerateOverrideVisitor extends CodeElementScanner { + + private final DeclaredType overrideType; + + public GenerateOverrideVisitor(DeclaredType overrideType) { + this.overrideType = overrideType; + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + if (!e.getModifiers().contains(Modifier.STATIC) && !e.getModifiers().contains(Modifier.PRIVATE)) { + String name = e.getSimpleName().toString(); + TypeMirror[] params = e.getParameterTypes(); + + for (AnnotationMirror mirror : e.getAnnotationMirrors()) { + if (ElementUtils.typeEquals(overrideType, mirror.getAnnotationType())) { + // already declared (may happen if method copied from super class) + return super.visitExecutable(e, p); + } + } + + if (isDeclaredMethodInSuperType(e.getEnclosingClass(), name, params)) { + e.addAnnotationMirror(new CodeAnnotationMirror(overrideType)); + } + } + return super.visitExecutable(e, p); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,489 @@ +/* + * 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.dsl.processor.java.transform; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.model.*; + +public final class OrganizedImports { + + private final Set staticImportUsage = new HashSet<>(); + + private final Map simpleNamesUsed = new HashMap<>(); + + private final Set declaredStaticMethods = new HashSet<>(); + private final Set declaredStaticFields = new HashSet<>(); + private final Set ambiguousStaticMethods = new HashSet<>(); + private final Set ambiguousStaticFields = new HashSet<>(); + + private final CodeTypeElement topLevelClass; + + private OrganizedImports(CodeTypeElement topLevelClass) { + this.topLevelClass = topLevelClass; + } + + public static OrganizedImports organize(CodeTypeElement topLevelClass) { + OrganizedImports organized = new OrganizedImports(topLevelClass); + organized.organizeImpl(); + return organized; + } + + private void organizeImpl() { + ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor(); + topLevelClass.accept(reference, null); + + processStaticImports(topLevelClass); + List types = ElementUtils.getSuperTypes(topLevelClass); + for (TypeElement typeElement : types) { + processStaticImports(typeElement); + } + + for (TypeMirror type : staticImportUsage) { + TypeElement element = fromTypeMirror(type); + if (element != null) { + // already processed by supertype + if (types.contains(element)) { + continue; + } + processStaticImports(element); + } + } + } + + public String createTypeReference(Element enclosedElement, TypeMirror type) { + switch (type.getKind()) { + case BOOLEAN: + case BYTE: + case CHAR: + case DOUBLE: + case FLOAT: + case SHORT: + case INT: + case LONG: + case VOID: + return ElementUtils.getSimpleName(type); + case DECLARED: + return createDeclaredTypeName(enclosedElement, (DeclaredType) type); + case ARRAY: + return createTypeReference(enclosedElement, ((ArrayType) type).getComponentType()) + "[]"; + case WILDCARD: + return createWildcardName(enclosedElement, (WildcardType) type); + case TYPEVAR: + return "?"; + default: + throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type); + } + } + + public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) { + return createStaticReference(enclosedElement, type, fieldName, ambiguousStaticFields); + } + + public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) { + return createStaticReference(enclosedElement, type, methodName, ambiguousStaticMethods); + } + + private String createStaticReference(Element enclosedElement, TypeMirror type, String name, Set ambiguousSymbols) { + if (ambiguousSymbols.contains(name)) { + // ambiguous import + return createTypeReference(enclosedElement, type) + "." + name; + } else { + // import declared and not ambiguous + return name; + } + } + + private String createWildcardName(Element enclosedElement, WildcardType type) { + StringBuilder b = new StringBuilder(); + if (type.getExtendsBound() != null) { + b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound())); + } + return b.toString(); + } + + private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) { + String name; + name = ElementUtils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString()); + + if (needsImport(enclosedElement, type)) { + TypeMirror usedByType = simpleNamesUsed.get(name); + if (usedByType == null) { + simpleNamesUsed.put(name, type); + usedByType = type; + } + + if (!typeEquals(type, usedByType)) { + name = getQualifiedName(type); + } + } + + if (type.getTypeArguments().size() == 0) { + return name; + } + + StringBuilder b = new StringBuilder(name); + b.append("<"); + if (type.getTypeArguments().size() > 0) { + for (int i = 0; i < type.getTypeArguments().size(); i++) { + b.append(createTypeReference(enclosedElement, type.getTypeArguments().get(i))); + if (i < type.getTypeArguments().size() - 1) { + b.append(", "); + } + } + } + b.append(">"); + return b.toString(); + } + + public Set generateImports() { + Set imports = new HashSet<>(); + + imports.addAll(generateImports(simpleNamesUsed.values())); + imports.addAll(generateStaticImports(staticImportUsage)); + + return imports; + } + + boolean processStaticImports(TypeElement element) { + Set importedMethods = new HashSet<>(); + List methods = ElementFilter.methodsIn(element.getEnclosedElements()); + for (ExecutableElement method : methods) { + if (method.getModifiers().contains(Modifier.STATIC)) { + importedMethods.add(method.getSimpleName().toString()); + } + } + + boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods); + + Set importedFields = new HashSet<>(); + List fields = ElementFilter.fieldsIn(element.getEnclosedElements()); + for (VariableElement field : fields) { + if (field.getModifiers().contains(Modifier.STATIC)) { + importedFields.add(field.getSimpleName().toString()); + } + } + + boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields); + + return allMethodsAmbiguous && allFieldsAmbiguous; + } + + private static boolean processStaticImportElements(Set newElements, Set ambiguousElements, Set declaredElements) { + boolean allAmbiguous = false; + if (declaredElements.containsAll(newElements)) { + // all types already declared -> we can remove the import completely -> they will all + // get ambiguous + allAmbiguous = true; + } + Set newAmbiguous = new HashSet<>(); + Set newDeclared = new HashSet<>(); + + for (String newElement : newElements) { + if (declaredElements.contains(newElement)) { + newAmbiguous.add(newElement); + } else if (ambiguousElements.contains(newElement)) { + // nothing to do + } else { + newDeclared.add(newElement); + } + } + + ambiguousElements.addAll(newAmbiguous); + declaredElements.addAll(newDeclared); + return allAmbiguous; + } + + private boolean needsImport(Element enclosedElement, TypeMirror importType) { + String importPackagName = getPackageName(importType); + if (importPackagName == null) { + return false; + } else if (importPackagName.equals("java.lang")) { + return false; + } else if (importPackagName.equals(getPackageName(topLevelClass)) && ElementUtils.isTopLevelClass(importType)) { + return false; // same package name -> no import + } + + List elements = ElementUtils.getElementHierarchy(enclosedElement); + + Set autoImportedTypes = new HashSet<>(); + for (Element element : elements) { + if (element.getKind().isClass()) { + collectSuperTypeImports((TypeElement) element, autoImportedTypes); + collectInnerTypeImports((TypeElement) element, autoImportedTypes); + } + } + + String qualifiedName = getQualifiedName(importType); + if (autoImportedTypes.contains(qualifiedName)) { + return false; + } + + return true; + } + + private static Set generateImports(Collection toGenerate) { + TreeSet importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + importObjects.add(new CodeImport(importType, getQualifiedName(importType), false)); + } + return importObjects; + } + + private static void collectInnerTypeImports(TypeElement e, Set autoImportedTypes) { + autoImportedTypes.add(getQualifiedName(e)); + for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) { + collectInnerTypeImports(innerClass, autoImportedTypes); + } + } + + private static void collectSuperTypeImports(TypeElement e, Set autoImportedTypes) { + List superTypes = getSuperTypes(e); + for (TypeElement superType : superTypes) { + List declaredTypes = getDeclaredTypes(superType); + for (TypeElement declaredType : declaredTypes) { + autoImportedTypes.add(getQualifiedName(declaredType)); + } + } + } + + private Set generateStaticImports(Set toGenerate) { + Set autoImportedStaticTypes = new HashSet<>(); + + // if type is declared inside a super type of this class -> no import + autoImportedStaticTypes.add(getQualifiedName(topLevelClass)); + autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(topLevelClass)); + + TreeSet importObjects = new TreeSet<>(); + for (TypeMirror importType : toGenerate) { + if (getPackageName(importType) == null) { + continue; // no package name -> no import + } + + String qualifiedName = getQualifiedName(importType); + if (autoImportedStaticTypes.contains(qualifiedName)) { + continue; + } + + importObjects.add(new CodeImport(importType, qualifiedName + ".*", true)); + } + + return importObjects; + } + + private abstract static class TypeReferenceVisitor extends CodeElementScanner { + + @Override + public void visitTree(CodeTree e, Void p) { + if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) { + visitStaticFieldReference(e, e.getType(), e.getString()); + } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) { + visitStaticMethodReference(e, e.getType(), e.getString()); + } else if (e.getType() != null) { + visitTypeReference(e, e.getType()); + } + super.visitTree(e, p); + } + + @Override + public Void visitExecutable(CodeExecutableElement e, Void p) { + visitAnnotations(e, e.getAnnotationMirrors()); + if (e.getReturnType() != null) { + visitTypeReference(e, e.getReturnType()); + } + for (TypeMirror type : e.getThrownTypes()) { + visitTypeReference(e, type); + } + return super.visitExecutable(e, p); + } + + @Override + public Void visitType(CodeTypeElement e, Void p) { + visitAnnotations(e, e.getAnnotationMirrors()); + + visitTypeReference(e, e.getSuperclass()); + for (TypeMirror type : e.getImplements()) { + visitTypeReference(e, type); + } + + return super.visitType(e, p); + } + + private void visitAnnotations(Element enclosingElement, List mirrors) { + for (AnnotationMirror mirror : mirrors) { + visitAnnotation(enclosingElement, mirror); + } + } + + public void visitAnnotation(Element enclosingElement, AnnotationMirror e) { + visitTypeReference(enclosingElement, e.getAnnotationType()); + if (!e.getElementValues().isEmpty()) { + Map values = e.getElementValues(); + Set methodsSet = values.keySet(); + List methodsList = new ArrayList<>(); + for (ExecutableElement method : methodsSet) { + if (values.get(method) == null) { + continue; + } + methodsList.add(method); + } + + for (int i = 0; i < methodsList.size(); i++) { + AnnotationValue value = values.get(methodsList.get(i)); + visitAnnotationValue(enclosingElement, value); + } + } + } + + public void visitAnnotationValue(Element enclosingElement, AnnotationValue e) { + e.accept(new AnnotationValueReferenceVisitor(enclosingElement), null); + } + + private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7 { + + private final Element enclosingElement; + + public AnnotationValueReferenceVisitor(Element enclosedElement) { + this.enclosingElement = enclosedElement; + } + + @Override + public Void visitBoolean(boolean b, Void p) { + return null; + } + + @Override + public Void visitByte(byte b, Void p) { + return null; + } + + @Override + public Void visitChar(char c, Void p) { + return null; + } + + @Override + public Void visitDouble(double d, Void p) { + return null; + } + + @Override + public Void visitFloat(float f, Void p) { + return null; + } + + @Override + public Void visitInt(int i, Void p) { + return null; + } + + @Override + public Void visitLong(long i, Void p) { + return null; + } + + @Override + public Void visitShort(short s, Void p) { + return null; + } + + @Override + public Void visitString(String s, Void p) { + return null; + } + + @Override + public Void visitType(TypeMirror t, Void p) { + visitTypeReference(enclosingElement, t); + return null; + } + + @Override + public Void visitEnumConstant(VariableElement c, Void p) { + visitTypeReference(enclosingElement, c.asType()); + return null; + } + + @Override + public Void visitAnnotation(AnnotationMirror a, Void p) { + TypeReferenceVisitor.this.visitAnnotation(enclosingElement, a); + return null; + } + + @Override + public Void visitArray(List vals, Void p) { + for (int i = 0; i < vals.size(); i++) { + TypeReferenceVisitor.this.visitAnnotationValue(enclosingElement, vals.get(i)); + } + return null; + } + } + + @Override + public Void visitVariable(VariableElement f, Void p) { + visitAnnotations(f, f.getAnnotationMirrors()); + visitTypeReference(f, f.asType()); + return super.visitVariable(f, p); + } + + @Override + public void visitImport(CodeImport e, Void p) { + } + + public abstract void visitTypeReference(Element enclosedType, TypeMirror type); + + public abstract void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName); + + public abstract void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName); + + } + + private class ImportTypeReferenceVisitor extends TypeReferenceVisitor { + + @Override + public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) { + staticImportUsage.add(type); + } + + @Override + public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) { + staticImportUsage.add(type); + } + + @Override + public void visitTypeReference(Element enclosedType, TypeMirror type) { + createTypeReference(enclosedType, type); + } + + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CreateCastData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CreateCastData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,40 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +public class CreateCastData extends TemplateMethod { + + private final List childNames; + + public CreateCastData(TemplateMethod method, List childNames) { + super(method); + this.childNames = childNames; + } + + public List getChildNames() { + return childNames; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,87 @@ +/* + * 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.dsl.processor.model; + +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public class ExecutableTypeData extends TemplateMethod { + + private final TypeSystemData typeSystem; + private final TypeData type; + + public ExecutableTypeData(TemplateMethod method, ExecutableElement executable, TypeSystemData typeSystem, TypeData type) { + super(method, executable); + this.typeSystem = typeSystem; + this.type = type; + if (executable.getParameters().size() < method.getMethod().getParameters().size()) { + throw new IllegalArgumentException(String.format("Method parameter count mismatch %s != %s.", executable.getParameters(), method.getMethod().getParameters())); + } + } + + public TypeData getType() { + return type; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public boolean hasUnexpectedValue(ProcessorContext context) { + return ElementUtils.canThrowType(getMethod().getThrownTypes(), context.getTruffleTypes().getUnexpectedValueException()); + } + + public boolean isFinal() { + return getMethod().getModifiers().contains(Modifier.FINAL); + } + + public boolean isAbstract() { + return getMethod().getModifiers().contains(Modifier.ABSTRACT); + } + + public int getEvaluatedCount() { + int count = 0; + for (Parameter parameter : getParameters()) { + if (parameter.getSpecification().isSignature()) { + count++; + } + } + return count; + } + + @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 c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,54 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +public class GuardData extends TemplateMethod { + + private List impliesExpressions; + + public GuardData(TemplateMethod method, List impliesExpressions) { + super(method); + this.impliesExpressions = impliesExpressions; + } + + public List getImpliesExpressions() { + return impliesExpressions; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GuardData) { + GuardData other = (GuardData) obj; + return getMethod().equals(other.getMethod()); + } + return false; + } + + @Override + public int hashCode() { + return getMethod().hashCode(); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,87 @@ +package com.oracle.truffle.dsl.processor.model; + +import java.util.*; + +public final class GuardExpression { + + private GuardData resolvedGuard; + + private final String guardName; + private final boolean negated; + + public GuardExpression(String expression) { + if (expression.startsWith("!")) { + guardName = expression.substring(1, expression.length()); + negated = true; + } else { + guardName = expression; + negated = false; + } + } + + public boolean isResolved() { + return resolvedGuard != null; + } + + public String getGuardName() { + return guardName; + } + + public void setGuard(GuardData guard) { + this.resolvedGuard = guard; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GuardExpression) { + GuardExpression other = (GuardExpression) obj; + if (isResolved() && other.isResolved()) { + return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated; + } else { + return guardName.equals(other.guardName) && negated == other.negated; + } + } + return false; + } + + @Override + public int hashCode() { + return Objects.hash(guardName, negated, resolvedGuard); + } + + public final boolean implies(GuardExpression other) { + if (other == this) { + return true; + } + if (getGuardName().equals(other.getGuardName())) { + if (isNegated() == other.isNegated()) { + return true; + } + } + + if (isResolved() && other.isResolved()) { + for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) { + if (implies.getGuardName().equals(other.getGuardName())) { + if (implies.isNegated() == other.isNegated()) { + return true; + } + } + } + } + return false; + } + + @Override + public String toString() { + return (negated ? "!" : "") + guardName; + } + + public boolean isNegated() { + return negated; + } + + public GuardData getResolvedGuard() { + return resolvedGuard; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,57 @@ +/* + * 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.dsl.processor.model; + + +public class ImplicitCastData extends TemplateMethod { + + private final TypeData sourceType; + private final TypeData targetType; + + public ImplicitCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { + super(method); + this.sourceType = sourceType; + this.targetType = targetType; + } + + public TypeData getSourceType() { + return sourceType; + } + + public TypeData getTargetType() { + return targetType; + } + + @Override + public int compareTo(TemplateMethod o) { + if (o instanceof ImplicitCastData && sourceType != null) { + // implicit casts are ordered by source type since + // its also the order in which they are checked. + TypeData otherSourceType = ((ImplicitCastData) o).getSourceType(); + if (otherSourceType != null) { + return this.sourceType.compareTo(otherSourceType); + } + } + return super.compareTo(o); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,261 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.tools.Diagnostic.Kind; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public abstract class MessageContainer implements Iterable { + + private final List messages = new ArrayList<>(); + + public final void addWarning(String text, Object... params) { + getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING)); + } + + public final void addWarning(AnnotationValue value, String text, Object... params) { + getMessages().add(new Message(value, this, String.format(text, params), Kind.WARNING)); + } + + public final void addError(String text, Object... params) { + addError(null, text, params); + } + + public final void addError(AnnotationValue value, String text, Object... params) { + getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR)); + } + + protected List findChildContainers() { + return Collections.emptyList(); + } + + public abstract Element getMessageElement(); + + public MessageContainer getBaseContainer() { + return null; + } + + public Iterator iterator() { + return findChildContainers().iterator(); + } + + public final void emitMessages(ProcessorContext context, Log log) { + emitMessagesImpl(context, log, new HashSet(), null); + } + + private void emitMessagesImpl(ProcessorContext context, Log log, Set visitedSinks, List verifiedMessages) { + List childMessages; + if (verifiedMessages == null) { + childMessages = collectMessagesWithElementChildren(new HashSet(), getMessageElement()); + } else { + childMessages = verifiedMessages; + } + verifyExpectedMessages(context, log, childMessages); + + for (int i = getMessages().size() - 1; i >= 0; i--) { + emitDefault(context, log, getMessages().get(i)); + } + + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + continue; + } + + visitedSinks.add(sink); + if (sink.getMessageElement() == this.getMessageElement()) { + sink.emitMessagesImpl(context, log, visitedSinks, childMessages); + } else { + sink.emitMessagesImpl(context, log, visitedSinks, null); + } + } + } + + private List collectMessagesWithElementChildren(Set visitedSinks, Element e) { + if (visitedSinks.contains(this)) { + return Collections.emptyList(); + } + visitedSinks.add(this); + + List foundMessages = new ArrayList<>(); + if (ElementUtils.typeEquals(getMessageElement().asType(), e.asType())) { + foundMessages.addAll(getMessages()); + } + for (MessageContainer sink : findChildContainers()) { + foundMessages.addAll(sink.collectMessagesWithElementChildren(visitedSinks, e)); + } + return foundMessages; + } + + private void verifyExpectedMessages(ProcessorContext context, Log log, List msgs) { + TypeElement expectError = context.getTruffleTypes().getExpectError(); + if (expectError != null) { + Element element = getMessageElement(); + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError); + if (mirror != null) { + List values = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); + if (values == null) { + values = Collections.emptyList(); + } + if (values.size() != msgs.size()) { + log.message(Kind.ERROR, element, mirror, ElementUtils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size())); + } + } + } + } + + private void emitDefault(ProcessorContext context, Log log, Message message) { + Kind kind = message.getKind(); + + Element messageElement = getMessageElement(); + AnnotationMirror messageAnnotation = getMessageAnnotation(); + AnnotationValue messageValue = getMessageAnnotationValue(); + if (message.getAnnotationValue() != null) { + messageValue = message.getAnnotationValue(); + } + + String text = message.getText(); + + TypeElement expectError = context.getTruffleTypes().getExpectError(); + if (expectError != null) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError); + if (mirror != null) { + List expectedTexts = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); + boolean found = false; + for (String expectedText : expectedTexts) { + if (expectedText.endsWith("%") && text.startsWith(expectedText.substring(0, expectedText.length() - 1))) { + found = true; + break; + } else if (text.equals(expectedText)) { + found = true; + break; + } + } + if (!found) { + log.message(kind, messageElement, mirror, ElementUtils.getAnnotationValue(mirror, "value"), "Message expected one of '%s' but was '%s'.", expectedTexts, text); + } else { + return; + } + + } + } + + log.message(kind, messageElement, messageAnnotation, messageValue, text); + } + + public AnnotationMirror getMessageAnnotation() { + return null; + } + + public AnnotationValue getMessageAnnotationValue() { + return null; + } + + public final boolean hasErrors() { + return hasErrorsImpl(new HashSet()); + } + + public final List collectMessages() { + List collectedMessages = new ArrayList<>(); + collectMessagesImpl(collectedMessages, new HashSet()); + return collectedMessages; + } + + private void collectMessagesImpl(List collectedMessages, Set visitedSinks) { + collectedMessages.addAll(getMessages()); + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + return; + } + + visitedSinks.add(sink); + sink.collectMessagesImpl(collectedMessages, visitedSinks); + } + } + + private boolean hasErrorsImpl(Set visitedSinks) { + for (Message msg : getMessages()) { + if (msg.getKind() == Kind.ERROR) { + return true; + } + } + for (MessageContainer sink : findChildContainers()) { + if (visitedSinks.contains(sink)) { + return false; + } + + visitedSinks.add(sink); + + if (sink.hasErrorsImpl(visitedSinks)) { + return true; + } + } + return false; + } + + public List getMessages() { + return messages; + } + + public static final class Message { + + private final MessageContainer originalContainer; + private final AnnotationValue annotationValue; + private final String text; + private final Kind kind; + + public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { + this.annotationValue = annotationValue; + this.originalContainer = originalContainer; + this.text = text; + this.kind = kind; + } + + public AnnotationValue getAnnotationValue() { + return annotationValue; + } + + public MessageContainer getOriginalContainer() { + return originalContainer; + } + + public String getText() { + return text; + } + + public Kind getKind() { + return kind; + } + + @Override + public String toString() { + return kind + ": " + text; + } + + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,239 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class MethodSpec { + + private final ParameterSpec returnType; + private final List optional = new ArrayList<>(); + private final List required = new ArrayList<>(); + + private boolean ignoreAdditionalParameters; + private boolean ignoreAdditionalSpecifications; + private boolean variableRequiredParameters; + + private List typeDefinitions; + + public MethodSpec(ParameterSpec returnType) { + this.returnType = returnType; + } + + public void setVariableRequiredParameters(boolean variableRequiredParameters) { + this.variableRequiredParameters = variableRequiredParameters; + } + + public boolean isVariableRequiredParameters() { + return variableRequiredParameters; + } + + public void setIgnoreAdditionalParameters(boolean ignoreAdditionalParameter) { + this.ignoreAdditionalParameters = ignoreAdditionalParameter; + } + + public boolean isIgnoreAdditionalParameters() { + return ignoreAdditionalParameters; + } + + public void addOptional(ParameterSpec spec) { + optional.add(spec); + } + + public ParameterSpec addRequired(ParameterSpec spec) { + required.add(spec); + return spec; + } + + public ParameterSpec getReturnType() { + return returnType; + } + + public List getRequired() { + return required; + } + + public List getOptional() { + return optional; + } + + public List getAll() { + List specs = new ArrayList<>(); + specs.add(getReturnType()); + specs.addAll(getOptional()); + specs.addAll(getRequired()); + return specs; + } + + public ParameterSpec findParameterSpec(String name) { + for (ParameterSpec spec : getAll()) { + if (spec.getName().equals(name)) { + return spec; + } + } + return null; + } + + public void applyTypeDefinitions(String prefix) { + this.typeDefinitions = createTypeDefinitions(prefix); + } + + private List createTypeDefinitions(String prefix) { + List typeDefs = new ArrayList<>(); + + int defIndex = 0; + for (ParameterSpec spec : getAll()) { + List allowedTypes = spec.getAllowedTypes(); + List types = spec.getAllowedTypes(); + if (types != null && allowedTypes.size() > 1) { + TypeDef foundDef = null; + for (TypeDef def : typeDefs) { + if (allowedTypes.equals(def.getTypes())) { + foundDef = def; + break; + } + } + if (foundDef == null) { + foundDef = new TypeDef(types, prefix + defIndex); + typeDefs.add(foundDef); + defIndex++; + } + + spec.setTypeDefinition(foundDef); + } + } + + return typeDefs; + } + + public String toSignatureString(String methodName) { + StringBuilder b = new StringBuilder(); + b.append(" "); + b.append(createTypeSignature(returnType, true)); + + b.append(" "); + b.append(methodName); + b.append("("); + + String sep = ""; + + for (ParameterSpec optionalSpec : getOptional()) { + b.append(sep); + b.append("["); + b.append(createTypeSignature(optionalSpec, false)); + b.append("]"); + sep = ", "; + } + + for (int i = 0; i < getRequired().size(); i++) { + ParameterSpec requiredSpec = getRequired().get(i); + b.append(sep); + + if (isVariableRequiredParameters() && i == getRequired().size() - 1) { + b.append(("{")); + } + b.append(createTypeSignature(requiredSpec, false)); + if (isVariableRequiredParameters() && i == getRequired().size() - 1) { + b.append(("}")); + } + + sep = ", "; + } + + b.append(")"); + + if (typeDefinitions != null && !typeDefinitions.isEmpty()) { + b.append("\n\n"); + + String lineSep = ""; + for (TypeDef def : typeDefinitions) { + b.append(lineSep); + b.append(" <").append(def.getName()).append(">"); + b.append(" = {"); + String separator = ""; + for (TypeMirror type : def.getTypes()) { + b.append(separator).append(ElementUtils.getSimpleName(type)); + separator = ", "; + } + b.append("}"); + lineSep = "\n"; + + } + } + return b.toString(); + } + + private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) { + StringBuilder builder = new StringBuilder(); + TypeDef foundTypeDef = spec.getTypeDefinition(); + if (foundTypeDef != null) { + builder.append("<" + foundTypeDef.getName() + ">"); + } else if (spec.getAllowedTypes().size() >= 1) { + builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().get(0))); + } else { + builder.append("void"); + } + if (!typeOnly) { + builder.append(" "); + builder.append(spec.getName()); + } + return builder.toString(); + } + + @Override + public String toString() { + return toSignatureString("methodName"); + } + + static class TypeDef { + + private final List types; + private final String name; + + private TypeDef(List types, String name) { + this.types = types; + this.name = name; + } + + public List getTypes() { + return types; + } + + public String getName() { + return name; + } + } + + public void setIgnoreAdditionalSpecifications(boolean ignoreAdditoinalSpecifications) { + this.ignoreAdditionalSpecifications = ignoreAdditoinalSpecifications; + } + + public boolean isIgnoreAdditionalSpecifications() { + return ignoreAdditionalSpecifications; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,139 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; + +public class NodeChildData extends MessageContainer { + + public enum Cardinality { + ONE, + MANY; + + public boolean isMany() { + return this == MANY; + } + + public boolean isOne() { + return this == ONE; + } + } + + private final Element sourceElement; + private final AnnotationMirror sourceAnnotationMirror; + private final String name; + private final TypeMirror type; + private final TypeMirror originalType; + private final Element accessElement; + private final Cardinality cardinality; + + private List executeWith = Collections.emptyList(); + + private NodeData childNode; + + public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, TypeMirror originalNodeType, Element accessElement, Cardinality cardinality) { + this.sourceElement = sourceElement; + this.sourceAnnotationMirror = sourceMirror; + this.name = name; + this.type = nodeType; + this.originalType = originalNodeType; + this.accessElement = accessElement; + this.cardinality = cardinality; + } + + public List getExecuteWith() { + return executeWith; + } + + public void setExecuteWith(List executeWith) { + this.executeWith = executeWith; + } + + public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) { + ExecutableTypeData executableType = childNode.findExecutableType(targetType, getExecuteWith().size()); + if (executableType == null) { + executableType = findAnyGenericExecutableType(context); + } + return executableType; + } + + public List findGenericExecutableTypes(ProcessorContext context) { + return childNode.findGenericExecutableTypes(context, getExecuteWith().size()); + } + + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { + return childNode.findAnyGenericExecutableType(context, getExecuteWith().size()); + } + + public TypeMirror getOriginalType() { + return originalType; + } + + @Override + public Element getMessageElement() { + return sourceElement; + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return sourceAnnotationMirror; + } + + public void setNode(NodeData nodeData) { + this.childNode = nodeData; + if (nodeData != null) { + getMessages().addAll(nodeData.collectMessages()); + } + } + + public Element getAccessElement() { + return accessElement; + } + + public TypeMirror getNodeType() { + return type; + } + + public Cardinality getCardinality() { + return cardinality; + } + + public NodeData getNodeData() { + return childNode; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "NodeFieldData[name=" + getName() + ", kind=" + cardinality + ", node=" + getNodeData() + "]"; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,466 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; +import com.oracle.truffle.dsl.processor.parser.*; + +public class NodeData extends Template implements Comparable { + + private final String nodeId; + private final String shortName; + private final List enclosingNodes = new ArrayList<>(); + private NodeData declaringNode; + + private final TypeSystemData typeSystem; + private final List children; + private final List childExecutions; + private final List fields; + private final List assumptions; + + private ParameterSpec instanceParameterSpec; + + private final List specializations = new ArrayList<>(); + private final List shortCircuits = new ArrayList<>(); + private final List casts = new ArrayList<>(); + private Map> executableTypes; + + private final NodeExecutionData thisExecution; + + public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, List children, List executions, + List fields, List assumptions) { + super(context, type, null, null); + this.nodeId = type.getSimpleName().toString(); + this.shortName = shortName; + this.typeSystem = typeSystem; + this.fields = fields; + this.children = children; + this.childExecutions = executions; + this.assumptions = assumptions; + this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false); + this.thisExecution.getChild().setNode(this); + } + + public NodeData(ProcessorContext context, TypeElement type) { + this(context, type, null, null, null, null, null, null); + } + + public NodeExecutionData getThisExecution() { + return thisExecution; + } + + public boolean isFallbackReachable() { + SpecializationData generic = getGenericSpecialization(); + if (generic != null) { + return generic.isReachable(); + } + return false; + } + + public void addEnclosedNode(NodeData node) { + this.enclosingNodes.add(node); + node.declaringNode = this; + } + + public List getChildExecutions() { + return childExecutions; + } + + public int getSignatureSize() { + if (getSpecializations() != null && !getSpecializations().isEmpty()) { + return getSpecializations().get(0).getSignatureSize(); + } + return 0; + } + + public boolean needsFrame(ProcessorContext context) { + for (SpecializationData specialization : specializations) { + if (!specialization.isReachable()) { + continue; + } + if (specialization.hasFrame(context)) { + return true; + } + } + return false; + } + + public boolean isPolymorphic(ProcessorContext context) { + return needsRewrites(context); + } + + public List getCasts() { + return casts; + } + + public String getShortName() { + return shortName; + } + + public List getFields() { + return fields; + } + + @Override + protected List findChildContainers() { + List containerChildren = new ArrayList<>(); + if (enclosingNodes != null) { + containerChildren.addAll(enclosingNodes); + } + if (typeSystem != null) { + containerChildren.add(typeSystem); + } + if (specializations != null) { + for (MessageContainer specialization : specializations) { + if (specialization.getMessageElement() != null) { + containerChildren.add(specialization); + } + } + } + if (executableTypes != null) { + containerChildren.addAll(getExecutableTypes()); + } + if (shortCircuits != null) { + containerChildren.addAll(shortCircuits); + } + if (children != null) { + containerChildren.addAll(children); + } + if (fields != null) { + containerChildren.addAll(fields); + } + if (casts != null) { + containerChildren.addAll(casts); + } + return containerChildren; + } + + public ParameterSpec getInstanceParameterSpec() { + return instanceParameterSpec; + } + + public void setInstanceParameterSpec(ParameterSpec instanceParameter) { + this.instanceParameterSpec = instanceParameter; + } + + public String getNodeId() { + return nodeId; + } + + public TypeMirror getNodeType() { + return getTemplateType().asType(); + } + + public List getAssumptions() { + return assumptions; + } + + public boolean needsFactory() { + if (specializations == null) { + return false; + } + if (getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { + return false; + } + + boolean noSpecialization = true; + for (SpecializationData specialization : specializations) { + noSpecialization = noSpecialization && !specialization.isSpecialized(); + } + return !noSpecialization; + } + + public boolean supportsFrame() { + if (executableTypes != null) { + for (ExecutableTypeData execType : getExecutableTypes(-1)) { + if (execType.findParameter("frameValue") == null) { + return false; + } + } + } + return true; + } + + public List getNodeDeclaringChildren() { + List nodeChildren = new ArrayList<>(); + for (NodeData child : getEnclosingNodes()) { + if (child.needsFactory()) { + nodeChildren.add(child); + } + nodeChildren.addAll(child.getNodeDeclaringChildren()); + } + return nodeChildren; + } + + public NodeData getDeclaringNode() { + return declaringNode; + } + + public List getEnclosingNodes() { + return enclosingNodes; + } + + public List getAllTemplateMethods() { + List methods = new ArrayList<>(); + + for (SpecializationData specialization : getSpecializations()) { + methods.add(specialization); + } + + methods.addAll(getExecutableTypes()); + methods.addAll(getShortCircuits()); + if (getCasts() != null) { + methods.addAll(getCasts()); + } + + return methods; + } + + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) { + List types = findGenericExecutableTypes(context, evaluatedCount); + for (ExecutableTypeData type : types) { + if (type.getType().isGeneric()) { + return type; + } + } + + for (ExecutableTypeData type : types) { + if (!type.getType().isVoid()) { + return type; + } + } + + for (ExecutableTypeData type : types) { + return type; + } + return null; + } + + public List getExecutableTypes(int evaluatedCount) { + if (executableTypes == null) { + return Collections.emptyList(); + } + if (evaluatedCount == -1) { + List typeData = new ArrayList<>(); + for (int currentEvaluationCount : executableTypes.keySet()) { + typeData.addAll(executableTypes.get(currentEvaluationCount)); + } + return typeData; + } else { + List types = executableTypes.get(evaluatedCount); + if (types == null) { + return Collections.emptyList(); + } + return types; + } + } + + public List findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) { + List types = new ArrayList<>(); + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { + if (!type.hasUnexpectedValue(context)) { + types.add(type); + } + } + return types; + } + + public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) { + for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { + if (ElementUtils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) { + return type; + } + } + return null; + } + + public boolean needsRewrites(ProcessorContext context) { + boolean needsRewrites = false; + + for (SpecializationData specialization : getSpecializations()) { + if (specialization.hasRewrite(context)) { + needsRewrites = true; + break; + } + } + return needsRewrites || getSpecializations().size() > 1; + } + + public SpecializationData getPolymorphicSpecialization() { + for (SpecializationData specialization : specializations) { + if (specialization.isPolymorphic()) { + return specialization; + } + } + return null; + } + + public SpecializationData getGenericSpecialization() { + for (SpecializationData specialization : specializations) { + if (specialization.isGeneric()) { + return specialization; + } + } + return null; + } + + public SpecializationData getUninitializedSpecialization() { + for (SpecializationData specialization : specializations) { + if (specialization.isUninitialized()) { + return specialization; + } + } + return null; + } + + @Override + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public String dump() { + return dump(0); + } + + private String dump(int level) { + String indent = ""; + for (int i = 0; i < level; i++) { + indent += " "; + } + StringBuilder builder = new StringBuilder(); + + builder.append(String.format("%s%s {", indent, toString())); + + dumpProperty(builder, indent, "templateClass", ElementUtils.getQualifiedName(getTemplateType())); + dumpProperty(builder, indent, "typeSystem", getTypeSystem()); + dumpProperty(builder, indent, "fields", getChildren()); + dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); + dumpProperty(builder, indent, "specializations", getSpecializations()); + dumpProperty(builder, indent, "assumptions", getAssumptions()); + dumpProperty(builder, indent, "casts", getCasts()); + dumpProperty(builder, indent, "messages", collectMessages()); + if (getEnclosingNodes().size() > 0) { + builder.append(String.format("\n%s children = [", indent)); + for (NodeData node : getEnclosingNodes()) { + builder.append("\n"); + builder.append(node.dump(level + 1)); + } + builder.append(String.format("\n%s ]", indent)); + } + builder.append(String.format("%s}", indent)); + return builder.toString(); + } + + private static void dumpProperty(StringBuilder b, String indent, String propertyName, Object value) { + if (value instanceof List) { + List list = (List) value; + if (!list.isEmpty()) { + b.append(String.format("\n%s %s = %s", indent, propertyName, dumpList(indent, (List) value))); + } + } else { + if (value != null) { + b.append(String.format("\n%s %s = %s", indent, propertyName, value)); + } + } + } + + private static String dumpList(String indent, List array) { + if (array == null) { + return "null"; + } + + if (array.isEmpty()) { + return "[]"; + } else if (array.size() == 1) { + return "[" + array.get(0).toString() + "]"; + } + + StringBuilder b = new StringBuilder(); + b.append("["); + for (Object object : array) { + b.append("\n "); + b.append(indent); + b.append(object); + b.append(", "); + } + b.append("\n ").append(indent).append("]"); + return b.toString(); + } + + public NodeChildData findChild(String name) { + for (NodeChildData field : getChildren()) { + if (field.getName().equals(name)) { + return field; + } + } + return null; + } + + public List getChildren() { + return children; + } + + public List getSpecializations() { + return specializations; + } + + public List getExecutableTypes() { + return getExecutableTypes(-1); + } + + public List getShortCircuits() { + return shortCircuits; + } + + public void setExecutableTypes(Map> executableTypes) { + this.executableTypes = executableTypes; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getNodeId() + "]"; + } + + public CreateCastData findCast(String name) { + if (getCasts() != null) { + for (CreateCastData cast : getCasts()) { + if (cast.getChildNames().contains(name)) { + return cast; + } + } + } + return null; + } + + public int compareTo(NodeData o) { + return getNodeId().compareTo(o.getNodeId()); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,75 @@ +/* + * 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.dsl.processor.model; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class NodeFieldData extends MessageContainer { + + private final Element messageElement; + private final AnnotationMirror messageAnnotation; + private final String name; + private final TypeMirror type; + private final boolean generated; + private ExecutableElement getter; + + public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, TypeMirror type, String name, boolean generated) { + this.messageElement = messageElement; + this.messageAnnotation = messageAnnotation; + this.name = name; + this.type = type; + this.generated = generated; + } + + public void setGetter(ExecutableElement getter) { + this.getter = getter; + } + + @Override + public Element getMessageElement() { + return messageElement; + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return messageAnnotation; + } + + public String getName() { + return name; + } + + public TypeMirror getType() { + return type; + } + + public boolean isGenerated() { + return generated; + } + + public ExecutableElement getGetter() { + return getter; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,116 @@ +/* + * 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.dsl.processor.model; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public final class Parameter { + + private final ParameterSpec specification; + private TypeData typeSystemType; + private TemplateMethod method; + private final String localName; + private final int specificationVarArgsIndex; + private final int typeVarArgsIndex; + private final TypeMirror actualType; + + public Parameter(ParameterSpec specification, TypeMirror actualType, int specificationVarArgsIndex, int typeVarArgsIndex) { + this.specification = specification; + this.actualType = actualType; + this.typeSystemType = null; + + this.specificationVarArgsIndex = specificationVarArgsIndex; + + String valueName = specification.getName() + "Value"; + if (specificationVarArgsIndex > -1) { + valueName += specificationVarArgsIndex; + } + this.typeVarArgsIndex = typeVarArgsIndex; + this.localName = valueName; + } + + public Parameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex) { + this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex); + this.typeSystemType = actualType; + } + + public Parameter(Parameter parameter, TypeData otherType) { + this(parameter.specification, otherType, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex); + } + + public Parameter(Parameter parameter) { + this.specification = parameter.specification; + this.actualType = parameter.actualType; + this.typeSystemType = parameter.typeSystemType; + this.specificationVarArgsIndex = parameter.specificationVarArgsIndex; + this.localName = parameter.localName; + this.typeVarArgsIndex = parameter.typeVarArgsIndex; + } + + public int getTypeVarArgsIndex() { + return typeVarArgsIndex; + } + + public int getSpecificationVarArgsIndex() { + return specificationVarArgsIndex; + } + + public String getLocalName() { + return localName; + } + + void setMethod(TemplateMethod method) { + this.method = method; + } + + public ParameterSpec getSpecification() { + return specification; + } + + public TemplateMethod getMethod() { + return method; + } + + public TypeMirror getType() { + return actualType; + } + + public TypeData getTypeSystemType() { + return typeSystemType; + } + + public boolean isTypeVarArgs() { + return typeVarArgsIndex >= 0; + } + + public Parameter getPreviousParameter() { + return method.getPreviousParam(this); + } + + @Override + public String toString() { + return ElementUtils.getSimpleName(actualType); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,135 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.MethodSpec.TypeDef; +import com.oracle.truffle.dsl.processor.parser.*; + +public class ParameterSpec { + + private final String name; + private final List allowedTypes; + + /** Type is bound to local final variable. */ + private boolean local; + private boolean signature; + + /** Optional bound execution of node. */ + private NodeExecutionData execution; + private TypeDef typeDefinition; + + public ParameterSpec(String name, List allowedTypes) { + this.name = name; + this.allowedTypes = allowedTypes; + } + + public ParameterSpec(String name, TypeMirror type) { + this(name, Arrays.asList(type)); + } + + public ParameterSpec(ParameterSpec o, List allowedTypes) { + this.name = o.name; + this.local = o.local; + this.typeDefinition = o.typeDefinition; + this.execution = o.execution; + this.signature = o.signature; + this.allowedTypes = allowedTypes; + } + + public NodeExecutionData getExecution() { + return execution; + } + + public void setExecution(NodeExecutionData executionData) { + this.execution = executionData; + this.signature = execution != null; + } + + public void setSignature(boolean signature) { + this.signature = signature; + } + + void setTypeDefinition(TypeDef typeDefinition) { + this.typeDefinition = typeDefinition; + } + + TypeDef getTypeDefinition() { + return typeDefinition; + } + + public void setLocal(boolean local) { + this.local = local; + } + + public boolean isSignature() { + return signature; + } + + public boolean isLocal() { + return local; + } + + public String getName() { + return name; + } + + public List getAllowedTypes() { + return allowedTypes; + } + + public boolean matches(TypeMirror actualType) { + for (TypeMirror mirror : allowedTypes) { + if (ElementUtils.typeEquals(actualType, mirror)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return toSignatureString(false); + } + + public String toSignatureString(boolean typeOnly) { + StringBuilder builder = new StringBuilder(); + if (typeDefinition != null) { + builder.append("<" + typeDefinition.getName() + ">"); + } else if (getAllowedTypes().size() >= 1) { + builder.append(ElementUtils.getSimpleName(getAllowedTypes().get(0))); + } else { + builder.append("void"); + } + if (!typeOnly) { + builder.append(" "); + builder.append(getName()); + } + return builder.toString(); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ShortCircuitData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ShortCircuitData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,70 @@ +/* + * 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.dsl.processor.model; + +import com.oracle.truffle.dsl.processor.java.*; + +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 (Parameter param : getParameters()) { + Parameter specializationParam = specialization.findParameter(param.getLocalName()); + if (!ElementUtils.typeEquals(param.getType(), specializationParam.getType())) { + return false; + } + } + return true; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,348 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public final class SpecializationData extends TemplateMethod { + + public enum SpecializationKind { + UNINITIALIZED, + SPECIALIZED, + POLYMORPHIC, + GENERIC + } + + private final NodeData node; + private final SpecializationKind kind; + private final List exceptions; + private List guards = Collections.emptyList(); + private List shortCircuits; + private List assumptions = Collections.emptyList(); + private final Set contains = new TreeSet<>(); + private final Set containsNames = new TreeSet<>(); + private final Set excludedBy = new TreeSet<>(); + private String insertBeforeName; + private SpecializationData insertBefore; + private boolean reachable; + private int index; + + public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind, List exceptions) { + super(template); + this.node = node; + this.kind = kind; + this.exceptions = exceptions; + this.index = template.getNaturalOrder(); + + for (SpecializationThrowsData exception : exceptions) { + exception.setSpecialization(this); + } + } + + public void setInsertBefore(SpecializationData insertBefore) { + this.insertBefore = insertBefore; + } + + public void setInsertBeforeName(String insertBeforeName) { + this.insertBeforeName = insertBeforeName; + } + + public SpecializationData getInsertBefore() { + return insertBefore; + } + + public String getInsertBeforeName() { + return insertBeforeName; + } + + public Set getContainsNames() { + return containsNames; + } + + public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind) { + this(node, template, kind, new ArrayList()); + } + + public Set getContains() { + return contains; + } + + public Set getExcludedBy() { + return excludedBy; + } + + public void setReachable(boolean reachable) { + this.reachable = reachable; + } + + public boolean isReachable() { + return reachable; + } + + public boolean isPolymorphic() { + return kind == SpecializationKind.POLYMORPHIC; + } + + @Override + protected List findChildContainers() { + List sinks = new ArrayList<>(); + if (exceptions != null) { + sinks.addAll(exceptions); + } + if (guards != null) { + for (GuardExpression guard : guards) { + if (guard.isResolved()) { + sinks.add(guard.getResolvedGuard()); + } + } + } + return sinks; + } + + public boolean hasRewrite(ProcessorContext context) { + if (!getExceptions().isEmpty()) { + return true; + } + if (!getGuards().isEmpty()) { + return true; + } + if (!getAssumptions().isEmpty()) { + return true; + } + for (Parameter parameter : getSignatureParameters()) { + ExecutableTypeData type = parameter.getSpecification().getExecution().getChild().findExecutableType(context, parameter.getTypeSystemType()); + if (type.hasUnexpectedValue(context)) { + return true; + } + if (type.getReturnType().getTypeSystemType().needsCastTo(parameter.getTypeSystemType())) { + return true; + } + + } + return false; + } + + @Override + public int compareTo(TemplateMethod other) { + if (this == other) { + return 0; + } else if (!(other instanceof SpecializationData)) { + return super.compareTo(other); + } + SpecializationData m2 = (SpecializationData) other; + int kindOrder = kind.compareTo(m2.kind); + if (kindOrder != 0) { + return kindOrder; + } + + int compare = 0; + int order1 = index; + int order2 = m2.index; + if (order1 != NO_NATURAL_ORDER && order2 != NO_NATURAL_ORDER) { + compare = Integer.compare(order1, order2); + if (compare != 0) { + return compare; + } + } + + return super.compareTo(other); + } + + public void setIndex(int order) { + this.index = order; + } + + public int getIndex() { + return index; + } + + public boolean isContainedBy(SpecializationData next) { + if (compareTo(next) > 0) { + // must be declared after the current specialization + return false; + } + + Iterator currentSignature = getSignatureParameters().iterator(); + Iterator nextSignature = next.getSignatureParameters().iterator(); + + while (currentSignature.hasNext() && nextSignature.hasNext()) { + TypeData currentType = currentSignature.next().getTypeSystemType(); + TypeData prevType = nextSignature.next().getTypeSystemType(); + + if (!currentType.isImplicitSubtypeOf(prevType)) { + return false; + } + } + + for (String nextAssumption : next.getAssumptions()) { + if (!getAssumptions().contains(nextAssumption)) { + return false; + } + } + + Iterator nextGuards = next.getGuards().iterator(); + while (nextGuards.hasNext()) { + GuardExpression nextGuard = nextGuards.next(); + boolean implied = false; + for (GuardExpression currentGuard : getGuards()) { + if (currentGuard.implies(nextGuard)) { + implied = true; + break; + } + } + if (!implied) { + return false; + } + } + + return true; + } + + public String createReferenceName() { + StringBuilder b = new StringBuilder(); + + b.append(getMethodName()); + b.append("("); + + String sep = ""; + for (Parameter parameter : getParameters()) { + b.append(sep); + b.append(ElementUtils.getSimpleName(parameter.getType())); + sep = ", "; + } + + b.append(")"); + return b.toString(); + } + + public NodeData getNode() { + return node; + } + + public void setGuards(List guards) { + this.guards = guards; + } + + public boolean isSpecialized() { + return kind == SpecializationKind.SPECIALIZED; + } + + public boolean isGeneric() { + return kind == SpecializationKind.GENERIC; + } + + public boolean isUninitialized() { + return kind == SpecializationKind.UNINITIALIZED; + } + + public List getExceptions() { + return exceptions; + } + + public List getGuards() { + return guards; + } + + public void setShortCircuits(List shortCircuits) { + this.shortCircuits = shortCircuits; + } + + public List getShortCircuits() { + return shortCircuits; + } + + public List getAssumptions() { + return assumptions; + } + + public void setAssumptions(List assumptions) { + this.assumptions = assumptions; + } + + public SpecializationData findNextSpecialization() { + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size() - 1; i++) { + if (specializations.get(i) == this) { + return specializations.get(i + 1); + } + } + return null; + } + + @Override + public String toString() { + return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature()); + } + + public boolean hasFrame(ProcessorContext context) { + for (Parameter param : getParameters()) { + if (ElementUtils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) { + return true; + } + } + return false; + } + + public boolean isReachableAfter(SpecializationData prev) { + if (!prev.isSpecialized()) { + return true; + } + + if (!prev.getExceptions().isEmpty()) { + return true; + } + + Iterator currentSignature = getSignatureParameters().iterator(); + Iterator prevSignature = prev.getSignatureParameters().iterator(); + + while (currentSignature.hasNext() && prevSignature.hasNext()) { + TypeData currentType = currentSignature.next().getTypeSystemType(); + TypeData prevType = prevSignature.next().getTypeSystemType(); + + if (!currentType.isImplicitSubtypeOf(prevType)) { + return true; + } + } + + for (String prevAssumption : prev.getAssumptions()) { + if (!getAssumptions().contains(prevAssumption)) { + return true; + } + } + + Iterator prevGuards = prev.getGuards().iterator(); + Iterator currentGuards = getGuards().iterator(); + while (prevGuards.hasNext()) { + GuardExpression prevGuard = prevGuards.next(); + GuardExpression currentGuard = currentGuards.hasNext() ? currentGuards.next() : null; + if (currentGuard == null || !currentGuard.implies(prevGuard)) { + return true; + } + } + + return false; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationThrowsData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationThrowsData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,75 @@ +/* + * 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.dsl.processor.model; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class SpecializationThrowsData extends MessageContainer { + + private final AnnotationValue annotationValue; + private final AnnotationMirror annotationMirror; + private final TypeMirror javaClass; + private SpecializationData specialization; + + public SpecializationThrowsData(AnnotationMirror annotationMirror, AnnotationValue value, TypeMirror javaClass) { + this.annotationMirror = annotationMirror; + this.annotationValue = value; + this.javaClass = javaClass; + } + + void setSpecialization(SpecializationData specialization) { + this.specialization = specialization; + } + + @Override + public Element getMessageElement() { + return specialization.getMessageElement(); + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return annotationMirror; + } + + @Override + public AnnotationValue getMessageAnnotationValue() { + return annotationValue; + } + + public TypeMirror getJavaClass() { + return javaClass; + } + + public SpecializationData getSpecialization() { + return specialization; + } + + public AnnotationMirror getAnnotationMirror() { + return annotationMirror; + } + + public SpecializationData getTransitionTo() { + return specialization.findNextSpecialization(); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Template.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Template.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,84 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public abstract class Template extends MessageContainer { + + private final ProcessorContext context; + private final TypeElement templateType; + private final String templateMethodName; + private final AnnotationMirror annotation; + + public Template(ProcessorContext context, TypeElement templateType, String templateMethodName, AnnotationMirror annotation) { + this.context = context; + this.templateType = templateType; + this.templateMethodName = templateMethodName; + this.annotation = annotation; + } + + public ProcessorContext getContext() { + return context; + } + + @Override + public MessageContainer getBaseContainer() { + return this; + } + + public abstract TypeSystemData getTypeSystem(); + + @Override + public Element getMessageElement() { + return templateType; + } + + @Override + protected List findChildContainers() { + return Collections.emptyList(); + } + + public String getTemplateMethodName() { + return templateMethodName; + } + + public TypeElement getTemplateType() { + return templateType; + } + + public AnnotationMirror getTemplateTypeAnnotation() { + return annotation; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + ElementUtils.getSimpleName(getTemplateType()) + "]"; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,434 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.util.*; + +/** + * Note: this class has a natural ordering that is inconsistent with equals. + */ +public class TemplateMethod extends MessageContainer implements Comparable { + + public static final int NO_NATURAL_ORDER = -1; + + private String id; + private final Template template; + private final int naturalOrder; + private final MethodSpec specification; + private final ExecutableElement method; + private final AnnotationMirror markerAnnotation; + private Parameter returnType; + private List parameters; + + public TemplateMethod(String id, int naturalOrder, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, Parameter returnType, + List parameters) { + this.template = template; + this.specification = specification; + this.naturalOrder = naturalOrder; + this.method = method; + this.markerAnnotation = markerAnnotation; + this.returnType = returnType; + this.parameters = new ArrayList<>(); + for (Parameter param : parameters) { + Parameter newParam = new Parameter(param); + this.parameters.add(newParam); + newParam.setMethod(this); + } + this.id = id; + } + + public int getNaturalOrder() { + return naturalOrder; + } + + public TemplateMethod(TemplateMethod method) { + this(method.id, method.naturalOrder, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); + getMessages().addAll(method.getMessages()); + } + + public TemplateMethod(TemplateMethod method, ExecutableElement executable) { + this(method.id, method.naturalOrder, method.template, method.specification, executable, method.markerAnnotation, method.returnType, method.parameters); + getMessages().addAll(method.getMessages()); + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + @Override + public Element getMessageElement() { + return method; + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return markerAnnotation; + } + + @Override + protected List findChildContainers() { + return Collections.emptyList(); + } + + public void setId(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public Template getTemplate() { + return template; + } + + public MethodSpec getSpecification() { + return specification; + } + + public Parameter getReturnType() { + return returnType; + } + + public void replaceParameter(String localName, Parameter newParameter) { + if (returnType.getLocalName().equals(localName)) { + returnType = newParameter; + returnType.setMethod(this); + } + + for (ListIterator iterator = parameters.listIterator(); iterator.hasNext();) { + Parameter parameter = iterator.next(); + if (parameter.getLocalName().equals(localName)) { + iterator.set(newParameter); + newParameter.setMethod(this); + } + } + } + + public List getRequiredParameters() { + List requiredParameters = new ArrayList<>(); + for (Parameter parameter : getParameters()) { + if (getSpecification().getRequired().contains(parameter.getSpecification())) { + requiredParameters.add(parameter); + } + } + return requiredParameters; + } + + public Iterable getSignatureParameters() { + return new FilteredIterable<>(getParameters(), new Predicate() { + public boolean evaluate(Parameter value) { + return value.getSpecification().isSignature(); + } + }); + } + + public List getParameters() { + return parameters; + } + + public List findParameters(ParameterSpec spec) { + List foundParameters = new ArrayList<>(); + for (Parameter param : getReturnTypeAndParameters()) { + if (param.getSpecification().getName().equals(spec.getName())) { + foundParameters.add(param); + } + } + return foundParameters; + } + + public Parameter findParameter(String valueName) { + for (Parameter param : getReturnTypeAndParameters()) { + if (param.getLocalName().equals(valueName)) { + return param; + } + } + return null; + } + + public List getReturnTypeAndParameters() { + List allParameters = new ArrayList<>(getParameters().size() + 1); + if (getReturnType() != null) { + allParameters.add(getReturnType()); + } + allParameters.addAll(getParameters()); + return Collections.unmodifiableList(allParameters); + } + + public boolean canBeAccessedByInstanceOf(TypeMirror type) { + TypeMirror methodType = ElementUtils.findNearestEnclosingType(getMethod()).asType(); + return ElementUtils.isAssignable(type, methodType) || ElementUtils.isAssignable(methodType, type); + } + + public ExecutableElement getMethod() { + return method; + } + + public String getMethodName() { + if (getMethod() != null) { + return getMethod().getSimpleName().toString(); + } else { + return "$synthetic"; + } + } + + public AnnotationMirror getMarkerAnnotation() { + return markerAnnotation; + } + + @Override + public String toString() { + return String.format("%s [id = %s, method = %s]", getClass().getSimpleName(), getId(), getMethod()); + } + + public Parameter getPreviousParam(Parameter searchParam) { + Parameter prev = null; + for (Parameter param : getParameters()) { + if (param == searchParam) { + return prev; + } + prev = param; + } + return prev; + } + + @SuppressWarnings("unused") + public int getSignatureSize() { + int signatureSize = 0; + for (Parameter parameter : getSignatureParameters()) { + signatureSize++; + } + return signatureSize; + } + + public TypeSignature getTypeSignature() { + TypeSignature signature = new TypeSignature(); + signature.types.add(getReturnType().getTypeSystemType()); + for (Parameter parameter : getSignatureParameters()) { + TypeData typeData = parameter.getTypeSystemType(); + if (typeData != null) { + signature.types.add(typeData); + } + } + return signature; + } + + public Parameter getSignatureParameter(int searchIndex) { + int index = 0; + for (Parameter parameter : getParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (index == searchIndex) { + return parameter; + } + index++; + } + return null; + } + + public void updateSignature(TypeSignature signature) { + // TODO(CH): fails in normal usage - output ok though + // assert signature.size() >= 1; + + int signatureIndex = 0; + for (Parameter parameter : getReturnTypeAndParameters()) { + if (!parameter.getSpecification().isSignature()) { + continue; + } + if (signatureIndex >= signature.size()) { + break; + } + TypeData newType = signature.get(signatureIndex++); + if (!parameter.getTypeSystemType().equals(newType)) { + replaceParameter(parameter.getLocalName(), new Parameter(parameter, newType)); + } + } + } + + @Override + public int compareTo(TemplateMethod o) { + if (this == o) { + return 0; + } + + int compare = compareBySignature(o); + if (compare == 0) { + // if signature sorting failed sort by id + compare = getId().compareTo(o.getId()); + } + if (compare == 0) { + // if still no difference sort by enclosing type name + TypeElement enclosingType1 = ElementUtils.findNearestEnclosingType(getMethod()); + TypeElement enclosingType2 = ElementUtils.findNearestEnclosingType(o.getMethod()); + compare = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString()); + } + return compare; + } + + public List getParametersAfter(Parameter genericParameter) { + boolean found = false; + List foundParameters = new ArrayList<>(); + for (Parameter param : getParameters()) { + if (param.getLocalName().equals(genericParameter.getLocalName())) { + found = true; + } else if (found) { + foundParameters.add(param); + } + } + return foundParameters; + } + + public int compareBySignature(TemplateMethod compareMethod) { + final TypeSystemData typeSystem = getTemplate().getTypeSystem(); + if (typeSystem != compareMethod.getTemplate().getTypeSystem()) { + throw new IllegalStateException("Cannot compare two methods with different type systems."); + } + + List signature1 = getSignatureTypes(this); + List signature2 = getSignatureTypes(compareMethod); + + int result = 0; + for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) { + TypeMirror t1 = i < signature1.size() ? signature1.get(i) : null; + TypeMirror t2 = i < signature2.size() ? signature2.get(i) : null; + result = compareParameter(typeSystem, t1, t2); + if (result != 0) { + break; + } + } + + return result; + } + + protected static int compareParameter(TypeSystemData data, TypeMirror signature1, TypeMirror signature2) { + if (signature1 == null) { + return 1; + } else if (signature2 == null) { + return -1; + } + + if (ElementUtils.typeEquals(signature1, signature2)) { + return 0; + } + + int index1 = data.findType(signature1); + int index2 = data.findType(signature2); + if (index1 != -1 && index2 != -1) { + return index1 - index2; + } + + // TODO this version if subclass of should be improved. + if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) { + TypeElement element1 = ElementUtils.fromTypeMirror(signature1); + TypeElement element2 = ElementUtils.fromTypeMirror(signature2); + + if (ElementUtils.getDirectSuperTypes(element1).contains(element2)) { + return -1; + } else if (ElementUtils.getDirectSuperTypes(element2).contains(element1)) { + return 1; + } + } + return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2)); + } + + public static List getSignatureTypes(TemplateMethod method) { + List types = new ArrayList<>(); + for (Parameter param : method.getSignatureParameters()) { + types.add(param.getType()); + } + return types; + } + + public static class TypeSignature implements Iterable, Comparable { + + private final List types; + + public TypeSignature() { + this.types = new ArrayList<>(); + } + + public TypeSignature(List signature) { + this.types = signature; + } + + @Override + public int hashCode() { + return types.hashCode(); + } + + public int size() { + return types.size(); + } + + public TypeData get(int index) { + return types.get(index); + } + + public int compareTo(TypeSignature other) { + if (this == other) { + return 0; + } else if (types.size() != other.types.size()) { + return types.size() - other.types.size(); + } else if (types.isEmpty()) { + return 0; + } + + for (int i = 0; i < types.size(); i++) { + TypeData type1 = types.get(i); + TypeData type2 = other.types.get(i); + + int comparison = type1.compareTo(type2); + if (comparison != 0) { + return comparison; + } + } + + return 0; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TypeSignature) { + return ((TypeSignature) obj).types.equals(types); + } + return super.equals(obj); + } + + public Iterator iterator() { + return types.iterator(); + } + + @Override + public String toString() { + return types.toString(); + } + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,357 @@ +/* + * 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.dsl.processor.model; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +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.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public abstract class TemplateMethodParser { + + private final ProcessorContext context; + + protected final T template; + + private boolean emitErrors = true; + private boolean parseNullOnError = false; + private boolean useVarArgs = false; + + public TemplateMethodParser(ProcessorContext context, T template) { + this.template = template; + this.context = context; + } + + protected void setUseVarArgs(boolean useVarArgs) { + this.useVarArgs = useVarArgs; + } + + public boolean isUseVarArgs() { + return useVarArgs; + } + + 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; + } + + public TypeSystemData getTypeSystem() { + return template.getTypeSystem(); + } + + public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); + + public abstract E create(TemplateMethod method, boolean invalid); + + 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; + int naturalOrder = 0; + for (ExecutableElement method : methods) { + if (!isParsable(method)) { + continue; + } + + Class annotationType = getAnnotationType(); + AnnotationMirror mirror = null; + if (annotationType != null) { + mirror = ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); + } + + E parsedMethod = parse(naturalOrder, method, mirror); + + if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { + parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); + parsedMethods.add(parsedMethod); + valid = false; + continue; + } + + if (parsedMethod != null) { + parsedMethods.add(parsedMethod); + } else { + valid = false; + } + naturalOrder++; + } + Collections.sort(parsedMethods); + + if (!valid && parseNullOnError) { + return null; + } + return parsedMethods; + } + + private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { + MethodSpec methodSpecification = createSpecification(method, annotation); + if (methodSpecification == null) { + return null; + } + + methodSpecification.applyTypeDefinitions("types"); + + String id = method.getSimpleName().toString(); + TypeMirror returnType = method.getReturnType(); + List parameterTypes = new ArrayList<>(); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); + } + + private E parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, List parameterTypes) { + ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); + Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); + if (returnTypeMirror == null) { + if (emitErrors) { + E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); + String expectedReturnType = returnTypeSpec.toSignatureString(true); + String actualReturnType = ElementUtils.getSimpleName(returnType); + + String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); + if (parameters == null) { + if (isEmitErrors() && method != null) { + E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + return create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters), false); + } + + private static String createActualSignature(ExecutableElement method) { + StringBuilder b = new StringBuilder("("); + String sep = ""; + if (method != null) { + for (VariableElement var : method.getParameters()) { + b.append(sep); + b.append(ElementUtils.getSimpleName(var.asType())); + sep = ", "; + } + } + b.append(")"); + return b.toString(); + } + + /* + * Parameter parsing tries to parse required arguments starting from offset 0 with increasing + * offset until it finds a signature end that matches the required specification. If there is no + * end matching the required arguments, parsing fails. Parameters prior to the parsed required + * ones are cut and used to parse the optional parameters. + */ + private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { + List parsedRequired = null; + int offset = 0; + for (; offset <= parameterTypes.size(); offset++) { + List parameters = new ArrayList<>(); + parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); + parsedRequired = parseParametersRequired(spec, parameters, varArgs); + if (parsedRequired != null) { + break; + } + } + + if (parsedRequired == null) { + return null; + } + + if (parsedRequired.isEmpty() && offset == 0) { + offset = parameterTypes.size(); + } + List potentialOptionals = parameterTypes.subList(0, offset); + List parsedOptionals = parseParametersOptional(spec, potentialOptionals); + if (parsedOptionals == null) { + return null; + } + + List finalParameters = new ArrayList<>(); + finalParameters.addAll(parsedOptionals); + finalParameters.addAll(parsedRequired); + return finalParameters; + } + + private List parseParametersOptional(MethodSpec spec, List types) { + List parsedParams = new ArrayList<>(); + + int typeStartIndex = 0; + List specifications = spec.getOptional(); + outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { + ParameterSpec specification = specifications.get(specIndex); + for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { + TypeMirror actualType = types.get(typeIndex); + Parameter optionalParam = matchParameter(specification, actualType, -1, -1); + if (optionalParam != null) { + parsedParams.add(optionalParam); + typeStartIndex = typeIndex + 1; + continue outer; + } + } + } + + if (typeStartIndex < types.size()) { + // not enough types found + return null; + } + return parsedParams; + } + + private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { + List parsedParams = new ArrayList<>(); + List specifications = spec.getRequired(); + boolean specVarArgs = spec.isVariableRequiredParameters(); + int typeIndex = 0; + int specificationIndex = 0; + + ParameterSpec specification; + while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { + TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); + if (actualType == null) { + if (spec.isIgnoreAdditionalSpecifications()) { + break; + } + return null; + } + + int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; + int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; + + if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { + // both specifications and types have a variable number of arguments + // we would get into an endless loop if we would continue + break; + } + + Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); + if (resolvedParameter == null) { + return null; + } + parsedParams.add(resolvedParameter); + typeIndex++; + specificationIndex++; + } + + if (typeIndex < types.size()) { + // additional types available + if (spec.isIgnoreAdditionalParameters()) { + return parsedParams; + } else { + return null; + } + } + + return parsedParams; + } + + private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { + if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { + return specifications.get(specifications.size() - 1); + } else if (specIndex < specifications.size()) { + return specifications.get(specIndex); + } else { + return null; + } + } + + private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { + if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { + // unpack varargs array argument + TypeMirror actualType = types.get(types.size() - 1); + if (actualType.getKind() == TypeKind.ARRAY) { + actualType = ((ArrayType) actualType).getComponentType(); + } + return actualType; + } else if (typeIndex < types.size()) { + return types.get(typeIndex); + } else { + return null; + } + } + + private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { + TypeMirror resolvedType = mirror; + if (hasError(resolvedType)) { + return null; + } + + if (!specification.matches(resolvedType)) { + return null; + } + + TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); + if (resolvedTypeData != null) { + return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); + } else { + return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); + } + } + + public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { + return parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,48 @@ +/* + * 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.dsl.processor.model; + + +public class TypeCastData extends TemplateMethod { + + private final TypeData targetType; + private final TypeData sourceType; + + public TypeCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { + super(method); + this.sourceType = sourceType; + this.targetType = targetType; + } + + public boolean isGeneric() { + return sourceType.isGeneric(); + } + + public TypeData getSourceType() { + return sourceType; + } + + public TypeData getTargetType() { + return targetType; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,49 @@ +/* + * 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.dsl.processor.model; + + +public class TypeCheckData extends TemplateMethod { + + private final TypeData checkedType; + private final TypeData valueType; + + public TypeCheckData(TemplateMethod method, TypeData checkedType, TypeData valueType) { + super(method); + this.checkedType = checkedType; + this.valueType = valueType; + } + + public boolean isGeneric() { + return valueType.isGeneric(); + } + + public TypeData getCheckedType() { + return checkedType; + } + + public TypeData getValueType() { + return valueType; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,161 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; + +public class TypeData extends MessageContainer implements Comparable { + + private final TypeSystemData typeSystem; + private final AnnotationValue annotationValue; + private final TypeMirror primitiveType; + private final TypeMirror boxedType; + + private final int index; + private final List typeCasts = new ArrayList<>(); + private final List typeChecks = new ArrayList<>(); + + public TypeData(TypeSystemData typeSystem, int index, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) { + this.index = index; + this.typeSystem = typeSystem; + this.annotationValue = value; + this.primitiveType = primitiveType; + this.boxedType = boxedType; + } + + @Override + public Element getMessageElement() { + return typeSystem.getMessageElement(); + } + + @Override + public AnnotationMirror getMessageAnnotation() { + return typeSystem.getMessageAnnotation(); + } + + @Override + public AnnotationValue getMessageAnnotationValue() { + return annotationValue; + } + + public void addTypeCast(TypeCastData typeCast) { + this.typeCasts.add(typeCast); + } + + public void addTypeCheck(TypeCheckData typeCheck) { + this.typeChecks.add(typeCheck); + } + + public List getTypeCasts() { + return typeCasts; + } + + public List getTypeChecks() { + return typeChecks; + } + + public TypeSystemData getTypeSystem() { + return typeSystem; + } + + public TypeMirror getPrimitiveType() { + return primitiveType; + } + + public TypeMirror getBoxedType() { + return boxedType; + } + + public boolean isGeneric() { + return ElementUtils.typeEquals(boxedType, getTypeSystem().getGenericType()); + } + + public boolean isVoid() { + if (getTypeSystem().getVoidType() == null) { + return false; + } + return ElementUtils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType()); + } + + public int compareTo(TypeData o) { + if (this.equals(o)) { + return 0; + } + return index - o.index; + } + + @Override + public int hashCode() { + return Objects.hash(index, primitiveType); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TypeData)) { + return false; + } + TypeData otherType = (TypeData) obj; + return index == otherType.index && ElementUtils.typeEquals(primitiveType, otherType.primitiveType); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + ElementUtils.getSimpleName(primitiveType) + "]"; + } + + public boolean equalsType(TypeData actualTypeData) { + return ElementUtils.typeEquals(boxedType, actualTypeData.boxedType); + } + + public boolean needsCastTo(TypeData targetType) { + return ElementUtils.needsCastTo(getPrimitiveType(), targetType.getPrimitiveType()); + } + + public boolean needsCastTo(TypeMirror targetType) { + return ElementUtils.needsCastTo(getPrimitiveType(), targetType); + } + + public boolean isPrimitive() { + return ElementUtils.isPrimitive(getPrimitiveType()); + } + + public boolean isImplicitSubtypeOf(TypeData other) { + List casts = other.getTypeSystem().lookupByTargetType(other); + for (ImplicitCastData cast : casts) { + if (isSubtypeOf(cast.getSourceType())) { + return true; + } + } + return isSubtypeOf(other); + } + + public boolean isSubtypeOf(TypeData other) { + return ElementUtils.isSubtype(boxedType, other.boxedType); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,207 @@ +/* + * 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.dsl.processor.model; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; + +public class TypeSystemData extends Template { + + private List types; + private List primitiveTypeMirrors = new ArrayList<>(); + private List boxedTypeMirrors = new ArrayList<>(); + + private List implicitCasts; + private List casts; + private List checks; + + private TypeMirror genericType; + private TypeData voidType; + + public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation) { + super(context, templateType, null, annotation); + } + + @Override + public TypeSystemData getTypeSystem() { + return this; + } + + public void setTypes(List types) { + this.types = types; + if (types != null) { + for (TypeData typeData : types) { + primitiveTypeMirrors.add(typeData.getPrimitiveType()); + boxedTypeMirrors.add(typeData.getBoxedType()); + } + } + } + + public void setImplicitCasts(List implicitCasts) { + this.implicitCasts = implicitCasts; + } + + public List getImplicitCasts() { + return implicitCasts; + } + + public void setCasts(List casts) { + this.casts = casts; + } + + public void setChecks(List checks) { + this.checks = checks; + } + + public void setGenericType(TypeMirror genericType) { + this.genericType = genericType; + } + + public void setVoidType(TypeData voidType) { + this.voidType = voidType; + } + + @Override + protected List findChildContainers() { + List sinks = new ArrayList<>(); + if (types != null) { + sinks.addAll(types); + } + if (checks != null) { + sinks.addAll(checks); + } + if (casts != null) { + sinks.addAll(casts); + } + if (implicitCasts != null) { + sinks.addAll(implicitCasts); + } + return sinks; + } + + public TypeData getVoidType() { + return voidType; + } + + public List getBoxedTypeMirrors() { + return boxedTypeMirrors; + } + + public List getPrimitiveTypeMirrors() { + return primitiveTypeMirrors; + } + + public List getTypes() { + return types; + } + + public TypeMirror getGenericType() { + return genericType; + } + + public TypeData getGenericTypeData() { + TypeData result = types.get(types.size() - 1); + assert result.getBoxedType() == genericType; + return result; + } + + public TypeData findType(String simpleName) { + for (TypeData type : types) { + if (ElementUtils.getSimpleName(type.getBoxedType()).equals(simpleName)) { + return type; + } + } + return null; + } + + public TypeData findTypeData(TypeMirror type) { + if (ElementUtils.typeEquals(voidType.getPrimitiveType(), type)) { + return voidType; + } + + int index = findType(type); + if (index == -1) { + return null; + } + return types.get(index); + } + + public int findType(TypeMirror type) { + for (int i = 0; i < types.size(); i++) { + if (ElementUtils.typeEquals(types.get(i).getPrimitiveType(), type)) { + return i; + } + } + return -1; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[template = " + ElementUtils.getSimpleName(getTemplateType()) + ", types = " + types + "]"; + } + + public List lookupByTargetType(TypeData targetType) { + if (getImplicitCasts() == null) { + return Collections.emptyList(); + } + List foundCasts = new ArrayList<>(); + for (ImplicitCastData cast : getImplicitCasts()) { + if (cast.getTargetType().equals(targetType)) { + foundCasts.add(cast); + } + } + return foundCasts; + } + + public ImplicitCastData lookupCast(TypeData sourceType, TypeData targetType) { + if (getImplicitCasts() == null) { + return null; + } + for (ImplicitCastData cast : getImplicitCasts()) { + if (cast.getSourceType().equals(sourceType) && cast.getTargetType().equals(targetType)) { + return cast; + } + } + return null; + } + + public List lookupSourceTypes(TypeData type) { + List sourceTypes = new ArrayList<>(); + sourceTypes.add(type); + if (getImplicitCasts() != null) { + for (ImplicitCastData cast : getImplicitCasts()) { + if (cast.getTargetType() == type) { + sourceTypes.add(cast.getSourceType()); + } + } + } + Collections.sort(sourceTypes); + return sourceTypes; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +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.dsl.processor.node; - -import java.util.*; - -import com.oracle.truffle.dsl.processor.template.*; - -public class CreateCastData extends TemplateMethod { - - private final List childNames; - - public CreateCastData(TemplateMethod method, List childNames) { - super(method); - this.childNames = childNames; - } - - public List getChildNames() { - return childNames; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/CreateCastParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +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.dsl.processor.node; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class CreateCastParser extends NodeMethodParser { - - public CreateCastParser(ProcessorContext context, NodeData operation) { - super(context, operation); - } - - @Override - public Class getAnnotationType() { - return CreateCast.class; - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - List childNames = Utils.getAnnotationValueList(String.class, mirror, "value"); - NodeChildData foundChild = null; - for (String childName : childNames) { - foundChild = getNode().findChild(childName); - if (foundChild != null) { - break; - } - } - TypeMirror baseType = getContext().getTruffleTypes().getNode(); - if (foundChild != null) { - baseType = foundChild.getOriginalType(); - } - - MethodSpec spec = new MethodSpec(new InheritsParameterSpec("child", baseType)); - addDefaultFieldMethodSpec(spec); - ParameterSpec childSpec = new ParameterSpec("castedChild", baseType); - childSpec.setSignature(true); - spec.addRequired(childSpec); - return spec; - } - - @Override - public CreateCastData create(TemplateMethod method, boolean invalid) { - AnnotationMirror mirror = method.getMarkerAnnotation(); - List childNames = Utils.getAnnotationValueList(String.class, mirror, "value"); - CreateCastData cast = new CreateCastData(method, childNames); - AnnotationValue value = Utils.getAnnotationValue(mirror, "value"); - TypeMirror type = null; - if (childNames == null || childNames.isEmpty()) { - cast.addError(value, "No value specified but required."); - return cast; - } - - for (String childName : childNames) { - NodeChildData child = getNode().findChild(childName); - if (child == null) { - // error - cast.addError(value, "Specified child '%s' not found.", childName); - continue; - } - if (type == null) { - type = child.getNodeType(); - } else if (!Utils.typeEquals(type, child.getNodeType())) { - cast.addError(value, "All child nodes for a cast must have the same node type."); - continue; - } - } - return cast; - } - - private static class InheritsParameterSpec extends ParameterSpec { - - public InheritsParameterSpec(String name, TypeMirror... allowedTypes) { - super(name, Arrays.asList(allowedTypes)); - } - - @Override - public boolean matches(TypeMirror actualType) { - boolean found = false; - for (TypeMirror specType : getAllowedTypes()) { - if (Utils.isAssignable(actualType, specType)) { - found = true; - break; - } - } - return found; - } - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +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.dsl.processor.node; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class ExecutableTypeData extends TemplateMethod { - - private final TypeSystemData typeSystem; - private final TypeData type; - - public ExecutableTypeData(TemplateMethod method, ExecutableElement executable, TypeSystemData typeSystem, TypeData type) { - super(method, executable); - this.typeSystem = typeSystem; - this.type = type; - if (executable.getParameters().size() < method.getMethod().getParameters().size()) { - throw new IllegalArgumentException(String.format("Method parameter count mismatch %s != %s.", executable.getParameters(), method.getMethod().getParameters())); - } - } - - 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); - } - - public boolean isAbstract() { - return getMethod().getModifiers().contains(Modifier.ABSTRACT); - } - - public int getEvaluatedCount() { - int count = 0; - for (ActualParameter parameter : getParameters()) { - if (parameter.getSpecification().isSignature()) { - count++; - } - } - return count; - } - - @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 c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +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.dsl.processor.node; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class ExecutableTypeMethodParser extends NodeMethodParser { - - public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { - super(context, node); - setEmitErrors(false); - setParseNullOnError(false); - setUseVarArgs(true); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null); - List requiredSpecs = new ArrayList<>(spec.getRequired()); - spec.getRequired().clear(); - - List allowedTypes = getNode().getTypeSystem().getPrimitiveTypeMirrors(); - for (ParameterSpec originalSpec : requiredSpecs) { - spec.addRequired(new ParameterSpec(originalSpec, allowedTypes)); - } - spec.setIgnoreAdditionalSpecifications(true); - spec.setIgnoreAdditionalParameters(true); - spec.setVariableRequiredParameters(true); - // varargs - ParameterSpec otherParameters = new ParameterSpec("other", allowedTypes); - otherParameters.setSignature(true); - spec.addRequired(otherParameters); - return spec; - } - - @Override - public final boolean isParsable(ExecutableElement method) { - if (method.getModifiers().contains(Modifier.STATIC)) { - return false; - } else if (method.getModifiers().contains(Modifier.NATIVE)) { - return false; - } - return method.getSimpleName().toString().startsWith("execute"); - } - - @Override - protected List nodeTypeMirrors(NodeData nodeData) { - List types = new ArrayList<>(getNode().getTypeSystem().getPrimitiveTypeMirrors()); - types.add(getNode().getTypeSystem().getVoidType().getPrimitiveType()); - return types; - } - - @Override - public ExecutableTypeData create(TemplateMethod method, boolean invalid) { - TypeData resolvedType = method.getReturnType().getTypeSystemType(); - return new ExecutableTypeData(method, method.getMethod(), getNode().getTypeSystem(), resolvedType); - } - - @Override - public Class getAnnotationType() { - return null; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/GenericParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +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.dsl.processor.node; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.node.SpecializationData.SpecializationKind; -import com.oracle.truffle.dsl.processor.template.*; - -public class GenericParser extends NodeMethodParser { - - public GenericParser(ProcessorContext context, NodeData node) { - super(context, node); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(method, mirror, true, null); - } - - @Override - protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - List execTypes = execution.getChild().findGenericExecutableTypes(getContext()); - List types = new ArrayList<>(); - for (ExecutableTypeData type : execTypes) { - types.add(type.getType().getPrimitiveType()); - } - ParameterSpec spec = new ParameterSpec(execution.getName(), types); - spec.setExecution(execution); - return spec; - } - - @Override - public SpecializationData create(TemplateMethod method, boolean invalid) { - return new SpecializationData(getNode(), method, SpecializationKind.GENERIC); - } - - @Override - public Class getAnnotationType() { - return Generic.class; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeChildData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeChildData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * 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.dsl.processor.node; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class NodeChildData extends MessageContainer { - - public enum Cardinality { - ONE, - MANY; - - public boolean isMany() { - return this == MANY; - } - - public boolean isOne() { - return this == ONE; - } - } - - private NodeData parentNode; - private final Element sourceElement; - private final AnnotationMirror sourceAnnotationMirror; - private final String name; - private final TypeMirror type; - private final TypeMirror originalType; - private final Element accessElement; - private final Cardinality cardinality; - - private List executeWith = Collections.emptyList(); - - private NodeData childNode; - - public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, TypeMirror originalNodeType, Element accessElement, Cardinality cardinality) { - this.sourceElement = sourceElement; - this.sourceAnnotationMirror = sourceMirror; - this.name = name; - this.type = nodeType; - this.originalType = originalNodeType; - this.accessElement = accessElement; - this.cardinality = cardinality; - } - - void setParentNode(NodeData parentNode) { - this.parentNode = parentNode; - } - - public List getExecuteWith() { - return executeWith; - } - - void setExecuteWith(List executeWith) { - this.executeWith = executeWith; - } - - public boolean needsImplicitCast(ProcessorContext context) { - if (!parentNode.needsRewrites(context)) { - return false; - } - - boolean used = false; - for (NodeExecutionData execution : parentNode.getChildExecutions()) { - if (execution.getChild() == this) { - used = true; - break; - } - } - if (!used) { - return false; - } - - return getNodeData().getTypeSystem().getImplicitCasts() != null && !getNodeData().getTypeSystem().getImplicitCasts().isEmpty(); - } - - public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) { - ExecutableTypeData executableType = childNode.findExecutableType(targetType, getExecuteWith().size()); - if (executableType == null) { - executableType = findAnyGenericExecutableType(context); - } - return executableType; - } - - public List findGenericExecutableTypes(ProcessorContext context) { - return childNode.findGenericExecutableTypes(context, getExecuteWith().size()); - } - - public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { - return childNode.findAnyGenericExecutableType(context, getExecuteWith().size()); - } - - public List findExecutableTypes() { - return childNode.getExecutableTypes(getExecuteWith().size()); - } - - public TypeMirror getOriginalType() { - return originalType; - } - - @Override - public Element getMessageElement() { - return sourceElement; - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return sourceAnnotationMirror; - } - - void setNode(NodeData nodeData) { - this.childNode = nodeData; - if (nodeData != null) { - getMessages().addAll(nodeData.collectMessages()); - } - } - - public Element getAccessElement() { - return accessElement; - } - - public TypeMirror getNodeType() { - return type; - } - - public Cardinality getCardinality() { - return cardinality; - } - - public NodeData getNodeData() { - return childNode; - } - - public String getName() { - return name; - } - - @Override - public String toString() { - return "NodeFieldData[name=" + getName() + ", kind=" + cardinality + ", node=" + getNodeData() + "]"; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2936 +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.dsl.processor.node; - -import static com.oracle.truffle.dsl.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.api.dsl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; -import com.oracle.truffle.dsl.processor.ast.CodeTypeMirror.ArrayCodeTypeMirror; -import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; -import com.oracle.truffle.dsl.processor.node.SpecializationGroup.TypeGuard; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class NodeCodeGenerator extends CompilationUnitFactory { - - private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; - - private static final String EXECUTE_CHAINED = "executeChained0"; - private static final String SPECIALIZE = "specialize0"; - private static final String DSLSHARE_REWRITE = "rewrite"; - private static final String DSLSHARE_FIND_ROOT = "findRoot"; - private static final String DSLSHARE_REWRITE_TO_POLYMORHPIC = "rewriteToPolymorphic"; - private static final String EXECUTE_UNINITIALIZED = "executeUninitialized0"; - private static final String REWRITE = "rewrite0"; - private static final String CREATE_INFO = "createInfo0"; - private static final String CONTAINS_FALLBACK = "containsFallback"; - - private static final String FACTORY_METHOD_NAME = "create0"; - private static final String EMPTY_CLASS_ARRAY = "EMPTY_CLASS_ARRAY"; - - private static final String METADATA_FIELD_NAME = "METADATA"; - - private TypeMirror getUnexpectedValueException() { - return getContext().getTruffleTypes().getUnexpectedValueException(); - } - - private static String factoryClassName(NodeData node) { - return node.getNodeId() + "Factory"; - } - - private static String nodeSpecializationClassName(SpecializationData specialization) { - String nodeid = resolveNodeId(specialization.getNode()); - String name = Utils.firstLetterUpperCase(nodeid); - name += Utils.firstLetterUpperCase(specialization.getId()); - name += "Node"; - return name; - } - - private static String nodePolymorphicClassName(NodeData node) { - return Utils.firstLetterUpperCase(resolveNodeId(node)) + "PolymorphicNode"; - } - - private static String resolveNodeId(NodeData node) { - String nodeid = node.getNodeId(); - if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { - nodeid = nodeid.substring(0, nodeid.length() - 4); - } - return nodeid; - } - - private static String valueNameEvaluated(ActualParameter targetParameter) { - return valueName(targetParameter) + "Evaluated"; - } - - private static String implicitTypeName(ActualParameter param) { - return param.getLocalName() + "ImplicitType"; - } - - private static String polymorphicTypeName(NodeExecutionData param) { - return param.getName() + "PolymorphicType"; - } - - private static String valueName(ActualParameter param) { - return param.getLocalName(); - } - - private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) { - String reference = thisReference; - if (reference == null) { - reference = "this"; - } - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - Element accessElement = targetExecution.getChild().getAccessElement(); - if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { - builder.string(reference).string(".").string(targetExecution.getChild().getName()); - } else if (accessElement.getKind() == ElementKind.FIELD) { - builder.string(reference).string(".").string(accessElement.getSimpleName().toString()); - } else { - throw new AssertionError(); - } - if (targetExecution.isIndexed()) { - builder.string("[" + targetExecution.getIndex() + "]"); - } - return builder.getRoot(); - } - - private static String castValueName(ActualParameter parameter) { - return valueName(parameter) + "Cast"; - } - - private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) { - if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { - method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); - } - for (ActualParameter parameter : specialization.getParameters()) { - ParameterSpec spec = parameter.getSpecification(); - if (forceFrame && spec.getName().equals("frame")) { - continue; - } - if (spec.isLocal()) { - continue; - } - - String name = valueName(parameter); - if (evaluated && spec.isSignature()) { - name = valueNameEvaluated(parameter); - } - - method.addParameter(new CodeVariableElement(parameter.getType(), name)); - } - } - - private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, - Map customNames) { - if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { - builder.string("frameValue"); - } - for (ActualParameter parameter : specialization.getParameters()) { - ParameterSpec spec = parameter.getSpecification(); - if (forceFrame && spec.getName().equals("frame")) { - continue; - } - - if (parameter.getSpecification().isLocal()) { - continue; - } - - ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); - - if (customNames != null && customNames.containsKey(parameter.getLocalName())) { - builder.string(customNames.get(parameter.getLocalName())); - } else if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { - builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); - } else if (sourceParameter != null) { - builder.string(valueName(sourceParameter, parameter)); - } else { - builder.string(valueName(parameter)); - } - } - } - - private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) { - if (!sourceParameter.getSpecification().isSignature()) { - return valueName(targetParameter); - } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { - if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) { - return castValueName(targetParameter); - } - } - return valueName(targetParameter); - } - - private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName, - String... customSignatureValueNames) { - CodeTreeBuilder builder = parent.create(); - - boolean castedValues = sourceMethod != targetMethod; - - builder.startGroup(); - ExecutableElement method = targetMethod.getMethod(); - if (method == null) { - throw new UnsupportedOperationException(); - } - TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); - NodeData node = (NodeData) targetMethod.getTemplate(); - - if (target == null) { - boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType()); - if (accessible) { - if (builder.findMethod().getModifiers().contains(STATIC)) { - if (method.getModifiers().contains(STATIC)) { - builder.type(targetClass.asType()); - } else { - builder.string(THIS_NODE_LOCAL_VAR_NAME); - } - } else { - if (targetMethod instanceof ExecutableTypeData) { - builder.string("this"); - } else { - builder.string("super"); - } - } - } else { - if (method.getModifiers().contains(STATIC)) { - builder.type(targetClass.asType()); - } else { - ActualParameter firstParameter = null; - for (ActualParameter searchParameter : targetMethod.getParameters()) { - if (searchParameter.getSpecification().isSignature()) { - firstParameter = searchParameter; - break; - } - } - if (firstParameter == null) { - throw new AssertionError(); - } - - ActualParameter sourceParameter = sourceMethod.findParameter(firstParameter.getLocalName()); - - if (castedValues && sourceParameter != null) { - builder.string(valueName(sourceParameter, firstParameter)); - } else { - builder.string(valueName(firstParameter)); - } - } - } - builder.string("."); - } else { - builder.tree(target); - } - builder.startCall(method.getSimpleName().toString()); - - int signatureIndex = 0; - - for (ActualParameter targetParameter : targetMethod.getParameters()) { - ActualParameter valueParameter = null; - if (sourceMethod != null) { - valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); - } - if (valueParameter == null) { - valueParameter = targetParameter; - } - TypeMirror targetType = targetParameter.getType(); - TypeMirror valueType = null; - if (valueParameter != null) { - valueType = valueParameter.getType(); - } - - if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) { - builder.string(customSignatureValueNames[signatureIndex]); - signatureIndex++; - } else if (targetParameter.getSpecification().isLocal()) { - builder.startGroup(); - if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { - builder.string(THIS_NODE_LOCAL_VAR_NAME).string("."); - } else { - builder.string("this."); - } - builder.string(targetParameter.getSpecification().getName()); - builder.end(); - } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { - builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); - } else if (!Utils.needsCastTo(valueType, targetType)) { - builder.startGroup(); - builder.string(valueName(targetParameter)); - builder.end(); - } else { - builder.string(castValueName(targetParameter)); - } - } - - builder.end().end(); - - return builder.getRoot(); - } - - private static String baseClassName(NodeData node) { - String nodeid = resolveNodeId(node); - String name = Utils.firstLetterUpperCase(nodeid); - name += "BaseNode"; - return name; - } - - private static CodeTree createCallTypeSystemMethod(CodeTreeBuilder parent, NodeData node, String methodName, CodeTree... args) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - startCallTypeSystemMethod(builder, node.getTypeSystem(), methodName); - for (CodeTree arg : args) { - builder.tree(arg); - } - builder.end().end(); - return builder.getRoot(); - } - - private static void startCallTypeSystemMethod(CodeTreeBuilder body, TypeSystemData typeSystem, String methodName) { - GeneratedTypeMirror typeMirror = new GeneratedTypeMirror(Utils.getPackageName(typeSystem.getTemplateType()), TypeSystemCodeGenerator.typeName(typeSystem)); - body.startGroup(); - body.staticReference(typeMirror, TypeSystemCodeGenerator.singletonName(typeSystem)); - body.string(".").startCall(methodName); - } - - /** - *

-     * variant1 $condition != null
-     *
-     * $type $name = defaultValue($type);
-     * if ($condition) {
-     *     $name = $value;
-     * }
-     *
-     * variant2 $condition != null
-     * $type $name = $value;
-     * 
- * - * . - */ - private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (condition == null) { - builder.declaration(type, name, value); - } else { - builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot()); - - builder.startIf().tree(condition).end(); - builder.startBlock(); - builder.startStatement(); - builder.string(name); - builder.string(" = "); - builder.tree(value); - builder.end(); // statement - builder.end(); // block - } - return builder.getRoot(); - } - - protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { - CodeTreeBuilder nodes = builder.create(); - CodeTreeBuilder arguments = builder.create(); - nodes.startCommaGroup(); - arguments.startCommaGroup(); - boolean empty = true; - for (ActualParameter parameter : current.getParameters()) { - NodeExecutionData executionData = parameter.getSpecification().getExecution(); - if (executionData != null) { - if (executionData.isShortCircuit()) { - nodes.nullLiteral(); - arguments.string(valueName(parameter.getPreviousParameter())); - } - nodes.tree(createAccessChild(executionData, "rootNode")); - arguments.string(valueName(parameter)); - empty = false; - } - } - nodes.end(); - arguments.end(); - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); - - builder.declaration(baseClassName(getModel()), "rootNode", builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_FIND_ROOT).string("this").end()); - builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class)); - builder.string("rootNode"); - builder.startNewArray(getContext().getTruffleTypes().getNodeArray(), null); - builder.tree(nodes.getRoot()); - builder.end(); - if (!empty) { - builder.tree(arguments.getRoot()); - } - builder.end().end(); - } - - private static List findUserConstructors(TypeMirror nodeType) { - List constructors = new ArrayList<>(); - for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) { - if (constructor.getModifiers().contains(PRIVATE)) { - continue; - } - if (isCopyConstructor(constructor)) { - continue; - } - constructors.add(constructor); - } - - if (constructors.isEmpty()) { - constructors.add(new CodeExecutableElement(null, Utils.getSimpleName(nodeType))); - } - - return constructors; - } - - private static ExecutableElement findCopyConstructor(TypeMirror type) { - for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(type).getEnclosedElements())) { - if (constructor.getModifiers().contains(PRIVATE)) { - continue; - } - if (isCopyConstructor(constructor)) { - return constructor; - } - } - - return null; - } - - private static boolean isCopyConstructor(ExecutableElement element) { - if (element.getParameters().size() != 1) { - return false; - } - VariableElement var = element.getParameters().get(0); - TypeElement enclosingType = Utils.findNearestEnclosingType(var); - if (Utils.typeEquals(var.asType(), enclosingType.asType())) { - return true; - } - List types = Utils.getDirectSuperTypes(enclosingType); - for (TypeElement type : types) { - if (!(type instanceof CodeTypeElement)) { - // no copy constructors which are not generated types - return false; - } - - if (Utils.typeEquals(var.asType(), type.asType())) { - return true; - } - } - return false; - } - - @Override - @SuppressWarnings("unchecked") - protected void createChildren(NodeData node) { - List casts = new ArrayList<>(getElement().getEnclosedElements()); - getElement().getEnclosedElements().clear(); - - Map> childTypes = new LinkedHashMap<>(); - for (NodeData nodeChild : node.getEnclosingNodes()) { - NodeCodeGenerator generator = new NodeCodeGenerator(); - childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements()); - } - - if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { - NodeFactoryFactory factory = new NodeFactoryFactory(childTypes); - add(factory, node); - factory.getElement().getEnclosedElements().addAll(casts); - } - } - - private static CodeTree createCastType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { - if (targetType == null) { - return value; - } else if (sourceType != null && !sourceType.needsCastTo(targetType)) { - return value; - } - - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - String targetMethodName; - if (expect) { - targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); - } else { - targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); - } - startCallTypeSystemMethod(builder, typeSystem, targetMethodName); - builder.tree(value); - builder.end().end(); - return builder.getRoot(); - } - - private static CodeTree createExpectType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, CodeTree expression) { - return createCastType(typeSystem, sourceType, targetType, true, expression); - } - - private CodeTree createDeoptimize(CodeTreeBuilder parent) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startStatement(); - builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end(); - builder.end(); - return builder.getRoot(); - } - - private class NodeFactoryFactory extends ClassElementFactory { - - private final Map> childTypes; - private CodeTypeElement generatedNode; - - public NodeFactoryFactory(Map> childElements) { - 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); - return clazz; - } - - @Override - protected void createChildren(NodeData node) { - CodeTypeElement clazz = getElement(); - - Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); - - if (node.needsFactory()) { - NodeBaseFactory factory = new NodeBaseFactory(); - add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); - generatedNode = factory.getElement(); - - createFactoryMethods(node, clazz, createVisibility); - - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isReachable() || specialization.isGeneric()) { - continue; - } - - if (specialization.isPolymorphic() && node.isPolymorphic(context)) { - PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(generatedNode); - add(polymorphicFactory, specialization); - continue; - } - - add(new SpecializedNodeFactory(generatedNode), specialization); - } - - TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getTruffleTypes().getNodeFactoryBase()), node.getNodeType()); - clazz.setSuperClass(nodeFactory); - clazz.add(createNodeFactoryConstructor(node)); - clazz.add(createCreateNodeMethod(node)); -// clazz.add(createGetNodeClassMethod(node)); -// clazz.add(createGetNodeSignaturesMethod()); -// clazz.add(createGetChildrenSignatureMethod(node)); - clazz.add(createGetInstanceMethod(node, createVisibility)); - clazz.add(createInstanceConstant(node, clazz.asType())); - } - - 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); - } - } - - List children = node.getNodeDeclaringChildren(); - if (node.getDeclaringNode() == null && children.size() > 0) { - clazz.add(createGetFactories(node)); - } - - } - - private Element createNodeFactoryConstructor(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), null, factoryClassName(node)); - CodeTreeBuilder builder = method.createBuilder(); - builder.startStatement(); - builder.startCall("super"); - - // node type - builder.typeLiteral(node.getNodeType()); - - // execution signature - builder.startGroup(); - if (node.getChildExecutions().isEmpty()) { - builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); - } else { - builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); - for (NodeExecutionData execution : node.getChildExecutions()) { - builder.typeLiteral(execution.getNodeType()); - } - builder.end(); - } - builder.end(); - - // node signatures - builder.startGroup(); - builder.startNewArray(new ArrayCodeTypeMirror(new ArrayCodeTypeMirror(context.getType(Class.class))), null); - List constructors = findUserConstructors(generatedNode.asType()); - for (ExecutableElement constructor : constructors) { - builder.startGroup(); - if (constructor.getParameters().isEmpty()) { - builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); - } else { - builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null); - for (VariableElement var : constructor.getParameters()) { - builder.typeLiteral(var.asType()); - } - builder.end(); - } - builder.end(); - } - builder.end(); - builder.end(); - - builder.end().end().end(); - return method; - } - - private CodeExecutableElement createCreateNodeMethod(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); - CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); - method.setVarArgs(true); - method.addParameter(arguments); - - CodeTreeBuilder builder = method.createBuilder(); - List signatures = findUserConstructors(generatedNode.asType()); - boolean ifStarted = false; - - for (ExecutableElement element : signatures) { - ifStarted = builder.startIf(ifStarted); - builder.string("arguments.length == " + element.getParameters().size()); - - int index = 0; - for (VariableElement param : element.getParameters()) { - if (Utils.isObject(param.asType())) { - continue; - } - builder.string(" && "); - if (!param.asType().getKind().isPrimitive()) { - builder.string("(arguments[" + index + "] == null || "); - } - builder.string("arguments[" + index + "] instanceof "); - builder.type(Utils.boxType(getContext(), param.asType())); - if (!param.asType().getKind().isPrimitive()) { - builder.string(")"); - } - index++; - } - builder.end(); - builder.startBlock(); - - builder.startReturn().startCall("create"); - index = 0; - for (VariableElement param : element.getParameters()) { - builder.startGroup(); - if (!Utils.isObject(param.asType())) { - builder.string("(").type(param.asType()).string(") "); - } - builder.string("arguments[").string(String.valueOf(index)).string("]"); - builder.end(); - index++; - } - builder.end().end(); - - builder.end(); // block - } - - builder.startElseBlock(); - builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); - builder.doubleQuote("Invalid create signature."); - builder.end().end(); - builder.end(); // else block - return method; - } - - private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { - TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); - TypeMirror returnType = Utils.getDeclaredType(nodeFactoryType, node.getNodeType()); - - CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance"); - if (visibility != null) { - method.getModifiers().add(visibility); - } - method.getModifiers().add(Modifier.STATIC); - - String varName = instanceVarName(node); - - CodeTreeBuilder builder = method.createBuilder(); - builder.startIf(); - builder.string(varName).string(" == null"); - builder.end().startBlock(); - - builder.startStatement(); - builder.string(varName); - builder.string(" = "); - builder.startNew(factoryClassName(node)).end(); - builder.end(); - - builder.end(); - builder.startReturn().string(varName).end(); - return method; - } - - private String instanceVarName(NodeData node) { - if (node.getDeclaringNode() != null) { - return Utils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; - } else { - return "instance"; - } - } - - private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { - String varName = instanceVarName(node); - CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); - var.getModifiers().add(Modifier.PRIVATE); - var.getModifiers().add(Modifier.STATIC); - return var; - } - - private ExecutableElement createGetFactories(NodeData node) { - List children = node.getNodeDeclaringChildren(); - if (node.needsFactory()) { - children.add(node); - } - - List nodeTypesList = new ArrayList<>(); - TypeMirror prev = null; - boolean allSame = true; - for (NodeData child : children) { - nodeTypesList.add(child.getNodeType()); - if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) { - allSame = false; - } - prev = child.getNodeType(); - } - TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); - - Types types = getContext().getEnvironment().getTypeUtils(); - TypeMirror factoryType = getContext().getType(NodeFactory.class); - TypeMirror baseType; - if (allSame) { - baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); - } else { - baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); - } - TypeMirror listType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType); - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); - - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn(); - builder.startStaticCall(getContext().getType(Arrays.class), "asList"); - - for (NodeData child : children) { - builder.startGroup(); - NodeData childNode = child; - List factories = new ArrayList<>(); - while (childNode.getDeclaringNode() != null) { - factories.add(childNode); - childNode = childNode.getDeclaringNode(); - } - Collections.reverse(factories); - for (NodeData nodeData : factories) { - builder.string(factoryClassName(nodeData)).string("."); - } - builder.string("getInstance()"); - builder.end(); - } - builder.end(); - builder.end(); - return method; - } - - private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { - List constructors = findUserConstructors(generatedNode.asType()); - for (ExecutableElement constructor : constructors) { - 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().isEmpty()) { - body.nullLiteral(); - } else { - body.startCall(nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME); - for (VariableElement var : method.getParameters()) { - body.string(var.getSimpleName().toString()); - } - body.end(); - } - body.end(); - return method; - } - - } - - private class NodeBaseFactory extends ClassElementFactory { - - @Override - protected CodeTypeElement create(SpecializationData specialization) { - NodeData node = specialization.getNode(); - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); - clazz.getImplements().add(context.getTruffleTypes().getDslNode()); - - for (NodeChildData child : node.getChildren()) { - clazz.add(createChildField(child)); - - if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { - ExecutableElement getter = (ExecutableElement) child.getAccessElement(); - CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); - method.getModifiers().remove(Modifier.ABSTRACT); - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn().string("this.").string(child.getName()).end(); - clazz.add(method); - } - } - - for (NodeFieldData field : node.getFields()) { - if (!field.isGenerated()) { - continue; - } - - clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), field.getType(), field.getName())); - if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { - CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), field.getGetter()); - method.getModifiers().remove(Modifier.ABSTRACT); - method.createBuilder().startReturn().string("this.").string(field.getName()).end(); - clazz.add(method); - } - } - - for (String assumption : node.getAssumptions()) { - clazz.add(createAssumptionField(assumption)); - } - - createConstructors(node, clazz); - - return clazz; - } - - @Override - protected void createChildren(SpecializationData specialization) { - NodeData node = specialization.getNode(); - CodeTypeElement clazz = getElement(); - - SpecializationGroup rootGroup = createSpecializationGroups(node); - - if (node.needsRewrites(context)) { - if (node.isPolymorphic(context)) { - - CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0"); - var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); - clazz.add(var); - - CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getPolymorphicSpecialization()); - clazz.add(genericCachedExecute); - - } - - for (CodeExecutableElement method : createImplicitChildrenAccessors()) { - clazz.add(method); - } - clazz.add(createInfoMessage(node)); - clazz.add(createMonomorphicRewrite()); - clazz.add(createCreateSpecializationMethod(node, rootGroup)); - } - - clazz.add(createAdoptChildren0()); - clazz.add(createGetMetadata0(true)); - clazz.add(createUpdateTypes0()); - clazz.add(createGetNext()); - } - - private Element createGetNext() { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(Node.class), "getNext0"); - CodeTreeBuilder builder = method.createBuilder(); - NodeData node = getModel().getNode(); - - if (node.isPolymorphic(context)) { - builder.startReturn().string("next0").end(); - } else { - builder.returnNull(); - } - - return method; - } - - protected final CodeExecutableElement createUpdateTypes0() { - ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(void.class), "updateTypes0"); - method.getParameters().add(new CodeVariableElement(classArray, "types")); - - if (getModel().isPolymorphic()) { - CodeTreeBuilder builder = method.createBuilder(); - - int index = 0; - for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) { - String fieldName = polymorphicTypeName(execution); - - builder.startStatement(); - builder.string(fieldName).string(" = ").string("types[").string(String.valueOf(index)).string("]"); - builder.end(); - index++; - } - } - - return method; - } - - protected final CodeExecutableElement createGetMetadata0(boolean empty) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getDslMetadata(), "getMetadata0"); - if (empty) { - method.createBuilder().startReturn().staticReference(context.getTruffleTypes().getDslMetadata(), "NONE").end(); - } else { - method.createBuilder().startReturn().string(METADATA_FIELD_NAME).end(); - } - return method; - } - - private CodeExecutableElement createAdoptChildren0() { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(void.class), "adoptChildren0"); - method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "other")); - method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "newNext")); - NodeData node = getModel().getNode(); - CodeTreeBuilder builder = method.createBuilder(); - List executions = node.getChildExecutions(); - - if (executions.size() > 0) { - builder.startIf().string("other == null").end().startBlock(); - for (NodeExecutionData execution : executions) { - builder.startStatement().tree(createAccessChild(execution, "this")).string(" = null").end(); - } - builder.end().startElseBlock(); - - String access; - if (executions.size() > 1) { - builder.declaration(baseClassName(node), "otherCast", builder.create().cast(baseClassName(node)).string("other")); - access = "otherCast"; - } else { - assert executions.size() == 1; - access = "((" + baseClassName(node) + ") other)"; - } - for (NodeExecutionData execution : executions) { - builder.startStatement().tree(createAccessChild(execution, "this")).string(" = ").tree(createAccessChild(execution, access)).end(); - } - - builder.end(); - } - - if (getModel().getNode().isPolymorphic(context)) { - builder.startIf().string("newNext == null").end().startBlock(); - builder.statement("this.next0 = null"); - builder.end().startElseBlock(); - builder.statement("this.next0 = (" + baseClassName(getModel().getNode()) + ") newNext"); - builder.end(); - } - - return method; - } - - private List createImplicitChildrenAccessors() { - NodeData node = getModel().getNode(); - List> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null); - List> expectTypes = new ArrayList<>(prototype); - - for (ExecutableTypeData executableType : node.getExecutableTypes()) { - for (int i = 0; i < executableType.getEvaluatedCount(); i++) { - ActualParameter parameter = executableType.getSignatureParameter(i); - if (i >= expectTypes.size()) { - break; - } - Set types = expectTypes.get(i); - if (types == null) { - types = new TreeSet<>(); - expectTypes.set(i, types); - } - types.add(parameter.getTypeSystemType()); - } - } - - List methods = new ArrayList<>(); - List> visitedList = new ArrayList<>(prototype); - for (SpecializationData spec : node.getSpecializations()) { - int signatureIndex = -1; - for (ActualParameter param : spec.getParameters()) { - if (!param.getSpecification().isSignature()) { - continue; - } - signatureIndex++; - Set visitedTypeData = visitedList.get(signatureIndex); - if (visitedTypeData == null) { - visitedTypeData = new TreeSet<>(); - visitedList.set(signatureIndex, visitedTypeData); - } - - if (visitedTypeData.contains(param.getTypeSystemType())) { - continue; - } - visitedTypeData.add(param.getTypeSystemType()); - - Set expect = expectTypes.get(signatureIndex); - if (expect == null) { - expect = Collections.emptySet(); - } - - methods.addAll(createExecuteChilds(param, expect)); - } - } - return methods; - } - - private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) { - CodeTreeBuilder builder = parent.create(); - builder.staticReference(getContext().getTruffleTypes().getTruffleOptions(), name); - return builder.getRoot(); - } - - private Element createInfoMessage(NodeData node) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), CREATE_INFO); - method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message")); - addInternalValueParameters(method, node.getGenericSpecialization(), false, false); - - CodeTreeBuilder builder = method.createBuilder(); - - builder.startIf().tree(truffleBooleanOption(builder, TruffleTypes.OPTION_DETAILED_REWRITE_REASONS)).end(); - builder.startBlock(); - - builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end(); - builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end(); - - String sep = null; - for (ActualParameter parameter : node.getGenericSpecialization().getSignatureParameters()) { - builder.startStatement(); - builder.string("builder"); - if (sep != null) { - builder.startCall(".append").doubleQuote(sep).end(); - } - builder.startCall(".append").doubleQuote(parameter.getLocalName()).end(); - builder.startCall(".append").doubleQuote(" = ").end(); - builder.startCall(".append").string(parameter.getLocalName()).end(); - builder.end(); - - if (!Utils.isPrimitive(parameter.getType())) { - builder.startIf().string(parameter.getLocalName() + " != null").end(); - builder.startBlock(); - } - builder.startStatement(); - if (Utils.isPrimitive(parameter.getType())) { - builder.startCall("builder.append").doubleQuote(" (" + Utils.getSimpleName(parameter.getType()) + ")").end(); - } else { - builder.startCall("builder.append").doubleQuote(" (").end(); - builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end(); - builder.startCall(".append").doubleQuote(")").end(); - } - builder.end(); - if (!Utils.isPrimitive(parameter.getType())) { - builder.end(); - } - - sep = ", "; - } - - builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end(); - builder.startReturn().string("builder.toString()").end(); - - builder.end(); - builder.startElseBlock(); - builder.startReturn().string("message").end(); - builder.end(); - - return method; - } - - private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) { - CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), EXECUTE_CHAINED); - addInternalValueParameters(cachedExecute, polymorph, true, false); - - ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); - boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); - if (sourceThrowsUnexpected && sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) { - sourceThrowsUnexpected = false; - } - if (sourceThrowsUnexpected) { - cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); - } - return cachedExecute; - - } - - private void createConstructors(NodeData node, CodeTypeElement clazz) { - List constructors = findUserConstructors(node.getNodeType()); - ExecutableElement sourceSectionConstructor = null; - if (constructors.isEmpty()) { - clazz.add(createUserConstructor(clazz, null)); - } else { - for (ExecutableElement constructor : constructors) { - clazz.add(createUserConstructor(clazz, constructor)); - if (NodeParser.isSourceSectionConstructor(context, constructor)) { - sourceSectionConstructor = constructor; - } - } - } - if (node.needsRewrites(getContext())) { - ExecutableElement copyConstructor = findCopyConstructor(node.getNodeType()); - clazz.add(createCopyConstructor(clazz, copyConstructor, sourceSectionConstructor)); - } - } - - private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { - CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); - CodeTreeBuilder builder = method.createBuilder(); - - NodeData node = getModel().getNode(); - - if (superConstructor != null) { - for (VariableElement param : superConstructor.getParameters()) { - method.getParameters().add(CodeVariableElement.clone(param)); - } - } - - if (superConstructor != null) { - builder.startStatement().startSuperCall(); - for (VariableElement param : superConstructor.getParameters()) { - builder.string(param.getSimpleName().toString()); - } - builder.end().end(); - } - - for (VariableElement var : type.getFields()) { - if (var.getModifiers().contains(STATIC)) { - continue; - } - NodeChildData child = node.findChild(var.getSimpleName().toString()); - - if (child != null) { - method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); - } else { - method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); - } - - builder.startStatement(); - String fieldName = var.getSimpleName().toString(); - - CodeTree init = createStaticCast(builder, child, fieldName); - - builder.string("this.").string(fieldName).string(" = ").tree(init); - builder.end(); - } - return method; - } - - private CodeTree createStaticCast(CodeTreeBuilder parent, NodeChildData child, String fieldName) { - NodeData parentNode = getModel().getNode(); - if (child != null) { - CreateCastData createCast = parentNode.findCast(child.getName()); - if (createCast != null) { - return createTemplateMethodCall(parent, null, parentNode.getGenericSpecialization(), createCast, null, fieldName); - } - } - return CodeTreeBuilder.singleString(fieldName); - } - - private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) { - CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); - CodeTreeBuilder builder = method.createBuilder(); - method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); - - if (superConstructor != null) { - builder.startStatement().startSuperCall().string("copy").end().end(); - } else if (sourceSectionConstructor != null) { - builder.startStatement().startSuperCall().string("copy.getSourceSection()").end().end(); - } - - for (VariableElement var : type.getFields()) { - if (var.getModifiers().contains(STATIC) || !var.getModifiers().contains(FINAL)) { - continue; - } - final String varName = var.getSimpleName().toString(); - final TypeMirror varType = var.asType(); - if (Utils.isAssignable(varType, getContext().getTruffleTypes().getNodeArray())) { - CodeTree size = builder.create().string("copy.", varName, ".length").getRoot(); - builder.startStatement().string("this.").string(varName).string(" = ").startNewArray((ArrayType) varType, size).end().end(); - } else { - builder.startStatement().string("this.", varName, " = copy.", varName).end(); - } - } - - return method; - } - - private CodeVariableElement createAssumptionField(String assumption) { - CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); - var.getModifiers().add(Modifier.FINAL); - return var; - } - - private CodeVariableElement createChildField(NodeChildData child) { - TypeMirror type = child.getNodeType(); - CodeVariableElement var = new CodeVariableElement(type, child.getName()); - var.getModifiers().add(Modifier.PROTECTED); - - DeclaredType annotationType; - if (child.getCardinality() == Cardinality.MANY) { - var.getModifiers().add(Modifier.FINAL); - annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); - } else { - annotationType = getContext().getTruffleTypes().getChildAnnotation(); - } - - var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); - return var; - } - - private SpecializationGroup createSpecializationGroups(final NodeData node) { - List specializations = node.getSpecializations(); - List filteredSpecializations = new ArrayList<>(); - for (SpecializationData current : specializations) { - if (current.isUninitialized() || current.isPolymorphic() || !current.isReachable()) { - continue; - } - filteredSpecializations.add(current); - } - - return SpecializationGroup.create(filteredSpecializations); - } - - protected final CodeExecutableElement createExecuteUninitialized() { - NodeData node = getModel().getNode(); - SpecializationData generic = node.getGenericSpecialization(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), generic.getReturnType().getType(), EXECUTE_UNINITIALIZED); - addInternalValueParameters(method, generic, true, false); - CodeTreeBuilder builder = method.createBuilder(); - - CodeTreeBuilder createSpecializationCall = builder.create(); - createSpecializationCall.startCall(SPECIALIZE); - addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null); - createSpecializationCall.end(); - builder.declaration(baseClassName(node), "newNode", createSpecializationCall); - - if (generic.isReachable()) { - builder.startIf().string("newNode == null").end().startBlock(); - - builder.startIf().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "inInterpreter").end().end().startBlock(); - builder.statement("containsFallback = true"); - builder.end(); - builder.tree(createGenericInvoke(builder, generic, generic)); - builder.end(); - builder.startElseBlock(); - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - } - - builder.startReturn(); - builder.startStaticCall(context.getTruffleTypes().getDslShare(), "rewriteUninitialized").string("this").string("newNode").end(); - builder.string(".").startCall(EXECUTE_CHAINED); - addInternalValueParameterNames(builder, generic, generic, null, true, null); - builder.end(); - builder.end(); - - if (generic.isReachable()) { - builder.end(); - } - - return method; - } - - private CodeTree createInfoCall(CodeTreeBuilder parent, SpecializationData specialization, String reason) { - CodeTreeBuilder builder = parent.create(); - builder.startCall(CREATE_INFO).string(reason); - addInternalValueParameterNames(builder, specialization, specialization, null, false, null); - builder.end(); - return builder.getRoot(); - } - - private CodeExecutableElement createMonomorphicRewrite() { - NodeData node = getModel().getNode(); - - SpecializationData generic = node.getGenericSpecialization(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), generic.getReturnType().getType(), REWRITE); - addInternalValueParameters(method, generic, true, false); - method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); - - CodeTreeBuilder builder = method.createBuilder(); - - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end(); - String baseClassName = baseClassName(getModel().getNode()); - CodeTreeBuilder createSpecializationCall = builder.create(); - createSpecializationCall.startCall(SPECIALIZE); - addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null); - createSpecializationCall.end(); - builder.declaration(baseClassName, "newNode", createSpecializationCall); - - builder.startIf().string("newNode == null").end().startBlock(); - builder.startStatement(); - String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization()); - builder.string("newNode = ").startNew(uninitializedName).string("this").end(); - builder.end(); - if (node.isFallbackReachable()) { - builder.startStatement().string("((", uninitializedName, ") newNode).containsFallback = true").end(); - } - builder.end(); - - builder.startStatement(); - builder.type(getContext().getType(String.class)).string(" message = ").tree(createInfoCall(builder, generic, "reason")); - builder.end(); - - builder.declaration(baseClassName, "returnNode", - builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().getRoot()); - builder.startIf().string("returnNode == null").end().startBlock(); - builder.tree(createRewritePolymorphic(builder, node, "this")); - builder.end(); - - builder.startReturn(); - builder.startCall("returnNode", EXECUTE_CHAINED); - addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, null); - builder.end(); - builder.end(); - - return method; - } - - private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node, String currentNode) { - String polyClassName = nodePolymorphicClassName(node); - CodeTreeBuilder builder = parent.create(); - - builder.startStatement().string("returnNode = "); - builder.startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE_TO_POLYMORHPIC); - builder.string("this"); - builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().getRoot()); - builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().getRoot()); - builder.startGroup().cast(baseClassName(node)).startCall("copy").end().end(); - builder.string("newNode"); - builder.string("message"); - builder.end(); - builder.end(); - - return builder.getRoot(); - } - - private CodeExecutableElement createCreateSpecializationMethod(NodeData node, SpecializationGroup group) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(Utils.getPackageName(node.getTemplateType()), baseClassName(node)), - SPECIALIZE); - if (!node.needsFrame(getContext())) { - method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath())); - } - - addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(getContext()), false); - final CodeTreeBuilder builder = method.createBuilder(); - builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, new CodeBlock() { - - public CodeTree create(CodeTreeBuilder b, SpecializationData current) { - return createCreateSpecializationMethodBody0(builder, current); - } - }, null, false, true, false, true)); - - emitUnreachableSpecializations(builder, node); - - return method; - } - - protected CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (current.isGeneric()) { - builder.startReturn().nullLiteral().end(); - } else { - String className = nodeSpecializationClassName(current); - if (!current.getExcludedBy().isEmpty()) { - builder.startIf().string("!").startStaticCall(context.getTruffleTypes().getDslShare(), "isExcluded"); - builder.string("this").string(nodeSpecializationClassName(current), ".", METADATA_FIELD_NAME).end().end(); - builder.startBlock(); - } - - if (current.getNode().getGenericSpecialization().isReachable()) { - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - } - builder.startReturn(); - builder.cast(baseClassName(getModel().getNode())); - builder.startGroup().startCall(className, FACTORY_METHOD_NAME).string("this"); - for (ActualParameter param : current.getSignatureParameters()) { - NodeChildData child = param.getSpecification().getExecution().getChild(); - List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); - if (types.size() > 1) { - builder.string(implicitTypeName(param)); - } - } - builder.end().end(); - builder.end(); - - if (!current.getExcludedBy().isEmpty()) { - builder.end(); - } - } - return builder.getRoot(); - - } - - private void emitUnreachableSpecializations(final CodeTreeBuilder builder, NodeData node) { - for (SpecializationData current : node.getSpecializations()) { - if (current.isReachable()) { - continue; - } - builder.string("// unreachable ").string(current.getId()).newLine(); - } - } - - protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final CodeBlock guardedblock, - final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts, final boolean castForGuardsOnly) { - return guard(outerParent, source, group, new CodeBlock() { - - public CodeTree create(CodeTreeBuilder parent, Integer ifCount) { - CodeTreeBuilder builder = parent.create(); - - if (group.getSpecialization() != null) { - builder.tree(guardedblock.create(builder, group.getSpecialization())); - - assert group.getChildren().isEmpty() : "missed a specialization"; - - } else { - for (SpecializationGroup childGroup : group.getChildren()) { - builder.tree(createExecuteTree(builder, source, childGroup, guardedblock, null, false, emitAssumptions, typedCasts, castForGuardsOnly)); - } - } - - return builder.getRoot(); - } - }, elseBlock, forceElse, emitAssumptions, typedCasts, castForGuardsOnly); - } - - private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, CodeBlock bodyBlock, CodeTree elseBlock, boolean forceElse, - boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) { - CodeTreeBuilder builder = parent.create(); - - int ifCount = emitGuards(builder, source, group, emitAssumptions, typedCasts, castForGuardsOnly); - - if (isReachableGroup(group, ifCount)) { - builder.tree(bodyBlock.create(builder, ifCount)); - } - - builder.end(ifCount); - - if (elseBlock != null) { - if (ifCount > 0 || forceElse) { - builder.tree(elseBlock); - } - } - - return builder.getRoot(); - } - - private boolean isReachableGroup(SpecializationGroup group, int ifCount) { - if (ifCount != 0) { - return true; - } - SpecializationGroup previous = group.getPreviousGroup(); - if (previous == null || previous.findElseConnectableGuards().isEmpty()) { - return true; - } - - /* - * Hacky else case. In this case the specialization is not reachable due to previous - * else branch. This is only true if the minimum state is not checked. - */ - if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && - (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { - return false; - } - - return true; - } - - private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) { - NodeData node = source.getNode(); - - CodeTreeBuilder guardsBuilder = builder.create(); - CodeTreeBuilder castBuilder = builder.create(); - CodeTreeBuilder guardsCastBuilder = builder.create(); - - String guardsAnd = ""; - String guardsCastAnd = ""; - - if (emitAssumptions) { - for (String assumption : group.getAssumptions()) { - guardsBuilder.string(guardsAnd); - guardsBuilder.string("this"); - guardsBuilder.string(".").string(assumption).string(".isValid()"); - guardsAnd = " && "; - } - } - - for (TypeGuard typeGuard : group.getTypeGuards()) { - ActualParameter valueParam = source.getSignatureParameter(typeGuard.getSignatureIndex()); - - if (valueParam == null) { - /* - * If used inside a execute evaluated method then the value param may not exist. - * In that case we assume that the value is executed generic or of the current - * specialization. - */ - if (group.getSpecialization() != null) { - valueParam = group.getSpecialization().getSignatureParameter(typeGuard.getSignatureIndex()); - } else { - valueParam = node.getGenericSpecialization().getSignatureParameter(typeGuard.getSignatureIndex()); - } - } - - NodeExecutionData execution = valueParam.getSpecification().getExecution(); - CodeTree implicitGuard = createTypeGuard(guardsBuilder, execution, valueParam, typeGuard.getType(), typedCasts); - if (implicitGuard != null) { - guardsBuilder.string(guardsAnd); - guardsBuilder.tree(implicitGuard); - guardsAnd = " && "; - } - - CodeTree implicitGetType = null; - if (castForGuardsOnly) { - implicitGetType = createGetImplicitType(builder, execution, valueParam, typeGuard.getType()); - } - - boolean performCast = true; - if (castForGuardsOnly) { - // if cast for guards we just cast if the type guard is used inside a guard. - performCast = group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard); - } - - if (performCast) { - CodeTree cast = createCast(castBuilder, execution, valueParam, typeGuard.getType(), typedCasts); - if (cast != null) { - castBuilder.tree(cast); - } - } - if (implicitGetType != null) { - castBuilder.tree(implicitGetType); - } - } - List elseGuards = group.findElseConnectableGuards(); - - for (GuardExpression guard : group.getGuards()) { - if (elseGuards.contains(guard)) { - continue; - } - - if (needsTypeGuard(source, group, guard)) { - guardsCastBuilder.tree(createMethodGuard(builder, guardsCastAnd, source, guard)); - guardsCastAnd = " && "; - } else { - guardsBuilder.tree(createMethodGuard(builder, guardsAnd, source, guard)); - guardsAnd = " && "; - } - } - - int ifCount = startGuardIf(builder, guardsBuilder, 0, elseGuards); - builder.tree(castBuilder.getRoot()); - ifCount = startGuardIf(builder, guardsCastBuilder, ifCount, elseGuards); - return ifCount; - } - - private int startGuardIf(CodeTreeBuilder builder, CodeTreeBuilder conditionBuilder, int ifCount, List elseGuard) { - int newIfCount = ifCount; - - if (!conditionBuilder.isEmpty()) { - if (ifCount == 0 && !elseGuard.isEmpty()) { - builder.startElseIf(); - } else { - builder.startIf(); - } - builder.tree(conditionBuilder.getRoot()); - builder.end().startBlock(); - newIfCount++; - } else if (ifCount == 0 && !elseGuard.isEmpty()) { - builder.startElseBlock(); - newIfCount++; - } - return newIfCount; - } - - private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) { - int signatureIndex = 0; - for (ActualParameter parameter : guard.getResolvedGuard().getParameters()) { - if (!parameter.getSpecification().isSignature()) { - continue; - } - - TypeGuard typeGuard = group.findTypeGuard(signatureIndex); - if (typeGuard != null) { - TypeData requiredType = typeGuard.getType(); - - ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); - if (sourceParameter == null) { - sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName()); - } - - if (Utils.needsCastTo(sourceParameter.getType(), requiredType.getPrimitiveType())) { - return true; - } - } - - signatureIndex++; - } - return false; - } - - private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeExecutionData execution, ActualParameter source, TypeData targetType, boolean typedCasts) { - NodeData node = execution.getChild().getNodeData(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - - TypeData sourceType = source.getTypeSystemType(); - - if (!sourceType.needsCastTo(targetType)) { - return null; - } - - builder.startGroup(); - - if (execution.isShortCircuit()) { - ActualParameter shortCircuit = source.getPreviousParameter(); - assert shortCircuit != null; - builder.string("("); - builder.string("!").string(valueName(shortCircuit)); - builder.string(" || "); - } - - String castMethodName; - String castTypeName = null; - List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); - if (types.size() > 1) { - castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType); - if (typedCasts) { - castTypeName = implicitTypeName(source); - } - } else { - castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType); - } - - startCallTypeSystemMethod(builder, node.getTypeSystem(), castMethodName); - builder.string(valueName(source)); - if (castTypeName != null) { - builder.string(castTypeName); - } - builder.end().end(); // call - - if (execution.isShortCircuit()) { - builder.string(")"); - } - - builder.end(); // group - - return builder.getRoot(); - } - - // TODO merge redundancies with #createTypeGuard - private CodeTree createCast(CodeTreeBuilder parent, NodeExecutionData execution, ActualParameter source, TypeData targetType, boolean typedCasts) { - NodeData node = execution.getChild().getNodeData(); - TypeData sourceType = source.getTypeSystemType(); - - if (!sourceType.needsCastTo(targetType)) { - return null; - } - - CodeTree condition = null; - if (execution.isShortCircuit()) { - ActualParameter shortCircuit = source.getPreviousParameter(); - assert shortCircuit != null; - condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); - } - - String castMethodName; - String castTypeName = null; - List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); - if (types.size() > 1) { - castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType); - if (typedCasts) { - castTypeName = implicitTypeName(source); - } - } else { - castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); - } - - List args = new ArrayList<>(); - args.add(CodeTreeBuilder.singleString(valueName(source))); - if (castTypeName != null) { - args.add(CodeTreeBuilder.singleString(castTypeName)); - } - - CodeTree cast = createCallTypeSystemMethod(parent, node, castMethodName, args.toArray(new CodeTree[0])); - - CodeTreeBuilder builder = parent.create(); - builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, cast)); - - return builder.getRoot(); - } - - private CodeTree createGetImplicitType(CodeTreeBuilder parent, NodeExecutionData execution, ActualParameter source, TypeData targetType) { - CodeTree condition = null; - if (execution.isShortCircuit()) { - ActualParameter shortCircuit = source.getPreviousParameter(); - assert shortCircuit != null; - condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); - } - - CodeTreeBuilder builder = parent.create(); - List types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); - if (types.size() > 1) { - CodeTree castType = createCallTypeSystemMethod(parent, execution.getChild().getNodeData(), TypeSystemCodeGenerator.getImplicitClass(targetType), - CodeTreeBuilder.singleString(valueName(source))); - builder.tree(createLazyAssignment(builder, implicitTypeName(source), getContext().getType(Class.class), condition, castType)); - } - return builder.getRoot(); - } - - private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardExpression guard) { - CodeTreeBuilder builder = parent.create(); - builder.string(prefix); - if (guard.isNegated()) { - builder.string("!"); - } - builder.tree(createTemplateMethodCall(builder, null, source, guard.getResolvedGuard(), null)); - return builder.getRoot(); - } - - protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - - if (current.getMethod() == null) { - emitEncounteredSynthetic(builder, current); - } else { - builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); - } - - return encloseThrowsWithFallThrough(current, builder.getRoot()); - } - - private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { - if (current.getExceptions().isEmpty()) { - return tree; - } - CodeTreeBuilder builder = new CodeTreeBuilder(null); - - builder.startTryBlock(); - builder.tree(tree); - for (SpecializationThrowsData exception : current.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); - builder.tree(createDeoptimize(builder)); - builder.tree(createCallRewriteMonomorphic(builder, false, current.getNode().getGenericSpecialization().getReturnType().getTypeSystemType(), current, null, - "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); - } - builder.end(); - - return builder.getRoot(); - } - - protected CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) { - TypeData type = executable.getType(); - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - NodeData node = specialization.getNode(); - - TypeData primaryType = castExecutable.getType(); - - boolean needsTry = castExecutable.hasUnexpectedValue(getContext()); - boolean returnVoid = type.isVoid(); - - List executeParameters = new ArrayList<>(); - for (ActualParameter sourceParameter : executable.getSignatureParameters()) { - ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName()); - if (targetParameter != null) { - executeParameters.add(targetParameter); - } - } - - // execute names are enforced no cast - String[] executeParameterNames = new String[executeParameters.size()]; - for (int i = 0; i < executeParameterNames.length; i++) { - executeParameterNames[i] = valueName(executeParameters.get(i)); - } - - builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null)); - boolean hasUnexpected = executable.hasUnexpectedValue(getContext()); - - CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null, executeParameterNames); - if (needsTry) { - if (!returnVoid) { - builder.declaration(primaryType.getPrimitiveType(), "value"); - } - builder.startTryBlock(); - - if (returnVoid) { - builder.statement(primaryExecuteCall); - } else { - builder.startStatement(); - builder.string("value = "); - builder.tree(primaryExecuteCall); - builder.end(); - } - - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - if (returnVoid) { - builder.string("// ignore").newLine(); - } else { - builder.startReturn(); - builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), hasUnexpected, executable.getType(), - CodeTreeBuilder.singleString("ex.getResult()"))); - builder.end(); - } - builder.end(); - - if (!returnVoid) { - builder.startReturn(); - builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), CodeTreeBuilder.singleString("value"))); - builder.end(); - } - } else { - if (returnVoid) { - builder.statement(primaryExecuteCall); - } else { - builder.startReturn(); - builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), primaryExecuteCall)); - builder.end(); - } - } - - return builder.getRoot(); - } - - protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, boolean hasUnexpected, TypeData exepctedType, CodeTree value) { - return createCastType(node.getTypeSystem(), sourceType, exepctedType, hasUnexpected, value); - } - - protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List targetParameters, - ActualParameter unexpectedParameter) { - CodeTreeBuilder builder = parent.create(); - for (ActualParameter targetParameter : targetParameters) { - if (!targetParameter.getSpecification().isSignature()) { - continue; - } - NodeExecutionData execution = targetParameter.getSpecification().getExecution(); - CodeTree executionExpressions = createExecuteChild(builder, execution, sourceExecutable, targetParameter, unexpectedParameter); - CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, specialization, sourceExecutable, targetParameter, execution.isShortCircuit(), unexpectedParameter); - CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, specialization, targetParameter, unexpectedParameter); - - if (shortCircuitTree == executionExpressions) { - if (containsNewLine(executionExpressions)) { - builder.declaration(targetParameter.getType(), valueName(targetParameter)); - builder.tree(shortCircuitTree); - } else { - builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end(); - } - } else { - builder.tree(shortCircuitTree); - } - - } - return builder.getRoot(); - } - - private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) { - ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(getContext(), type); - if (targetExecutable == null) { - targetExecutable = execution.getChild().findAnyGenericExecutableType(getContext()); - } - return targetExecutable; - } - - private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, ActualParameter targetParameter, - ActualParameter unexpectedParameter) { - SpecializationData specialization = getModel(); - TreeSet possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter); - if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null && possiblePolymorphicTypes.size() > 1) { - - CodeTreeBuilder builder = parent.create(); - - boolean elseIf = false; - for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) { - if (possiblePolymoprhicType.isGeneric()) { - continue; - } - elseIf = builder.startIf(elseIf); - - ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; - builder.string(polymorphicTypeName(targetParameter.getSpecification().getExecution())).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType()); - builder.end().startBlock(); - builder.startStatement(); - builder.tree(createExecuteChildExpression(parent, execution, sourceType, new ActualParameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null)); - builder.end(); - builder.end(); - } - - builder.startElseBlock(); - builder.startStatement().tree(createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter)).end(); - builder.end(); - - return builder.getRoot(); - } else { - return createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter); - } - } - - protected final List getImplicitTypeParameters(SpecializationData model) { - List parameter = new ArrayList<>(); - for (ActualParameter param : model.getSignatureParameters()) { - NodeChildData child = param.getSpecification().getExecution().getChild(); - List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); - if (types.size() > 1) { - parameter.add(param); - } - } - return parameter; - } - - protected final TreeSet lookupPolymorphicTargetTypes(ActualParameter param) { - SpecializationData specialization = getModel(); - TreeSet possiblePolymorphicTypes = new TreeSet<>(); - for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) { - if (!otherSpecialization.isSpecialized()) { - continue; - } - ActualParameter otherParameter = otherSpecialization.findParameter(param.getLocalName()); - if (otherParameter != null) { - possiblePolymorphicTypes.add(otherParameter.getTypeSystemType()); - } - } - return possiblePolymorphicTypes; - } - - private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, ActualParameter param, ActualParameter unexpectedParameter) { - CodeTreeBuilder builder = parent.create(); - ActualParameter sourceParameter = sourceExecutable.findParameter(param.getLocalName()); - String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null); - if (childExecuteName != null) { - builder.string(valueName(param)); - builder.string(" = "); - builder.startCall(childExecuteName); - - for (ActualParameter parameters : sourceExecutable.getParameters()) { - if (parameters.getSpecification().isSignature()) { - continue; - } - builder.string(parameters.getLocalName()); - } - - if (sourceParameter != null) { - builder.string(valueNameEvaluated(sourceParameter)); - } - - builder.string(implicitTypeName(param)); - - builder.end(); - } else { - List sourceTypes = execution.getChild().getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); - TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; - if (sourceTypes.size() > 1) { - builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType)); - } else { - builder.tree(createExecuteChildExpression(parent, execution, expectType, param, unexpectedParameter, null)); - } - } - return builder.getRoot(); - } - - private String createExecuteChildMethodName(ActualParameter param, boolean expect) { - NodeExecutionData execution = param.getSpecification().getExecution(); - NodeChildData child = execution.getChild(); - if (child.getExecuteWith().size() > 0) { - return null; - } - List sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); - if (sourceTypes.size() <= 1) { - return null; - } - String prefix = expect ? "expect" : "execute"; - String suffix = execution.getIndex() > -1 ? String.valueOf(execution.getIndex()) : ""; - return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + suffix; - } - - private List createExecuteChilds(ActualParameter param, Set expectTypes) { - CodeExecutableElement executeMethod = createExecuteChild(param, null); - if (executeMethod == null) { - return Collections.emptyList(); - } - List childs = new ArrayList<>(); - childs.add(executeMethod); - - for (TypeData expectType : expectTypes) { - CodeExecutableElement method = createExecuteChild(param, expectType); - if (method != null) { - childs.add(method); - } - } - return childs; - } - - private CodeExecutableElement createExecuteChild(ActualParameter param, TypeData expectType) { - String childExecuteName = createExecuteChildMethodName(param, expectType != null); - if (childExecuteName == null) { - return null; - } - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName); - method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException()); - method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); - if (expectType != null) { - method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param))); - } - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param))); - - CodeTreeBuilder builder = method.createBuilder(); - builder.declaration(param.getType(), valueName(param)); - builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType)); - builder.startReturn().string(valueName(param)).end(); - - return method; - } - - private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, ActualParameter targetParameter, TypeData expectType) { - CodeTreeBuilder builder = parent.create(); - NodeData node = getModel().getNode(); - NodeExecutionData execution = targetParameter.getSpecification().getExecution(); - List sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType()); - boolean elseIf = false; - int index = 0; - for (TypeData sourceType : sourceTypes) { - if (index < sourceTypes.size() - 1) { - elseIf = builder.startIf(elseIf); - builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType()); - builder.end(); - builder.startBlock(); - } else { - builder.startElseBlock(); - } - - ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(getContext(), sourceType); - if (implictExecutableTypeData == null) { - /* - * For children with executeWith.size() > 0 an executable type may not exist so - * use the generic executable type which is guaranteed to exist. An expect call - * is inserted automatically by #createExecuteExpression. - */ - implictExecutableTypeData = execution.getChild().getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), execution.getChild().getExecuteWith().size()); - } - - ImplicitCastData cast = execution.getChild().getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType()); - CodeTree execute = createExecuteChildExpression(builder, execution, expectType, targetParameter, null, cast); - builder.statement(execute); - builder.end(); - index++; - } - return builder.getRoot(); - } - - private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData execution, TypeData sourceParameterType, ActualParameter targetParameter, - ActualParameter unexpectedParameter, ImplicitCastData cast) { - // assignments: targetType <- castTargetType <- castSourceType <- sourceType - TypeData sourceType = sourceParameterType; - TypeData targetType = targetParameter.getTypeSystemType(); - TypeData castSourceType = targetType; - TypeData castTargetType = targetType; - - if (cast != null) { - castSourceType = cast.getSourceType(); - castTargetType = cast.getTargetType(); - } - - CodeTree expression; - if (sourceType == null) { - ExecutableTypeData targetExecutable = resolveExecutableType(execution, castSourceType); - expression = createExecuteChildExpression(parent, execution, targetExecutable, unexpectedParameter); - sourceType = targetExecutable.getType(); - } else { - expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); - } - - // target = expectTargetType(implicitCast(expectCastSourceType(source))) - TypeSystemData typeSystem = execution.getChild().getNodeData().getTypeSystem(); - expression = createExpectType(typeSystem, sourceType, castSourceType, expression); - expression = createImplicitCast(parent, typeSystem, cast, expression); - expression = createExpectType(typeSystem, castTargetType, targetType, expression); - - CodeTreeBuilder builder = parent.create(); - builder.string(valueName(targetParameter)); - builder.string(" = "); - builder.tree(expression); - return builder.getRoot(); - } - - private CodeTree createImplicitCast(CodeTreeBuilder parent, TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) { - if (cast == null) { - return expression; - } - CodeTreeBuilder builder = parent.create(); - startCallTypeSystemMethod(builder, typeSystem, cast.getMethodName()); - builder.tree(expression); - builder.end().end(); - return builder.getRoot(); - } - - private boolean containsNewLine(CodeTree tree) { - if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) { - return true; - } - - for (CodeTree codeTree : tree.getEnclosedElements()) { - if (containsNewLine(codeTree)) { - return true; - } - } - return false; - } - - private boolean hasUnexpected(ActualParameter sourceParameter, ActualParameter targetParameter, ActualParameter unexpectedParameter) { - NodeExecutionData execution = targetParameter.getSpecification().getExecution(); - - if (getModel().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) { - // check for other polymorphic types - TreeSet polymorphicTargetTypes = lookupPolymorphicTargetTypes(targetParameter); - if (polymorphicTargetTypes.size() > 1) { - for (TypeData polymorphicTargetType : polymorphicTargetTypes) { - if (hasUnexpectedType(execution, sourceParameter, polymorphicTargetType)) { - return true; - } - } - } - } - - if (hasUnexpectedType(execution, sourceParameter, targetParameter.getTypeSystemType())) { - return true; - } - return false; - } - - private boolean hasUnexpectedType(NodeExecutionData execution, ActualParameter sourceParameter, TypeData targetType) { - List implicitSourceTypes = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); - - for (TypeData implicitSourceType : implicitSourceTypes) { - TypeData sourceType; - ExecutableTypeData targetExecutable = resolveExecutableType(execution, implicitSourceType); - if (sourceParameter != null) { - sourceType = sourceParameter.getTypeSystemType(); - } else { - if (targetExecutable.hasUnexpectedValue(getContext())) { - return true; - } - sourceType = targetExecutable.getType(); - } - - ImplicitCastData cast = getModel().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType); - if (cast != null) { - if (cast.getSourceType().needsCastTo(targetType)) { - return true; - } - } - - if (sourceType.needsCastTo(targetType)) { - return true; - } - } - return false; - } - - private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ExecutableTypeData currentExecutable, ActualParameter param, - boolean shortCircuit, ActualParameter unexpectedParameter) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - ActualParameter sourceParameter = currentExecutable.findParameter(param.getLocalName()); - boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter); - if (!unexpected) { - return body; - } - - if (!shortCircuit) { - builder.declaration(param.getType(), valueName(param)); - } - builder.startTryBlock(); - - if (containsNewLine(body)) { - builder.tree(body); - } else { - builder.statement(body); - } - - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - SpecializationData generic = specialization.getNode().getGenericSpecialization(); - ActualParameter genericParameter = generic.findParameter(param.getLocalName()); - - List genericParameters = generic.getParametersAfter(genericParameter); - builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter)); - if (specialization.isPolymorphic()) { - builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); - } else { - builder.tree(createCallRewriteMonomorphic(builder, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), specialization, param, - "Expected " + param.getLocalName() + " instanceof " + Utils.getSimpleName(param.getType()))); - } - builder.end(); // catch block - - return builder.getRoot(); - } - - private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, ActualParameter param) { - NodeData node = specialization.getNode(); - SpecializationData polymorphic = node.getPolymorphicSpecialization(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - builder.startStatement().string(polymorphicTypeName(param.getSpecification().getExecution())).string(" = ").typeLiteral(getContext().getType(Object.class)).end(); - - builder.startReturn(); - - CodeTreeBuilder execute = new CodeTreeBuilder(builder); - execute.startCall("next0", EXECUTE_CHAINED); - addInternalValueParameterNames(execute, specialization, polymorphic, param.getLocalName(), true, null); - execute.end(); - - TypeData sourceType = polymorphic.getReturnType().getTypeSystemType(); - - builder.tree(createExpectExecutableType(node, sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.getRoot())); - - builder.end(); - return builder.getRoot(); - } - - private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, ActualParameter unexpectedParameter) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (targetExecution != null) { - builder.tree(createAccessChild(targetExecution, null)); - builder.string("."); - } - - builder.startCall(targetExecutable.getMethodName()); - - // TODO this should be merged with #createTemplateMethodCall - int index = 0; - for (ActualParameter parameter : targetExecutable.getParameters()) { - - if (!parameter.getSpecification().isSignature()) { - builder.string(parameter.getLocalName()); - } else { - - if (index < targetExecution.getChild().getExecuteWith().size()) { - NodeChildData child = targetExecution.getChild().getExecuteWith().get(index); - - ParameterSpec spec = getModel().getSpecification().findParameterSpec(child.getName()); - List specializationParams = getModel().findParameters(spec); - - if (specializationParams.isEmpty()) { - builder.defaultValue(parameter.getType()); - continue; - } - - ActualParameter specializationParam = specializationParams.get(0); - - TypeData targetType = parameter.getTypeSystemType(); - TypeData sourceType = specializationParam.getTypeSystemType(); - String localName = specializationParam.getLocalName(); - - if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) { - localName = "ex.getResult()"; - sourceType = getModel().getNode().getTypeSystem().getGenericTypeData(); - } - - CodeTree value = CodeTreeBuilder.singleString(localName); - - if (sourceType.needsCastTo(targetType)) { - value = createCallTypeSystemMethod(builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value); - } - builder.tree(value); - } else { - builder.defaultValue(parameter.getType()); - } - index++; - } - } - - builder.end(); - - return builder.getRoot(); - } - - private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { - NodeExecutionData execution = parameter.getSpecification().getExecution(); - if (execution == null || !execution.isShortCircuit()) { - return body; - } - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); - builder.tree(createShortCircuitValue(builder, specialization, execution, shortCircuitParam, exceptionParam)); - builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); - builder.startIf().string(shortCircuitParam.getLocalName()).end(); - builder.startBlock(); - - if (containsNewLine(body)) { - builder.tree(body); - } else { - builder.statement(body); - } - builder.end(); - - return builder.getRoot(); - } - - private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeExecutionData execution, ActualParameter shortCircuitParam, - ActualParameter exceptionParam) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - int shortCircuitIndex = 0; - for (NodeExecutionData otherExectuion : specialization.getNode().getChildExecutions()) { - if (otherExectuion.isShortCircuit()) { - if (otherExectuion == execution) { - break; - } - shortCircuitIndex++; - } - } - - builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); - ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); - builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); - builder.end(); // statement - - return builder.getRoot(); - } - - protected CodeTree createCallRewriteMonomorphic(CodeTreeBuilder parent, boolean hasUnexpected, TypeData returnType, SpecializationData current, ActualParameter exceptionParam, String reason) { - NodeData node = current.getNode(); - SpecializationData generic = node.getGenericSpecialization(); - CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); - specializeCall.startCall(REWRITE); - addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, null); - specializeCall.doubleQuote(reason); - specializeCall.end().end(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - - builder.startReturn(); - builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.getRoot())); - builder.end(); - - return builder.getRoot(); - } - - } - - private class PolymorphicNodeFactory extends SpecializedNodeFactory { - - public PolymorphicNodeFactory(CodeTypeElement nodeGen) { - super(nodeGen); - } - - @Override - public CodeTypeElement create(SpecializationData polymorph) { - NodeData node = polymorph.getNode(); - TypeMirror baseType = node.getNodeType(); - if (nodeGen != null) { - baseType = nodeGen.asType(); - } - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false); - - clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.POLYMORPHIC)); - - for (ActualParameter polymorphParameter : polymorph.getSignatureParameters()) { - if (!polymorphParameter.getTypeSystemType().isGeneric()) { - continue; - } - Set types = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isSpecialized()) { - continue; - } - ActualParameter parameter = specialization.findParameter(polymorphParameter.getLocalName()); - assert parameter != null; - types.add(parameter.getTypeSystemType()); - } - - } - - for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) { - String fieldName = polymorphicTypeName(execution); - CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), getContext().getType(Class.class), fieldName); - var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getCompilationFinal())); - clazz.add(var); - } - - return clazz; - } - - @Override - protected void createChildren(SpecializationData specialization) { - CodeTypeElement clazz = getElement(); - - createConstructors(clazz); - createExecuteMethods(specialization); - - clazz.add(createUpdateTypes0()); - createCachedExecuteMethods(specialization); - } - - } - - private class SpecializedNodeFactory extends NodeBaseFactory { - - protected final CodeTypeElement nodeGen; - - public SpecializedNodeFactory(CodeTypeElement nodeGen) { - this.nodeGen = nodeGen; - } - - @Override - public CodeTypeElement create(SpecializationData specialization) { - NodeData node = specialization.getNode(); - TypeMirror baseType = node.getNodeType(); - if (nodeGen != null) { - baseType = nodeGen.asType(); - } - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); - - if (specialization.isSpecialized() || specialization.isUninitialized()) { - clazz.add(createGetMetadata0(false)); - clazz.add(createMetadataLiteral()); - } - - NodeCost cost; - if (specialization.isGeneric()) { - cost = NodeCost.MEGAMORPHIC; - } else if (specialization.isUninitialized()) { - cost = NodeCost.UNINITIALIZED; - } else if (specialization.isPolymorphic()) { - cost = NodeCost.POLYMORPHIC; - } else if (specialization.isSpecialized()) { - cost = NodeCost.MONOMORPHIC; - } else { - throw new AssertionError(); - } - clazz.getAnnotationMirrors().add(createNodeInfo(node, cost)); - - if (specialization.isUninitialized() && node.getGenericSpecialization().isReachable()) { - clazz.add(createUninitializedGetCostOverride()); - } - - return clazz; - } - - private Element createUninitializedGetCostOverride() { - TypeMirror returnType = context.getTruffleTypes().getNodeCost(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost"); - CodeTreeBuilder builder = method.createBuilder(); - builder.startIf().string(CONTAINS_FALLBACK).end().startBlock(); - builder.startReturn().staticReference(returnType, "MONOMORPHIC").end(); - builder.end(); - builder.startReturn().string("super.getCost()").end(); - return method; - } - - private CodeVariableElement createMetadataLiteral() { - CodeVariableElement includes = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getTruffleTypes().getDslMetadata(), METADATA_FIELD_NAME); - - CodeTreeBuilder builder = includes.createInitBuilder(); - - SpecializationData specialization = getModel(); - NodeData node = specialization.getNode(); - - Set contains = specialization.getContains(); - if (specialization.isUninitialized()) { - contains = new HashSet<>(); - - SpecializationData polymorphic = node.getPolymorphicSpecialization(); - if (polymorphic != null) { - contains.addAll(polymorphic.getContains()); - } - SpecializationData generic = node.getGenericSpecialization(); - if (generic != null) { - contains.addAll(generic.getContains()); - } - } - - builder.startNew(context.getTruffleTypes().getDslMetadata()); - builder.startGroup().string(nodeSpecializationClassName(getModel()), ".class").end(); - builder.tree(createSpecializationListLiteral(builder, contains)); - builder.tree(createSpecializationListLiteral(builder, getModel().getExcludedBy())); - builder.tree(createSpecializationTypeLiteral(builder, SpecializationData.getSignatureTypes(getModel()))); - builder.string("0").string("0"); - builder.end(); - return includes; - } - - private CodeTree createSpecializationTypeLiteral(CodeTreeBuilder parent, List list) { - ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); - CodeTreeBuilder builder = parent.create(); - - if (list.isEmpty()) { - builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); - } else { - builder.startNewArray(classArray, null); - for (TypeMirror type : list) { - builder.typeLiteral(type); - } - builder.end(); - } - - return builder.getRoot(); - } - - private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set list) { - ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class)); - CodeTreeBuilder builder = parent.create(); - - if (list.isEmpty()) { - builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY); - } else { - builder.startNewArray(classArray, null); - for (SpecializationData specialization : list) { - if (specialization.isGeneric() || specialization.isPolymorphic()) { - specialization = getModel().getNode().getUninitializedSpecialization(); - } - builder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); - } - builder.end(); - } - - return builder.getRoot(); - } - - protected CodeAnnotationMirror createNodeInfo(NodeData node, NodeCost cost) { - String shortName = node.getShortName(); - CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); - if (shortName != null) { - nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); - } - - DeclaredType nodeinfoCost = getContext().getTruffleTypes().getNodeCost(); - VariableElement varKind = Utils.findVariableElement(nodeinfoCost, cost.name()); - - nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind)); - return nodeInfoMirror; - } - - @Override - protected void createChildren(SpecializationData specialization) { - CodeTypeElement clazz = getElement(); - createConstructors(clazz); - - createExecuteMethods(specialization); - createCachedExecuteMethods(specialization); - - if (specialization.isUninitialized()) { - if (specialization.getNode().isFallbackReachable()) { - CodeVariableElement var = new CodeVariableElement(modifiers(Modifier.PRIVATE), context.getType(boolean.class), CONTAINS_FALLBACK); - var.addAnnotationMirror(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal())); - clazz.add(var); - } - clazz.add(createExecuteUninitialized()); - } - - if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) { - clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization)); - } else { - for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { - if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) { - // skip copy constructor - not used - continue; - } - clazz.add(createConstructorFactoryMethod(specialization, constructor)); - } - } - } - - protected void createConstructors(CodeTypeElement clazz) { - TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); - SpecializationData specialization = getModel(); - NodeData node = specialization.getNode(); - for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { - if (specialization.isUninitialized()) { - // ignore copy constructors for uninitialized if not polymorphic - if (isCopyConstructor(constructor) && !node.isPolymorphic(context)) { - continue; - } - } else if (node.getUninitializedSpecialization() != null) { - // ignore others than copy constructors for specialized nodes - if (!isCopyConstructor(constructor)) { - continue; - } - } - - CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); - if (superConstructor == null) { - continue; - } - CodeTree body = superConstructor.getBodyTree(); - CodeTreeBuilder builder = superConstructor.createBuilder(); - builder.tree(body); - - if (superConstructor != null) { - for (ActualParameter param : getImplicitTypeParameters(getModel())) { - clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param))); - superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param))); - - builder.startStatement(); - builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param)); - builder.end(); - } - - clazz.add(superConstructor); - } - } - } - - protected void createExecuteMethods(SpecializationData specialization) { - NodeData node = specialization.getNode(); - CodeTypeElement clazz = getElement(); - - for (ExecutableTypeData execType : node.getExecutableTypes()) { - if (execType.isFinal()) { - continue; - } - CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true); - clazz.add(executeMethod); - CodeTreeBuilder builder = executeMethod.getBuilder(); - CodeTree result = createExecuteBody(builder, specialization, execType); - if (result != null) { - builder.tree(result); - } else { - clazz.remove(executeMethod); - } - } - } - - protected void createCachedExecuteMethods(SpecializationData specialization) { - NodeData node = specialization.getNode(); - if (!node.isPolymorphic(context)) { - return; - } - - CodeTypeElement clazz = getElement(); - - final SpecializationData polymorphic = node.getPolymorphicSpecialization(); - ExecutableElement executeCached = nodeGen.getMethod(EXECUTE_CHAINED); - CodeExecutableElement executeMethod = CodeExecutableElement.clone(getContext().getEnvironment(), executeCached); - executeMethod.getModifiers().remove(Modifier.ABSTRACT); - CodeTreeBuilder builder = executeMethod.createBuilder(); - - if (specialization.isPolymorphic()) { - builder.startReturn().startCall("this.next0", EXECUTE_CHAINED); - addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null); - builder.end().end(); - } else if (specialization.isUninitialized()) { - if (node.getGenericSpecialization().isReachable()) { - builder.startIf().string("!containsFallback").end().startBlock(); - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - builder.end(); - } else { - builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - } - builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED); - addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null); - builder.end().end(); - } else { - CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); - elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED); - addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, null); - elseBuilder.end().end(); - - builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock() { - - public CodeTree create(CodeTreeBuilder b, SpecializationData current) { - return createGenericInvoke(b, polymorphic, current); - } - }, elseBuilder.getRoot(), false, true, true, false)); - } - clazz.add(executeMethod); - } - - private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - - List primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount()); - - if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) { - builder.tree(createFunctionalExecute(builder, specialization, execType)); - } else if (needsCastingExecuteMethod(execType)) { - assert !primaryExecutes.isEmpty(); - builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0))); - } else { - return null; - } - - return builder.getRoot(); - } - - private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { - CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); - - method.getAnnotationMirrors().clear(); - for (VariableElement variable : method.getParameters()) { - variable.getAnnotationMirrors().clear(); - } - - CodeTreeBuilder builder = method.createBuilder(); - int i = 0; - int signatureIndex = -1; - for (VariableElement param : method.getParameters()) { - CodeVariableElement var = CodeVariableElement.clone(param); - ActualParameter actualParameter = i < execType.getParameters().size() ? execType.getParameters().get(i) : null; - String name; - if (actualParameter != null) { - if (actualParameter.getSpecification().isSignature()) { - signatureIndex++; - } - - if (evaluated && actualParameter.getSpecification().isSignature()) { - name = valueNameEvaluated(actualParameter); - } else { - name = valueName(actualParameter); - } - - int varArgCount = getModel().getSignatureSize() - signatureIndex; - if (evaluated && actualParameter.isTypeVarArgs()) { - ActualParameter baseVarArgs = actualParameter; - name = valueName(baseVarArgs) + "Args"; - - builder.startAssert().string(name).string(" != null").end(); - builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end(); - if (varArgCount > 0) { - List varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size()); - for (ActualParameter varArg : varArgsParameter) { - if (varArgCount <= 0) { - break; - } - TypeMirror type = baseVarArgs.getType(); - if (type.getKind() == TypeKind.ARRAY) { - type = ((ArrayType) type).getComponentType(); - } - builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getTypeVarArgsIndex() + "]"); - varArgCount--; - } - } - } - } else { - name = "arg" + i; - } - var.setName(name); - method.getParameters().set(i, var); - i++; - } - - method.getAnnotationMirrors().clear(); - method.getModifiers().remove(Modifier.ABSTRACT); - return method; - } - - private boolean needsCastingExecuteMethod(ExecutableTypeData execType) { - if (execType.isAbstract()) { - return true; - } - if (execType.getType().isGeneric()) { - return true; - } - return false; - } - - private List findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) { - TypeData primaryType = specialization.getReturnType().getTypeSystemType(); - List otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount); - - List filteredTypes = new ArrayList<>(); - for (ExecutableTypeData compareType : otherTypes) { - if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) { - continue; - } - filteredTypes.add(compareType); - } - - // no direct matches found use generic where the type is Object - if (filteredTypes.isEmpty()) { - for (ExecutableTypeData compareType : otherTypes) { - if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) { - filteredTypes.add(compareType); - } - } - } - - if (filteredTypes.isEmpty()) { - for (ExecutableTypeData compareType : otherTypes) { - if (compareType.getType().isGeneric()) { - filteredTypes.add(compareType); - } - } - } - - return filteredTypes; - } - - private CodeTree createFunctionalExecute(CodeTreeBuilder parent, final SpecializationData specialization, final ExecutableTypeData executable) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (specialization.isUninitialized()) { - builder.tree(createDeoptimize(builder)); - } - - builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null)); - - CodeTree returnSpecialized = null; - - if (specialization.findNextSpecialization() != null) { - CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); - returnBuilder.tree(createDeoptimize(builder)); - returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, - "One of guards " + specialization.getGuards() + " failed")); - returnSpecialized = returnBuilder.getRoot(); - } - - builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock() { - - public CodeTree create(CodeTreeBuilder b, SpecializationData current) { - return createExecute(b, executable, specialization); - } - }, returnSpecialized, false, false, false, false)); - - return builder.getRoot(); - } - - private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { - NodeData node = specialization.getNode(); - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { - builder.startTryBlock(); - } - - for (String assumption : specialization.getAssumptions()) { - builder.startStatement(); - builder.string("this.").string(assumption).string(".check()"); - builder.end(); - } - - CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); - if (specialization.isPolymorphic()) { - returnBuilder.startCall("next0", EXECUTE_CHAINED); - addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null); - returnBuilder.end(); - } else if (specialization.isUninitialized()) { - returnBuilder.startCall(EXECUTE_UNINITIALIZED); - addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null); - returnBuilder.end(); - } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { - emitEncounteredSynthetic(builder, specialization); - } else { - returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); - } - - if (!returnBuilder.isEmpty()) { - TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); - TypeData sourceType = specialization.getReturnType().getTypeSystemType(); - - builder.startReturn(); - if (targetType == null || sourceType == null) { - builder.tree(returnBuilder.getRoot()); - } else if (sourceType.needsCastTo(targetType)) { - String castMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); - if (!executable.hasUnexpectedValue(context)) { - castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); - } - builder.tree(createCallTypeSystemMethod(parent, node, castMethodName, returnBuilder.getRoot())); - } else { - builder.tree(returnBuilder.getRoot()); - } - builder.end(); - } - - if (!specialization.getExceptions().isEmpty()) { - for (SpecializationThrowsData exception : specialization.getExceptions()) { - builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - builder.tree(createDeoptimize(builder)); - builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, - "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); - } - builder.end(); - } - if (!specialization.getAssumptions().isEmpty()) { - builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); - builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, "Assumption failed")); - builder.end(); - } - - return builder.getRoot(); - } - - protected CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) { - List implicitTypeParams = getImplicitTypeParameters(specialization); - String baseName = "current"; - CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME); - method.addParameter(new CodeVariableElement(specialization.getNode().getNodeType(), baseName)); - for (ActualParameter implicitTypeParam : implicitTypeParams) { - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam))); - } - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn(); - builder.startNew(getElement().asType()); - builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end(); - for (ActualParameter param : implicitTypeParams) { - builder.string(implicitTypeName(param)); - } - builder.end().end(); - return method; - } - - protected CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) { - List parameters = constructor.getParameters(); - CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME, - parameters.toArray(new CodeVariableElement[parameters.size()])); - CodeTreeBuilder builder = method.createBuilder(); - builder.startReturn(); - builder.startNew(getElement().asType()); - for (VariableElement param : parameters) { - builder.string(((CodeVariableElement) param).getName()); - } - builder.end().end(); - return method; - } - } - - private interface CodeBlock { - - CodeTree create(CodeTreeBuilder parent, T value); - - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,516 +0,0 @@ -/* - * 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.dsl.processor.node; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class NodeData extends Template implements Comparable { - - private final String nodeId; - private final String shortName; - private final List enclosingNodes = new ArrayList<>(); - private NodeData declaringNode; - - private final TypeSystemData typeSystem; - private final List children; - private final List childExecutions; - private final List fields; - private final List assumptions; - - private ParameterSpec instanceParameterSpec; - - private final List specializations = new ArrayList<>(); - private final List shortCircuits = new ArrayList<>(); - private final List casts = new ArrayList<>(); - private Map> executableTypes; - - private final NodeExecutionData thisExecution; - - public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, List children, List executions, - List fields, List assumptions) { - super(context, type, null, null); - this.nodeId = type.getSimpleName().toString(); - this.shortName = shortName; - this.typeSystem = typeSystem; - this.fields = fields; - this.children = children; - this.childExecutions = executions; - this.assumptions = assumptions; - this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false); - this.thisExecution.getChild().setNode(this); - if (children != null) { - for (NodeChildData child : children) { - child.setParentNode(this); - } - } - } - - public NodeData(ProcessorContext context, TypeElement type) { - this(context, type, null, null, null, null, null, null); - } - - public NodeExecutionData getThisExecution() { - return thisExecution; - } - - public boolean isFallbackReachable() { - SpecializationData generic = getGenericSpecialization(); - if (generic != null) { - return generic.isReachable(); - } - return false; - } - - public void addEnclosedNode(NodeData node) { - this.enclosingNodes.add(node); - node.declaringNode = this; - } - - public List getChildExecutions() { - return childExecutions; - } - - public int getSignatureSize() { - if (getSpecializations() != null && !getSpecializations().isEmpty()) { - return getSpecializations().get(0).getSignatureSize(); - } - return 0; - } - - public boolean needsFrame(ProcessorContext context) { - for (SpecializationData specialization : specializations) { - if (!specialization.isReachable()) { - continue; - } - if (specialization.hasFrame(context)) { - return true; - } - } - return false; - } - - public boolean needsImplicitCast(ProcessorContext context) { - for (NodeChildData child : getChildren()) { - if (child.needsImplicitCast(context)) { - return true; - } - } - return false; - } - - public boolean isPolymorphic(ProcessorContext context) { - return needsRewrites(context); - } - - public List getCasts() { - return casts; - } - - public String getShortName() { - return shortName; - } - - public List getFields() { - return fields; - } - - @Override - protected List findChildContainers() { - List containerChildren = new ArrayList<>(); - if (enclosingNodes != null) { - containerChildren.addAll(enclosingNodes); - } - if (typeSystem != null) { - containerChildren.add(typeSystem); - } - if (specializations != null) { - for (MessageContainer specialization : specializations) { - if (specialization.getMessageElement() != null) { - containerChildren.add(specialization); - } - } - } - if (executableTypes != null) { - containerChildren.addAll(getExecutableTypes()); - } - if (shortCircuits != null) { - containerChildren.addAll(shortCircuits); - } - if (children != null) { - containerChildren.addAll(children); - } - if (fields != null) { - containerChildren.addAll(fields); - } - if (casts != null) { - containerChildren.addAll(casts); - } - return containerChildren; - } - - public ParameterSpec getInstanceParameterSpec() { - return instanceParameterSpec; - } - - public void setInstanceParameterSpec(ParameterSpec instanceParameter) { - this.instanceParameterSpec = instanceParameter; - } - - public String getNodeId() { - return nodeId; - } - - public TypeMirror getNodeType() { - return getTemplateType().asType(); - } - - public List getAssumptions() { - return assumptions; - } - - public boolean needsFactory() { - if (specializations == null) { - return false; - } - if (getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { - return false; - } - - boolean noSpecialization = true; - for (SpecializationData specialization : specializations) { - noSpecialization = noSpecialization && !specialization.isSpecialized(); - } - return !noSpecialization; - } - - public boolean supportsFrame() { - if (executableTypes != null) { - for (ExecutableTypeData execType : getExecutableTypes(-1)) { - if (execType.findParameter("frameValue") == null) { - return false; - } - } - } - return true; - } - - public List getNodeDeclaringChildren() { - List nodeChildren = new ArrayList<>(); - for (NodeData child : getEnclosingNodes()) { - if (child.needsFactory()) { - nodeChildren.add(child); - } - nodeChildren.addAll(child.getNodeDeclaringChildren()); - } - return nodeChildren; - } - - public NodeData getDeclaringNode() { - return declaringNode; - } - - public List getEnclosingNodes() { - return enclosingNodes; - } - - public List getAllTemplateMethods() { - List methods = new ArrayList<>(); - - for (SpecializationData specialization : getSpecializations()) { - methods.add(specialization); - } - - methods.addAll(getExecutableTypes()); - methods.addAll(getShortCircuits()); - if (getCasts() != null) { - methods.addAll(getCasts()); - } - - return methods; - } - - public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type, int evaluatedCount) { - List types = findGenericExecutableTypes(context, evaluatedCount); - for (ExecutableTypeData availableType : types) { - if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) { - return availableType; - } - } - return null; - } - - public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) { - List types = findGenericExecutableTypes(context, evaluatedCount); - for (ExecutableTypeData type : types) { - if (type.getType().isGeneric()) { - return type; - } - } - - for (ExecutableTypeData type : types) { - if (!type.getType().isVoid()) { - return type; - } - } - - for (ExecutableTypeData type : types) { - return type; - } - return null; - } - - public List getExecutableTypes(int evaluatedCount) { - if (executableTypes == null) { - return Collections.emptyList(); - } - if (evaluatedCount == -1) { - List typeData = new ArrayList<>(); - for (int currentEvaluationCount : executableTypes.keySet()) { - typeData.addAll(executableTypes.get(currentEvaluationCount)); - } - return typeData; - } else { - List types = executableTypes.get(evaluatedCount); - if (types == null) { - return Collections.emptyList(); - } - return types; - } - } - - public List findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) { - List types = new ArrayList<>(); - for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { - if (!type.hasUnexpectedValue(context)) { - types.add(type); - } - } - return types; - } - - public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) { - for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) { - 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().getTypeSystemType() == type) { - if (result != null) { - // Result not unique; - return null; - } - result = specialization; - } - } - return result; - } - - public boolean needsRewrites(ProcessorContext context) { - boolean needsRewrites = false; - - for (SpecializationData specialization : getSpecializations()) { - if (specialization.hasRewrite(context)) { - needsRewrites = true; - break; - } - } - return needsRewrites || getSpecializations().size() > 1; - } - - public SpecializationData getPolymorphicSpecialization() { - for (SpecializationData specialization : specializations) { - if (specialization.isPolymorphic()) { - return specialization; - } - } - return null; - } - - public SpecializationData getGenericSpecialization() { - for (SpecializationData specialization : specializations) { - if (specialization.isGeneric()) { - return specialization; - } - } - return null; - } - - public SpecializationData getUninitializedSpecialization() { - for (SpecializationData specialization : specializations) { - if (specialization.isUninitialized()) { - return specialization; - } - } - return null; - } - - @Override - public TypeSystemData getTypeSystem() { - return typeSystem; - } - - public String dump() { - return dump(0); - } - - private String dump(int level) { - String indent = ""; - for (int i = 0; i < level; i++) { - indent += " "; - } - StringBuilder builder = new StringBuilder(); - - builder.append(String.format("%s%s {", indent, toString())); - - dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType())); - dumpProperty(builder, indent, "typeSystem", getTypeSystem()); - dumpProperty(builder, indent, "fields", getChildren()); - dumpProperty(builder, indent, "executableTypes", getExecutableTypes()); - dumpProperty(builder, indent, "specializations", getSpecializations()); - dumpProperty(builder, indent, "assumptions", getAssumptions()); - dumpProperty(builder, indent, "casts", getCasts()); - dumpProperty(builder, indent, "messages", collectMessages()); - if (getEnclosingNodes().size() > 0) { - builder.append(String.format("\n%s children = [", indent)); - for (NodeData node : getEnclosingNodes()) { - builder.append("\n"); - builder.append(node.dump(level + 1)); - } - builder.append(String.format("\n%s ]", indent)); - } - builder.append(String.format("%s}", indent)); - return builder.toString(); - } - - private static void dumpProperty(StringBuilder b, String indent, String propertyName, Object value) { - if (value instanceof List) { - List list = (List) value; - if (!list.isEmpty()) { - b.append(String.format("\n%s %s = %s", indent, propertyName, dumpList(indent, (List) value))); - } - } else { - if (value != null) { - b.append(String.format("\n%s %s = %s", indent, propertyName, value)); - } - } - } - - private static String dumpList(String indent, List array) { - if (array == null) { - return "null"; - } - - if (array.isEmpty()) { - return "[]"; - } else if (array.size() == 1) { - return "[" + array.get(0).toString() + "]"; - } - - StringBuilder b = new StringBuilder(); - b.append("["); - for (Object object : array) { - b.append("\n "); - b.append(indent); - b.append(object); - b.append(", "); - } - b.append("\n ").append(indent).append("]"); - return b.toString(); - } - - public NodeExecutionData findExecution(String name) { - if (getChildExecutions() == null) { - return null; - } - for (NodeExecutionData execution : getChildExecutions()) { - if (execution.getName().equals(name)) { - return execution; - } - } - return null; - } - - public NodeChildData findChild(String name) { - for (NodeChildData field : getChildren()) { - if (field.getName().equals(name)) { - return field; - } - } - return null; - } - - public List getChildren() { - return children; - } - - public List getSpecializations() { - return specializations; - } - - public List getExecutableTypes() { - return getExecutableTypes(-1); - } - - public List getShortCircuits() { - return shortCircuits; - } - - public void setExecutableTypes(Map> executableTypes) { - this.executableTypes = executableTypes; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + getNodeId() + "]"; - } - - public CreateCastData findCast(String name) { - if (getCasts() != null) { - for (CreateCastData cast : getCasts()) { - if (cast.getChildNames().contains(name)) { - return cast; - } - } - } - return null; - } - - public int compareTo(NodeData o) { - return getNodeId().compareTo(o.getNodeId()); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeExecutionData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeExecutionData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * 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.dsl.processor.node; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; - -public class NodeExecutionData { - - private final NodeChildData child; - private final String name; - private final int index; - private final boolean shortCircuit; - - public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { - this.child = child; - this.index = index; - this.shortCircuit = shortCircuit; - this.name = createName(); - } - - private String createName() { - if (isIndexed()) { - return child.getName() + index; - } - return child.getName(); - } - - public TypeMirror getNodeType() { - TypeMirror type; - if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { - type = ((ArrayType) child.getNodeType()).getComponentType(); - } else { - type = child.getNodeType(); - } - return type; - } - - public String getName() { - return name; - } - - public NodeChildData getChild() { - return child; - } - - public int getIndex() { - return index; - } - - public boolean isIndexed() { - return index > -1; - } - - public boolean isShortCircuit() { - return shortCircuit; - } - - public String getShortCircuitId() { - return createShortCircuitId(child, index); - } - - public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { - String shortCircuitName = child.getName(); - if (child.getCardinality().isMany()) { - shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; - } - return shortCircuitName; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeFieldData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * 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.dsl.processor.node; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.template.*; - -public class NodeFieldData extends MessageContainer { - - private final Element messageElement; - private final AnnotationMirror messageAnnotation; - private final String name; - private final TypeMirror type; - private final boolean generated; - private ExecutableElement getter; - - public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, TypeMirror type, String name, boolean generated) { - this.messageElement = messageElement; - this.messageAnnotation = messageAnnotation; - this.name = name; - this.type = type; - this.generated = generated; - } - - void setGetter(ExecutableElement getter) { - this.getter = getter; - } - - @Override - public Element getMessageElement() { - return messageElement; - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return messageAnnotation; - } - - public String getName() { - return name; - } - - public TypeMirror getType() { - return type; - } - - public boolean isGenerated() { - return generated; - } - - public ExecutableElement getGetter() { - return getter; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeMethodParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +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.dsl.processor.node; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public abstract class NodeMethodParser extends TemplateMethodParser { - - public NodeMethodParser(ProcessorContext context, NodeData node) { - super(context, node); - } - - public NodeData getNode() { - return template; - } - - protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(execution.getChild().getNodeData())); - spec.setExecution(execution); - return spec; - } - - protected List nodeTypeMirrors(NodeData nodeData) { - Set typeMirrors = new LinkedHashSet<>(); - - for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { - typeMirrors.add(typeData.getType().getPrimitiveType()); - } - - typeMirrors.add(nodeData.getTypeSystem().getGenericType()); - - return new ArrayList<>(typeMirrors); - } - - protected ParameterSpec createReturnParameterSpec() { - ParameterSpec returnValue = new ParameterSpec("returnValue", nodeTypeMirrors(getNode())); - returnValue.setExecution(getNode().getThisExecution()); - return returnValue; - } - - @Override - public boolean isParsable(ExecutableElement method) { - if (getAnnotationType() != null) { - return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; - } - - return true; - } - - @SuppressWarnings("unused") - protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) { - MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec()); - - addDefaultFrame(methodSpec); - addDefaultFieldMethodSpec(methodSpec); - addDefaultChildren(shortCircuitsEnabled, shortCircuitName, methodSpec); - - return methodSpec; - } - - public void addDefaultChildren(boolean shortCircuitsEnabled, String breakName, MethodSpec spec) { - if (getNode().getChildren() == null) { - // children are null when parsing executable types - return; - } - - for (NodeExecutionData execution : getNode().getChildExecutions()) { - if (breakName != null && execution.getShortCircuitId().equals(breakName)) { - break; - } - - if (execution.isShortCircuit() && shortCircuitsEnabled) { - spec.addRequired(new ParameterSpec(shortCircuitValueName(execution.getName()), getContext().getType(boolean.class))); - } - spec.addRequired(createValueParameterSpec(execution)); - } - } - - private void addDefaultFrame(MethodSpec methodSpec) { - if (getNode().supportsFrame()) { - methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); - } - } - - protected void addDefaultFieldMethodSpec(MethodSpec methodSpec) { - for (NodeFieldData field : getNode().getFields()) { - if (field.getGetter() == null) { - ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); - spec.setLocal(true); - methodSpec.addOptional(spec); - } - } - } - - private static String shortCircuitValueName(String valueName) { - return "has" + Utils.firstLetterUpperCase(valueName); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1351 +0,0 @@ -/* - * 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.dsl.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 javax.tools.Diagnostic.Kind; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.compiler.*; -import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; -import com.oracle.truffle.dsl.processor.node.SpecializationData.SpecializationKind; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class NodeParser extends AbstractParser { - - public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, - NodeChildren.class); - - private Map parsedNodes; - - @Override - protected NodeData parse(Element element, AnnotationMirror mirror) { - NodeData node = null; - try { - parsedNodes = new HashMap<>(); - node = resolveNode((TypeElement) element); - if (Log.DEBUG) { - NodeData parsed = parsedNodes.get(Utils.getQualifiedName((TypeElement) element)); - if (node != null) { - String dump = parsed.dump(); - log.message(Kind.ERROR, null, null, null, dump); - } - } - } finally { - parsedNodes = null; - } - - return node; - } - - @Override - protected NodeData filterErrorElements(NodeData model) { - for (Iterator iterator = model.getEnclosingNodes().iterator(); iterator.hasNext();) { - NodeData node = filterErrorElements(iterator.next()); - if (node == null) { - iterator.remove(); - } - } - if (model.hasErrors()) { - return null; - } - return model; - } - - @Override - public boolean isDelegateToRootDeclaredType() { - return true; - } - - @Override - public Class getAnnotationType() { - return null; - } - - @Override - public List> getTypeDelegatedAnnotationTypes() { - return ANNOTATIONS; - } - - private NodeData resolveNode(TypeElement rootType) { - String typeName = Utils.getQualifiedName(rootType); - if (parsedNodes.containsKey(typeName)) { - return parsedNodes.get(typeName); - } - - List enclosedNodes = new ArrayList<>(); - for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) { - NodeData enclosedChild = resolveNode(enclosedType); - if (enclosedChild != null) { - enclosedNodes.add(enclosedChild); - } - } - - NodeData node = parseNode(rootType); - if (node == null && !enclosedNodes.isEmpty()) { - node = new NodeData(context, rootType); - } - - if (node != null) { - for (NodeData enclosedNode : enclosedNodes) { - node.addEnclosedNode(enclosedNode); - } - } - - parsedNodes.put(typeName, node); - return node; - } - - private NodeData parseNode(TypeElement originalTemplateType) { - // reloading the type elements is needed for ecj - TypeElement templateType = Utils.fromTypeMirror(context.reloadTypeElement(originalTemplateType)); - - if (Utils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) { - // generated nodes should not get called again. - return null; - } - - List lookupTypes = collectSuperClasses(new ArrayList(), templateType); - if (!Utils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) { - return null; - } - List elements = CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType); - - NodeData node = parseNodeData(templateType, elements, lookupTypes); - if (node.hasErrors()) { - return node; // error sync point - } - - initializeChildren(node); - - node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements)); - node.getSpecializations().addAll(new GenericParser(context, node).parse(elements)); - node.getCasts().addAll(new CreateCastParser(context, node).parse(elements)); - node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements)); - - if (node.hasErrors()) { - return node; // error sync point - } - - verifySpecializationSameLength(node); - initializeSpecializations(elements, node); - initializeShortCircuits(node); // requires specializations and polymorphic specializations - - verifyVisibilities(node); - verifyMissingAbstractMethods(node, elements); - verifyConstructors(node); - verifyNamingConvention(node.getShortCircuits(), "needs"); - verifySpecializationThrows(node); - return node; - } - - private NodeData parseNodeData(TypeElement templateType, List elements, List typeHierarchy) { - AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); - if (typeSystemMirror == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(templateType)); - return nodeData; - } - - TypeMirror typeSystemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); - if (typeSystem == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSystemType)); - return nodeData; - } - - List assumptionsList = new ArrayList<>(); - for (int i = typeHierarchy.size() - 1; i >= 0; i--) { - TypeElement type = typeHierarchy.get(i); - AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); - if (assumptions != null) { - List assumptionStrings = Utils.getAnnotationValueList(String.class, assumptions, "value"); - for (String string : assumptionStrings) { - if (assumptionsList.contains(string)) { - assumptionsList.remove(string); - } - assumptionsList.add(string); - } - } - } - AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); - String shortName = null; - if (nodeInfoMirror != null) { - shortName = Utils.getAnnotationValue(String.class, nodeInfoMirror, "shortName"); - } - - List fields = parseFields(typeHierarchy, elements); - List children = parseChildren(typeHierarchy, elements); - List executions = parseExecutions(children, elements); - - NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList); - nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); - - parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); - - return nodeData; - } - - private List parseFields(List typeHierarchy, List elements) { - Set names = new HashSet<>(); - - List fields = new ArrayList<>(); - for (VariableElement field : ElementFilter.fieldsIn(elements)) { - if (field.getModifiers().contains(Modifier.STATIC)) { - continue; - } - if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { - String name = field.getSimpleName().toString(); - fields.add(new NodeFieldData(field, null, field.asType(), name, false)); - names.add(name); - } - } - - List reversedTypeHierarchy = new ArrayList<>(typeHierarchy); - Collections.reverse(reversedTypeHierarchy); - for (TypeElement typeElement : reversedTypeHierarchy) { - AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, typeElement, NodeFields.class); - List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", typeElement, NodeField.class); - - for (AnnotationMirror mirror : children) { - String name = Utils.firstLetterLowerCase(Utils.getAnnotationValue(String.class, mirror, "name")); - TypeMirror type = Utils.getAnnotationValue(TypeMirror.class, mirror, "type"); - - NodeFieldData field = new NodeFieldData(typeElement, mirror, type, name, true); - if (name.isEmpty()) { - field.addError(Utils.getAnnotationValue(mirror, "name"), "Field name cannot be empty."); - } else if (names.contains(name)) { - field.addError(Utils.getAnnotationValue(mirror, "name"), "Duplicate field name '%s'.", name); - } - names.add(name); - - fields.add(field); - } - } - - for (NodeFieldData nodeFieldData : fields) { - nodeFieldData.setGetter(findGetter(elements, nodeFieldData.getName(), nodeFieldData.getType())); - } - - return fields; - } - - private List parseChildren(final List typeHierarchy, List elements) { - Set shortCircuits = new HashSet<>(); - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); - if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); - } - } - Map castNodeTypes = new HashMap<>(); - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class); - if (mirror != null) { - List children = (Utils.getAnnotationValueList(String.class, mirror, "value")); - if (children != null) { - for (String child : children) { - castNodeTypes.put(child, method.getReturnType()); - } - } - } - } - - List parsedChildren = new ArrayList<>(); - List typeHierarchyReversed = new ArrayList<>(typeHierarchy); - Collections.reverse(typeHierarchyReversed); - for (TypeElement type : typeHierarchyReversed) { - AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class); - - TypeMirror nodeClassType = type.getSuperclass(); - if (!Utils.isAssignable(nodeClassType, context.getTruffleTypes().getNode())) { - nodeClassType = null; - } - - List children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); - int index = 0; - for (AnnotationMirror childMirror : children) { - String name = Utils.getAnnotationValue(String.class, childMirror, "value"); - if (name.equals("")) { - name = "child" + index; - } - - Cardinality cardinality = Cardinality.ONE; - - TypeMirror childType = inheritType(childMirror, "type", nodeClassType); - if (childType.getKind() == TypeKind.ARRAY) { - cardinality = Cardinality.MANY; - } - - TypeMirror originalChildType = childType; - TypeMirror castNodeType = castNodeTypes.get(name); - if (castNodeType != null) { - childType = castNodeType; - } - - Element getter = findGetter(elements, name, childType); - - NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality); - - parsedChildren.add(nodeChild); - - if (nodeChild.getNodeType() == null) { - nodeChild.addError("No valid node type could be resoleved."); - } - if (nodeChild.hasErrors()) { - continue; - } - - index++; - } - } - - List filteredChildren = new ArrayList<>(); - Set encounteredNames = new HashSet<>(); - for (int i = parsedChildren.size() - 1; i >= 0; i--) { - NodeChildData child = parsedChildren.get(i); - if (!encounteredNames.contains(child.getName())) { - filteredChildren.add(0, child); - encounteredNames.add(child.getName()); - } - } - - for (NodeChildData child : filteredChildren) { - List executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); - AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); - List executeWith = new ArrayList<>(); - for (String executeWithString : executeWithStrings) { - - if (child.getName().equals(executeWithString)) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); - continue; - } - - NodeChildData found = null; - boolean before = true; - for (NodeChildData resolveChild : filteredChildren) { - if (resolveChild == child) { - before = false; - continue; - } - if (resolveChild.getName().equals(executeWithString)) { - found = resolveChild; - break; - } - } - - if (found == null) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); - continue; - } else if (!before) { - child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, - executeWithString); - continue; - } - executeWith.add(found); - } - child.setExecuteWith(executeWith); - if (child.getNodeData() == null) { - continue; - } - } - - return filteredChildren; - } - - private List parseExecutions(List children, List elements) { - if (children == null) { - return null; - } - - // pre-parse short circuits - Set shortCircuits = new HashSet<>(); - List methods = ElementFilter.methodsIn(elements); - for (ExecutableElement method : methods) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); - if (mirror != null) { - shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); - } - } - - boolean hasVarArgs = false; - int maxSignatureSize = 0; - if (!children.isEmpty()) { - int lastIndex = children.size() - 1; - hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY; - if (hasVarArgs) { - maxSignatureSize = lastIndex; - } else { - maxSignatureSize = children.size(); - } - } - - // pre-parse specializations - for (ExecutableElement method : methods) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class); - if (mirror == null) { - continue; - } - - int currentArgumentCount = 0; - boolean skipShortCircuit = false; - for (VariableElement var : method.getParameters()) { - TypeMirror type = var.asType(); - if (currentArgumentCount == 0) { - // skip optionals - if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) { - continue; - } - // TODO skip optional fields? - } - int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1; - if (childIndex == -1) { - continue; - } - if (!skipShortCircuit) { - NodeChildData child = children.get(childIndex); - if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { - skipShortCircuit = true; - continue; - } - } else { - skipShortCircuit = false; - } - - currentArgumentCount++; - } - maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); - } - - List executions = new ArrayList<>(); - for (int i = 0; i < maxSignatureSize; i++) { - int childIndex = i; - boolean varArg = false; - if (childIndex >= children.size() - 1) { - if (hasVarArgs) { - childIndex = children.size() - 1; - varArg = hasVarArgs; - } else if (childIndex >= children.size()) { - break; - } - } - int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; - NodeChildData child = children.get(childIndex); - boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex)); - executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); - } - return executions; - } - - private static Map> groupExecutableTypes(List executableTypes) { - Map> groupedTypes = new TreeMap<>(); - for (ExecutableTypeData type : executableTypes) { - int evaluatedCount = type.getEvaluatedCount(); - - List types = groupedTypes.get(evaluatedCount); - if (types == null) { - types = new ArrayList<>(); - groupedTypes.put(evaluatedCount, types); - } - types.add(type); - } - - for (List types : groupedTypes.values()) { - Collections.sort(types); - } - return groupedTypes; - } - - private void initializeChildren(NodeData node) { - for (NodeChildData nodeChild : node.getChildren()) { - NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeChild.getNodeType())); - nodeChild.setNode(fieldNodeData); - if (fieldNodeData == null) { - nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(nodeChild.getNodeType())); - } else if (!Utils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { - nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), - NodeChild.class.getSimpleName(), Utils.getSimpleName(node.getTypeSystem().getTemplateType()), Utils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); - } - if (fieldNodeData != null) { - List types = nodeChild.findGenericExecutableTypes(context); - if (types.isEmpty()) { - AnnotationValue executeWithValue = Utils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith"); - nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(), - Utils.getSimpleName(nodeChild.getNodeType())); - } - } - } - } - - private void initializeSpecializations(List elements, final NodeData node) { - if (node.getSpecializations().isEmpty()) { - return; - } - - initializeGuards(elements, node); - initializeGeneric(node); - initializeUninitialized(node); - initializeOrder(node); - initializePolymorphism(node); // requires specializations - initializeReachability(node); - initializeContains(node); - - if (!node.hasErrors()) { - initializeExceptions(node); - } - resolveContains(node); - - List needsId = new ArrayList<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (specialization.isGeneric()) { - specialization.setId("Generic"); - } else if (specialization.isUninitialized()) { - specialization.setId("Uninitialized"); - } else if (specialization.isPolymorphic()) { - specialization.setId("Polymorphic"); - } else if (specialization.isSpecialized()) { - needsId.add(specialization); - } else { - throw new AssertionError(); - } - } - - // verify specialization parameter length - List ids = initializeSpecializationIds(needsId); - for (int i = 0; i < ids.size(); i++) { - needsId.get(i).setId(ids.get(i)); - } - - } - - private static void initializeOrder(NodeData node) { - List specializations = node.getSpecializations(); - Collections.sort(specializations); - - for (SpecializationData specialization : specializations) { - String searchName = specialization.getInsertBeforeName(); - if (searchName == null || specialization.getMethod() == null) { - continue; - } - SpecializationData found = lookupSpecialization(node, searchName); - if (found == null || found.getMethod() == null) { - AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore"); - specialization.addError(value, "The referenced specialization '%s' could not be found.", searchName); - continue; - } - - ExecutableElement currentMethod = specialization.getMethod(); - ExecutableElement insertBeforeMethod = found.getMethod(); - - TypeMirror currentEnclosedType = currentMethod.getEnclosingElement().asType(); - TypeMirror insertBeforeEnclosedType = insertBeforeMethod.getEnclosingElement().asType(); - - if (Utils.typeEquals(currentEnclosedType, insertBeforeEnclosedType) || !Utils.isSubtype(currentEnclosedType, insertBeforeEnclosedType)) { - AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore"); - specialization.addError(value, "Specializations can only be inserted before specializations in superclasses.", searchName); - continue; - } - - specialization.setInsertBefore(found); - } - - int endIndex = specializations.size() - 1; - for (int i = endIndex; i >= 0; i--) { - SpecializationData specialization = specializations.get(i); - if (specialization.isGeneric() || specialization.isPolymorphic()) { - endIndex--; - continue; - } - - SpecializationData insertBefore = specialization.getInsertBefore(); - if (insertBefore != null) { - int insertIndex = specializations.indexOf(insertBefore); - if (insertIndex < i) { - List range = new ArrayList<>(specializations.subList(i, endIndex + 1)); - specializations.removeAll(range); - specializations.addAll(insertIndex, range); - } - } - } - - for (int i = 0; i < specializations.size(); i++) { - specializations.get(i).setIndex(i); - } - } - - private static void initializeExceptions(NodeData node) { - List specializations = node.getSpecializations(); - for (int i = 0; i < specializations.size(); i++) { - SpecializationData cur = specializations.get(i); - if (cur.getExceptions().isEmpty()) { - continue; - } - SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; - - if (!cur.isContainedBy(next)) { - // error should be able to contain - next.addError("This specialiation is not a valid exceptional rewrite target for %s. To fix this make %s compatible to %s or remove the exceptional rewrite.", - cur.createReferenceName(), next.createReferenceName(), cur.createReferenceName()); - continue; - } - if (!next.getContains().contains(cur)) { - next.getContains().add(cur); - // TODO resolve transitive contains - } - } - - for (SpecializationData cur : specializations) { - if (cur.getExceptions().isEmpty()) { - continue; - } - for (SpecializationData child : specializations) { - if (child != null && child != cur && child.getContains().contains(cur)) { - cur.getExcludedBy().add(child); - } - } - } - } - - private static void initializeContains(NodeData node) { - for (SpecializationData specialization : node.getSpecializations()) { - Set resolvedSpecializations = specialization.getContains(); - resolvedSpecializations.clear(); - Set includeNames = specialization.getContainsNames(); - for (String includeName : includeNames) { - // TODO reduce complexity of this lookup. - SpecializationData foundSpecialization = lookupSpecialization(node, includeName); - - if (foundSpecialization == null) { - AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); - specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName); - } else { - if (!foundSpecialization.isContainedBy(specialization)) { - AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); - if (foundSpecialization.compareTo(specialization) > 0) { - specialization.addError(value, "The contained specialization '%s' must be declared before the containing specialization.", includeName); - } else { - specialization.addError(value, - "The contained specialization '%s' is not fully compatible. The contained specialization must be strictly more generic than the containing one.", - includeName); - } - - } - resolvedSpecializations.add(foundSpecialization); - } - } - } - } - - private void resolveContains(NodeData node) { - // flatten transitive includes - for (SpecializationData specialization : node.getSpecializations()) { - if (specialization.getContains().isEmpty()) { - continue; - } - Set foundSpecializations = new HashSet<>(); - collectIncludes(specialization, foundSpecializations, new HashSet()); - specialization.getContains().addAll(foundSpecializations); - } - } - - private static SpecializationData lookupSpecialization(NodeData node, String includeName) { - SpecializationData foundSpecialization = null; - for (SpecializationData searchSpecialization : node.getSpecializations()) { - if (searchSpecialization.getMethodName().equals(includeName)) { - foundSpecialization = searchSpecialization; - break; - } - } - return foundSpecialization; - } - - private void collectIncludes(SpecializationData specialization, Set found, Set visited) { - if (visited.contains(specialization)) { - // circle found - specialization.addError("Circular contained specialization '%s' found.", specialization.createReferenceName()); - return; - } - visited.add(specialization); - - for (SpecializationData included : specialization.getContains()) { - collectIncludes(included, found, new HashSet<>(visited)); - found.add(included); - } - } - - private static void initializeReachability(final NodeData node) { - List specializations = node.getSpecializations(); - for (int i = specializations.size() - 1; i >= 0; i--) { - SpecializationData current = specializations.get(i); - if (current.isPolymorphic()) { - current.setReachable(true); - continue; - } - - List shadowedBy = null; - for (int j = i - 1; j >= 0; j--) { - SpecializationData prev = specializations.get(j); - if (prev.isPolymorphic()) { - continue; - } - if (!current.isReachableAfter(prev)) { - if (shadowedBy == null) { - shadowedBy = new ArrayList<>(); - } - shadowedBy.add(prev); - } - } - - if (shadowedBy != null) { - StringBuilder name = new StringBuilder(); - String sep = ""; - for (SpecializationData shadowSpecialization : shadowedBy) { - name.append(sep); - name.append(shadowSpecialization.createReferenceName()); - sep = ", "; - } - current.addError("%s is not reachable. It is shadowed by %s.", current.isGeneric() ? "Generic" : "Specialization", name); - } - current.setReachable(shadowedBy == null); - } - } - - private static List initializeSpecializationIds(List specializations) { - int lastSize = -1; - List> signatureChunks = new ArrayList<>(); - for (SpecializationData other : specializations) { - if (!other.isSpecialized()) { - continue; - } - List paramIds = new LinkedList<>(); - paramIds.add(Utils.getTypeId(other.getReturnType().getType())); - for (ActualParameter param : other.getParameters()) { - if (param.getSpecification().getExecution() == null) { - continue; - } - paramIds.add(Utils.getTypeId(param.getType())); - } - assert lastSize == -1 || lastSize == paramIds.size(); - if (lastSize != -1 && lastSize != paramIds.size()) { - throw new AssertionError(); - } - signatureChunks.add(paramIds); - lastSize = paramIds.size(); - } - - // reduce id vertically - for (int i = 0; i < lastSize; i++) { - String prev = null; - boolean allSame = true; - for (List signature : signatureChunks) { - String arg = signature.get(i); - if (prev == null) { - prev = arg; - continue; - } else if (!prev.equals(arg)) { - allSame = false; - break; - } - prev = arg; - } - - if (allSame) { - for (List signature : signatureChunks) { - signature.remove(i); - } - lastSize--; - } - } - - // reduce id horizontally - for (List signature : signatureChunks) { - if (signature.isEmpty()) { - continue; - } - String prev = null; - boolean allSame = true; - for (String arg : signature) { - if (prev == null) { - prev = arg; - continue; - } else if (!prev.equals(arg)) { - allSame = false; - break; - } - prev = arg; - } - - if (allSame) { - signature.clear(); - signature.add(prev); - } - } - - // create signatures - List signatures = new ArrayList<>(); - for (List signatureChunk : signatureChunks) { - StringBuilder b = new StringBuilder(); - if (signatureChunk.isEmpty()) { - b.append("Default"); - } else { - for (String s : signatureChunk) { - b.append(s); - } - } - signatures.add(b.toString()); - } - - Map counts = new HashMap<>(); - for (String s1 : signatures) { - Integer count = counts.get(s1); - if (count == null) { - count = 0; - } - count++; - counts.put(s1, count); - } - - for (String s : counts.keySet()) { - int count = counts.get(s); - if (count > 1) { - int number = 0; - for (ListIterator iterator = signatures.listIterator(); iterator.hasNext();) { - String s2 = iterator.next(); - if (s.equals(s2)) { - iterator.set(s2 + number); - number++; - } - } - } - } - - return signatures; - } - - private void initializeGuards(List elements, NodeData node) { - Map> guards = new HashMap<>(); - for (SpecializationData specialization : node.getSpecializations()) { - for (GuardExpression exp : specialization.getGuards()) { - guards.put(exp.getGuardName(), null); - } - } - - GuardParser parser = new GuardParser(context, node, null, guards.keySet()); - List resolvedGuards = parser.parse(elements); - for (GuardData guard : resolvedGuards) { - List groupedGuards = guards.get(guard.getMethodName()); - if (groupedGuards == null) { - groupedGuards = new ArrayList<>(); - guards.put(guard.getMethodName(), groupedGuards); - } - groupedGuards.add(guard); - } - - for (SpecializationData specialization : node.getSpecializations()) { - for (GuardExpression exp : specialization.getGuards()) { - resolveGuardExpression(node, specialization, guards, exp); - } - } - } - - private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { - List availableGuards = guards.get(expression.getGuardName()); - if (availableGuards == null) { - source.addError("No compatible guard with method name '%s' found. Please note that all signature types of the method guard must be declared in the type system.", expression.getGuardName()); - return; - } - List guardMethods = new ArrayList<>(); - for (GuardData guard : availableGuards) { - guardMethods.add(guard.getMethod()); - } - GuardParser parser = new GuardParser(context, node, source, new HashSet<>(Arrays.asList(expression.getGuardName()))); - List matchingGuards = parser.parse(guardMethods); - if (!matchingGuards.isEmpty()) { - GuardData guard = matchingGuards.get(0); - // use the shared instance of the guard data - for (GuardData guardData : availableGuards) { - if (guardData.getMethod() == guard.getMethod()) { - expression.setGuard(guardData); - return; - } - } - throw new AssertionError("Should not reach here."); - } else { - MethodSpec spec = parser.createSpecification(source.getMethod(), source.getMarkerAnnotation()); - spec.applyTypeDefinitions("types"); - source.addError("No guard with name '%s' matched the required signature. Expected signature: %n%s", expression.getGuardName(), spec.toSignatureString("guard")); - } - } - - private void initializeGeneric(final NodeData node) { - if (!node.needsRewrites(context)) { - return; - } - - List generics = new ArrayList<>(); - for (SpecializationData spec : node.getSpecializations()) { - if (spec.isGeneric()) { - generics.add(spec); - } - } - - if (generics.size() == 1 && node.getSpecializations().size() == 1) { - // TODO this limitation should be lifted - for (SpecializationData generic : generics) { - generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); - } - } - - if (generics.isEmpty()) { - node.getSpecializations().add(createGenericSpecialization(node)); - } else { - if (generics.size() > 1) { - for (SpecializationData generic : generics) { - generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); - } - } - } - } - - private SpecializationData createGenericSpecialization(final NodeData node) { - GenericParser parser = new GenericParser(context, node); - MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null); - - List parameterTypes = new ArrayList<>(); - int signatureIndex = 1; - for (ParameterSpec spec : specification.getRequired()) { - parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex)); - if (spec.isSignature()) { - signatureIndex++; - } - } - - TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0); - SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes); - if (generic == null) { - throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + "."); - } - - return generic; - } - - private TypeMirror createGenericType(ParameterSpec spec, List specializations, int signatureIndex) { - NodeExecutionData execution = spec.getExecution(); - if (execution == null) { - if (spec.getAllowedTypes().size() == 1) { - return spec.getAllowedTypes().get(0); - } else { - return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); - } - } else { - Set types = new HashSet<>(); - for (SpecializationData specialization : specializations) { - types.add(specialization.getTypeSignature().get(signatureIndex)); - } - - NodeChildData child = execution.getChild(); - TypeData genericType = null; - if (types.size() == 1) { - ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); - if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) { - genericType = types.iterator().next(); - } - } - if (genericType == null) { - genericType = child.findAnyGenericExecutableType(context).getType(); - } - return genericType.getPrimitiveType(); - } - } - - private static void initializeUninitialized(final NodeData node) { - SpecializationData generic = node.getGenericSpecialization(); - if (generic == null) { - return; - } - for (ActualParameter parameter : generic.getReturnTypeAndParameters()) { - if (Utils.isObject(parameter.getType())) { - continue; - } - Set types = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName()); - if (actualParameter != null) { - types.add(Utils.getQualifiedName(actualParameter.getType())); - } - } - if (types.size() > 1) { - generic.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData())); - } - } - TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); - // should not use messages from generic specialization - uninializedMethod.getMessages().clear(); - node.getSpecializations().add(new SpecializationData(node, uninializedMethod, SpecializationKind.UNINITIALIZED)); - } - - private void initializePolymorphism(NodeData node) { - if (!node.needsRewrites(context)) { - return; - } - - SpecializationData generic = node.getGenericSpecialization(); - - List polymorphicSignature = new ArrayList<>(); - List updatePolymorphic = Arrays.asList(); - for (ActualParameter genericParameter : updatePolymorphic) { - if (!genericParameter.getSpecification().isSignature()) { - continue; - } - - Set usedTypes = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isSpecialized()) { - continue; - } - ActualParameter parameter = specialization.findParameter(genericParameter.getLocalName()); - if (parameter == null) { - throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); - } - usedTypes.add(parameter.getTypeSystemType()); - } - - TypeData polymorphicType; - if (usedTypes.size() == 1) { - polymorphicType = usedTypes.iterator().next(); - } else { - polymorphicType = node.getTypeSystem().getGenericTypeData(); - } - polymorphicSignature.add(polymorphicType); - } - - SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); - polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); - node.getSpecializations().add(polymorphic); - } - - private void initializeShortCircuits(NodeData node) { - Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); - - boolean valid = true; - List shortCircuitExecutions = new ArrayList<>(); - for (NodeExecutionData execution : node.getChildExecutions()) { - if (!execution.isShortCircuit()) { - continue; - } - shortCircuitExecutions.add(execution); - String valueName = execution.getShortCircuitId(); - List availableCircuits = groupedShortCircuits.get(valueName); - - if (availableCircuits == null || availableCircuits.isEmpty()) { - node.addError("@%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) { - circuit.addError("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)) { - genericCircuit = circuit; - break; - } - } - - if (genericCircuit == null) { - node.addError("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; - } - - List specializations = new ArrayList<>(); - specializations.addAll(node.getSpecializations()); - for (SpecializationData specialization : specializations) { - List assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size()); - - for (NodeExecutionData shortCircuit : shortCircuitExecutions) { - List availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId()); - - ShortCircuitData genericShortCircuit = null; - ShortCircuitData compatibleShortCircuit = null; - for (ShortCircuitData circuit : availableShortCuts) { - if (circuit.isGeneric()) { - genericShortCircuit = circuit; - } else if (circuit.isCompatibleTo(specialization)) { - compatibleShortCircuit = circuit; - } - } - - if (compatibleShortCircuit == null) { - compatibleShortCircuit = genericShortCircuit; - } - assignedShortCuts.add(compatibleShortCircuit); - } - specialization.setShortCircuits(assignedShortCuts); - } - } - - private boolean isGenericShortCutMethod(ShortCircuitData method) { - for (ActualParameter parameter : method.getParameters()) { - NodeExecutionData execution = parameter.getSpecification().getExecution(); - if (execution == null) { - continue; - } - ExecutableTypeData found = null; - List executableElements = execution.getChild().findGenericExecutableTypes(context); - for (ExecutableTypeData executable : executableElements) { - if (executable.getType().equalsType(parameter.getTypeSystemType())) { - found = executable; - break; - } - } - if (found == null) { - 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 static boolean verifySpecializationSameLength(NodeData nodeData) { - int lastArgs = -1; - for (SpecializationData specializationData : nodeData.getSpecializations()) { - int signatureArgs = specializationData.getSignatureSize(); - if (lastArgs == signatureArgs) { - continue; - } - if (lastArgs != -1) { - for (SpecializationData specialization : nodeData.getSpecializations()) { - specialization.addError("All specializations must have the same number of arguments."); - } - return false; - } else { - lastArgs = signatureArgs; - } - } - return true; - } - - private static void verifyVisibilities(NodeData node) { - if (node.getTemplateType().getModifiers().contains(Modifier.PRIVATE) && node.getSpecializations().size() > 0) { - node.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); - } - } - - private static void verifyMissingAbstractMethods(NodeData nodeData, List originalElements) { - if (!nodeData.needsFactory()) { - // missing abstract methods only needs to be implemented - // if we need go generate factory for it. - return; - } - - List elements = new ArrayList<>(originalElements); - Set unusedElements = new HashSet<>(elements); - for (TemplateMethod method : nodeData.getAllTemplateMethods()) { - unusedElements.remove(method.getMethod()); - } - - for (NodeFieldData field : nodeData.getFields()) { - if (field.getGetter() != null) { - unusedElements.remove(field.getGetter()); - } - } - - for (NodeChildData child : nodeData.getChildren()) { - if (child.getAccessElement() != null) { - unusedElements.remove(child.getAccessElement()); - } - } - - for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { - if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { - nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod)); - } - } - } - - private static void verifyNamingConvention(List methods, String prefix) { - for (int i = 0; i < methods.size(); i++) { - TemplateMethod m1 = methods.get(i); - if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { - m1.addError("Naming convention: method name must start with '%s'.", prefix); - } - } - } - - private static void verifySpecializationThrows(NodeData node) { - Map specializationMap = new HashMap<>(); - for (SpecializationData spec : node.getSpecializations()) { - specializationMap.put(spec.getMethodName(), spec); - } - for (SpecializationData sourceSpecialization : node.getSpecializations()) { - if (sourceSpecialization.getExceptions() != null) { - for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { - for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { - if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { - throwsData.addError("Duplicate exception type."); - } - } - } - } - } - } - - private void verifyConstructors(NodeData nodeData) { - if (!nodeData.needsRewrites(context)) { - // no specialization constructor is needed if the node never rewrites. - return; - } - - TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType()); - List constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); - - boolean parametersFound = false; - for (ExecutableElement constructor : constructors) { - if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) { - parametersFound = true; - } - } - if (!parametersFound) { - return; - } - 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)) { - nodeData.addError("The specialization constructor must not be private."); - } else if (constructors.size() <= 1) { - nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); - } - return; - } - } - } - - // not found - nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type)); - } - - static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) { - return constructor.getParameters().size() == 1 && Utils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection()); - } - - 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 TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) { - TypeMirror inhertNodeType = context.getTruffleTypes().getNode(); - TypeMirror value = Utils.getAnnotationValue(TypeMirror.class, annotation, valueName); - if (Utils.typeEquals(inhertNodeType, value)) { - return parentType; - } else { - return value; - } - } - - private ExecutableElement findGetter(List elements, String variableName, TypeMirror type) { - if (type == null) { - return null; - } - String methodName; - if (Utils.typeEquals(type, context.getType(boolean.class))) { - methodName = "is" + Utils.firstLetterUpperCase(variableName); - } else { - methodName = "get" + Utils.firstLetterUpperCase(variableName); - } - - for (ExecutableElement method : ElementFilter.methodsIn(elements)) { - if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.isAssignable(type, method.getReturnType())) { - return method; - } - } - return null; - } - - private static List collectSuperClasses(List collection, TypeElement element) { - if (element != null) { - collection.add(element); - if (element.getSuperclass() != null) { - collectSuperClasses(collection, Utils.fromTypeMirror(element.getSuperclass())); - } - } - return collection; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ShortCircuitData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ShortCircuitData.java Mon Aug 11 15:53:05 2014 +0200 +++ /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.dsl.processor.node; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.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()) { - ActualParameter specializationParam = specialization.findParameter(param.getLocalName()); - if (!Utils.typeEquals(param.getType(), specializationParam.getType())) { - return false; - } - } - return true; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ShortCircuitParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ShortCircuitParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /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.dsl.processor.node; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class ShortCircuitParser extends NodeMethodParser { - - private final Set shortCircuitValues; - - public ShortCircuitParser(ProcessorContext context, NodeData node) { - super(context, node); - - shortCircuitValues = new HashSet<>(); - for (NodeExecutionData execution : node.getChildExecutions()) { - if (execution.isShortCircuit()) { - shortCircuitValues.add(execution.getShortCircuitId()); - } - } - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value"); - - return createDefaultMethodSpec(method, mirror, true, shortCircuitValue); - } - - @Override - protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("has", getContext().getType(boolean.class)); - } - - @Override - public ShortCircuitData create(TemplateMethod method, boolean invalid) { - String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value"); - - if (!shortCircuitValues.contains(shortCircuitValue)) { - method.addError("Invalid short circuit value %s.", shortCircuitValue); - } - - return new ShortCircuitData(method, shortCircuitValue); - } - - @Override - public Class getAnnotationType() { - return ShortCircuit.class; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,496 +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.dsl.processor.node; - -import java.util.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public final class SpecializationData extends TemplateMethod { - - public enum SpecializationKind { - UNINITIALIZED, - SPECIALIZED, - POLYMORPHIC, - GENERIC - } - - private final NodeData node; - private final SpecializationKind kind; - private final List exceptions; - private List guards = Collections.emptyList(); - private List shortCircuits; - private List assumptions = Collections.emptyList(); - private final Set contains = new TreeSet<>(); - private final Set containsNames = new TreeSet<>(); - private final Set excludedBy = new TreeSet<>(); - private String insertBeforeName; - private SpecializationData insertBefore; - private boolean reachable; - private int index; - - public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind, List exceptions) { - super(template); - this.node = node; - this.kind = kind; - this.exceptions = exceptions; - this.index = template.getNaturalOrder(); - - for (SpecializationThrowsData exception : exceptions) { - exception.setSpecialization(this); - } - } - - public void setInsertBefore(SpecializationData insertBefore) { - this.insertBefore = insertBefore; - } - - public void setInsertBeforeName(String insertBeforeName) { - this.insertBeforeName = insertBeforeName; - } - - public SpecializationData getInsertBefore() { - return insertBefore; - } - - public String getInsertBeforeName() { - return insertBeforeName; - } - - public Set getContainsNames() { - return containsNames; - } - - public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind) { - this(node, template, kind, new ArrayList()); - } - - public Set getContains() { - return contains; - } - - public Set getExcludedBy() { - return excludedBy; - } - - public void setReachable(boolean reachable) { - this.reachable = reachable; - } - - public boolean isReachable() { - return reachable; - } - - public boolean isPolymorphic() { - return kind == SpecializationKind.POLYMORPHIC; - } - - @Override - protected List findChildContainers() { - List sinks = new ArrayList<>(); - if (exceptions != null) { - sinks.addAll(exceptions); - } - if (guards != null) { - for (GuardExpression guard : guards) { - if (guard.isResolved()) { - sinks.add(guard.getResolvedGuard()); - } - } - } - return sinks; - } - - public boolean hasRewrite(ProcessorContext context) { - if (!getExceptions().isEmpty()) { - return true; - } - if (!getGuards().isEmpty()) { - return true; - } - if (!getAssumptions().isEmpty()) { - return true; - } - for (ActualParameter parameter : getSignatureParameters()) { - ExecutableTypeData type = parameter.getSpecification().getExecution().getChild().findExecutableType(context, parameter.getTypeSystemType()); - if (type.hasUnexpectedValue(context)) { - return true; - } - if (type.getReturnType().getTypeSystemType().needsCastTo(parameter.getTypeSystemType())) { - return true; - } - - } - return false; - } - - @Override - public int compareTo(TemplateMethod other) { - if (this == other) { - return 0; - } else if (!(other instanceof SpecializationData)) { - return super.compareTo(other); - } - SpecializationData m2 = (SpecializationData) other; - int kindOrder = kind.compareTo(m2.kind); - if (kindOrder != 0) { - return kindOrder; - } - - int compare = 0; - int order1 = index; - int order2 = m2.index; - if (order1 != NO_NATURAL_ORDER && order2 != NO_NATURAL_ORDER) { - compare = Integer.compare(order1, order2); - if (compare != 0) { - return compare; - } - } - - return super.compareTo(other); - } - - public void setIndex(int order) { - this.index = order; - } - - public int getIndex() { - return index; - } - - public int compareByConcreteness(SpecializationData m2) { - int kindOrder = kind.compareTo(m2.kind); - if (kindOrder != 0) { - return kindOrder; - } - - if (getTemplate() != m2.getTemplate()) { - throw new UnsupportedOperationException("Cannot compare two specializations with different templates."); - } - boolean intersects = intersects(m2); - int result = 0; - if (intersects) { - if (this.contains(m2)) { - return 1; - } else if (m2.contains(this)) { - return -1; - } - } - - result = compareBySignature(m2); - if (result != 0) { - return result; - } - - result = compareGuards(getGuards(), m2.getGuards()); - if (result != 0) { - return result; - } - - result = compareAssumptions(getAssumptions(), m2.getAssumptions()); - if (result != 0) { - return result; - } - - result = compareParameter(node.getTypeSystem(), getReturnType().getType(), m2.getReturnType().getType()); - if (result != 0) { - return result; - } - - result = m2.getExceptions().size() - getExceptions().size(); - if (result != 0) { - return result; - } - - return result; - } - - public boolean contains(SpecializationData other) { - return getContains().contains(other); - } - - private int compareAssumptions(List assumptions1, List assumptions2) { - Iterator iterator1 = assumptions1.iterator(); - Iterator iterator2 = assumptions2.iterator(); - while (iterator1.hasNext() && iterator2.hasNext()) { - String a1 = iterator1.next(); - String a2 = iterator2.next(); - - int index1 = getNode().getAssumptions().indexOf(a1); - int index2 = getNode().getAssumptions().indexOf(a2); - int result = index1 - index2; - if (result != 0) { - return result; - } - } - if (iterator1.hasNext()) { - return -1; - } else if (iterator2.hasNext()) { - return 1; - } - return 0; - } - - public boolean isContainedBy(SpecializationData next) { - if (compareTo(next) > 0) { - // must be declared after the current specialization - return false; - } - - Iterator currentSignature = getSignatureParameters().iterator(); - Iterator nextSignature = next.getSignatureParameters().iterator(); - - while (currentSignature.hasNext() && nextSignature.hasNext()) { - TypeData currentType = currentSignature.next().getTypeSystemType(); - TypeData prevType = nextSignature.next().getTypeSystemType(); - - if (!currentType.isImplicitSubtypeOf(prevType)) { - return false; - } - } - - for (String nextAssumption : next.getAssumptions()) { - if (!getAssumptions().contains(nextAssumption)) { - return false; - } - } - - Iterator nextGuards = next.getGuards().iterator(); - while (nextGuards.hasNext()) { - GuardExpression nextGuard = nextGuards.next(); - boolean implied = false; - for (GuardExpression currentGuard : getGuards()) { - if (currentGuard.implies(nextGuard)) { - implied = true; - break; - } - } - if (!implied) { - return false; - } - } - - return true; - } - - public boolean intersects(SpecializationData other) { - return intersectsTypeGuards(other) || intersectsMethodGuards(other); - } - - private boolean intersectsTypeGuards(SpecializationData other) { - final TypeSystemData typeSystem = getTemplate().getTypeSystem(); - if (typeSystem != other.getTemplate().getTypeSystem()) { - throw new IllegalStateException("Cannot compare two methods with different type systems."); - } - - Iterator signature1 = getSignatureParameters().iterator(); - Iterator signature2 = other.getSignatureParameters().iterator(); - while (signature1.hasNext() && signature2.hasNext()) { - TypeData parameter1 = signature1.next().getTypeSystemType(); - TypeData parameter2 = signature2.next().getTypeSystemType(); - if (parameter1 == null || parameter2 == null) { - continue; - } - if (!parameter1.intersects(parameter2)) { - return false; - } - } - return true; - } - - private boolean intersectsMethodGuards(SpecializationData other) { - for (GuardExpression guard1 : getGuards()) { - for (GuardExpression guard2 : other.getGuards()) { - if (guard1.impliesNot(guard2) || guard2.impliesNot(guard1)) { - return false; - } - } - } - return true; - } - - private static int compareGuards(List guards1, List guards2) { - Iterator signature1 = guards1.iterator(); - Iterator signature2 = guards2.iterator(); - boolean allSame = true; - while (signature1.hasNext() && signature2.hasNext()) { - GuardExpression guard1 = signature1.next(); - GuardExpression guard2 = signature2.next(); - boolean g1impliesg2 = guard1.implies(guard2); - boolean g2impliesg1 = guard2.implies(guard1); - if (g1impliesg2 && g2impliesg1) { - continue; - } else if (g1impliesg2) { - return -1; - } else if (g2impliesg1) { - return 1; - } else { - allSame = false; - } - } - - if (allSame) { - if (signature1.hasNext()) { - return -1; - } else if (signature2.hasNext()) { - return 1; - } - } - - return 0; - } - - public String createReferenceName() { - StringBuilder b = new StringBuilder(); - - b.append(getMethodName()); - b.append("("); - - String sep = ""; - for (ActualParameter parameter : getParameters()) { - b.append(sep); - b.append(Utils.getSimpleName(parameter.getType())); - sep = ", "; - } - - b.append(")"); - return b.toString(); - } - - public NodeData getNode() { - return node; - } - - public void setGuards(List guards) { - this.guards = guards; - } - - public boolean isSpecialized() { - return kind == SpecializationKind.SPECIALIZED; - } - - public boolean isGeneric() { - return kind == SpecializationKind.GENERIC; - } - - public boolean isUninitialized() { - return kind == SpecializationKind.UNINITIALIZED; - } - - public List getExceptions() { - return exceptions; - } - - public List getGuards() { - return guards; - } - - public void setShortCircuits(List shortCircuits) { - this.shortCircuits = shortCircuits; - } - - public List getShortCircuits() { - return shortCircuits; - } - - public List getAssumptions() { - return assumptions; - } - - void setAssumptions(List assumptions) { - this.assumptions = assumptions; - } - - public SpecializationData findNextSpecialization() { - List specializations = node.getSpecializations(); - for (int i = 0; i < specializations.size() - 1; i++) { - if (specializations.get(i) == this) { - return specializations.get(i + 1); - } - } - return null; - } - - @Override - public String toString() { - return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature()); - } - - public boolean equalsGuards(SpecializationData specialization) { - if (assumptions.equals(specialization.getAssumptions()) && guards.equals(specialization.getGuards()) && getTypeSignature().equalsParameters(specialization.getTypeSignature())) { - return true; - } - return false; - } - - public boolean hasFrame(ProcessorContext context) { - for (ActualParameter param : getParameters()) { - if (Utils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) { - return true; - } - } - return false; - } - - public boolean isReachableAfter(SpecializationData prev) { - if (!prev.isSpecialized()) { - return true; - } - - if (!prev.getExceptions().isEmpty()) { - return true; - } - - Iterator currentSignature = getSignatureParameters().iterator(); - Iterator prevSignature = prev.getSignatureParameters().iterator(); - - while (currentSignature.hasNext() && prevSignature.hasNext()) { - TypeData currentType = currentSignature.next().getTypeSystemType(); - TypeData prevType = prevSignature.next().getTypeSystemType(); - - if (!currentType.isImplicitSubtypeOf(prevType)) { - return true; - } - } - - for (String prevAssumption : prev.getAssumptions()) { - if (!getAssumptions().contains(prevAssumption)) { - return true; - } - } - - Iterator prevGuards = prev.getGuards().iterator(); - Iterator currentGuards = getGuards().iterator(); - while (prevGuards.hasNext()) { - GuardExpression prevGuard = prevGuards.next(); - GuardExpression currentGuard = currentGuards.hasNext() ? currentGuards.next() : null; - if (currentGuard == null || !currentGuard.implies(prevGuard)) { - return true; - } - } - - return false; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGroup.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,448 +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.dsl.processor.node; - -import java.util.*; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature; -import com.oracle.truffle.dsl.processor.typesystem.*; - -/** - * Class creates groups of specializations to optimize the layout of generated executeAndSpecialize - * and generic execute methods. - */ -public final class SpecializationGroup { - - private final List assumptions; - private final List typeGuards; - private final List guards; - - private final NodeData node; - private final SpecializationData specialization; - private final List children = new ArrayList<>(); - - private SpecializationGroup parent; - - private SpecializationGroup(SpecializationData data) { - this.node = data.getNode(); - this.assumptions = new ArrayList<>(); - this.typeGuards = new ArrayList<>(); - this.guards = new ArrayList<>(); - this.specialization = data; - - this.assumptions.addAll(data.getAssumptions()); - TypeSignature sig = data.getTypeSignature(); - for (int i = 1; i < sig.size(); i++) { - typeGuards.add(new TypeGuard(sig.get(i), i - 1)); - } - this.guards.addAll(data.getGuards()); - } - - public SpecializationGroup(List children, List assumptionMatches, List typeGuardsMatches, List guardMatches) { - assert !children.isEmpty() : "children must not be empty"; - this.assumptions = assumptionMatches; - this.typeGuards = typeGuardsMatches; - this.guards = guardMatches; - this.node = children.get(0).node; - this.specialization = null; - updateChildren(children); - } - - public List getAllGuards() { - List collectedGuards = new ArrayList<>(); - collectedGuards.addAll(typeGuards); - if (parent != null) { - collectedGuards.addAll(parent.getAllGuards()); - } - return collectedGuards; - } - - public TypeGuard findTypeGuard(int signatureIndex) { - for (TypeGuard guard : typeGuards) { - if (guard.getSignatureIndex() == signatureIndex) { - return guard; - } - } - return null; - } - - public List findElseConnectableGuards() { - if (!getTypeGuards().isEmpty() || !getAssumptions().isEmpty()) { - return Collections.emptyList(); - } - - if (getGuards().isEmpty()) { - return Collections.emptyList(); - } - - List elseConnectableGuards = new ArrayList<>(); - int guardIndex = 0; - while (guardIndex < getGuards().size() && findNegatedGuardInPrevious(getGuards().get(guardIndex)) != null) { - elseConnectableGuards.add(getGuards().get(guardIndex)); - guardIndex++; - } - - return elseConnectableGuards; - } - - private GuardExpression findNegatedGuardInPrevious(GuardExpression guard) { - SpecializationGroup previous = this.getPreviousGroup(); - if (previous == null) { - return null; - } - List elseConnectedGuards = previous.findElseConnectableGuards(); - - if (previous == null || previous.getGuards().size() != elseConnectedGuards.size() + 1) { - return null; - } - - /* Guard is else branch can be connected in previous specialization. */ - if (elseConnectedGuards.contains(guard)) { - return guard; - } - - GuardExpression previousGuard = previous.getGuards().get(elseConnectedGuards.size()); - if (guard.getResolvedGuard().getMethod().equals(previousGuard.getResolvedGuard().getMethod()) && guard.isNegated() != previousGuard.isNegated()) { - return guard; - } - return null; - } - - private void updateChildren(List childs) { - if (!children.isEmpty()) { - children.clear(); - } - this.children.addAll(childs); - for (SpecializationGroup child : childs) { - child.parent = this; - } - } - - public SpecializationGroup getParent() { - return parent; - } - - public List getAssumptions() { - return assumptions; - } - - public List getTypeGuards() { - return typeGuards; - } - - public List getGuards() { - return guards; - } - - public List getChildren() { - return children; - } - - public SpecializationData getSpecialization() { - return specialization; - } - - private static SpecializationGroup combine(List groups) { - if (groups.isEmpty()) { - throw new IllegalArgumentException("empty combinations"); - } - if (groups.size() == 1) { - return null; - } - - List assumptionMatches = new ArrayList<>(); - List typeGuardsMatches = new ArrayList<>(); - List guardMatches = new ArrayList<>(); - - SpecializationGroup first = groups.get(0); - List others = groups.subList(1, groups.size()); - - outer: for (String assumption : first.assumptions) { - for (SpecializationGroup other : others) { - if (!other.assumptions.contains(assumption)) { - // assumptions can be combined unordered - continue outer; - } - } - assumptionMatches.add(assumption); - } - - outer: for (TypeGuard typeGuard : first.typeGuards) { - for (SpecializationGroup other : others) { - if (!other.typeGuards.contains(typeGuard)) { - // type guards can be combined unordered - continue outer; - } - } - typeGuardsMatches.add(typeGuard); - } - - outer: for (GuardExpression guard : first.guards) { - for (SpecializationGroup other : others) { - if (!other.guards.contains(guard)) { - // we must break here. One guard may depend on the other. - break outer; - } - } - guardMatches.add(guard); - } - - // check for guards for required type casts - for (Iterator iterator = guardMatches.iterator(); iterator.hasNext();) { - GuardExpression guardMatch = iterator.next(); - - int signatureIndex = 0; - for (ActualParameter parameter : guardMatch.getResolvedGuard().getParameters()) { - signatureIndex++; - if (!parameter.getSpecification().isSignature()) { - continue; - } - - TypeMirror guardType = parameter.getType(); - - // object guards can be safely moved up - if (Utils.isObject(guardType)) { - continue; - } - - // generic guards can be safely moved up - SpecializationData generic = first.node.getGenericSpecialization(); - if (generic != null) { - ActualParameter genericParameter = generic.findParameter(parameter.getLocalName()); - if (genericParameter != null && Utils.typeEquals(genericParameter.getType(), guardType)) { - continue; - } - } - - // signature index required for moving up guards - if (containsIndex(typeGuardsMatches, signatureIndex) || (first.getParent() != null && first.getParent().containsTypeGuardIndex(signatureIndex))) { - continue; - } - - iterator.remove(); - break; - } - } - - if (assumptionMatches.isEmpty() && typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) { - return null; - } - - for (SpecializationGroup group : groups) { - group.assumptions.removeAll(assumptionMatches); - group.typeGuards.removeAll(typeGuardsMatches); - group.guards.removeAll(guardMatches); - } - - List newChildren = new ArrayList<>(groups); - return new SpecializationGroup(newChildren, assumptionMatches, typeGuardsMatches, guardMatches); - } - - private boolean containsTypeGuardIndex(int index) { - if (containsIndex(typeGuards, index)) { - return true; - } - if (parent != null) { - return parent.containsTypeGuardIndex(index); - } - return false; - } - - private static boolean containsIndex(List typeGuards, int signatureIndex) { - for (TypeGuard guard : typeGuards) { - if (guard.signatureIndex == signatureIndex) { - return true; - } - } - return false; - } - - public static SpecializationGroup create(SpecializationData specialization) { - return new SpecializationGroup(specialization); - } - - public static SpecializationGroup create(List specializations) { - List groups = new ArrayList<>(); - for (SpecializationData specialization : specializations) { - groups.add(new SpecializationGroup(specialization)); - } - return new SpecializationGroup(createCombinationalGroups(groups), Collections. emptyList(), Collections. emptyList(), Collections. emptyList()); - } - - @Override - public String toString() { - return "SpecializationGroup [assumptions=" + assumptions + ", typeGuards=" + typeGuards + ", guards=" + guards + "]"; - } - - private static List createCombinationalGroups(List groups) { - if (groups.size() <= 1) { - return groups; - } - List newGroups = new ArrayList<>(); - - int i = 0; - for (i = 0; i < groups.size();) { - SpecializationGroup combined = null; - for (int j = groups.size(); j > i + 1; j--) { - combined = combine(groups.subList(i, j)); - if (combined != null) { - break; - } - } - SpecializationGroup newGroup; - if (combined == null) { - newGroup = groups.get(i); - i++; - } else { - newGroup = combined; - List originalGroups = new ArrayList<>(combined.children); - combined.updateChildren(createCombinationalGroups(originalGroups)); - i += originalGroups.size(); - } - - newGroups.add(newGroup); - - } - - return newGroups; - } - - public SpecializationGroup getPreviousGroup() { - if (parent == null || parent.children.isEmpty()) { - return null; - } - int index = parent.children.indexOf(this); - if (index <= 0) { - return null; - } - return parent.children.get(index - 1); - } - - public int getUncheckedSpecializationIndex() { - int groupMaxIndex = getMaxSpecializationIndex(); - - int genericIndex = node.getSpecializations().indexOf(node.getGenericSpecialization()); - if (groupMaxIndex >= genericIndex) { - // no minimum state check for an generic index - groupMaxIndex = -1; - } - - if (groupMaxIndex > -1) { - // no minimum state check if already checked by parent group - int parentMaxIndex = -1; - if (getParent() != null) { - parentMaxIndex = getParent().getMaxSpecializationIndex(); - } - if (groupMaxIndex == parentMaxIndex) { - groupMaxIndex = -1; - } - } - return groupMaxIndex; - } - - public int getMaxSpecializationIndex() { - if (specialization != null) { - return specialization.getNode().getSpecializations().indexOf(specialization); - } else { - int max = Integer.MIN_VALUE; - for (SpecializationGroup childGroup : getChildren()) { - max = Math.max(max, childGroup.getMaxSpecializationIndex()); - } - return max; - } - } - - public static final class TypeGuard { - - private final int signatureIndex; - private final TypeData type; - - public TypeGuard(TypeData type, int signatureIndex) { - this.type = type; - this.signatureIndex = signatureIndex; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + signatureIndex; - result = prime * result + type.hashCode(); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } else if (obj == null) { - return false; - } else if (getClass() != obj.getClass()) { - return false; - } - - TypeGuard other = (TypeGuard) obj; - if (signatureIndex != other.signatureIndex) { - return false; - } else if (!type.equals(other.type)) { - return false; - } - return true; - } - - public int getSignatureIndex() { - return signatureIndex; - } - - public TypeData getType() { - return type; - } - } - - public boolean isTypeGuardUsedInAnyGuardBelow(ProcessorContext context, SpecializationData source, TypeGuard typeGuard) { - - for (GuardExpression guard : guards) { - ActualParameter guardParameter = guard.getResolvedGuard().getSignatureParameter(typeGuard.getSignatureIndex()); - if (guardParameter == null) { - // guardParameters are optional - continue; - } - ActualParameter sourceParameter = source.getSignatureParameter(typeGuard.getSignatureIndex()); - if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { - return true; - } - } - - for (SpecializationGroup group : getChildren()) { - if (group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard)) { - return true; - } - } - - return false; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGuardData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationGuardData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +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.dsl.processor.node; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class SpecializationGuardData extends MessageContainer { - - private final SpecializationData specialization; - private final AnnotationValue value; - private final String guardMethod; - private final boolean onSpecialization; - private final boolean onExecution; - - private GuardData guardDeclaration; - - public SpecializationGuardData(SpecializationData specialization, AnnotationValue value, String guardMethod, boolean onSpecialization, boolean onExecution) { - this.specialization = specialization; - this.guardMethod = guardMethod; - this.onSpecialization = onSpecialization; - this.onExecution = onExecution; - this.value = value; - } - - @Override - public Element getMessageElement() { - return specialization.getMessageElement(); - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return specialization.getMessageAnnotation(); - } - - @Override - public AnnotationValue getMessageAnnotationValue() { - return value; - } - - 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 c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationMethodParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +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.dsl.processor.node; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.node.SpecializationData.SpecializationKind; -import com.oracle.truffle.dsl.processor.template.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class SpecializationMethodParser extends NodeMethodParser { - - public SpecializationMethodParser(ProcessorContext context, NodeData operation) { - super(context, operation); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(method, mirror, true, null); - } - - @Override - public SpecializationData create(TemplateMethod method, boolean invalid) { - return parseSpecialization(method); - } - - @Override - public Class getAnnotationType() { - return Specialization.class; - } - - private SpecializationData parseSpecialization(TemplateMethod method) { - AnnotationValue rewriteValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn"); - List exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); - List exceptionData = new ArrayList<>(); - for (TypeMirror exceptionType : exceptionTypes) { - SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType); - if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { - throwsData.addError("Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType)); - } - exceptionData.add(throwsData); - } - - Collections.sort(exceptionData, new Comparator() { - - @Override - public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { - return Utils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); - } - }); - SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData); - - String insertBeforeName = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore"); - if (!insertBeforeName.equals("")) { - specialization.setInsertBeforeName(insertBeforeName); - } - - List guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); - List guardExpressions = new ArrayList<>(); - for (String guardDef : guardDefs) { - guardExpressions.add(new GuardExpression(guardDef)); - } - specialization.setGuards(guardExpressions); - - List containsDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains"); - Set containsNames = specialization.getContainsNames(); - containsNames.clear(); - if (containsDefs != null) { - for (String include : containsDefs) { - if (!containsNames.contains(include)) { - specialization.getContainsNames().add(include); - } else { - AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); - specialization.addError(value, "Duplicate contains declaration '%s'.", include); - } - } - - } - - List assumptionDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); - specialization.setAssumptions(assumptionDefs); - - for (String assumption : assumptionDefs) { - if (!getNode().getAssumptions().contains(assumption)) { - specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption); - } - } - - return specialization; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationThrowsData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationThrowsData.java Mon Aug 11 15:53:05 2014 +0200 +++ /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.dsl.processor.node; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.template.*; - -public class SpecializationThrowsData extends MessageContainer { - - private final AnnotationValue annotationValue; - private final AnnotationMirror annotationMirror; - private final TypeMirror javaClass; - private SpecializationData specialization; - - public SpecializationThrowsData(AnnotationMirror annotationMirror, AnnotationValue value, TypeMirror javaClass) { - this.annotationMirror = annotationMirror; - this.annotationValue = value; - this.javaClass = javaClass; - } - - void setSpecialization(SpecializationData specialization) { - this.specialization = specialization; - } - - @Override - public Element getMessageElement() { - return specialization.getMessageElement(); - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return annotationMirror; - } - - @Override - public AnnotationValue getMessageAnnotationValue() { - return annotationValue; - } - - public TypeMirror getJavaClass() { - return javaClass; - } - - public SpecializationData getSpecialization() { - return specialization; - } - - public AnnotationMirror getAnnotationMirror() { - return annotationMirror; - } - - public SpecializationData getTransitionTo() { - return specialization.findNextSpecialization(); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/AbstractParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/AbstractParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,148 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.Kind; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.MessageContainer.Message; + +/** + * THIS IS NOT PUBLIC API. + */ +public abstract class AbstractParser { + + protected final ProcessorContext context; + protected final ProcessingEnvironment processingEnv; + + protected final Log log; + + public AbstractParser() { + this.context = ProcessorContext.getInstance(); + this.processingEnv = context.getEnvironment(); + this.log = context.getLog(); + } + + public final M parse(Element element) { + M model = null; + try { + AnnotationMirror mirror = null; + if (getAnnotationType() != null) { + mirror = ElementUtils.findAnnotationMirror(processingEnv, element.getAnnotationMirrors(), getAnnotationType()); + } + + if (!context.getTruffleTypes().verify(context, element, mirror)) { + return null; + } + model = parse(element, mirror); + if (model == null) { + return null; + } + + redirectMessages(new HashSet(), model, model); + model.emitMessages(context, log); + return filterErrorElements(model); + } catch (CompileErrorException e) { + log.message(Kind.WARNING, element, null, null, "The truffle processor could not parse class due to error: %s", e.getMessage()); + return null; + } + } + + private void redirectMessages(Set visitedSinks, MessageContainer model, MessageContainer baseContainer) { + List messages = model.getMessages(); + for (int i = messages.size() - 1; i >= 0; i--) { + Message message = messages.get(i); + if (!ElementUtils.isEnclosedIn(baseContainer.getMessageElement(), message.getOriginalContainer().getMessageElement())) { + // redirect message + MessageContainer original = message.getOriginalContainer(); + String text = wrapText(original.getMessageElement(), original.getMessageAnnotation(), message.getText()); + Message redirectedMessage = new Message(null, baseContainer, text, message.getKind()); + model.getMessages().remove(i); + baseContainer.getMessages().add(redirectedMessage); + } + } + + for (MessageContainer childContainer : model) { + if (visitedSinks.contains(childContainer)) { + continue; + } + visitedSinks.add(childContainer); + + MessageContainer newBase = baseContainer; + if (childContainer.getBaseContainer() != null) { + newBase = childContainer.getBaseContainer(); + } + redirectMessages(visitedSinks, childContainer, newBase); + } + } + + private static String wrapText(Element element, AnnotationMirror mirror, String text) { + StringBuilder b = new StringBuilder(); + if (element != null) { + b.append("Element " + element.toString()); + } + if (mirror != null) { + b.append(" at annotation @" + ElementUtils.getSimpleName(mirror.getAnnotationType())); + } + + if (b.length() > 0) { + b.append(" is erroneous: ").append(text); + return b.toString(); + } else { + return text; + } + } + + protected M filterErrorElements(M model) { + return model.hasErrors() ? null : model; + } + + protected abstract M parse(Element element, AnnotationMirror mirror); + + public abstract Class 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 c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,117 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class CreateCastParser extends NodeMethodParser { + + public CreateCastParser(ProcessorContext context, NodeData operation) { + super(context, operation); + } + + @Override + public Class getAnnotationType() { + return CreateCast.class; + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List childNames = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); + NodeChildData foundChild = null; + for (String childName : childNames) { + foundChild = getNode().findChild(childName); + if (foundChild != null) { + break; + } + } + TypeMirror baseType = getContext().getTruffleTypes().getNode(); + if (foundChild != null) { + baseType = foundChild.getOriginalType(); + } + + MethodSpec spec = new MethodSpec(new InheritsParameterSpec("child", baseType)); + addDefaultFieldMethodSpec(spec); + ParameterSpec childSpec = new ParameterSpec("castedChild", baseType); + childSpec.setSignature(true); + spec.addRequired(childSpec); + return spec; + } + + @Override + public CreateCastData create(TemplateMethod method, boolean invalid) { + AnnotationMirror mirror = method.getMarkerAnnotation(); + List childNames = ElementUtils.getAnnotationValueList(String.class, mirror, "value"); + CreateCastData cast = new CreateCastData(method, childNames); + AnnotationValue value = ElementUtils.getAnnotationValue(mirror, "value"); + TypeMirror type = null; + if (childNames == null || childNames.isEmpty()) { + cast.addError(value, "No value specified but required."); + return cast; + } + + for (String childName : childNames) { + NodeChildData child = getNode().findChild(childName); + if (child == null) { + // error + cast.addError(value, "Specified child '%s' not found.", childName); + continue; + } + if (type == null) { + type = child.getNodeType(); + } else if (!ElementUtils.typeEquals(type, child.getNodeType())) { + cast.addError(value, "All child nodes for a cast must have the same node type."); + continue; + } + } + return cast; + } + + private static class InheritsParameterSpec extends ParameterSpec { + + public InheritsParameterSpec(String name, TypeMirror... allowedTypes) { + super(name, Arrays.asList(allowedTypes)); + } + + @Override + public boolean matches(TypeMirror actualType) { + boolean found = false; + for (TypeMirror specType : getAllowedTypes()) { + if (ElementUtils.isAssignable(actualType, specType)) { + found = true; + break; + } + } + return found; + } + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,91 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class ExecutableTypeMethodParser extends NodeMethodParser { + + public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { + super(context, node); + setEmitErrors(false); + setParseNullOnError(false); + setUseVarArgs(true); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null); + List requiredSpecs = new ArrayList<>(spec.getRequired()); + spec.getRequired().clear(); + + List allowedTypes = getNode().getTypeSystem().getPrimitiveTypeMirrors(); + for (ParameterSpec originalSpec : requiredSpecs) { + spec.addRequired(new ParameterSpec(originalSpec, allowedTypes)); + } + spec.setIgnoreAdditionalSpecifications(true); + spec.setIgnoreAdditionalParameters(true); + spec.setVariableRequiredParameters(true); + // varargs + ParameterSpec otherParameters = new ParameterSpec("other", allowedTypes); + otherParameters.setSignature(true); + spec.addRequired(otherParameters); + return spec; + } + + @Override + public final boolean isParsable(ExecutableElement method) { + if (method.getModifiers().contains(Modifier.STATIC)) { + return false; + } else if (method.getModifiers().contains(Modifier.NATIVE)) { + return false; + } + return method.getSimpleName().toString().startsWith("execute"); + } + + @Override + protected List nodeTypeMirrors(NodeData nodeData) { + List types = new ArrayList<>(getNode().getTypeSystem().getPrimitiveTypeMirrors()); + types.add(getNode().getTypeSystem().getVoidType().getPrimitiveType()); + return types; + } + + @Override + public ExecutableTypeData create(TemplateMethod method, boolean invalid) { + TypeData resolvedType = method.getReturnType().getTypeSystemType(); + return new ExecutableTypeData(method, method.getMethod(), getNode().getTypeSystem(), resolvedType); + } + + @Override + public Class getAnnotationType() { + return null; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,69 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; + +public class GenericParser extends NodeMethodParser { + + public GenericParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return createDefaultMethodSpec(method, mirror, true, null); + } + + @Override + protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { + List execTypes = execution.getChild().findGenericExecutableTypes(getContext()); + List types = new ArrayList<>(); + for (ExecutableTypeData type : execTypes) { + types.add(type.getType().getPrimitiveType()); + } + ParameterSpec spec = new ParameterSpec(execution.getName(), types); + spec.setExecution(execution); + return spec; + } + + @Override + public SpecializationData create(TemplateMethod method, boolean invalid) { + return new SpecializationData(getNode(), method, SpecializationKind.GENERIC); + } + + @Override + public Class getAnnotationType() { + return Generic.class; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,104 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class GuardParser extends NodeMethodParser { + + private final Set guardNames; + private final TemplateMethod compatibleSource; + + public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, Set guardNames) { + super(context, node); + this.guardNames = guardNames; + this.compatibleSource = compatibleSource; + setEmitErrors(false); + setParseNullOnError(false); + } + + @Override + protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { + return super.createValueParameterSpec(execution); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null); + spec.setIgnoreAdditionalSpecifications(true); + if (compatibleSource != null) { + spec.getRequired().clear(); + for (Parameter parameter : compatibleSource.getRequiredParameters()) { + spec.addRequired(new ParameterSpec(parameter.getSpecification(), ElementUtils.getAssignableTypes(getContext(), parameter.getType()))); + } + } + return spec; + } + + @Override + protected List nodeTypeMirrors(NodeData nodeData) { + Set typeMirrors = new LinkedHashSet<>(); + typeMirrors.addAll(nodeData.getTypeSystem().getPrimitiveTypeMirrors()); + typeMirrors.addAll(nodeData.getTypeSystem().getBoxedTypeMirrors()); + return new ArrayList<>(typeMirrors); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("returnType", getContext().getType(boolean.class)); + } + + @Override + public boolean isParsable(ExecutableElement method) { + return guardNames.contains(method.getSimpleName().toString()); + } + + @Override + public GuardData create(TemplateMethod method, boolean invalid) { + Implies impliesAnnotation = method.getMethod().getAnnotation(Implies.class); + String[] impliesExpressions = new String[0]; + if (impliesAnnotation != null) { + impliesExpressions = impliesAnnotation.value(); + } + List guardExpressions = new ArrayList<>(); + for (String string : impliesExpressions) { + guardExpressions.add(new GuardExpression(string)); + } + return new GuardData(method, guardExpressions); + } + + @Override + public Class getAnnotationType() { + return null; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,75 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class ImplicitCastParser extends TypeSystemMethodParser { + + public ImplicitCastParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public Class getAnnotationType() { + return ImplicitCast.class; + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + List types = new ArrayList<>(); + for (TypeData typeData : getTypeSystem().getTypes()) { + types.add(typeData.getPrimitiveType()); + } + MethodSpec spec = new MethodSpec(new ParameterSpec("target", types)); + spec.addRequired(new ParameterSpec("source", types)); + return spec; + } + + @Override + public ImplicitCastData create(TemplateMethod method, boolean invalid) { + if (invalid) { + return new ImplicitCastData(method, null, null); + } + + Parameter target = method.findParameter("targetValue"); + Parameter source = method.findParameter("sourceValue"); + + TypeData targetType = target.getTypeSystemType(); + TypeData sourceType = source.getTypeSystemType(); + + if (targetType.equals(sourceType)) { + method.addError("Target type and source type of an @%s must not be the same type.", ImplicitCast.class.getSimpleName()); + } + + return new ImplicitCastData(method, sourceType, targetType); + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,93 @@ +/* + * 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.dsl.processor.parser; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; + +public class NodeExecutionData { + + private final NodeChildData child; + private final String name; + private final int index; + private final boolean shortCircuit; + + public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { + this.child = child; + this.index = index; + this.shortCircuit = shortCircuit; + this.name = createName(); + } + + private String createName() { + if (isIndexed()) { + return child.getName() + index; + } + return child.getName(); + } + + public TypeMirror getNodeType() { + TypeMirror type; + if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { + type = ((ArrayType) child.getNodeType()).getComponentType(); + } else { + type = child.getNodeType(); + } + return type; + } + + public String getName() { + return name; + } + + public NodeChildData getChild() { + return child; + } + + public int getIndex() { + return index; + } + + public boolean isIndexed() { + return index > -1; + } + + public boolean isShortCircuit() { + return shortCircuit; + } + + public String getShortCircuitId() { + return createShortCircuitId(child, index); + } + + public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { + String shortCircuitName = child.getName(); + if (child.getCardinality().isMany()) { + shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; + } + return shortCircuitName; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,126 @@ +/* + * 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.dsl.processor.parser; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public abstract class NodeMethodParser extends TemplateMethodParser { + + public NodeMethodParser(ProcessorContext context, NodeData node) { + super(context, node); + } + + public NodeData getNode() { + return template; + } + + protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { + ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(execution.getChild().getNodeData())); + spec.setExecution(execution); + return spec; + } + + protected List nodeTypeMirrors(NodeData nodeData) { + Set typeMirrors = new LinkedHashSet<>(); + + for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) { + typeMirrors.add(typeData.getType().getPrimitiveType()); + } + + typeMirrors.add(nodeData.getTypeSystem().getGenericType()); + + return new ArrayList<>(typeMirrors); + } + + protected ParameterSpec createReturnParameterSpec() { + ParameterSpec returnValue = new ParameterSpec("returnValue", nodeTypeMirrors(getNode())); + returnValue.setExecution(getNode().getThisExecution()); + return returnValue; + } + + @Override + public boolean isParsable(ExecutableElement method) { + if (getAnnotationType() != null) { + return ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + } + + return true; + } + + @SuppressWarnings("unused") + protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) { + MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec()); + + addDefaultFrame(methodSpec); + addDefaultFieldMethodSpec(methodSpec); + addDefaultChildren(shortCircuitsEnabled, shortCircuitName, methodSpec); + + return methodSpec; + } + + private void addDefaultChildren(boolean shortCircuitsEnabled, String breakName, MethodSpec spec) { + if (getNode().getChildren() == null) { + // children are null when parsing executable types + return; + } + + for (NodeExecutionData execution : getNode().getChildExecutions()) { + if (breakName != null && execution.getShortCircuitId().equals(breakName)) { + break; + } + + if (execution.isShortCircuit() && shortCircuitsEnabled) { + spec.addRequired(new ParameterSpec(shortCircuitValueName(execution.getName()), getContext().getType(boolean.class))); + } + spec.addRequired(createValueParameterSpec(execution)); + } + } + + private void addDefaultFrame(MethodSpec methodSpec) { + if (getNode().supportsFrame()) { + methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame())); + } + } + + protected void addDefaultFieldMethodSpec(MethodSpec methodSpec) { + for (NodeFieldData field : getNode().getFields()) { + if (field.getGetter() == null) { + ParameterSpec spec = new ParameterSpec(field.getName(), field.getType()); + spec.setLocal(true); + methodSpec.addOptional(spec); + } + } + } + + private static String shortCircuitValueName(String valueName) { + return "has" + ElementUtils.firstLetterUpperCase(valueName); + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,1353 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import javax.tools.Diagnostic.Kind; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.java.compiler.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; +import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; +import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; + +public class NodeParser extends AbstractParser { + + public static final List> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, + NodeChildren.class); + + private Map parsedNodes; + + @Override + protected NodeData parse(Element element, AnnotationMirror mirror) { + NodeData node = null; + try { + parsedNodes = new HashMap<>(); + node = resolveNode((TypeElement) element); + if (Log.DEBUG) { + NodeData parsed = parsedNodes.get(ElementUtils.getQualifiedName((TypeElement) element)); + if (node != null) { + String dump = parsed.dump(); + log.message(Kind.ERROR, null, null, null, dump); + } + } + } finally { + parsedNodes = null; + } + + return node; + } + + @Override + protected NodeData filterErrorElements(NodeData model) { + for (Iterator iterator = model.getEnclosingNodes().iterator(); iterator.hasNext();) { + NodeData node = filterErrorElements(iterator.next()); + if (node == null) { + iterator.remove(); + } + } + if (model.hasErrors()) { + return null; + } + return model; + } + + @Override + public boolean isDelegateToRootDeclaredType() { + return true; + } + + @Override + public Class getAnnotationType() { + return null; + } + + @Override + public List> getTypeDelegatedAnnotationTypes() { + return ANNOTATIONS; + } + + private NodeData resolveNode(TypeElement rootType) { + String typeName = ElementUtils.getQualifiedName(rootType); + if (parsedNodes.containsKey(typeName)) { + return parsedNodes.get(typeName); + } + + List enclosedNodes = new ArrayList<>(); + for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) { + NodeData enclosedChild = resolveNode(enclosedType); + if (enclosedChild != null) { + enclosedNodes.add(enclosedChild); + } + } + + NodeData node = parseNode(rootType); + if (node == null && !enclosedNodes.isEmpty()) { + node = new NodeData(context, rootType); + } + + if (node != null) { + for (NodeData enclosedNode : enclosedNodes) { + node.addEnclosedNode(enclosedNode); + } + } + + parsedNodes.put(typeName, node); + return node; + } + + private NodeData parseNode(TypeElement originalTemplateType) { + // reloading the type elements is needed for ecj + TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType)); + + if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) { + // generated nodes should not get called again. + return null; + } + + List lookupTypes = collectSuperClasses(new ArrayList(), templateType); + if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) { + return null; + } + List elements = CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType); + + NodeData node = parseNodeData(templateType, elements, lookupTypes); + if (node.hasErrors()) { + return node; // error sync point + } + + initializeChildren(node); + + node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements)); + node.getSpecializations().addAll(new GenericParser(context, node).parse(elements)); + node.getCasts().addAll(new CreateCastParser(context, node).parse(elements)); + node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements)); + + if (node.hasErrors()) { + return node; // error sync point + } + + verifySpecializationSameLength(node); + initializeSpecializations(elements, node); + initializeShortCircuits(node); // requires specializations and polymorphic specializations + + verifyVisibilities(node); + verifyMissingAbstractMethods(node, elements); + verifyConstructors(node); + verifyNamingConvention(node.getShortCircuits(), "needs"); + verifySpecializationThrows(node); + return node; + } + + private NodeData parseNodeData(TypeElement templateType, List elements, List typeHierarchy) { + AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); + if (typeSystemMirror == null) { + NodeData nodeData = new NodeData(context, templateType); + nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType)); + return nodeData; + } + + TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); + if (typeSystem == null) { + NodeData nodeData = new NodeData(context, templateType); + nodeData.addError("The used type system '%s' is invalid or not a Node.", ElementUtils.getQualifiedName(typeSystemType)); + return nodeData; + } + + List assumptionsList = new ArrayList<>(); + for (int i = typeHierarchy.size() - 1; i >= 0; i--) { + TypeElement type = typeHierarchy.get(i); + AnnotationMirror assumptions = ElementUtils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class); + if (assumptions != null) { + List assumptionStrings = ElementUtils.getAnnotationValueList(String.class, assumptions, "value"); + for (String string : assumptionStrings) { + if (assumptionsList.contains(string)) { + assumptionsList.remove(string); + } + assumptionsList.add(string); + } + } + } + AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); + String shortName = null; + if (nodeInfoMirror != null) { + shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName"); + } + + List fields = parseFields(typeHierarchy, elements); + List children = parseChildren(typeHierarchy, elements); + List executions = parseExecutions(children, elements); + + NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList); + nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); + + parsedNodes.put(ElementUtils.getQualifiedName(templateType), nodeData); + + return nodeData; + } + + private List parseFields(List typeHierarchy, List elements) { + Set names = new HashSet<>(); + + List fields = new ArrayList<>(); + for (VariableElement field : ElementFilter.fieldsIn(elements)) { + if (field.getModifiers().contains(Modifier.STATIC)) { + continue; + } + if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) { + String name = field.getSimpleName().toString(); + fields.add(new NodeFieldData(field, null, field.asType(), name, false)); + names.add(name); + } + } + + List reversedTypeHierarchy = new ArrayList<>(typeHierarchy); + Collections.reverse(reversedTypeHierarchy); + for (TypeElement typeElement : reversedTypeHierarchy) { + AnnotationMirror nodeChildrenMirror = ElementUtils.findAnnotationMirror(processingEnv, typeElement, NodeFields.class); + List children = ElementUtils.collectAnnotations(context, nodeChildrenMirror, "value", typeElement, NodeField.class); + + for (AnnotationMirror mirror : children) { + String name = ElementUtils.firstLetterLowerCase(ElementUtils.getAnnotationValue(String.class, mirror, "name")); + TypeMirror type = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "type"); + + NodeFieldData field = new NodeFieldData(typeElement, mirror, type, name, true); + if (name.isEmpty()) { + field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Field name cannot be empty."); + } else if (names.contains(name)) { + field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Duplicate field name '%s'.", name); + } + names.add(name); + + fields.add(field); + } + } + + for (NodeFieldData nodeFieldData : fields) { + nodeFieldData.setGetter(findGetter(elements, nodeFieldData.getName(), nodeFieldData.getType())); + } + + return fields; + } + + private List parseChildren(final List typeHierarchy, List elements) { + Set shortCircuits = new HashSet<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); + if (mirror != null) { + shortCircuits.add(ElementUtils.getAnnotationValue(String.class, mirror, "value")); + } + } + Map castNodeTypes = new HashMap<>(); + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, CreateCast.class); + if (mirror != null) { + List children = (ElementUtils.getAnnotationValueList(String.class, mirror, "value")); + if (children != null) { + for (String child : children) { + castNodeTypes.put(child, method.getReturnType()); + } + } + } + } + + List parsedChildren = new ArrayList<>(); + List typeHierarchyReversed = new ArrayList<>(typeHierarchy); + Collections.reverse(typeHierarchyReversed); + for (TypeElement type : typeHierarchyReversed) { + AnnotationMirror nodeChildrenMirror = ElementUtils.findAnnotationMirror(processingEnv, type, NodeChildren.class); + + TypeMirror nodeClassType = type.getSuperclass(); + if (!ElementUtils.isAssignable(nodeClassType, context.getTruffleTypes().getNode())) { + nodeClassType = null; + } + + List children = ElementUtils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class); + int index = 0; + for (AnnotationMirror childMirror : children) { + String name = ElementUtils.getAnnotationValue(String.class, childMirror, "value"); + if (name.equals("")) { + name = "child" + index; + } + + Cardinality cardinality = Cardinality.ONE; + + TypeMirror childType = inheritType(childMirror, "type", nodeClassType); + if (childType.getKind() == TypeKind.ARRAY) { + cardinality = Cardinality.MANY; + } + + TypeMirror originalChildType = childType; + TypeMirror castNodeType = castNodeTypes.get(name); + if (castNodeType != null) { + childType = castNodeType; + } + + Element getter = findGetter(elements, name, childType); + + NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality); + + parsedChildren.add(nodeChild); + + if (nodeChild.getNodeType() == null) { + nodeChild.addError("No valid node type could be resoleved."); + } + if (nodeChild.hasErrors()) { + continue; + } + + index++; + } + } + + List filteredChildren = new ArrayList<>(); + Set encounteredNames = new HashSet<>(); + for (int i = parsedChildren.size() - 1; i >= 0; i--) { + NodeChildData child = parsedChildren.get(i); + if (!encounteredNames.contains(child.getName())) { + filteredChildren.add(0, child); + encounteredNames.add(child.getName()); + } + } + + for (NodeChildData child : filteredChildren) { + List executeWithStrings = ElementUtils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith"); + AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith"); + List executeWith = new ArrayList<>(); + for (String executeWithString : executeWithStrings) { + + if (child.getName().equals(executeWithString)) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString); + continue; + } + + NodeChildData found = null; + boolean before = true; + for (NodeChildData resolveChild : filteredChildren) { + if (resolveChild == child) { + before = false; + continue; + } + if (resolveChild.getName().equals(executeWithString)) { + found = resolveChild; + break; + } + } + + if (found == null) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString); + continue; + } else if (!before) { + child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, + executeWithString); + continue; + } + executeWith.add(found); + } + child.setExecuteWith(executeWith); + if (child.getNodeData() == null) { + continue; + } + } + + return filteredChildren; + } + + private List parseExecutions(List children, List elements) { + if (children == null) { + return null; + } + + // pre-parse short circuits + Set shortCircuits = new HashSet<>(); + List methods = ElementFilter.methodsIn(elements); + for (ExecutableElement method : methods) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); + if (mirror != null) { + shortCircuits.add(ElementUtils.getAnnotationValue(String.class, mirror, "value")); + } + } + + boolean hasVarArgs = false; + int maxSignatureSize = 0; + if (!children.isEmpty()) { + int lastIndex = children.size() - 1; + hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY; + if (hasVarArgs) { + maxSignatureSize = lastIndex; + } else { + maxSignatureSize = children.size(); + } + } + + // pre-parse specializations + for (ExecutableElement method : methods) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class); + if (mirror == null) { + continue; + } + + int currentArgumentCount = 0; + boolean skipShortCircuit = false; + for (VariableElement var : method.getParameters()) { + TypeMirror type = var.asType(); + if (currentArgumentCount == 0) { + // skip optionals + if (ElementUtils.typeEquals(type, context.getTruffleTypes().getFrame())) { + continue; + } + // TODO skip optional fields? + } + int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1; + if (childIndex == -1) { + continue; + } + if (!skipShortCircuit) { + NodeChildData child = children.get(childIndex); + if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { + skipShortCircuit = true; + continue; + } + } else { + skipShortCircuit = false; + } + + currentArgumentCount++; + } + maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); + } + + List executions = new ArrayList<>(); + for (int i = 0; i < maxSignatureSize; i++) { + int childIndex = i; + boolean varArg = false; + if (childIndex >= children.size() - 1) { + if (hasVarArgs) { + childIndex = children.size() - 1; + varArg = hasVarArgs; + } else if (childIndex >= children.size()) { + break; + } + } + int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; + NodeChildData child = children.get(childIndex); + boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex)); + executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); + } + return executions; + } + + private static Map> groupExecutableTypes(List executableTypes) { + Map> groupedTypes = new TreeMap<>(); + for (ExecutableTypeData type : executableTypes) { + int evaluatedCount = type.getEvaluatedCount(); + + List types = groupedTypes.get(evaluatedCount); + if (types == null) { + types = new ArrayList<>(); + groupedTypes.put(evaluatedCount, types); + } + types.add(type); + } + + for (List types : groupedTypes.values()) { + Collections.sort(types); + } + return groupedTypes; + } + + private void initializeChildren(NodeData node) { + for (NodeChildData nodeChild : node.getChildren()) { + NodeData fieldNodeData = resolveNode(ElementUtils.fromTypeMirror(nodeChild.getNodeType())); + nodeChild.setNode(fieldNodeData); + if (fieldNodeData == null) { + nodeChild.addError("Node type '%s' is invalid or not a valid Node.", ElementUtils.getQualifiedName(nodeChild.getNodeType())); + } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { + nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), + NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()), + ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); + } + if (fieldNodeData != null) { + List types = nodeChild.findGenericExecutableTypes(context); + if (types.isEmpty()) { + AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith"); + nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(), + ElementUtils.getSimpleName(nodeChild.getNodeType())); + } + } + } + } + + private void initializeSpecializations(List elements, final NodeData node) { + if (node.getSpecializations().isEmpty()) { + return; + } + + initializeGuards(elements, node); + initializeGeneric(node); + initializeUninitialized(node); + initializeOrder(node); + initializePolymorphism(node); // requires specializations + initializeReachability(node); + initializeContains(node); + + if (!node.hasErrors()) { + initializeExceptions(node); + } + resolveContains(node); + + List needsId = new ArrayList<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isGeneric()) { + specialization.setId("Generic"); + } else if (specialization.isUninitialized()) { + specialization.setId("Uninitialized"); + } else if (specialization.isPolymorphic()) { + specialization.setId("Polymorphic"); + } else if (specialization.isSpecialized()) { + needsId.add(specialization); + } else { + throw new AssertionError(); + } + } + + // verify specialization parameter length + List ids = initializeSpecializationIds(needsId); + for (int i = 0; i < ids.size(); i++) { + needsId.get(i).setId(ids.get(i)); + } + + } + + private static void initializeOrder(NodeData node) { + List specializations = node.getSpecializations(); + Collections.sort(specializations); + + for (SpecializationData specialization : specializations) { + String searchName = specialization.getInsertBeforeName(); + if (searchName == null || specialization.getMethod() == null) { + continue; + } + SpecializationData found = lookupSpecialization(node, searchName); + if (found == null || found.getMethod() == null) { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore"); + specialization.addError(value, "The referenced specialization '%s' could not be found.", searchName); + continue; + } + + ExecutableElement currentMethod = specialization.getMethod(); + ExecutableElement insertBeforeMethod = found.getMethod(); + + TypeMirror currentEnclosedType = currentMethod.getEnclosingElement().asType(); + TypeMirror insertBeforeEnclosedType = insertBeforeMethod.getEnclosingElement().asType(); + + if (ElementUtils.typeEquals(currentEnclosedType, insertBeforeEnclosedType) || !ElementUtils.isSubtype(currentEnclosedType, insertBeforeEnclosedType)) { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore"); + specialization.addError(value, "Specializations can only be inserted before specializations in superclasses.", searchName); + continue; + } + + specialization.setInsertBefore(found); + } + + int endIndex = specializations.size() - 1; + for (int i = endIndex; i >= 0; i--) { + SpecializationData specialization = specializations.get(i); + if (specialization.isGeneric() || specialization.isPolymorphic()) { + endIndex--; + continue; + } + + SpecializationData insertBefore = specialization.getInsertBefore(); + if (insertBefore != null) { + int insertIndex = specializations.indexOf(insertBefore); + if (insertIndex < i) { + List range = new ArrayList<>(specializations.subList(i, endIndex + 1)); + specializations.removeAll(range); + specializations.addAll(insertIndex, range); + } + } + } + + for (int i = 0; i < specializations.size(); i++) { + specializations.get(i).setIndex(i); + } + } + + private static void initializeExceptions(NodeData node) { + List specializations = node.getSpecializations(); + for (int i = 0; i < specializations.size(); i++) { + SpecializationData cur = specializations.get(i); + if (cur.getExceptions().isEmpty()) { + continue; + } + SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null; + + if (!cur.isContainedBy(next)) { + // error should be able to contain + next.addError("This specialiation is not a valid exceptional rewrite target for %s. To fix this make %s compatible to %s or remove the exceptional rewrite.", + cur.createReferenceName(), next.createReferenceName(), cur.createReferenceName()); + continue; + } + if (!next.getContains().contains(cur)) { + next.getContains().add(cur); + // TODO resolve transitive contains + } + } + + for (SpecializationData cur : specializations) { + if (cur.getExceptions().isEmpty()) { + continue; + } + for (SpecializationData child : specializations) { + if (child != null && child != cur && child.getContains().contains(cur)) { + cur.getExcludedBy().add(child); + } + } + } + } + + private static void initializeContains(NodeData node) { + for (SpecializationData specialization : node.getSpecializations()) { + Set resolvedSpecializations = specialization.getContains(); + resolvedSpecializations.clear(); + Set includeNames = specialization.getContainsNames(); + for (String includeName : includeNames) { + // TODO reduce complexity of this lookup. + SpecializationData foundSpecialization = lookupSpecialization(node, includeName); + + if (foundSpecialization == null) { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); + specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName); + } else { + if (!foundSpecialization.isContainedBy(specialization)) { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); + if (foundSpecialization.compareTo(specialization) > 0) { + specialization.addError(value, "The contained specialization '%s' must be declared before the containing specialization.", includeName); + } else { + specialization.addError(value, + "The contained specialization '%s' is not fully compatible. The contained specialization must be strictly more generic than the containing one.", + includeName); + } + + } + resolvedSpecializations.add(foundSpecialization); + } + } + } + } + + private void resolveContains(NodeData node) { + // flatten transitive includes + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.getContains().isEmpty()) { + continue; + } + Set foundSpecializations = new HashSet<>(); + collectIncludes(specialization, foundSpecializations, new HashSet()); + specialization.getContains().addAll(foundSpecializations); + } + } + + private static SpecializationData lookupSpecialization(NodeData node, String includeName) { + SpecializationData foundSpecialization = null; + for (SpecializationData searchSpecialization : node.getSpecializations()) { + if (searchSpecialization.getMethodName().equals(includeName)) { + foundSpecialization = searchSpecialization; + break; + } + } + return foundSpecialization; + } + + private void collectIncludes(SpecializationData specialization, Set found, Set visited) { + if (visited.contains(specialization)) { + // circle found + specialization.addError("Circular contained specialization '%s' found.", specialization.createReferenceName()); + return; + } + visited.add(specialization); + + for (SpecializationData included : specialization.getContains()) { + collectIncludes(included, found, new HashSet<>(visited)); + found.add(included); + } + } + + private static void initializeReachability(final NodeData node) { + List specializations = node.getSpecializations(); + for (int i = specializations.size() - 1; i >= 0; i--) { + SpecializationData current = specializations.get(i); + if (current.isPolymorphic()) { + current.setReachable(true); + continue; + } + + List shadowedBy = null; + for (int j = i - 1; j >= 0; j--) { + SpecializationData prev = specializations.get(j); + if (prev.isPolymorphic()) { + continue; + } + if (!current.isReachableAfter(prev)) { + if (shadowedBy == null) { + shadowedBy = new ArrayList<>(); + } + shadowedBy.add(prev); + } + } + + if (shadowedBy != null) { + StringBuilder name = new StringBuilder(); + String sep = ""; + for (SpecializationData shadowSpecialization : shadowedBy) { + name.append(sep); + name.append(shadowSpecialization.createReferenceName()); + sep = ", "; + } + current.addError("%s is not reachable. It is shadowed by %s.", current.isGeneric() ? "Generic" : "Specialization", name); + } + current.setReachable(shadowedBy == null); + } + } + + private static List initializeSpecializationIds(List specializations) { + int lastSize = -1; + List> signatureChunks = new ArrayList<>(); + for (SpecializationData other : specializations) { + if (!other.isSpecialized()) { + continue; + } + List paramIds = new LinkedList<>(); + paramIds.add(ElementUtils.getTypeId(other.getReturnType().getType())); + for (Parameter param : other.getParameters()) { + if (param.getSpecification().getExecution() == null) { + continue; + } + paramIds.add(ElementUtils.getTypeId(param.getType())); + } + assert lastSize == -1 || lastSize == paramIds.size(); + if (lastSize != -1 && lastSize != paramIds.size()) { + throw new AssertionError(); + } + signatureChunks.add(paramIds); + lastSize = paramIds.size(); + } + + // reduce id vertically + for (int i = 0; i < lastSize; i++) { + String prev = null; + boolean allSame = true; + for (List signature : signatureChunks) { + String arg = signature.get(i); + if (prev == null) { + prev = arg; + continue; + } else if (!prev.equals(arg)) { + allSame = false; + break; + } + prev = arg; + } + + if (allSame) { + for (List signature : signatureChunks) { + signature.remove(i); + } + lastSize--; + } + } + + // reduce id horizontally + for (List signature : signatureChunks) { + if (signature.isEmpty()) { + continue; + } + String prev = null; + boolean allSame = true; + for (String arg : signature) { + if (prev == null) { + prev = arg; + continue; + } else if (!prev.equals(arg)) { + allSame = false; + break; + } + prev = arg; + } + + if (allSame) { + signature.clear(); + signature.add(prev); + } + } + + // create signatures + List signatures = new ArrayList<>(); + for (List signatureChunk : signatureChunks) { + StringBuilder b = new StringBuilder(); + if (signatureChunk.isEmpty()) { + b.append("Default"); + } else { + for (String s : signatureChunk) { + b.append(s); + } + } + signatures.add(b.toString()); + } + + Map counts = new HashMap<>(); + for (String s1 : signatures) { + Integer count = counts.get(s1); + if (count == null) { + count = 0; + } + count++; + counts.put(s1, count); + } + + for (String s : counts.keySet()) { + int count = counts.get(s); + if (count > 1) { + int number = 0; + for (ListIterator iterator = signatures.listIterator(); iterator.hasNext();) { + String s2 = iterator.next(); + if (s.equals(s2)) { + iterator.set(s2 + number); + number++; + } + } + } + } + + return signatures; + } + + private void initializeGuards(List elements, NodeData node) { + Map> guards = new HashMap<>(); + for (SpecializationData specialization : node.getSpecializations()) { + for (GuardExpression exp : specialization.getGuards()) { + guards.put(exp.getGuardName(), null); + } + } + + GuardParser parser = new GuardParser(context, node, null, guards.keySet()); + List resolvedGuards = parser.parse(elements); + for (GuardData guard : resolvedGuards) { + List groupedGuards = guards.get(guard.getMethodName()); + if (groupedGuards == null) { + groupedGuards = new ArrayList<>(); + guards.put(guard.getMethodName(), groupedGuards); + } + groupedGuards.add(guard); + } + + for (SpecializationData specialization : node.getSpecializations()) { + for (GuardExpression exp : specialization.getGuards()) { + resolveGuardExpression(node, specialization, guards, exp); + } + } + } + + private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { + List availableGuards = guards.get(expression.getGuardName()); + if (availableGuards == null) { + source.addError("No compatible guard with method name '%s' found. Please note that all signature types of the method guard must be declared in the type system.", expression.getGuardName()); + return; + } + List guardMethods = new ArrayList<>(); + for (GuardData guard : availableGuards) { + guardMethods.add(guard.getMethod()); + } + GuardParser parser = new GuardParser(context, node, source, new HashSet<>(Arrays.asList(expression.getGuardName()))); + List matchingGuards = parser.parse(guardMethods); + if (!matchingGuards.isEmpty()) { + GuardData guard = matchingGuards.get(0); + // use the shared instance of the guard data + for (GuardData guardData : availableGuards) { + if (guardData.getMethod() == guard.getMethod()) { + expression.setGuard(guardData); + return; + } + } + throw new AssertionError("Should not reach here."); + } else { + MethodSpec spec = parser.createSpecification(source.getMethod(), source.getMarkerAnnotation()); + spec.applyTypeDefinitions("types"); + source.addError("No guard with name '%s' matched the required signature. Expected signature: %n%s", expression.getGuardName(), spec.toSignatureString("guard")); + } + } + + private void initializeGeneric(final NodeData node) { + if (!node.needsRewrites(context)) { + return; + } + + List generics = new ArrayList<>(); + for (SpecializationData spec : node.getSpecializations()) { + if (spec.isGeneric()) { + generics.add(spec); + } + } + + if (generics.size() == 1 && node.getSpecializations().size() == 1) { + // TODO this limitation should be lifted + for (SpecializationData generic : generics) { + generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); + } + } + + if (generics.isEmpty()) { + node.getSpecializations().add(createGenericSpecialization(node)); + } else { + if (generics.size() > 1) { + for (SpecializationData generic : generics) { + generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName()); + } + } + } + } + + private SpecializationData createGenericSpecialization(final NodeData node) { + GenericParser parser = new GenericParser(context, node); + MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null); + + List parameterTypes = new ArrayList<>(); + int signatureIndex = 1; + for (ParameterSpec spec : specification.getRequired()) { + parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex)); + if (spec.isSignature()) { + signatureIndex++; + } + } + + TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0); + SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes); + if (generic == null) { + throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + "."); + } + + return generic; + } + + private TypeMirror createGenericType(ParameterSpec spec, List specializations, int signatureIndex) { + NodeExecutionData execution = spec.getExecution(); + if (execution == null) { + if (spec.getAllowedTypes().size() == 1) { + return spec.getAllowedTypes().get(0); + } else { + return ElementUtils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); + } + } else { + Set types = new HashSet<>(); + for (SpecializationData specialization : specializations) { + types.add(specialization.getTypeSignature().get(signatureIndex)); + } + + NodeChildData child = execution.getChild(); + TypeData genericType = null; + if (types.size() == 1) { + ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); + if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) { + genericType = types.iterator().next(); + } + } + if (genericType == null) { + genericType = child.findAnyGenericExecutableType(context).getType(); + } + return genericType.getPrimitiveType(); + } + } + + private static void initializeUninitialized(final NodeData node) { + SpecializationData generic = node.getGenericSpecialization(); + if (generic == null) { + return; + } + for (Parameter parameter : generic.getReturnTypeAndParameters()) { + if (ElementUtils.isObject(parameter.getType())) { + continue; + } + Set types = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + Parameter actualParameter = specialization.findParameter(parameter.getLocalName()); + if (actualParameter != null) { + types.add(ElementUtils.getQualifiedName(actualParameter.getType())); + } + } + if (types.size() > 1) { + generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, node.getTypeSystem().getGenericTypeData())); + } + } + TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); + // should not use messages from generic specialization + uninializedMethod.getMessages().clear(); + node.getSpecializations().add(new SpecializationData(node, uninializedMethod, SpecializationKind.UNINITIALIZED)); + } + + private void initializePolymorphism(NodeData node) { + if (!node.needsRewrites(context)) { + return; + } + + SpecializationData generic = node.getGenericSpecialization(); + + List polymorphicSignature = new ArrayList<>(); + List updatePolymorphic = Arrays.asList(); + for (Parameter genericParameter : updatePolymorphic) { + if (!genericParameter.getSpecification().isSignature()) { + continue; + } + + Set usedTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (!specialization.isSpecialized()) { + continue; + } + Parameter parameter = specialization.findParameter(genericParameter.getLocalName()); + if (parameter == null) { + throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + } + usedTypes.add(parameter.getTypeSystemType()); + } + + TypeData polymorphicType; + if (usedTypes.size() == 1) { + polymorphicType = usedTypes.iterator().next(); + } else { + polymorphicType = node.getTypeSystem().getGenericTypeData(); + } + polymorphicSignature.add(polymorphicType); + } + + SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); + polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); + node.getSpecializations().add(polymorphic); + } + + private void initializeShortCircuits(NodeData node) { + Map> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); + + boolean valid = true; + List shortCircuitExecutions = new ArrayList<>(); + for (NodeExecutionData execution : node.getChildExecutions()) { + if (!execution.isShortCircuit()) { + continue; + } + shortCircuitExecutions.add(execution); + String valueName = execution.getShortCircuitId(); + List availableCircuits = groupedShortCircuits.get(valueName); + + if (availableCircuits == null || availableCircuits.isEmpty()) { + node.addError("@%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) { + circuit.addError("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)) { + genericCircuit = circuit; + break; + } + } + + if (genericCircuit == null) { + node.addError("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; + } + + List specializations = new ArrayList<>(); + specializations.addAll(node.getSpecializations()); + for (SpecializationData specialization : specializations) { + List assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size()); + + for (NodeExecutionData shortCircuit : shortCircuitExecutions) { + List availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId()); + + ShortCircuitData genericShortCircuit = null; + ShortCircuitData compatibleShortCircuit = null; + for (ShortCircuitData circuit : availableShortCuts) { + if (circuit.isGeneric()) { + genericShortCircuit = circuit; + } else if (circuit.isCompatibleTo(specialization)) { + compatibleShortCircuit = circuit; + } + } + + if (compatibleShortCircuit == null) { + compatibleShortCircuit = genericShortCircuit; + } + assignedShortCuts.add(compatibleShortCircuit); + } + specialization.setShortCircuits(assignedShortCuts); + } + } + + private boolean isGenericShortCutMethod(ShortCircuitData method) { + for (Parameter parameter : method.getParameters()) { + NodeExecutionData execution = parameter.getSpecification().getExecution(); + if (execution == null) { + continue; + } + ExecutableTypeData found = null; + List executableElements = execution.getChild().findGenericExecutableTypes(context); + for (ExecutableTypeData executable : executableElements) { + if (executable.getType().equalsType(parameter.getTypeSystemType())) { + found = executable; + break; + } + } + if (found == null) { + 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 static boolean verifySpecializationSameLength(NodeData nodeData) { + int lastArgs = -1; + for (SpecializationData specializationData : nodeData.getSpecializations()) { + int signatureArgs = specializationData.getSignatureSize(); + if (lastArgs == signatureArgs) { + continue; + } + if (lastArgs != -1) { + for (SpecializationData specialization : nodeData.getSpecializations()) { + specialization.addError("All specializations must have the same number of arguments."); + } + return false; + } else { + lastArgs = signatureArgs; + } + } + return true; + } + + private static void verifyVisibilities(NodeData node) { + if (node.getTemplateType().getModifiers().contains(Modifier.PRIVATE) && node.getSpecializations().size() > 0) { + node.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); + } + } + + private static void verifyMissingAbstractMethods(NodeData nodeData, List originalElements) { + if (!nodeData.needsFactory()) { + // missing abstract methods only needs to be implemented + // if we need go generate factory for it. + return; + } + + List elements = new ArrayList<>(originalElements); + Set unusedElements = new HashSet<>(elements); + for (TemplateMethod method : nodeData.getAllTemplateMethods()) { + unusedElements.remove(method.getMethod()); + } + + for (NodeFieldData field : nodeData.getFields()) { + if (field.getGetter() != null) { + unusedElements.remove(field.getGetter()); + } + } + + for (NodeChildData child : nodeData.getChildren()) { + if (child.getAccessElement() != null) { + unusedElements.remove(child.getAccessElement()); + } + } + + for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) { + if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) { + nodeData.addError("The type %s must implement the inherited abstract method %s.", ElementUtils.getSimpleName(nodeData.getTemplateType()), + ElementUtils.getReadableSignature(unusedMethod)); + } + } + } + + private static void verifyNamingConvention(List methods, String prefix) { + for (int i = 0; i < methods.size(); i++) { + TemplateMethod m1 = methods.get(i); + if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) { + m1.addError("Naming convention: method name must start with '%s'.", prefix); + } + } + } + + private static void verifySpecializationThrows(NodeData node) { + Map specializationMap = new HashMap<>(); + for (SpecializationData spec : node.getSpecializations()) { + specializationMap.put(spec.getMethodName(), spec); + } + for (SpecializationData sourceSpecialization : node.getSpecializations()) { + if (sourceSpecialization.getExceptions() != null) { + for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) { + for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) { + if (otherThrowsData != throwsData && ElementUtils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) { + throwsData.addError("Duplicate exception type."); + } + } + } + } + } + } + + private void verifyConstructors(NodeData nodeData) { + if (!nodeData.needsRewrites(context)) { + // no specialization constructor is needed if the node never rewrites. + return; + } + + TypeElement type = ElementUtils.fromTypeMirror(nodeData.getNodeType()); + List constructors = ElementFilter.constructorsIn(type.getEnclosedElements()); + + boolean parametersFound = false; + for (ExecutableElement constructor : constructors) { + if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) { + parametersFound = true; + } + } + if (!parametersFound) { + return; + } + for (ExecutableElement e : constructors) { + if (e.getParameters().size() == 1) { + TypeMirror firstArg = e.getParameters().get(0).asType(); + if (ElementUtils.typeEquals(firstArg, nodeData.getNodeType())) { + if (e.getModifiers().contains(Modifier.PRIVATE)) { + nodeData.addError("The specialization constructor must not be private."); + } else if (constructors.size() <= 1) { + nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required."); + } + return; + } + } + } + + // not found + nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", ElementUtils.getSimpleName(type), ElementUtils.getSimpleName(type)); + } + + public static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) { + return constructor.getParameters().size() == 1 && ElementUtils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection()); + } + + private AnnotationMirror findFirstAnnotation(List elements, Class annotation) { + for (Element element : elements) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, element, annotation); + if (mirror != null) { + return mirror; + } + } + return null; + } + + private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) { + TypeMirror inhertNodeType = context.getTruffleTypes().getNode(); + TypeMirror value = ElementUtils.getAnnotationValue(TypeMirror.class, annotation, valueName); + if (ElementUtils.typeEquals(inhertNodeType, value)) { + return parentType; + } else { + return value; + } + } + + private ExecutableElement findGetter(List elements, String variableName, TypeMirror type) { + if (type == null) { + return null; + } + String methodName; + if (ElementUtils.typeEquals(type, context.getType(boolean.class))) { + methodName = "is" + ElementUtils.firstLetterUpperCase(variableName); + } else { + methodName = "get" + ElementUtils.firstLetterUpperCase(variableName); + } + + for (ExecutableElement method : ElementFilter.methodsIn(elements)) { + if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && ElementUtils.isAssignable(type, method.getReturnType())) { + return method; + } + } + return null; + } + + private static List collectSuperClasses(List collection, TypeElement element) { + if (element != null) { + collection.add(element); + if (element.getSuperclass() != null) { + collectSuperClasses(collection, ElementUtils.fromTypeMirror(element.getSuperclass())); + } + } + return collection; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class ShortCircuitParser extends NodeMethodParser { + + private final Set shortCircuitValues; + + public ShortCircuitParser(ProcessorContext context, NodeData node) { + super(context, node); + + shortCircuitValues = new HashSet<>(); + for (NodeExecutionData execution : node.getChildExecutions()) { + if (execution.isShortCircuit()) { + shortCircuitValues.add(execution.getShortCircuitId()); + } + } + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + String shortCircuitValue = ElementUtils.getAnnotationValue(String.class, mirror, "value"); + + return createDefaultMethodSpec(method, mirror, true, shortCircuitValue); + } + + @Override + protected ParameterSpec createReturnParameterSpec() { + return new ParameterSpec("has", getContext().getType(boolean.class)); + } + + @Override + public ShortCircuitData create(TemplateMethod method, boolean invalid) { + String shortCircuitValue = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value"); + + if (!shortCircuitValues.contains(shortCircuitValue)) { + method.addError("Invalid short circuit value %s.", shortCircuitValue); + } + + return new ShortCircuitData(method, shortCircuitValue); + } + + @Override + public Class getAnnotationType() { + return ShortCircuit.class; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,448 @@ +/* + * 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.dsl.processor.parser; + +import java.util.*; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; + +/** + * Class creates groups of specializations to optimize the layout of generated executeAndSpecialize + * and generic execute methods. + */ +public final class SpecializationGroup { + + private final List assumptions; + private final List typeGuards; + private final List guards; + + private final NodeData node; + private final SpecializationData specialization; + private final List children = new ArrayList<>(); + + private SpecializationGroup parent; + + private SpecializationGroup(SpecializationData data) { + this.node = data.getNode(); + this.assumptions = new ArrayList<>(); + this.typeGuards = new ArrayList<>(); + this.guards = new ArrayList<>(); + this.specialization = data; + + this.assumptions.addAll(data.getAssumptions()); + TypeSignature sig = data.getTypeSignature(); + for (int i = 1; i < sig.size(); i++) { + typeGuards.add(new TypeGuard(sig.get(i), i - 1)); + } + this.guards.addAll(data.getGuards()); + } + + public SpecializationGroup(List children, List assumptionMatches, List typeGuardsMatches, List guardMatches) { + assert !children.isEmpty() : "children must not be empty"; + this.assumptions = assumptionMatches; + this.typeGuards = typeGuardsMatches; + this.guards = guardMatches; + this.node = children.get(0).node; + this.specialization = null; + updateChildren(children); + } + + public List getAllGuards() { + List collectedGuards = new ArrayList<>(); + collectedGuards.addAll(typeGuards); + if (parent != null) { + collectedGuards.addAll(parent.getAllGuards()); + } + return collectedGuards; + } + + public TypeGuard findTypeGuard(int signatureIndex) { + for (TypeGuard guard : typeGuards) { + if (guard.getSignatureIndex() == signatureIndex) { + return guard; + } + } + return null; + } + + public List findElseConnectableGuards() { + if (!getTypeGuards().isEmpty() || !getAssumptions().isEmpty()) { + return Collections.emptyList(); + } + + if (getGuards().isEmpty()) { + return Collections.emptyList(); + } + + List elseConnectableGuards = new ArrayList<>(); + int guardIndex = 0; + while (guardIndex < getGuards().size() && findNegatedGuardInPrevious(getGuards().get(guardIndex)) != null) { + elseConnectableGuards.add(getGuards().get(guardIndex)); + guardIndex++; + } + + return elseConnectableGuards; + } + + private GuardExpression findNegatedGuardInPrevious(GuardExpression guard) { + SpecializationGroup previous = this.getPreviousGroup(); + if (previous == null) { + return null; + } + List elseConnectedGuards = previous.findElseConnectableGuards(); + + if (previous == null || previous.getGuards().size() != elseConnectedGuards.size() + 1) { + return null; + } + + /* Guard is else branch can be connected in previous specialization. */ + if (elseConnectedGuards.contains(guard)) { + return guard; + } + + GuardExpression previousGuard = previous.getGuards().get(elseConnectedGuards.size()); + if (guard.getResolvedGuard().getMethod().equals(previousGuard.getResolvedGuard().getMethod()) && guard.isNegated() != previousGuard.isNegated()) { + return guard; + } + return null; + } + + private void updateChildren(List childs) { + if (!children.isEmpty()) { + children.clear(); + } + this.children.addAll(childs); + for (SpecializationGroup child : childs) { + child.parent = this; + } + } + + public SpecializationGroup getParent() { + return parent; + } + + public List getAssumptions() { + return assumptions; + } + + public List getTypeGuards() { + return typeGuards; + } + + public List getGuards() { + return guards; + } + + public List getChildren() { + return children; + } + + public SpecializationData getSpecialization() { + return specialization; + } + + private static SpecializationGroup combine(List groups) { + if (groups.isEmpty()) { + throw new IllegalArgumentException("empty combinations"); + } + if (groups.size() == 1) { + return null; + } + + List assumptionMatches = new ArrayList<>(); + List typeGuardsMatches = new ArrayList<>(); + List guardMatches = new ArrayList<>(); + + SpecializationGroup first = groups.get(0); + List others = groups.subList(1, groups.size()); + + outer: for (String assumption : first.assumptions) { + for (SpecializationGroup other : others) { + if (!other.assumptions.contains(assumption)) { + // assumptions can be combined unordered + continue outer; + } + } + assumptionMatches.add(assumption); + } + + outer: for (TypeGuard typeGuard : first.typeGuards) { + for (SpecializationGroup other : others) { + if (!other.typeGuards.contains(typeGuard)) { + // type guards can be combined unordered + continue outer; + } + } + typeGuardsMatches.add(typeGuard); + } + + outer: for (GuardExpression guard : first.guards) { + for (SpecializationGroup other : others) { + if (!other.guards.contains(guard)) { + // we must break here. One guard may depend on the other. + break outer; + } + } + guardMatches.add(guard); + } + + // check for guards for required type casts + for (Iterator iterator = guardMatches.iterator(); iterator.hasNext();) { + GuardExpression guardMatch = iterator.next(); + + int signatureIndex = 0; + for (Parameter parameter : guardMatch.getResolvedGuard().getParameters()) { + signatureIndex++; + if (!parameter.getSpecification().isSignature()) { + continue; + } + + TypeMirror guardType = parameter.getType(); + + // object guards can be safely moved up + if (ElementUtils.isObject(guardType)) { + continue; + } + + // generic guards can be safely moved up + SpecializationData generic = first.node.getGenericSpecialization(); + if (generic != null) { + Parameter genericParameter = generic.findParameter(parameter.getLocalName()); + if (genericParameter != null && ElementUtils.typeEquals(genericParameter.getType(), guardType)) { + continue; + } + } + + // signature index required for moving up guards + if (containsIndex(typeGuardsMatches, signatureIndex) || (first.getParent() != null && first.getParent().containsTypeGuardIndex(signatureIndex))) { + continue; + } + + iterator.remove(); + break; + } + } + + if (assumptionMatches.isEmpty() && typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) { + return null; + } + + for (SpecializationGroup group : groups) { + group.assumptions.removeAll(assumptionMatches); + group.typeGuards.removeAll(typeGuardsMatches); + group.guards.removeAll(guardMatches); + } + + List newChildren = new ArrayList<>(groups); + return new SpecializationGroup(newChildren, assumptionMatches, typeGuardsMatches, guardMatches); + } + + private boolean containsTypeGuardIndex(int index) { + if (containsIndex(typeGuards, index)) { + return true; + } + if (parent != null) { + return parent.containsTypeGuardIndex(index); + } + return false; + } + + private static boolean containsIndex(List typeGuards, int signatureIndex) { + for (TypeGuard guard : typeGuards) { + if (guard.signatureIndex == signatureIndex) { + return true; + } + } + return false; + } + + public static SpecializationGroup create(SpecializationData specialization) { + return new SpecializationGroup(specialization); + } + + public static SpecializationGroup create(List specializations) { + List groups = new ArrayList<>(); + for (SpecializationData specialization : specializations) { + groups.add(new SpecializationGroup(specialization)); + } + return new SpecializationGroup(createCombinationalGroups(groups), Collections. emptyList(), Collections. emptyList(), Collections. emptyList()); + } + + @Override + public String toString() { + return "SpecializationGroup [assumptions=" + assumptions + ", typeGuards=" + typeGuards + ", guards=" + guards + "]"; + } + + private static List createCombinationalGroups(List groups) { + if (groups.size() <= 1) { + return groups; + } + List newGroups = new ArrayList<>(); + + int i = 0; + for (i = 0; i < groups.size();) { + SpecializationGroup combined = null; + for (int j = groups.size(); j > i + 1; j--) { + combined = combine(groups.subList(i, j)); + if (combined != null) { + break; + } + } + SpecializationGroup newGroup; + if (combined == null) { + newGroup = groups.get(i); + i++; + } else { + newGroup = combined; + List originalGroups = new ArrayList<>(combined.children); + combined.updateChildren(createCombinationalGroups(originalGroups)); + i += originalGroups.size(); + } + + newGroups.add(newGroup); + + } + + return newGroups; + } + + public SpecializationGroup getPreviousGroup() { + if (parent == null || parent.children.isEmpty()) { + return null; + } + int index = parent.children.indexOf(this); + if (index <= 0) { + return null; + } + return parent.children.get(index - 1); + } + + public int getUncheckedSpecializationIndex() { + int groupMaxIndex = getMaxSpecializationIndex(); + + int genericIndex = node.getSpecializations().indexOf(node.getGenericSpecialization()); + if (groupMaxIndex >= genericIndex) { + // no minimum state check for an generic index + groupMaxIndex = -1; + } + + if (groupMaxIndex > -1) { + // no minimum state check if already checked by parent group + int parentMaxIndex = -1; + if (getParent() != null) { + parentMaxIndex = getParent().getMaxSpecializationIndex(); + } + if (groupMaxIndex == parentMaxIndex) { + groupMaxIndex = -1; + } + } + return groupMaxIndex; + } + + public int getMaxSpecializationIndex() { + if (specialization != null) { + return specialization.getNode().getSpecializations().indexOf(specialization); + } else { + int max = Integer.MIN_VALUE; + for (SpecializationGroup childGroup : getChildren()) { + max = Math.max(max, childGroup.getMaxSpecializationIndex()); + } + return max; + } + } + + public static final class TypeGuard { + + private final int signatureIndex; + private final TypeData type; + + public TypeGuard(TypeData type, int signatureIndex) { + this.type = type; + this.signatureIndex = signatureIndex; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + signatureIndex; + result = prime * result + type.hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj == null) { + return false; + } else if (getClass() != obj.getClass()) { + return false; + } + + TypeGuard other = (TypeGuard) obj; + if (signatureIndex != other.signatureIndex) { + return false; + } else if (!type.equals(other.type)) { + return false; + } + return true; + } + + public int getSignatureIndex() { + return signatureIndex; + } + + public TypeData getType() { + return type; + } + } + + public boolean isTypeGuardUsedInAnyGuardBelow(ProcessorContext context, SpecializationData source, TypeGuard typeGuard) { + + for (GuardExpression guard : guards) { + Parameter guardParameter = guard.getResolvedGuard().getSignatureParameter(typeGuard.getSignatureIndex()); + if (guardParameter == null) { + // guardParameters are optional + continue; + } + Parameter sourceParameter = source.getSignatureParameter(typeGuard.getSignatureIndex()); + if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { + return true; + } + } + + for (SpecializationGroup group : getChildren()) { + if (group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard)) { + return true; + } + } + + return false; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,117 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; +import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; + +public class SpecializationMethodParser extends NodeMethodParser { + + public SpecializationMethodParser(ProcessorContext context, NodeData operation) { + super(context, operation); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + return createDefaultMethodSpec(method, mirror, true, null); + } + + @Override + public SpecializationData create(TemplateMethod method, boolean invalid) { + return parseSpecialization(method); + } + + @Override + public Class getAnnotationType() { + return Specialization.class; + } + + private SpecializationData parseSpecialization(TemplateMethod method) { + AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn"); + List exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn"); + List exceptionData = new ArrayList<>(); + for (TypeMirror exceptionType : exceptionTypes) { + SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType); + if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) { + throwsData.addError("Method must specify a throws clause with the exception type '%s'.", ElementUtils.getQualifiedName(exceptionType)); + } + exceptionData.add(throwsData); + } + + Collections.sort(exceptionData, new Comparator() { + + @Override + public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) { + return ElementUtils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass()); + } + }); + SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData); + + String insertBeforeName = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore"); + if (!insertBeforeName.equals("")) { + specialization.setInsertBeforeName(insertBeforeName); + } + + List guardDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); + List guardExpressions = new ArrayList<>(); + for (String guardDef : guardDefs) { + guardExpressions.add(new GuardExpression(guardDef)); + } + specialization.setGuards(guardExpressions); + + List containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains"); + Set containsNames = specialization.getContainsNames(); + containsNames.clear(); + if (containsDefs != null) { + for (String include : containsDefs) { + if (!containsNames.contains(include)) { + specialization.getContainsNames().add(include); + } else { + AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains"); + specialization.addError(value, "Duplicate contains declaration '%s'.", include); + } + } + + } + + List assumptionDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions"); + specialization.setAssumptions(assumptionDefs); + + for (String assumption : assumptionDefs) { + if (!getNode().getAssumptions().contains(assumption)) { + specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption); + } + } + + return specialization; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,77 @@ +/* + * 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.dsl.processor.parser; + +import java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +class TypeCastParser extends TypeSystemMethodParser { + + public TypeCastParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as"); + if (targetType == null) { + return null; + } + MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetType.getPrimitiveType())); + spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); + return spec; + } + + @Override + public TypeCastData create(TemplateMethod method, boolean invalid) { + if (invalid) { + return new TypeCastData(method, null, null); + } + + TypeData targetType = findTypeByMethodName(method, "as"); + Parameter parameter = method.findParameter("valueValue"); + + TypeData sourceType = null; + if (parameter != null) { + sourceType = getTypeSystem().findTypeData(parameter.getType()); + } + TypeCastData cast = new TypeCastData(method, sourceType, targetType); + + if (targetType != method.getReturnType().getTypeSystemType()) { + cast.addError("Cast type %s does not match to the returned type %s.", ElementUtils.getSimpleName(targetType.getPrimitiveType()), + method.getReturnType() != null ? ElementUtils.getSimpleName(method.getReturnType().getTypeSystemType().getPrimitiveType()) : null); + } + return cast; + } + + @Override + public Class getAnnotationType() { + return TypeCast.class; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -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.dsl.processor.parser; + +import java.lang.annotation.*; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.model.*; + +class TypeCheckParser extends TypeSystemMethodParser { + + public TypeCheckParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { + TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is"); + if (targetType == null) { + return null; + } + MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class))); + spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); + return spec; + } + + @Override + public TypeCheckData create(TemplateMethod method, boolean invalid) { + TypeData checkedType = findTypeByMethodName(method, "is"); + assert checkedType != null; + Parameter parameter = method.findParameter("valueValue"); + assert parameter != null; + return new TypeCheckData(method, checkedType, parameter.getTypeSystemType()); + } + + @Override + public Class getAnnotationType() { + return TypeCheck.class; + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,67 @@ +/* + * 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.dsl.processor.parser; + +import javax.lang.model.element.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +abstract class TypeSystemMethodParser extends TemplateMethodParser { + + public TypeSystemMethodParser(ProcessorContext context, TypeSystemData typeSystem) { + super(context, typeSystem); + } + + @Override + public final boolean isParsable(ExecutableElement method) { + return ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; + } + + protected TypeData findTypeByMethodName(String methodName, String prefix) { + String typeName = methodName.substring(prefix.length(), methodName.length()); + TypeData type = getTypeSystem().findType(typeName); + return type; + } + + protected TypeData findTypeByMethodName(TemplateMethod method, String prefix) { + String methodName = method.getMethodName(); + if (!methodName.startsWith(prefix)) { + String annotationName = ElementUtils.getSimpleName(method.getMessageAnnotation().getAnnotationType()); + method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix)); + return null; + } + String typeName = methodName.substring(prefix.length(), methodName.length()); + TypeData type = getTypeSystem().findType(typeName); + if (type == null) { + String annotationName = TypeSystem.class.getSimpleName(); + method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName); + return null; + } + + return type; + } + +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java Mon Aug 11 15:57:14 2014 +0200 @@ -0,0 +1,306 @@ +/* + * 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.dsl.processor.parser; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +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.dsl.*; +import com.oracle.truffle.dsl.processor.generator.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public class TypeSystemParser extends AbstractParser { + + public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); + + @Override + public Class getAnnotationType() { + return TypeSystem.class; + } + + @Override + protected TypeSystemData parse(Element element, AnnotationMirror mirror) { + TypeElement templateType = (TypeElement) element; + AnnotationMirror templateTypeAnnotation = mirror; + TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation); + + // annotation type on class path!? + TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); + if (annotationTypeElement == null) { + typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName()); + } + if (templateType.getModifiers().contains(Modifier.PRIVATE)) { + typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName()); + } + + if (templateType.getModifiers().contains(Modifier.FINAL)) { + typeSystem.addError("The @%s must not be final.", getAnnotationType().getName()); + } + if (typeSystem.hasErrors()) { + return typeSystem; + } + + typeSystem.setTypes(parseTypes(typeSystem)); + if (typeSystem.hasErrors()) { + return typeSystem; + } + + TypeMirror genericType = context.getType(Object.class); + TypeData voidType = new TypeData(typeSystem, typeSystem.getTypes().size(), null, context.getType(void.class), context.getType(Void.class)); + + typeSystem.setGenericType(genericType); + typeSystem.setVoidType(voidType); + + verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); + + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); + List implicitCasts = new ImplicitCastParser(context, typeSystem).parse(elements); + List casts = new TypeCastParser(context, typeSystem).parse(elements); + List checks = new TypeCheckParser(context, typeSystem).parse(elements); + + if (casts == null || checks == null || implicitCasts == null) { + return typeSystem; + } + + typeSystem.setImplicitCasts(implicitCasts); + typeSystem.setCasts(casts); + typeSystem.setChecks(checks); + + if (typeSystem.hasErrors()) { + return typeSystem; + } + + for (TypeCheckData check : checks) { + check.getCheckedType().addTypeCheck(check); + } + + for (TypeCastData cast : casts) { + cast.getTargetType().addTypeCast(cast); + } + + verifyGenericTypeChecksAndCasts(typeSystem); + verifyMethodSignatures(typeSystem); + verifyNamesUnique(typeSystem); + + return typeSystem; + } + + private void verifyExclusiveMethodAnnotation(Template template, Class... annotationTypes) { + List methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements()); + for (ExecutableElement method : methods) { + List foundAnnotations = new ArrayList<>(); + for (int i = 0; i < annotationTypes.length; i++) { + Class annotationType = annotationTypes[i]; + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(context.getEnvironment(), method, annotationType); + if (mirror != null) { + foundAnnotations.add(mirror); + } + } + if (foundAnnotations.size() > 1) { + List annotationNames = new ArrayList<>(); + for (AnnotationMirror mirror : foundAnnotations) { + annotationNames.add("@" + ElementUtils.getSimpleName(mirror.getAnnotationType())); + } + + template.addError("Non exclusive usage of annotations %s.", annotationNames); + } + } + } + + private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) { + for (TypeData type : typeSystem.getTypes()) { + if (!type.getTypeChecks().isEmpty()) { + boolean hasGeneric = false; + for (TypeCheckData typeCheck : type.getTypeChecks()) { + if (typeCheck.isGeneric()) { + hasGeneric = true; + break; + } + } + if (!hasGeneric) { + type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), ElementUtils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), + Object.class.getSimpleName()); + } + } + if (!type.getTypeCasts().isEmpty()) { + boolean hasGeneric = false; + for (TypeCastData typeCast : type.getTypeCasts()) { + if (typeCast.isGeneric()) { + hasGeneric = true; + break; + } + } + if (!hasGeneric) { + type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", + TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), ElementUtils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), + Object.class.getSimpleName()); + } + } + } + } + + private List parseTypes(TypeSystemData typeSystem) { + List types = new ArrayList<>(); + List typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); + if (typeMirrors.isEmpty()) { + typeSystem.addError("At least one type must be defined."); + return types; + } + + final AnnotationValue annotationValue = ElementUtils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value"); + final TypeMirror objectType = context.getType(Object.class); + + int index = 0; + for (TypeMirror primitiveType : typeMirrors) { + TypeMirror boxedType = ElementUtils.boxType(context, primitiveType); + TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitiveType, boxedType); + + if (isPrimitiveWrapper(primitiveType)) { + typeData.addError("Types must not contain primitive wrapper types."); + } + + if (ElementUtils.typeEquals(boxedType, objectType)) { + typeData.addError("Types must not contain the generic type java.lang.Object."); + } + + types.add(typeData); + index++; + } + + verifyTypeOrder(types); + + types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType)); + + return types; + } + + private static void verifyTypeOrder(List types) { + Map> invalidTypes = new HashMap<>(); + + for (int i = types.size() - 1; i >= 0; i--) { + TypeData typeData = types.get(i); + TypeMirror type = typeData.getBoxedType(); + if (invalidTypes.containsKey(ElementUtils.getQualifiedName(type))) { + typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)), ElementUtils.getQualifiedName(type)); + } + List nextInvalidTypes = ElementUtils.getQualifiedSuperTypeNames(ElementUtils.fromTypeMirror(type)); + nextInvalidTypes.add(getQualifiedName(type)); + + for (String qualifiedName : nextInvalidTypes) { + List inheritedTypes = invalidTypes.get(qualifiedName); + if (inheritedTypes == null) { + inheritedTypes = new ArrayList<>(); + invalidTypes.put(qualifiedName, inheritedTypes); + } + inheritedTypes.add(ElementUtils.getQualifiedName(typeData.getBoxedType())); + } + } + } + + private boolean isPrimitiveWrapper(TypeMirror type) { + Types types = context.getEnvironment().getTypeUtils(); + for (TypeKind kind : TypeKind.values()) { + if (!kind.isPrimitive()) { + continue; + } + if (ElementUtils.typeEquals(type, types.boxedClass(types.getPrimitiveType(kind)).asType())) { + return true; + } + } + return false; + } + + private void verifyMethodSignatures(TypeSystemData typeSystem) { + Set generatedIsMethodNames = new HashSet<>(); + Set generatedAsMethodNames = new HashSet<>(); + Set generatedExpectMethodNames = new HashSet<>(); + + for (TypeData typeData : typeSystem.getTypes()) { + generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData)); + generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData)); + generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData)); + } + + List methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements()); + for (ExecutableElement method : methods) { + if (method.getModifiers().contains(Modifier.PRIVATE)) { + // will not conflict overridden methods + continue; + } else if (method.getParameters().size() != 1) { + continue; + } + String methodName = method.getSimpleName().toString(); + if (generatedIsMethodNames.contains(methodName)) { + verifyIsMethod(typeSystem, method); + } else if (generatedAsMethodNames.contains(methodName)) { + verifyAsMethod(typeSystem, method); + } else if (generatedExpectMethodNames.contains(methodName)) { + verifyExpectMethod(typeSystem); + } + } + } + + private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCheck.class); + if (mirror == null) { + typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); + return false; + } + return true; + } + + private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) { + AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCast.class); + if (mirror == null) { + typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); + return false; + } + return true; + } + + private static boolean verifyExpectMethod(TypeSystemData typeSystem) { + typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually."); + return false; + } + + private static void verifyNamesUnique(TypeSystemData typeSystem) { + List types = typeSystem.getTypes(); + for (int i = 0; i < types.size(); i++) { + for (int j = i + 1; j < types.size(); j++) { + String name1 = ElementUtils.getSimpleName(types.get(i).getBoxedType()); + String name2 = ElementUtils.getSimpleName(types.get(j).getBoxedType()); + if (name1.equalsIgnoreCase(name2)) { + typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2); + } + } + } + } +} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/* - * 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.dsl.processor.template; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public class ActualParameter { - - private final ParameterSpec specification; - private TypeData typeSystemType; - private TemplateMethod method; - private final String localName; - private final int specificationVarArgsIndex; - private final int typeVarArgsIndex; - private final TypeMirror actualType; - - public ActualParameter(ParameterSpec specification, TypeMirror actualType, int specificationVarArgsIndex, int typeVarArgsIndex) { - this.specification = specification; - this.actualType = actualType; - this.typeSystemType = null; - - this.specificationVarArgsIndex = specificationVarArgsIndex; - - String valueName = specification.getName() + "Value"; - if (specificationVarArgsIndex > -1) { - valueName += specificationVarArgsIndex; - } - this.typeVarArgsIndex = typeVarArgsIndex; - this.localName = valueName; - } - - public ActualParameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex) { - this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex); - this.typeSystemType = actualType; - } - - public ActualParameter(ActualParameter parameter, TypeData otherType) { - this(parameter.specification, otherType, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex); - } - - public ActualParameter(ActualParameter parameter) { - this.specification = parameter.specification; - this.actualType = parameter.actualType; - this.typeSystemType = parameter.typeSystemType; - this.specificationVarArgsIndex = parameter.specificationVarArgsIndex; - this.localName = parameter.localName; - this.typeVarArgsIndex = parameter.typeVarArgsIndex; - } - - public int getTypeVarArgsIndex() { - return typeVarArgsIndex; - } - - public int getSpecificationVarArgsIndex() { - return specificationVarArgsIndex; - } - - public String getLocalName() { - return localName; - } - - void setMethod(TemplateMethod method) { - this.method = method; - } - - public ParameterSpec getSpecification() { - return specification; - } - - public TemplateMethod getMethod() { - return method; - } - - public TypeMirror getType() { - return actualType; - } - - public TypeData getTypeSystemType() { - return typeSystemType; - } - - public boolean isTypeVarArgs() { - return typeVarArgsIndex >= 0; - } - - public ActualParameter getPreviousParameter() { - return method.getPreviousParam(this); - } - - @Override - public String toString() { - return Utils.getSimpleName(actualType); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ClassElementFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ClassElementFactory.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * 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.dsl.processor.template; - -import static com.oracle.truffle.dsl.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.api.dsl.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public abstract class ClassElementFactory extends CodeElementFactory { - - @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(); - TypeElement superClass = fromTypeMirror(clazz.getSuperclass()); - ExecutableElement constructor = findConstructor(superClass); - if (constructor != null && constructor.getParameters().size() > 0) { - builder.startStatement(); - builder.startSuperCall(); - for (VariableElement parameter : constructor.getParameters()) { - method.addParameter(new CodeVariableElement(parameter.asType(), parameter.getSimpleName().toString())); - builder.string(parameter.getSimpleName().toString()); - } - builder.end(); // super - builder.end(); // statement - } - - for (VariableElement field : clazz.getFields()) { - if (field.getModifiers().contains(STATIC)) { - continue; - } - String fieldName = field.getSimpleName().toString(); - method.addParameter(new CodeVariableElement(field.asType(), fieldName)); - builder.startStatement(); - builder.string("this."); - builder.string(fieldName); - builder.string(" = "); - if (isAssignable(field.asType(), getContext().getTruffleTypes().getNode())) { - builder.string("adoptChild(").string(fieldName).string(")"); - } else { - builder.string(fieldName); - } - builder.end(); // statement - } - - return method; - } - - private static ExecutableElement findConstructor(TypeElement clazz) { - List constructors = ElementFilter.constructorsIn(clazz.getEnclosedElements()); - if (constructors.isEmpty()) { - return null; - } else { - return constructors.get(0); - } - } - - 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(); - - PackageElement pack = getContext().getEnvironment().getElementUtils().getPackageOf(templateType); - CodeTypeElement clazz = new CodeTypeElement(modifiers, enumType ? ElementKind.ENUM : ElementKind.CLASS, pack, simpleName); - TypeMirror resolvedSuperType = superType; - if (resolvedSuperType == null) { - resolvedSuperType = getContext().getType(Object.class); - } - clazz.setSuperClass(resolvedSuperType); - - CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class)); - generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType())); - if (model.getTemplateMethodName() != null) { - generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName())); - } - - clazz.addAnnotationMirror(generatedByAnnotation); - - context.registerType(model.getTemplateType(), clazz.asType()); - - return clazz; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/CodeElementFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/CodeElementFactory.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* - * 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.dsl.processor.template; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; - -public abstract class CodeElementFactory { - - protected final ProcessorContext context; - private M model; - - private CodeElement element; - - public CodeElementFactory() { - this.context = ProcessorContext.getInstance(); - } - - protected abstract CodeElement create(M m); - - @SuppressWarnings("unused") - protected void createChildren(M m) { - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public CodeElement process(CodeElement parent, M m) { - model = m; - element = (CodeElement) create(model); - if (parent != null) { - parent.add(element); - } - if (element != null) { - createChildren(model); - } - return element; - } - - @SuppressWarnings("rawtypes") - public CodeElement getElement() { - return element; - } - - protected void add(CodeElementFactory factory, MO m) { - factory.process(this.element, m); - } - - public ProcessorContext getContext() { - return context; - } - - public M getModel() { - return model; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/CompilationUnitFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/CompilationUnitFactory.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - * 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.dsl.processor.template; - -import com.oracle.truffle.dsl.processor.ast.*; - -public abstract class CompilationUnitFactory extends CodeElementFactory { - - @Override - public final CodeCompilationUnit create(M m) { - return new CodeCompilationUnit(); - } - - @SuppressWarnings("rawtypes") - @Override - public CodeCompilationUnit process(CodeElement parent, M m) { - return (CodeCompilationUnit) super.process(parent, m); - } - - @Override - protected abstract void createChildren(M m); - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MessageContainer.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MessageContainer.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/* - * 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.dsl.processor.template; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; - -import com.oracle.truffle.dsl.processor.*; - -public abstract class MessageContainer implements Iterable { - - private final List messages = new ArrayList<>(); - - public final void addWarning(String text, Object... params) { - getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING)); - } - - public final void addWarning(AnnotationValue value, String text, Object... params) { - getMessages().add(new Message(value, this, String.format(text, params), Kind.WARNING)); - } - - public final void addError(String text, Object... params) { - addError(null, text, params); - } - - public final void addError(AnnotationValue value, String text, Object... params) { - getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR)); - } - - protected List findChildContainers() { - return Collections.emptyList(); - } - - public abstract Element getMessageElement(); - - public MessageContainer getBaseContainer() { - return null; - } - - public Iterator iterator() { - return findChildContainers().iterator(); - } - - public final void emitMessages(ProcessorContext context, Log log) { - emitMessagesImpl(context, log, new HashSet(), null); - } - - private void emitMessagesImpl(ProcessorContext context, Log log, Set visitedSinks, List verifiedMessages) { - List childMessages; - if (verifiedMessages == null) { - childMessages = collectMessagesWithElementChildren(new HashSet(), getMessageElement()); - } else { - childMessages = verifiedMessages; - } - verifyExpectedMessages(context, log, childMessages); - - for (int i = getMessages().size() - 1; i >= 0; i--) { - emitDefault(context, log, getMessages().get(i)); - } - - for (MessageContainer sink : findChildContainers()) { - if (visitedSinks.contains(sink)) { - continue; - } - - visitedSinks.add(sink); - if (sink.getMessageElement() == this.getMessageElement()) { - sink.emitMessagesImpl(context, log, visitedSinks, childMessages); - } else { - sink.emitMessagesImpl(context, log, visitedSinks, null); - } - } - } - - private List collectMessagesWithElementChildren(Set visitedSinks, Element e) { - if (visitedSinks.contains(this)) { - return Collections.emptyList(); - } - visitedSinks.add(this); - - List foundMessages = new ArrayList<>(); - if (Utils.typeEquals(getMessageElement().asType(), e.asType())) { - foundMessages.addAll(getMessages()); - } - for (MessageContainer sink : findChildContainers()) { - foundMessages.addAll(sink.collectMessagesWithElementChildren(visitedSinks, e)); - } - return foundMessages; - } - - private void verifyExpectedMessages(ProcessorContext context, Log log, List msgs) { - TypeElement expectError = context.getTruffleTypes().getExpectError(); - if (expectError != null) { - Element element = getMessageElement(); - AnnotationMirror mirror = Utils.findAnnotationMirror(element.getAnnotationMirrors(), expectError); - if (mirror != null) { - List values = Utils.getAnnotationValueList(String.class, mirror, "value"); - if (values == null) { - values = Collections.emptyList(); - } - if (values.size() != msgs.size()) { - log.message(Kind.ERROR, element, mirror, Utils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size())); - } - } - } - } - - private void emitDefault(ProcessorContext context, Log log, Message message) { - Kind kind = message.getKind(); - - Element messageElement = getMessageElement(); - AnnotationMirror messageAnnotation = getMessageAnnotation(); - AnnotationValue messageValue = getMessageAnnotationValue(); - if (message.getAnnotationValue() != null) { - messageValue = message.getAnnotationValue(); - } - - String text = message.getText(); - - TypeElement expectError = context.getTruffleTypes().getExpectError(); - if (expectError != null) { - AnnotationMirror mirror = Utils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError); - if (mirror != null) { - List expectedTexts = Utils.getAnnotationValueList(String.class, mirror, "value"); - boolean found = false; - for (String expectedText : expectedTexts) { - if (expectedText.endsWith("%") && text.startsWith(expectedText.substring(0, expectedText.length() - 1))) { - found = true; - break; - } else if (text.equals(expectedText)) { - found = true; - break; - } - } - if (!found) { - log.message(kind, messageElement, mirror, Utils.getAnnotationValue(mirror, "value"), "Message expected one of '%s' but was '%s'.", expectedTexts, text); - } else { - return; - } - - } - } - - log.message(kind, messageElement, messageAnnotation, messageValue, text); - } - - public AnnotationMirror getMessageAnnotation() { - return null; - } - - public AnnotationValue getMessageAnnotationValue() { - return null; - } - - public final boolean hasErrors() { - return hasErrorsImpl(new HashSet()); - } - - public final List collectMessages() { - List collectedMessages = new ArrayList<>(); - collectMessagesImpl(collectedMessages, new HashSet()); - return collectedMessages; - } - - private void collectMessagesImpl(List collectedMessages, Set visitedSinks) { - collectedMessages.addAll(getMessages()); - for (MessageContainer sink : findChildContainers()) { - if (visitedSinks.contains(sink)) { - return; - } - - visitedSinks.add(sink); - sink.collectMessagesImpl(collectedMessages, visitedSinks); - } - } - - private boolean hasErrorsImpl(Set visitedSinks) { - for (Message msg : getMessages()) { - if (msg.getKind() == Kind.ERROR) { - return true; - } - } - for (MessageContainer sink : findChildContainers()) { - if (visitedSinks.contains(sink)) { - return false; - } - - visitedSinks.add(sink); - - if (sink.hasErrorsImpl(visitedSinks)) { - return true; - } - } - return false; - } - - public List getMessages() { - return messages; - } - - public static final class Message { - - private final MessageContainer originalContainer; - private final AnnotationValue annotationValue; - private final String text; - private final Kind kind; - - public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) { - this.annotationValue = annotationValue; - this.originalContainer = originalContainer; - this.text = text; - this.kind = kind; - } - - public AnnotationValue getAnnotationValue() { - return annotationValue; - } - - public MessageContainer getOriginalContainer() { - return originalContainer; - } - - public String getText() { - return text; - } - - public Kind getKind() { - return kind; - } - - @Override - public String toString() { - return kind + ": " + text; - } - - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,239 +0,0 @@ -/* - * 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.dsl.processor.template; - -import java.util.*; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; - -public class MethodSpec { - - private final ParameterSpec returnType; - private final List optional = new ArrayList<>(); - private final List required = new ArrayList<>(); - - private boolean ignoreAdditionalParameters; - private boolean ignoreAdditionalSpecifications; - private boolean variableRequiredParameters; - - private List typeDefinitions; - - public MethodSpec(ParameterSpec returnType) { - this.returnType = returnType; - } - - public void setVariableRequiredParameters(boolean variableRequiredParameters) { - this.variableRequiredParameters = variableRequiredParameters; - } - - public boolean isVariableRequiredParameters() { - return variableRequiredParameters; - } - - public void setIgnoreAdditionalParameters(boolean ignoreAdditionalParameter) { - this.ignoreAdditionalParameters = ignoreAdditionalParameter; - } - - public boolean isIgnoreAdditionalParameters() { - return ignoreAdditionalParameters; - } - - public void addOptional(ParameterSpec spec) { - optional.add(spec); - } - - public ParameterSpec addRequired(ParameterSpec spec) { - required.add(spec); - return spec; - } - - public ParameterSpec getReturnType() { - return returnType; - } - - public List getRequired() { - return required; - } - - public List getOptional() { - return optional; - } - - public List getAll() { - List specs = new ArrayList<>(); - specs.add(getReturnType()); - specs.addAll(getOptional()); - specs.addAll(getRequired()); - return specs; - } - - public ParameterSpec findParameterSpec(String name) { - for (ParameterSpec spec : getAll()) { - if (spec.getName().equals(name)) { - return spec; - } - } - return null; - } - - public void applyTypeDefinitions(String prefix) { - this.typeDefinitions = createTypeDefinitions(prefix); - } - - private List createTypeDefinitions(String prefix) { - List typeDefs = new ArrayList<>(); - - int defIndex = 0; - for (ParameterSpec spec : getAll()) { - List allowedTypes = spec.getAllowedTypes(); - List types = spec.getAllowedTypes(); - if (types != null && allowedTypes.size() > 1) { - TypeDef foundDef = null; - for (TypeDef def : typeDefs) { - if (allowedTypes.equals(def.getTypes())) { - foundDef = def; - break; - } - } - if (foundDef == null) { - foundDef = new TypeDef(types, prefix + defIndex); - typeDefs.add(foundDef); - defIndex++; - } - - spec.setTypeDefinition(foundDef); - } - } - - return typeDefs; - } - - public String toSignatureString(String methodName) { - StringBuilder b = new StringBuilder(); - b.append(" "); - b.append(createTypeSignature(returnType, true)); - - b.append(" "); - b.append(methodName); - b.append("("); - - String sep = ""; - - for (ParameterSpec optionalSpec : getOptional()) { - b.append(sep); - b.append("["); - b.append(createTypeSignature(optionalSpec, false)); - b.append("]"); - sep = ", "; - } - - for (int i = 0; i < getRequired().size(); i++) { - ParameterSpec requiredSpec = getRequired().get(i); - b.append(sep); - - if (isVariableRequiredParameters() && i == getRequired().size() - 1) { - b.append(("{")); - } - b.append(createTypeSignature(requiredSpec, false)); - if (isVariableRequiredParameters() && i == getRequired().size() - 1) { - b.append(("}")); - } - - sep = ", "; - } - - b.append(")"); - - if (typeDefinitions != null && !typeDefinitions.isEmpty()) { - b.append("\n\n"); - - String lineSep = ""; - for (TypeDef def : typeDefinitions) { - b.append(lineSep); - b.append(" <").append(def.getName()).append(">"); - b.append(" = {"); - String separator = ""; - for (TypeMirror type : def.getTypes()) { - b.append(separator).append(Utils.getSimpleName(type)); - separator = ", "; - } - b.append("}"); - lineSep = "\n"; - - } - } - return b.toString(); - } - - private static String createTypeSignature(ParameterSpec spec, boolean typeOnly) { - StringBuilder builder = new StringBuilder(); - TypeDef foundTypeDef = spec.getTypeDefinition(); - if (foundTypeDef != null) { - builder.append("<" + foundTypeDef.getName() + ">"); - } else if (spec.getAllowedTypes().size() >= 1) { - builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0))); - } else { - builder.append("void"); - } - if (!typeOnly) { - builder.append(" "); - builder.append(spec.getName()); - } - return builder.toString(); - } - - @Override - public String toString() { - return toSignatureString("methodName"); - } - - static class TypeDef { - - private final List types; - private final String name; - - public TypeDef(List types, String name) { - this.types = types; - this.name = name; - } - - public List getTypes() { - return types; - } - - public String getName() { - return name; - } - } - - public void setIgnoreAdditionalSpecifications(boolean ignoreAdditoinalSpecifications) { - this.ignoreAdditionalSpecifications = ignoreAdditoinalSpecifications; - } - - public boolean isIgnoreAdditionalSpecifications() { - return ignoreAdditionalSpecifications; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ParameterSpec.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * 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.dsl.processor.template; - -import java.util.*; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.node.*; -import com.oracle.truffle.dsl.processor.template.MethodSpec.TypeDef; - -public class ParameterSpec { - - private final String name; - private final List allowedTypes; - - /** Type is bound to local final variable. */ - private boolean local; - private boolean signature; - - /** Optional bound execution of node. */ - private NodeExecutionData execution; - private TypeDef typeDefinition; - - public ParameterSpec(String name, List allowedTypes) { - this.name = name; - this.allowedTypes = allowedTypes; - } - - public ParameterSpec(String name, TypeMirror type) { - this(name, Arrays.asList(type)); - } - - public ParameterSpec(ParameterSpec o, List allowedTypes) { - this.name = o.name; - this.local = o.local; - this.typeDefinition = o.typeDefinition; - this.execution = o.execution; - this.signature = o.signature; - this.allowedTypes = allowedTypes; - } - - public NodeExecutionData getExecution() { - return execution; - } - - public void setExecution(NodeExecutionData executionData) { - this.execution = executionData; - this.signature = execution != null; - } - - public void setSignature(boolean signature) { - this.signature = signature; - } - - void setTypeDefinition(TypeDef typeDefinition) { - this.typeDefinition = typeDefinition; - } - - TypeDef getTypeDefinition() { - return typeDefinition; - } - - public void setLocal(boolean local) { - this.local = local; - } - - public boolean isSignature() { - return signature; - } - - public boolean isLocal() { - return local; - } - - public String getName() { - return name; - } - - public List getAllowedTypes() { - return allowedTypes; - } - - public boolean matches(TypeMirror actualType) { - for (TypeMirror mirror : allowedTypes) { - if (Utils.typeEquals(actualType, mirror)) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return toSignatureString(false); - } - - public String toSignatureString(boolean typeOnly) { - StringBuilder builder = new StringBuilder(); - if (typeDefinition != null) { - builder.append("<" + typeDefinition.getName() + ">"); - } else if (getAllowedTypes().size() >= 1) { - builder.append(Utils.getSimpleName(getAllowedTypes().get(0))); - } else { - builder.append("void"); - } - if (!typeOnly) { - builder.append(" "); - builder.append(getName()); - } - return builder.toString(); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/Template.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/Template.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/* - * 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.dsl.processor.template; - -import java.util.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public abstract class Template extends MessageContainer { - - private final ProcessorContext context; - private final TypeElement templateType; - private final String templateMethodName; - private final AnnotationMirror annotation; - - public Template(ProcessorContext context, TypeElement templateType, String templateMethodName, AnnotationMirror annotation) { - this.context = context; - this.templateType = templateType; - this.templateMethodName = templateMethodName; - this.annotation = annotation; - } - - public ProcessorContext getContext() { - return context; - } - - @Override - public MessageContainer getBaseContainer() { - return this; - } - - public abstract TypeSystemData getTypeSystem(); - - @Override - public Element getMessageElement() { - return templateType; - } - - @Override - protected List findChildContainers() { - return Collections.emptyList(); - } - - public String getTemplateMethodName() { - return templateMethodName; - } - - public TypeElement getTemplateType() { - return templateType; - } - - public AnnotationMirror getTemplateTypeAnnotation() { - return annotation; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + Utils.getSimpleName(getTemplateType()) + "]"; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,493 +0,0 @@ -/* - * 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.dsl.processor.template; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.typesystem.*; -import com.oracle.truffle.dsl.processor.util.*; - -/** - * Note: this class has a natural ordering that is inconsistent with equals. - */ -public class TemplateMethod extends MessageContainer implements Comparable { - - public static final int NO_NATURAL_ORDER = -1; - - private String id; - private final Template template; - private final int naturalOrder; - private final MethodSpec specification; - private final ExecutableElement method; - private final AnnotationMirror markerAnnotation; - private ActualParameter returnType; - private List parameters; - - public TemplateMethod(String id, int naturalOrder, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, - List parameters) { - this.template = template; - this.specification = specification; - this.naturalOrder = naturalOrder; - this.method = method; - this.markerAnnotation = markerAnnotation; - this.returnType = returnType; - this.parameters = new ArrayList<>(); - for (ActualParameter param : parameters) { - ActualParameter newParam = new ActualParameter(param); - this.parameters.add(newParam); - newParam.setMethod(this); - } - this.id = id; - } - - public int getNaturalOrder() { - return naturalOrder; - } - - public TemplateMethod(TemplateMethod method) { - this(method.id, method.naturalOrder, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); - getMessages().addAll(method.getMessages()); - } - - public TemplateMethod(TemplateMethod method, ExecutableElement executable) { - this(method.id, method.naturalOrder, method.template, method.specification, executable, method.markerAnnotation, method.returnType, method.parameters); - getMessages().addAll(method.getMessages()); - } - - public void setParameters(List parameters) { - this.parameters = parameters; - } - - @Override - public Element getMessageElement() { - return method; - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return markerAnnotation; - } - - @Override - protected List findChildContainers() { - return Collections.emptyList(); - } - - public void setId(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - public Template getTemplate() { - return template; - } - - public MethodSpec getSpecification() { - return specification; - } - - public ActualParameter getReturnType() { - return returnType; - } - - public void replaceParameter(String localName, ActualParameter newParameter) { - if (returnType.getLocalName().equals(localName)) { - returnType = newParameter; - returnType.setMethod(this); - } - - for (ListIterator iterator = parameters.listIterator(); iterator.hasNext();) { - ActualParameter parameter = iterator.next(); - if (parameter.getLocalName().equals(localName)) { - iterator.set(newParameter); - newParameter.setMethod(this); - } - } - } - - public List getRequiredParameters() { - List requiredParameters = new ArrayList<>(); - for (ActualParameter parameter : getParameters()) { - if (getSpecification().getRequired().contains(parameter.getSpecification())) { - requiredParameters.add(parameter); - } - } - return requiredParameters; - } - - public Iterable getSignatureParameters() { - return new FilteredIterable<>(getParameters(), new Predicate() { - public boolean evaluate(ActualParameter value) { - return value.getSpecification().isSignature(); - } - }); - } - - public List getParameters() { - return parameters; - } - - public List findParameters(ParameterSpec spec) { - List foundParameters = new ArrayList<>(); - for (ActualParameter param : getReturnTypeAndParameters()) { - if (param.getSpecification().getName().equals(spec.getName())) { - foundParameters.add(param); - } - } - return foundParameters; - } - - public ActualParameter findParameter(String valueName) { - for (ActualParameter param : getReturnTypeAndParameters()) { - if (param.getLocalName().equals(valueName)) { - return param; - } - } - return null; - } - - public List getReturnTypeAndParameters() { - List allParameters = new ArrayList<>(getParameters().size() + 1); - if (getReturnType() != null) { - allParameters.add(getReturnType()); - } - allParameters.addAll(getParameters()); - return Collections.unmodifiableList(allParameters); - } - - public boolean canBeAccessedByInstanceOf(TypeMirror type) { - TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType(); - return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type); - } - - public ExecutableElement getMethod() { - return method; - } - - public String getMethodName() { - if (getMethod() != null) { - return getMethod().getSimpleName().toString(); - } else { - return "$synthetic"; - } - } - - public AnnotationMirror getMarkerAnnotation() { - return markerAnnotation; - } - - @Override - public String toString() { - return String.format("%s [id = %s, method = %s]", getClass().getSimpleName(), getId(), getMethod()); - } - - public ActualParameter getPreviousParam(ActualParameter searchParam) { - ActualParameter prev = null; - for (ActualParameter param : getParameters()) { - if (param == searchParam) { - return prev; - } - prev = param; - } - return prev; - } - - @SuppressWarnings("unused") - public int getSignatureSize() { - int signatureSize = 0; - for (ActualParameter parameter : getSignatureParameters()) { - signatureSize++; - } - return signatureSize; - } - - public TypeSignature getTypeSignature() { - TypeSignature signature = new TypeSignature(); - signature.types.add(getReturnType().getTypeSystemType()); - for (ActualParameter parameter : getSignatureParameters()) { - TypeData typeData = parameter.getTypeSystemType(); - if (typeData != null) { - signature.types.add(typeData); - } - } - return signature; - } - - public ActualParameter getSignatureParameter(int searchIndex) { - int index = 0; - for (ActualParameter parameter : getParameters()) { - if (!parameter.getSpecification().isSignature()) { - continue; - } - if (index == searchIndex) { - return parameter; - } - index++; - } - return null; - } - - public void updateSignature(TypeSignature signature) { - // TODO(CH): fails in normal usage - output ok though - // assert signature.size() >= 1; - - int signatureIndex = 0; - for (ActualParameter parameter : getReturnTypeAndParameters()) { - if (!parameter.getSpecification().isSignature()) { - continue; - } - if (signatureIndex >= signature.size()) { - break; - } - TypeData newType = signature.get(signatureIndex++); - if (!parameter.getTypeSystemType().equals(newType)) { - replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, newType)); - } - } - } - - @Override - public int compareTo(TemplateMethod o) { - if (this == o) { - return 0; - } - - int compare = compareBySignature(o); - if (compare == 0) { - // if signature sorting failed sort by id - compare = getId().compareTo(o.getId()); - } - if (compare == 0) { - // if still no difference sort by enclosing type name - TypeElement enclosingType1 = Utils.findNearestEnclosingType(getMethod()); - TypeElement enclosingType2 = Utils.findNearestEnclosingType(o.getMethod()); - compare = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString()); - } - return compare; - } - - public List getParametersAfter(ActualParameter genericParameter) { - boolean found = false; - List foundParameters = new ArrayList<>(); - for (ActualParameter param : getParameters()) { - if (param.getLocalName().equals(genericParameter.getLocalName())) { - found = true; - } else if (found) { - foundParameters.add(param); - } - } - return foundParameters; - } - - public int compareBySignature(TemplateMethod compareMethod) { - final TypeSystemData typeSystem = getTemplate().getTypeSystem(); - if (typeSystem != compareMethod.getTemplate().getTypeSystem()) { - throw new IllegalStateException("Cannot compare two methods with different type systems."); - } - - List signature1 = getSignatureTypes(this); - List signature2 = getSignatureTypes(compareMethod); - - int result = 0; - for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) { - TypeMirror t1 = i < signature1.size() ? signature1.get(i) : null; - TypeMirror t2 = i < signature2.size() ? signature2.get(i) : null; - result = compareParameter(typeSystem, t1, t2); - if (result != 0) { - break; - } - } - - return result; - } - - protected static int compareParameter(TypeSystemData data, TypeMirror signature1, TypeMirror signature2) { - if (signature1 == null) { - return 1; - } else if (signature2 == null) { - return -1; - } - - if (Utils.typeEquals(signature1, signature2)) { - return 0; - } - - int index1 = data.findType(signature1); - int index2 = data.findType(signature2); - if (index1 != -1 && index2 != -1) { - return index1 - index2; - } - - // TODO this version if subclass of should be improved. - if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) { - TypeElement element1 = Utils.fromTypeMirror(signature1); - TypeElement element2 = Utils.fromTypeMirror(signature2); - - if (Utils.getDirectSuperTypes(element1).contains(element2)) { - return -1; - } else if (Utils.getDirectSuperTypes(element2).contains(element1)) { - return 1; - } - } - return Utils.getSimpleName(signature1).compareTo(Utils.getSimpleName(signature2)); - } - - public static List getSignatureTypes(TemplateMethod method) { - List types = new ArrayList<>(); - for (ActualParameter param : method.getSignatureParameters()) { - types.add(param.getType()); - } - return types; - } - - public static class TypeSignature implements Iterable, Comparable { - - final List types; - - public TypeSignature() { - this.types = new ArrayList<>(); - } - - public TypeSignature(List signature) { - this.types = signature; - } - - @Override - public int hashCode() { - return types.hashCode(); - } - - public int size() { - return types.size(); - } - - public TypeData get(int index) { - return types.get(index); - } - - public int compareTo(TypeSignature other) { - if (this == other) { - return 0; - } else if (types.size() != other.types.size()) { - return types.size() - other.types.size(); - } else if (types.isEmpty()) { - return 0; - } - - for (int i = 0; i < types.size(); i++) { - TypeData type1 = types.get(i); - TypeData type2 = other.types.get(i); - - int comparison = type1.compareTo(type2); - if (comparison != 0) { - return comparison; - } - } - - return 0; - } - - public TypeSignature combine(TypeSignature genericSignature, TypeSignature other) { - assert types.size() == other.types.size(); - assert genericSignature.types.size() == other.types.size(); - - if (this.equals(other)) { - return this; - } - - TypeSignature signature = new TypeSignature(); - for (int i = 0; i < types.size(); i++) { - TypeData type1 = types.get(i); - TypeData type2 = other.types.get(i); - if (type1.equals(type2)) { - signature.types.add(type1); - } else { - signature.types.add(genericSignature.types.get(i)); - } - } - return signature; - } - - public boolean equalsParameters(TypeSignature other) { - if (size() != other.size()) { - return false; - } - return types.subList(1, types.size()).equals(other.types.subList(1, other.types.size())); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof TypeSignature) { - return ((TypeSignature) obj).types.equals(types); - } - return super.equals(obj); - } - - public Iterator iterator() { - return types.iterator(); - } - - @Override - public String toString() { - return types.toString(); - } - - public boolean hasAnyParameterMatch(TypeSignature other) { - for (int i = 1; i < types.size(); i++) { - TypeData type1 = types.get(i); - TypeData type2 = other.types.get(i); - if (type1.equals(type2)) { - return true; - } - } - return false; - } - - public boolean isCompatibleTo(TypeSignature signature) { - if (size() != signature.size()) { - return false; - } - - for (int i = 0; i < size(); i++) { - TypeData o1 = get(i); - TypeData o2 = signature.get(i); - if (o1.equals(o2)) { - continue; - } else if (o2.isGeneric()) { - continue; - } else { - return false; - } - } - return true; - } - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -/* - * 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.dsl.processor.template; - -import static com.oracle.truffle.dsl.processor.Utils.*; - -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.dsl.processor.*; -import com.oracle.truffle.dsl.processor.typesystem.*; - -public abstract class TemplateMethodParser { - - private final ProcessorContext context; - - protected final T template; - - private boolean emitErrors = true; - private boolean parseNullOnError = false; - private boolean useVarArgs = false; - - public TemplateMethodParser(ProcessorContext context, T template) { - this.template = template; - this.context = context; - } - - protected void setUseVarArgs(boolean useVarArgs) { - this.useVarArgs = useVarArgs; - } - - public boolean isUseVarArgs() { - return useVarArgs; - } - - 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; - } - - public TypeSystemData getTypeSystem() { - return template.getTypeSystem(); - } - - public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); - - public abstract E create(TemplateMethod method, boolean invalid); - - 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; - int naturalOrder = 0; - for (ExecutableElement method : methods) { - if (!isParsable(method)) { - continue; - } - - Class annotationType = getAnnotationType(); - AnnotationMirror mirror = null; - if (annotationType != null) { - mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); - } - - E parsedMethod = parse(naturalOrder, method, mirror); - - if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { - parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); - parsedMethods.add(parsedMethod); - valid = false; - continue; - } - - if (parsedMethod != null) { - parsedMethods.add(parsedMethod); - } else { - valid = false; - } - naturalOrder++; - } - Collections.sort(parsedMethods); - - if (!valid && parseNullOnError) { - return null; - } - return parsedMethods; - } - - private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { - MethodSpec methodSpecification = createSpecification(method, annotation); - if (methodSpecification == null) { - return null; - } - - methodSpecification.applyTypeDefinitions("types"); - - String id = method.getSimpleName().toString(); - TypeMirror returnType = method.getReturnType(); - List parameterTypes = new ArrayList<>(); - for (VariableElement var : method.getParameters()) { - parameterTypes.add(var.asType()); - } - - return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); - } - - private E parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, List parameterTypes) { - ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, template, -1, -1); - if (returnTypeMirror == null) { - if (emitErrors) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String expectedReturnType = returnTypeSpec.toSignatureString(true); - String actualReturnType = Utils.getSimpleName(returnType); - - String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); - if (parameters == null) { - if (isEmitErrors() && method != null) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - return create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters), false); - } - - private static String createActualSignature(ExecutableElement method) { - StringBuilder b = new StringBuilder("("); - String sep = ""; - if (method != null) { - for (VariableElement var : method.getParameters()) { - b.append(sep); - b.append(Utils.getSimpleName(var.asType())); - sep = ", "; - } - } - b.append(")"); - return b.toString(); - } - - /* - * Parameter parsing tries to parse required arguments starting from offset 0 with increasing - * offset until it finds a signature end that matches the required specification. If there is no - * end matching the required arguments, parsing fails. Parameters prior to the parsed required - * ones are cut and used to parse the optional parameters. - */ - private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { - List parsedRequired = null; - int offset = 0; - for (; offset <= parameterTypes.size(); offset++) { - List parameters = new ArrayList<>(); - parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); - parsedRequired = parseParametersRequired(spec, parameters, varArgs); - if (parsedRequired != null) { - break; - } - } - - if (parsedRequired == null) { - return null; - } - - if (parsedRequired.isEmpty() && offset == 0) { - offset = parameterTypes.size(); - } - List potentialOptionals = parameterTypes.subList(0, offset); - List parsedOptionals = parseParametersOptional(spec, potentialOptionals); - if (parsedOptionals == null) { - return null; - } - - List finalParameters = new ArrayList<>(); - finalParameters.addAll(parsedOptionals); - finalParameters.addAll(parsedRequired); - return finalParameters; - } - - private List parseParametersOptional(MethodSpec spec, List types) { - List parsedParams = new ArrayList<>(); - - int typeStartIndex = 0; - List specifications = spec.getOptional(); - outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { - ParameterSpec specification = specifications.get(specIndex); - for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { - TypeMirror actualType = types.get(typeIndex); - ActualParameter optionalParam = matchParameter(specification, actualType, template, -1, -1); - if (optionalParam != null) { - parsedParams.add(optionalParam); - typeStartIndex = typeIndex + 1; - continue outer; - } - } - } - - if (typeStartIndex < types.size()) { - // not enough types found - return null; - } - return parsedParams; - } - - private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { - List parsedParams = new ArrayList<>(); - List specifications = spec.getRequired(); - boolean specVarArgs = spec.isVariableRequiredParameters(); - int typeIndex = 0; - int specificationIndex = 0; - - ParameterSpec specification; - while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { - TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); - if (actualType == null) { - if (spec.isIgnoreAdditionalSpecifications()) { - break; - } - return null; - } - - int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; - int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; - - if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { - // both specifications and types have a variable number of arguments - // we would get into an endless loop if we would continue - break; - } - - ActualParameter resolvedParameter = matchParameter(specification, actualType, template, specVarArgsIndex, typeVarArgsIndex); - if (resolvedParameter == null) { - return null; - } - parsedParams.add(resolvedParameter); - typeIndex++; - specificationIndex++; - } - - if (typeIndex < types.size()) { - // additional types available - if (spec.isIgnoreAdditionalParameters()) { - return parsedParams; - } else { - return null; - } - } - - return parsedParams; - } - - private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { - if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { - return specifications.get(specifications.size() - 1); - } else if (specIndex < specifications.size()) { - return specifications.get(specIndex); - } else { - return null; - } - } - - private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { - if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { - // unpack varargs array argument - TypeMirror actualType = types.get(types.size() - 1); - if (actualType.getKind() == TypeKind.ARRAY) { - actualType = ((ArrayType) actualType).getComponentType(); - } - return actualType; - } else if (typeIndex < types.size()) { - return types.get(typeIndex); - } else { - return null; - } - } - - protected final ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int specificationIndex, int varArgsIndex) { - TypeMirror resolvedType = mirror; - if (hasError(resolvedType)) { - resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate); - } - - if (!specification.matches(resolvedType)) { - return null; - } - - TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); - if (resolvedTypeData != null) { - return new ActualParameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); - } else { - return new ActualParameter(specification, resolvedType, specificationIndex, varArgsIndex); - } - } - - public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { - return parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +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.dsl.processor.typesystem; - -import java.util.*; - -import com.oracle.truffle.dsl.processor.template.*; - -public class GuardData extends TemplateMethod { - - private List impliesExpressions; - - public GuardData(TemplateMethod method, List impliesExpressions) { - super(method); - this.impliesExpressions = impliesExpressions; - } - - public List getImpliesExpressions() { - return impliesExpressions; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof GuardData) { - GuardData other = (GuardData) obj; - return getMethod().equals(other.getMethod()); - } - return false; - } - - @Override - public int hashCode() { - return getMethod().hashCode(); - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardExpression.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -package com.oracle.truffle.dsl.processor.typesystem; - -import java.util.*; - -public final class GuardExpression { - - private GuardData resolvedGuard; - - private final String guardName; - private final boolean negated; - - public GuardExpression(String expression) { - if (expression.startsWith("!")) { - guardName = expression.substring(1, expression.length()); - negated = true; - } else { - guardName = expression; - negated = false; - } - } - - public boolean isResolved() { - return resolvedGuard != null; - } - - public String getGuardName() { - return guardName; - } - - public void setGuard(GuardData guard) { - this.resolvedGuard = guard; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof GuardExpression) { - GuardExpression other = (GuardExpression) obj; - if (isResolved() && other.isResolved()) { - return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated; - } else { - return guardName.equals(other.guardName) && negated == other.negated; - } - } - return false; - } - - @Override - public int hashCode() { - return Objects.hash(guardName, negated, resolvedGuard); - } - - public int compareConcreteness(GuardExpression other) { - if (other == null) { - return -1; - } else if (this == other) { - return 0; - } - - /* - * Positive and negated guard are always disjunct. So we can choose the positive to be - * first. - */ - if (getGuardName().equals(other.getGuardName())) { - if (negated == !other.negated) { - if (negated) { - return 1; - } else { - return -1; - } - } - } - - /* - * Very simple version of the implies annotation implementation. - */ - if (isResolved() && other.isResolved()) { - if (impliesNot(other)) { - return 1; - } else if (other.impliesNot(this)) { - return -1; - } - } - return 0; - } - - public final boolean implies(GuardExpression other) { - if (other == this) { - return true; - } - if (getGuardName().equals(other.getGuardName())) { - if (isNegated() == other.isNegated()) { - return true; - } - } - - if (isResolved() && other.isResolved()) { - for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) { - if (implies.getGuardName().equals(other.getGuardName())) { - if (implies.isNegated() == other.isNegated()) { - return true; - } - } - } - } - return false; - } - - public final boolean impliesNot(GuardExpression other) { - if (other == this) { - return false; - } - if (getGuardName().equals(other.getGuardName())) { - if (isNegated() != other.isNegated()) { - return true; - } - } - - if (isResolved() && other.isResolved()) { - for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) { - if (implies.getGuardName().equals(other.getGuardName())) { - if (implies.isNegated() != other.isNegated()) { - return true; - } - } - } - } - return false; - } - - @Override - public String toString() { - return (negated ? "!" : "") + guardName; - } - - public boolean isNegated() { - return negated; - } - - public GuardData getResolvedGuard() { - return resolvedGuard; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +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.dsl.processor.typesystem; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.node.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class GuardParser extends NodeMethodParser { - - private final Set guardNames; - private final TemplateMethod compatibleSource; - - public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, Set guardNames) { - super(context, node); - this.guardNames = guardNames; - this.compatibleSource = compatibleSource; - setEmitErrors(false); - setParseNullOnError(false); - } - - @Override - protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) { - return super.createValueParameterSpec(execution); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null); - spec.setIgnoreAdditionalSpecifications(true); - if (compatibleSource != null) { - spec.getRequired().clear(); - for (ActualParameter parameter : compatibleSource.getRequiredParameters()) { - spec.addRequired(new ParameterSpec(parameter.getSpecification(), Utils.getAssignableTypes(getContext(), parameter.getType()))); - } - } - return spec; - } - - @Override - protected List nodeTypeMirrors(NodeData nodeData) { - Set typeMirrors = new LinkedHashSet<>(); - typeMirrors.addAll(nodeData.getTypeSystem().getPrimitiveTypeMirrors()); - typeMirrors.addAll(nodeData.getTypeSystem().getBoxedTypeMirrors()); - return new ArrayList<>(typeMirrors); - } - - @Override - protected ParameterSpec createReturnParameterSpec() { - return new ParameterSpec("returnType", getContext().getType(boolean.class)); - } - - @Override - public boolean isParsable(ExecutableElement method) { - return guardNames.contains(method.getSimpleName().toString()); - } - - @Override - public GuardData create(TemplateMethod method, boolean invalid) { - Implies impliesAnnotation = method.getMethod().getAnnotation(Implies.class); - String[] impliesExpressions = new String[0]; - if (impliesAnnotation != null) { - impliesExpressions = impliesAnnotation.value(); - } - List guardExpressions = new ArrayList<>(); - for (String string : impliesExpressions) { - guardExpressions.add(new GuardExpression(string)); - } - return new GuardData(method, guardExpressions); - } - - @Override - public Class getAnnotationType() { - return null; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/ImplicitCastData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/ImplicitCastData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +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.dsl.processor.typesystem; - -import com.oracle.truffle.dsl.processor.template.*; - -public class ImplicitCastData extends TemplateMethod { - - private final TypeData sourceType; - private final TypeData targetType; - - public ImplicitCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { - super(method); - this.sourceType = sourceType; - this.targetType = targetType; - } - - public TypeData getSourceType() { - return sourceType; - } - - public TypeData getTargetType() { - return targetType; - } - - @Override - public int compareTo(TemplateMethod o) { - if (o instanceof ImplicitCastData && sourceType != null) { - // implicit casts are ordered by source type since - // its also the order in which they are checked. - TypeData otherSourceType = ((ImplicitCastData) o).getSourceType(); - if (otherSourceType != null) { - return this.sourceType.compareTo(otherSourceType); - } - } - return super.compareTo(o); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/ImplicitCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/ImplicitCastParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /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.dsl.processor.typesystem; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class ImplicitCastParser extends TypeSystemMethodParser { - - public ImplicitCastParser(ProcessorContext context, TypeSystemData typeSystem) { - super(context, typeSystem); - } - - @Override - public Class getAnnotationType() { - return ImplicitCast.class; - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - List types = new ArrayList<>(); - for (TypeData typeData : getTypeSystem().getTypes()) { - types.add(typeData.getPrimitiveType()); - } - MethodSpec spec = new MethodSpec(new ParameterSpec("target", types)); - spec.addRequired(new ParameterSpec("source", types)); - return spec; - } - - @Override - public ImplicitCastData create(TemplateMethod method, boolean invalid) { - if (invalid) { - return new ImplicitCastData(method, null, null); - } - - ActualParameter target = method.findParameter("targetValue"); - ActualParameter source = method.findParameter("sourceValue"); - - TypeData targetType = target.getTypeSystemType(); - TypeData sourceType = source.getTypeSystemType(); - - if (targetType.equals(sourceType)) { - method.addError("Target type and source type of an @%s must not be the same type.", ImplicitCast.class.getSimpleName()); - } - - return new ImplicitCastData(method, sourceType, targetType); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCastData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCastData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +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.dsl.processor.typesystem; - -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeCastData extends TemplateMethod { - - private final TypeData targetType; - private final TypeData sourceType; - - public TypeCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) { - super(method); - this.sourceType = sourceType; - this.targetType = targetType; - } - - public boolean isGeneric() { - return sourceType.isGeneric(); - } - - public TypeData getSourceType() { - return sourceType; - } - - public TypeData getTargetType() { - return targetType; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCastParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCastParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +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.dsl.processor.typesystem; - -import java.lang.annotation.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -class TypeCastParser extends TypeSystemMethodParser { - - public TypeCastParser(ProcessorContext context, TypeSystemData typeSystem) { - super(context, typeSystem); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as"); - if (targetType == null) { - return null; - } - MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetType.getPrimitiveType())); - spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); - return spec; - } - - @Override - public TypeCastData create(TemplateMethod method, boolean invalid) { - if (invalid) { - return new TypeCastData(method, null, null); - } - - TypeData targetType = findTypeByMethodName(method, "as"); - ActualParameter parameter = method.findParameter("valueValue"); - - TypeData sourceType = null; - if (parameter != null) { - sourceType = getTypeSystem().findTypeData(parameter.getType()); - } - TypeCastData cast = new TypeCastData(method, sourceType, targetType); - - if (targetType != method.getReturnType().getTypeSystemType()) { - cast.addError("Cast type %s does not match to the returned type %s.", Utils.getSimpleName(targetType.getPrimitiveType()), - method.getReturnType() != null ? Utils.getSimpleName(method.getReturnType().getTypeSystemType().getPrimitiveType()) : null); - } - return cast; - } - - @Override - public Class getAnnotationType() { - return TypeCast.class; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCheckData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCheckData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.dsl.processor.typesystem; - -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeCheckData extends TemplateMethod { - - private final TypeData checkedType; - private final TypeData valueType; - - public TypeCheckData(TemplateMethod method, TypeData checkedType, TypeData valueType) { - super(method); - this.checkedType = checkedType; - this.valueType = valueType; - } - - public boolean isGeneric() { - return valueType.isGeneric(); - } - - public TypeData getCheckedType() { - return checkedType; - } - - public TypeData getValueType() { - return valueType; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCheckParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeCheckParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +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.dsl.processor.typesystem; - -import java.lang.annotation.*; - -import javax.lang.model.element.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -class TypeCheckParser extends TypeSystemMethodParser { - - public TypeCheckParser(ProcessorContext context, TypeSystemData typeSystem) { - super(context, typeSystem); - } - - @Override - public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is"); - if (targetType == null) { - return null; - } - MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class))); - spec.addRequired(new ParameterSpec("value", getTypeSystem().getPrimitiveTypeMirrors())); - return spec; - } - - @Override - public TypeCheckData create(TemplateMethod method, boolean invalid) { - TypeData checkedType = findTypeByMethodName(method, "is"); - assert checkedType != null; - ActualParameter parameter = method.findParameter("valueValue"); - assert parameter != null; - return new TypeCheckData(method, checkedType, parameter.getTypeSystemType()); - } - - @Override - public Class getAnnotationType() { - return TypeCheck.class; - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,171 +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.dsl.processor.typesystem; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeData extends MessageContainer implements Comparable { - - private final TypeSystemData typeSystem; - private final AnnotationValue annotationValue; - private final TypeMirror primitiveType; - private final TypeMirror boxedType; - - private final int index; - private final List typeCasts = new ArrayList<>(); - private final List typeChecks = new ArrayList<>(); - - public TypeData(TypeSystemData typeSystem, int index, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) { - this.index = index; - this.typeSystem = typeSystem; - this.annotationValue = value; - this.primitiveType = primitiveType; - this.boxedType = boxedType; - } - - @Override - public Element getMessageElement() { - return typeSystem.getMessageElement(); - } - - @Override - public AnnotationMirror getMessageAnnotation() { - return typeSystem.getMessageAnnotation(); - } - - @Override - public AnnotationValue getMessageAnnotationValue() { - return annotationValue; - } - - void addTypeCast(TypeCastData typeCast) { - this.typeCasts.add(typeCast); - } - - void addTypeCheck(TypeCheckData typeCheck) { - this.typeChecks.add(typeCheck); - } - - public List getTypeCasts() { - return typeCasts; - } - - public List getTypeChecks() { - return typeChecks; - } - - public TypeSystemData getTypeSystem() { - return typeSystem; - } - - public TypeMirror getPrimitiveType() { - return primitiveType; - } - - public TypeMirror getBoxedType() { - return boxedType; - } - - public boolean isGeneric() { - return Utils.typeEquals(boxedType, getTypeSystem().getGenericType()); - } - - public boolean isVoid() { - if (getTypeSystem().getVoidType() == null) { - return false; - } - return Utils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType()); - } - - public int compareTo(TypeData o) { - if (this.equals(o)) { - return 0; - } - return index - o.index; - } - - @Override - public int hashCode() { - return Objects.hash(index, primitiveType); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TypeData)) { - return false; - } - TypeData otherType = (TypeData) obj; - return index == otherType.index && Utils.typeEquals(primitiveType, otherType.primitiveType); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + Utils.getSimpleName(primitiveType) + "]"; - } - - public boolean equalsType(TypeData actualTypeData) { - return Utils.typeEquals(boxedType, actualTypeData.boxedType); - } - - public boolean needsCastTo(TypeData targetType) { - return Utils.needsCastTo(getPrimitiveType(), targetType.getPrimitiveType()); - } - - public boolean needsCastTo(TypeMirror targetType) { - return Utils.needsCastTo(getPrimitiveType(), targetType); - } - - public boolean isPrimitive() { - return Utils.isPrimitive(getPrimitiveType()); - } - - public boolean isImplicitSubtypeOf(TypeData other) { - List casts = other.getTypeSystem().lookupByTargetType(other); - for (ImplicitCastData cast : casts) { - if (isSubtypeOf(cast.getSourceType())) { - return true; - } - } - return isSubtypeOf(other); - } - - public boolean isSubtypeOf(TypeData other) { - return Utils.isSubtype(boxedType, other.boxedType); - } - - public boolean intersects(TypeData type) { - if (this.equals(type)) { - return true; - } - if (type.isGeneric() || isGeneric()) { - return true; - } - return isSubtypeOf(type) || type.isSubtypeOf(this); - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,300 +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.dsl.processor.typesystem; - -import static com.oracle.truffle.dsl.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.dsl.processor.*; -import com.oracle.truffle.dsl.processor.ast.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeSystemCodeGenerator extends CompilationUnitFactory { - - public static String isTypeMethodName(TypeData type) { - return "is" + Utils.getTypeId(type.getBoxedType()); - } - - public static String isImplicitTypeMethodName(TypeData type) { - return "isImplicit" + Utils.getTypeId(type.getBoxedType()); - } - - public static String asTypeMethodName(TypeData type) { - return "as" + Utils.getTypeId(type.getBoxedType()); - } - - public static String asImplicitTypeMethodName(TypeData type) { - return "asImplicit" + Utils.getTypeId(type.getBoxedType()); - } - - public static String getImplicitClass(TypeData type) { - return "getImplicit" + Utils.getTypeId(type.getBoxedType()) + "Class"; - } - - public static String expectTypeMethodName(TypeData type) { - return "expect" + Utils.getTypeId(type.getBoxedType()); - } - - public static String typeName(TypeSystemData typeSystem) { - String name = getSimpleName(typeSystem.getTemplateType()); - return name + "Gen"; - } - - public static String singletonName(TypeSystemData type) { - return createConstantName(getSimpleName(type.getTemplateType().asType())); - } - - /** - * Finds the generated singleton field for a TypeSytemData instance. TypeSystemCodeGenerator - * must be applied to the TypeSystemData model before use. - */ - public static VariableElement findSingleton(ProcessorContext context, TypeSystemData typeSystem) { - TypeMirror type = context.findGeneratedClassBySimpleName(typeName(typeSystem), typeSystem); - return Utils.findDeclaredField(type, singletonName(typeSystem)); - } - - @Override - protected void createChildren(TypeSystemData m) { - add(new TypeClassFactory(), m); - } - - protected static class TypeClassFactory extends ClassElementFactory { - - private static final String LOCAL_VALUE = "value"; - - @Override - public CodeTypeElement create(TypeSystemData typeSystem) { - String name = typeName(typeSystem); - CodeTypeElement clazz = createClass(typeSystem, modifiers(PUBLIC, FINAL), name, typeSystem.getTemplateType().asType(), false); - - clazz.add(createConstructorUsingFields(modifiers(PROTECTED), clazz)); - CodeVariableElement singleton = createSingleton(clazz); - clazz.add(singleton); - - for (TypeData type : typeSystem.getTypes()) { - if (!type.isGeneric()) { - clazz.addOptional(createIsTypeMethod(type)); - clazz.addOptional(createAsTypeMethod(type)); - - for (TypeData sourceType : collectExpectSourceTypes(type)) { - clazz.addOptional(createExpectTypeMethod(type, sourceType)); - } - - clazz.addOptional(createAsImplicitTypeMethod(type, true)); - clazz.addOptional(createAsImplicitTypeMethod(type, false)); - clazz.addOptional(createIsImplicitTypeMethod(type, true)); - clazz.addOptional(createIsImplicitTypeMethod(type, false)); - clazz.addOptional(createGetTypeIndex(type)); - } - } - - return clazz; - } - - private static List collectExpectSourceTypes(TypeData type) { - Set sourceTypes = new HashSet<>(); - sourceTypes.add(type.getTypeSystem().getGenericTypeData()); - for (TypeCastData cast : type.getTypeCasts()) { - sourceTypes.add(cast.getSourceType()); - } - for (TypeCheckData cast : type.getTypeChecks()) { - sourceTypes.add(cast.getCheckedType()); - } - return new ArrayList<>(sourceTypes); - } - - private CodeVariableElement createSingleton(CodeTypeElement clazz) { - CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(getModel())); - field.createInitBuilder().startNew(clazz.asType()).end(); - return field; - } - - private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) { - TypeSystemData typeSystem = getModel(); - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; - } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type)); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); - if (typed) { - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); - } - CodeTreeBuilder builder = method.createBuilder(); - - List sourceTypes = typeSystem.lookupSourceTypes(type); - - builder.startReturn(); - String sep = ""; - for (TypeData sourceType : sourceTypes) { - builder.string(sep); - if (typed) { - builder.string("(typeHint == ").typeLiteral(sourceType.getPrimitiveType()).string(" && "); - } - builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); - if (typed) { - builder.string(")"); - } - if (sourceTypes.lastIndexOf(sourceType) != sourceTypes.size() - 1) { - builder.newLine(); - } - if (sep.equals("")) { - builder.startIndention(); - } - sep = " || "; - } - builder.end(); - builder.end(); - return method; - } - - private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean typed) { - TypeSystemData typeSystem = getModel(); - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; - } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asImplicitTypeMethodName(type)); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); - if (typed) { - method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "typeHint")); - } - - List sourceTypes = typeSystem.lookupSourceTypes(type); - - CodeTreeBuilder builder = method.createBuilder(); - boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { - elseIf = builder.startIf(elseIf); - if (typed) { - builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType()); - } else { - builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); - } - - builder.end().startBlock(); - - builder.startReturn(); - ImplicitCastData cast = typeSystem.lookupCast(sourceType, type); - if (cast != null) { - builder.startCall(cast.getMethodName()); - } - builder.startCall(asTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); - if (cast != null) { - builder.end(); - } - builder.end(); - builder.end(); - } - - builder.startElseBlock(); - builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); - builder.end(); - return method; - } - - private CodeExecutableElement createGetTypeIndex(TypeData type) { - TypeSystemData typeSystem = getModel(); - List casts = typeSystem.lookupByTargetType(type); - if (casts.isEmpty()) { - return null; - } - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(type)); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); - - List sourceTypes = typeSystem.lookupSourceTypes(type); - CodeTreeBuilder builder = method.createBuilder(); - boolean elseIf = false; - for (TypeData sourceType : sourceTypes) { - elseIf = builder.startIf(elseIf); - builder.startCall(isTypeMethodName(sourceType)).string(LOCAL_VALUE).end(); - builder.end().startBlock(); - builder.startReturn().typeLiteral(sourceType.getPrimitiveType()).end(); - builder.end(); - } - - builder.startElseBlock(); - builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end(); - builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end(); - builder.end(); - - return method; - } - - private CodeExecutableElement createIsTypeMethod(TypeData type) { - if (!type.getTypeChecks().isEmpty()) { - return null; - } - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getContext().getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(type)); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); - - DeclaredType suppressWarnings = (DeclaredType) getContext().getType(SuppressWarnings.class); - CodeAnnotationMirror annotationMirror = new CodeAnnotationMirror(suppressWarnings); - annotationMirror.setElementValue(annotationMirror.findExecutableElement("value"), new CodeAnnotationValue("static-method")); - method.getAnnotationMirrors().add(annotationMirror); - - CodeTreeBuilder body = method.createBuilder(); - body.startReturn().instanceOf(LOCAL_VALUE, type.getBoxedType()).end(); - - return method; - } - - private CodeExecutableElement createAsTypeMethod(TypeData type) { - if (!type.getTypeCasts().isEmpty()) { - return null; - } - - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asTypeMethodName(type)); - method.addParameter(new CodeVariableElement(getContext().getType(Object.class), LOCAL_VALUE)); - - CodeTreeBuilder body = method.createBuilder(); - String assertMessage = typeName(getModel()) + "." + asTypeMethodName(type) + ": " + Utils.getSimpleName(type.getBoxedType()) + " expected"; - body.startAssert().startCall(isTypeMethodName(type)).string(LOCAL_VALUE).end().string(" : ").doubleQuote(assertMessage).end(); - body.startReturn().cast(type.getPrimitiveType(), body.create().string(LOCAL_VALUE).getTree()).end(); - - return method; - } - - private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); - method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE)); - method.addThrownType(getContext().getTruffleTypes().getUnexpectedValueException()); - - CodeTreeBuilder body = method.createBuilder(); - body.startIf().startCall(TypeSystemCodeGenerator.isTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end().startBlock(); - body.startReturn().startCall(TypeSystemCodeGenerator.asTypeMethodName(expectedType)).string(LOCAL_VALUE).end().end(); - body.end(); // if-block - body.startThrow().startNew(getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end(); - - return method; - } - - } -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemData.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +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.dsl.processor.typesystem; - -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeSystemData extends Template { - - private List types; - private List primitiveTypeMirrors = new ArrayList<>(); - private List boxedTypeMirrors = new ArrayList<>(); - - private List implicitCasts; - private List casts; - private List checks; - - private TypeMirror genericType; - private TypeData voidType; - - public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation) { - super(context, templateType, null, annotation); - } - - @Override - public TypeSystemData getTypeSystem() { - return this; - } - - void setTypes(List types) { - this.types = types; - if (types != null) { - for (TypeData typeData : types) { - primitiveTypeMirrors.add(typeData.getPrimitiveType()); - boxedTypeMirrors.add(typeData.getBoxedType()); - } - } - } - - public void setImplicitCasts(List implicitCasts) { - this.implicitCasts = implicitCasts; - } - - public List getImplicitCasts() { - return implicitCasts; - } - - public void setCasts(List casts) { - this.casts = casts; - } - - public void setChecks(List checks) { - this.checks = checks; - } - - void setGenericType(TypeMirror genericType) { - this.genericType = genericType; - } - - void setVoidType(TypeData voidType) { - this.voidType = voidType; - } - - @Override - protected List findChildContainers() { - List sinks = new ArrayList<>(); - if (types != null) { - sinks.addAll(types); - } - if (checks != null) { - sinks.addAll(checks); - } - if (casts != null) { - sinks.addAll(casts); - } - if (implicitCasts != null) { - sinks.addAll(implicitCasts); - } - return sinks; - } - - public boolean isGeneric(TypeMirror type) { - return Utils.typeEquals(getGenericType(), type); - } - - public TypeData getVoidType() { - return voidType; - } - - public List getBoxedTypeMirrors() { - return boxedTypeMirrors; - } - - public List getPrimitiveTypeMirrors() { - return primitiveTypeMirrors; - } - - public List getTypes() { - return types; - } - - public TypeMirror getGenericType() { - return genericType; - } - - public TypeData getGenericTypeData() { - TypeData result = types.get(types.size() - 1); - assert result.getBoxedType() == genericType; - return result; - } - - public TypeData findType(String simpleName) { - for (TypeData type : types) { - if (Utils.getSimpleName(type.getBoxedType()).equals(simpleName)) { - return type; - } - } - 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.get(index); - } - - public int findType(TypeData typeData) { - return findType(typeData.getPrimitiveType()); - } - - public int findType(TypeMirror type) { - for (int i = 0; i < types.size(); i++) { - if (Utils.typeEquals(types.get(i).getPrimitiveType(), type)) { - return i; - } - } - return -1; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + types + "]"; - } - - public Set lookupCastSourceTypes() { - if (getImplicitCasts() == null) { - return null; - } - - Set sourceTypes = new TreeSet<>(); - for (ImplicitCastData cast : getImplicitCasts()) { - sourceTypes.add(cast.getSourceType()); - } - return sourceTypes; - } - - public List lookupByTargetType(TypeData targetType) { - if (getImplicitCasts() == null) { - return Collections.emptyList(); - } - List foundCasts = new ArrayList<>(); - for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getTargetType().equals(targetType)) { - foundCasts.add(cast); - } - } - return foundCasts; - } - - public ImplicitCastData lookupCast(TypeData sourceType, TypeData targetType) { - if (getImplicitCasts() == null) { - return null; - } - for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getSourceType().equals(sourceType) && cast.getTargetType().equals(targetType)) { - return cast; - } - } - return null; - } - - public List lookupSourceTypes(TypeData type) { - List sourceTypes = new ArrayList<>(); - sourceTypes.add(type); - if (getImplicitCasts() != null) { - for (ImplicitCastData cast : getImplicitCasts()) { - if (cast.getTargetType() == type) { - sourceTypes.add(cast.getSourceType()); - } - } - } - Collections.sort(sourceTypes); - return sourceTypes; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemMethodParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /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.dsl.processor.typesystem; - -import javax.lang.model.element.*; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -abstract class TypeSystemMethodParser extends TemplateMethodParser { - - public TypeSystemMethodParser(ProcessorContext context, TypeSystemData typeSystem) { - super(context, typeSystem); - } - - @Override - public final boolean isParsable(ExecutableElement method) { - return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; - } - - protected TypeData findTypeByMethodName(String methodName, String prefix) { - String typeName = methodName.substring(prefix.length(), methodName.length()); - TypeData type = getTypeSystem().findType(typeName); - return type; - } - - protected TypeData findTypeByMethodName(TemplateMethod method, String prefix) { - String methodName = method.getMethodName(); - if (!methodName.startsWith(prefix)) { - String annotationName = Utils.getSimpleName(method.getMessageAnnotation().getAnnotationType()); - method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix)); - return null; - } - String typeName = methodName.substring(prefix.length(), methodName.length()); - TypeData type = getTypeSystem().findType(typeName); - if (type == null) { - String annotationName = TypeSystem.class.getSimpleName(); - method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName); - return null; - } - - return type; - } - -} diff -r c5f8eeb3cbc8 -r 23415229349b graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java Mon Aug 11 15:53:05 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,305 +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.dsl.processor.typesystem; - -import static com.oracle.truffle.dsl.processor.Utils.*; - -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.dsl.*; -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.template.*; - -public class TypeSystemParser extends AbstractParser { - - public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); - - @Override - public Class getAnnotationType() { - return TypeSystem.class; - } - - @Override - protected TypeSystemData parse(Element element, AnnotationMirror mirror) { - TypeElement templateType = (TypeElement) element; - AnnotationMirror templateTypeAnnotation = mirror; - TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation); - - // annotation type on class path!? - TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName()); - if (annotationTypeElement == null) { - typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName()); - } - if (templateType.getModifiers().contains(Modifier.PRIVATE)) { - typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName()); - } - - if (templateType.getModifiers().contains(Modifier.FINAL)) { - typeSystem.addError("The @%s must not be final.", getAnnotationType().getName()); - } - if (typeSystem.hasErrors()) { - return typeSystem; - } - - typeSystem.setTypes(parseTypes(typeSystem)); - if (typeSystem.hasErrors()) { - return typeSystem; - } - - TypeMirror genericType = context.getType(Object.class); - TypeData voidType = new TypeData(typeSystem, typeSystem.getTypes().size(), null, context.getType(void.class), context.getType(Void.class)); - - typeSystem.setGenericType(genericType); - typeSystem.setVoidType(voidType); - - verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class); - - List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType)); - List implicitCasts = new ImplicitCastParser(context, typeSystem).parse(elements); - List casts = new TypeCastParser(context, typeSystem).parse(elements); - List checks = new TypeCheckParser(context, typeSystem).parse(elements); - - if (casts == null || checks == null || implicitCasts == null) { - return typeSystem; - } - - typeSystem.setImplicitCasts(implicitCasts); - typeSystem.setCasts(casts); - typeSystem.setChecks(checks); - - if (typeSystem.hasErrors()) { - return typeSystem; - } - - for (TypeCheckData check : checks) { - check.getCheckedType().addTypeCheck(check); - } - - for (TypeCastData cast : casts) { - cast.getTargetType().addTypeCast(cast); - } - - verifyGenericTypeChecksAndCasts(typeSystem); - verifyMethodSignatures(typeSystem); - verifyNamesUnique(typeSystem); - - return typeSystem; - } - - protected void verifyExclusiveMethodAnnotation(Template template, Class... annotationTypes) { - List methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements()); - for (ExecutableElement method : methods) { - List foundAnnotations = new ArrayList<>(); - for (int i = 0; i < annotationTypes.length; i++) { - Class annotationType = annotationTypes[i]; - AnnotationMirror mirror = Utils.findAnnotationMirror(context.getEnvironment(), method, annotationType); - if (mirror != null) { - foundAnnotations.add(mirror); - } - } - if (foundAnnotations.size() > 1) { - List annotationNames = new ArrayList<>(); - for (AnnotationMirror mirror : foundAnnotations) { - annotationNames.add("@" + Utils.getSimpleName(mirror.getAnnotationType())); - } - - template.addError("Non exclusive usage of annotations %s.", annotationNames); - } - } - } - - private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) { - for (TypeData type : typeSystem.getTypes()) { - if (!type.getTypeChecks().isEmpty()) { - boolean hasGeneric = false; - for (TypeCheckData typeCheck : type.getTypeChecks()) { - if (typeCheck.isGeneric()) { - hasGeneric = true; - break; - } - } - if (!hasGeneric) { - type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", - TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), - Object.class.getSimpleName()); - } - } - if (!type.getTypeCasts().isEmpty()) { - boolean hasGeneric = false; - for (TypeCastData typeCast : type.getTypeCasts()) { - if (typeCast.isGeneric()) { - hasGeneric = true; - break; - } - } - if (!hasGeneric) { - type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.", - TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), - Object.class.getSimpleName()); - } - } - } - } - - private List parseTypes(TypeSystemData typeSystem) { - List types = new ArrayList<>(); - List typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value"); - if (typeMirrors.isEmpty()) { - typeSystem.addError("At least one type must be defined."); - return types; - } - - final AnnotationValue annotationValue = Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value"); - final TypeMirror objectType = context.getType(Object.class); - - int index = 0; - for (TypeMirror primitiveType : typeMirrors) { - TypeMirror boxedType = Utils.boxType(context, primitiveType); - TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitiveType, boxedType); - - if (isPrimitiveWrapper(primitiveType)) { - typeData.addError("Types must not contain primitive wrapper types."); - } - - if (Utils.typeEquals(boxedType, objectType)) { - typeData.addError("Types must not contain the generic type java.lang.Object."); - } - - types.add(typeData); - index++; - } - - verifyTypeOrder(types); - - types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType)); - - return types; - } - - private static void verifyTypeOrder(List types) { - Map> invalidTypes = new HashMap<>(); - - for (int i = types.size() - 1; i >= 0; i--) { - TypeData typeData = types.get(i); - TypeMirror type = typeData.getBoxedType(); - if (invalidTypes.containsKey(Utils.getQualifiedName(type))) { - typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type)); - } - List nextInvalidTypes = Utils.getQualifiedSuperTypeNames(Utils.fromTypeMirror(type)); - nextInvalidTypes.add(getQualifiedName(type)); - - for (String qualifiedName : nextInvalidTypes) { - List inheritedTypes = invalidTypes.get(qualifiedName); - if (inheritedTypes == null) { - inheritedTypes = new ArrayList<>(); - invalidTypes.put(qualifiedName, inheritedTypes); - } - inheritedTypes.add(Utils.getQualifiedName(typeData.getBoxedType())); - } - } - } - - private boolean isPrimitiveWrapper(TypeMirror type) { - Types types = context.getEnvironment().getTypeUtils(); - for (TypeKind kind : TypeKind.values()) { - if (!kind.isPrimitive()) { - continue; - } - if (Utils.typeEquals(type, types.boxedClass(types.getPrimitiveType(kind)).asType())) { - return true; - } - } - return false; - } - - private void verifyMethodSignatures(TypeSystemData typeSystem) { - Set generatedIsMethodNames = new HashSet<>(); - Set generatedAsMethodNames = new HashSet<>(); - Set generatedExpectMethodNames = new HashSet<>(); - - for (TypeData typeData : typeSystem.getTypes()) { - generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData)); - generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData)); - generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData)); - } - - List methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements()); - for (ExecutableElement method : methods) { - if (method.getModifiers().contains(Modifier.PRIVATE)) { - // will not conflict overridden methods - continue; - } else if (method.getParameters().size() != 1) { - continue; - } - String methodName = method.getSimpleName().toString(); - if (generatedIsMethodNames.contains(methodName)) { - verifyIsMethod(typeSystem, method); - } else if (generatedAsMethodNames.contains(methodName)) { - verifyAsMethod(typeSystem, method); - } else if (generatedExpectMethodNames.contains(methodName)) { - verifyExpectMethod(typeSystem); - } - } - } - - private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCheck.class); - if (mirror == null) { - typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName()); - return false; - } - return true; - } - - private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) { - AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCast.class); - if (mirror == null) { - typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName()); - return false; - } - return true; - } - - private static boolean verifyExpectMethod(TypeSystemData typeSystem) { - typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually."); - return false; - } - - private static void verifyNamesUnique(TypeSystemData typeSystem) { - List types = typeSystem.getTypes(); - for (int i = 0; i < types.size(); i++) { - for (int j = i + 1; j < types.size(); j++) { - String name1 = Utils.getSimpleName(types.get(i).getBoxedType()); - String name2 = Utils.getSimpleName(types.get(j).getBoxedType()); - if (name1.equalsIgnoreCase(name2)) { - typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2); - } - } - } - } -}