# HG changeset patch # User Thomas Wuerthinger # Date 1361876100 -3600 # Node ID 3828c61190731becc449e77166be62aba0b767e8 # Parent 45bce3579308d0b5230722042fbf0cf7c2e0285e# Parent dbbdc0a30a163ac0829e5d4a283bb278099543ce Merge. diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Tue Feb 26 11:55:00 2013 +0100 @@ -758,7 +758,7 @@ if (blockChanged) { block.localsLiveIn.clear(); block.localsLiveIn.or(block.localsLiveOut); - block.localsLiveIn.xor(block.localsLiveKill); + block.localsLiveIn.andNot(block.localsLiveKill); block.localsLiveIn.or(block.localsLiveGen); Debug.log(" end B%d [%d, %d] in: %s out: %s gen: %s kill: %s", block.blockID, block.startBci, block.endBci, block.localsLiveIn, block.localsLiveOut, block.localsLiveGen, block.localsLiveKill); diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java Tue Feb 26 11:55:00 2013 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.api.codegen; + +import java.util.*; + +/** + * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate + * generated node classes without using reflection. + */ +public interface NodeFactory { + + /** + * Instantiates the node using the arguments array. The arguments length and types must suffice + * one of the returned signatures in {@link #getNodeSignatures()}. If the arguments array does + * not suffice one of the node signatures an {@link IllegalArgumentException} is thrown. + * + * @param arguments the argument values + * @return the instantiated node + * @throws IllegalArgumentException + */ + T createNode(Object... arguments); + + /** + * Instantiates a new specialized variant of the node. This is an optional method and throws an + * {@link UnsupportedOperationException} if not supported. + * + * @param thisNode the current node + * @param specializionClasses + * @return the specialized node + */ + T createNodeSpecialized(T thisNode, Class... specializionClasses); + + /** + * Returns the node class that will get created by {@link #createNode(Object...)}. The node + * class does not match exactly to the instantiated object but they are guaranteed to be + * assignable. + */ + Class getNodeClass(); + + /** + * Returns a list of signatures that can be used to invoke {@link #createNode(Object...)}. + */ + List>> getNodeSignatures(); + +} diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java Tue Feb 26 11:55:00 2013 +0100 @@ -28,6 +28,7 @@ import javax.lang.model.type.*; import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.intrinsics.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.nodes.Node.Child; import com.oracle.truffle.api.nodes.Node.Children; @@ -44,6 +45,7 @@ private final TypeMirror stableAnnotation; private final TypeMirror contentStableAnnotation; private final TypeMirror typeConversion; + private final TypeMirror truffleIntrinsics; private final List errors = new ArrayList<>(); @@ -55,6 +57,7 @@ stableAnnotation = getRequired(context, Child.class); contentStableAnnotation = getRequired(context, Children.class); typeConversion = getRequired(context, TypeConversion.class); + truffleIntrinsics = getRequired(context, TruffleIntrinsics.class); } public boolean verify(ProcessorContext context, Element element, AnnotationMirror mirror) { @@ -77,6 +80,10 @@ return type; } + public TypeMirror getTruffleIntrinsics() { + return truffleIntrinsics; + } + public TypeMirror getTypeConversion() { return typeConversion; } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Tue Feb 26 11:55:00 2013 +0100 @@ -47,6 +47,14 @@ } } + 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 collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element, Class annotationClass) { List result = Utils.getAnnotationValueList(markerAnnotation, elementName); @@ -61,6 +69,42 @@ 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; + } + + public 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(); @@ -146,31 +190,43 @@ case LONG: return "long"; case DECLARED: - return getGenericName(fromTypeMirror(mirror)); + return getDeclaredName((DeclaredType) mirror); case ARRAY: return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]"; case VOID: return "void"; + case WILDCARD: + return getWildcardName((WildcardType) mirror); case TYPEVAR: - return ((TypeParameterElement) ((TypeVariable) mirror).asElement()).getSimpleName().toString(); + return "?"; default: throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); } } - private static String getGenericName(TypeElement element) { - String simpleName = element.getSimpleName().toString(); + 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(); + } - if (element.getTypeParameters().size() == 0) { + private static String getDeclaredName(DeclaredType element) { + String simpleName = element.asElement().getSimpleName().toString(); + + if (element.getTypeArguments().size() == 0) { return simpleName; } StringBuilder b = new StringBuilder(simpleName); b.append("<"); - if (element.getTypeParameters().size() > 0) { - for (int i = 0; i < element.getTypeParameters().size(); i++) { - b.append("?"); - if (i < element.getTypeParameters().size() - 1) { + 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(", "); } } @@ -282,6 +338,19 @@ 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 getSuperTypes(TypeElement element) { List types = new ArrayList<>(); List superTypes = null; @@ -468,8 +537,10 @@ for (int i = 0; i < params.length; i++) { TypeMirror param1 = params[i]; TypeMirror param2 = method.getParameters().get(i).asType(); - if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { - continue method; + if (param1.getKind() != TypeKind.TYPEVAR && param2.getKind() != TypeKind.TYPEVAR) { + if (!getQualifiedName(param1).equals(getQualifiedName(param2))) { + continue method; + } } } return method; diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java Tue Feb 26 11:55:00 2013 +0100 @@ -114,7 +114,7 @@ } public CodeTreeBuilder createBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(); + CodeTreeBuilder builder = new CodeTreeBuilder(null); this.bodyTree = builder.getTree(); this.bodyTree.setEnclosingElement(this); this.body = null; diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java Tue Feb 26 11:55:00 2013 +0100 @@ -33,17 +33,25 @@ public class CodeTreeBuilder { + private final CodeTreeBuilder parent; + private BuilderCodeTree currentElement; private final BuilderCodeTree root; - public CodeTreeBuilder() { + private int treeCount; + + public CodeTreeBuilder(CodeTreeBuilder parent) { this.root = new BuilderCodeTree(GROUP, null, null); this.currentElement = root; + this.parent = parent; } - public CodeTreeBuilder(CodeTree tree) { - this.root = (BuilderCodeTree) tree; - this.currentElement = root; + public int getTreeCount() { + return treeCount; + } + + public boolean isEmpty() { + return treeCount == 0; } public CodeTreeBuilder statement(String statement) { @@ -55,11 +63,11 @@ } public static CodeTreeBuilder createBuilder() { - return new CodeTreeBuilder(); + return new CodeTreeBuilder(null); } public static CodeTree singleString(String s) { - return new CodeTreeBuilder().string(s).getTree(); + return new CodeTreeBuilder(null).string(s).getTree(); } private CodeTreeBuilder push(CodeTreeKind kind) { @@ -89,11 +97,14 @@ currentElement = tree; break; } + treeCount++; return this; } private void clearLast(CodeTreeKind kind) { - clearLastRec(kind, currentElement.getEnclosedElements()); + if (clearLastRec(kind, currentElement.getEnclosedElements())) { + treeCount--; + } } public CodeTreeBuilder startStatement() { @@ -193,6 +204,24 @@ 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(); @@ -211,6 +240,10 @@ return this; } + public CodeTreeBuilder doubleQuote(String s) { + return startGroup().string("\"").string(s).string("\"").end(); + } + public CodeTreeBuilder startDoubleQuote() { startGroup().string("\""); registerCallBack(new EndCallback() { @@ -271,6 +304,15 @@ return startGroup().string("if ").startParanthesesCommaGroup().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(); @@ -346,6 +388,19 @@ 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(); } @@ -358,6 +413,13 @@ 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(); @@ -372,9 +434,9 @@ } private void toParent() { - Element parent = currentElement.getEnclosingElement(); + Element parentElement = currentElement.getEnclosingElement(); if (currentElement != root) { - this.currentElement = (BuilderCodeTree) parent; + this.currentElement = (BuilderCodeTree) parentElement; } else { this.currentElement = root; } @@ -433,7 +495,7 @@ } public CodeTreeBuilder create() { - return new CodeTreeBuilder(); + return new CodeTreeBuilder(null); } public CodeTreeBuilder type(TypeMirror type) { @@ -496,7 +558,11 @@ while (element != null && (element.getKind() != ElementKind.METHOD)) { element = element.getEnclosingElement(); } - return element != null ? (ExecutableElement) element : null; + ExecutableElement found = element != null ? (ExecutableElement) element : null; + if (found == null && parent != null) { + found = parent.findMethod(); + } + return found; } public CodeTreeBuilder returnTrue() { diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeVariableElement.java Tue Feb 26 11:55:00 2013 +0100 @@ -58,7 +58,7 @@ } public CodeTreeBuilder createInitBuilder() { - CodeTreeBuilder builder = new CodeTreeBuilder(); + CodeTreeBuilder builder = new CodeTreeBuilder(null); init = builder.getTree(); init.setEnclosingElement(this); return builder; diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java Tue Feb 26 11:55:00 2013 +0100 @@ -36,9 +36,16 @@ public abstract class AbstractCodeWriter extends CodeElementScanner { + private static final int 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; @@ -56,8 +63,7 @@ Writer w = null; try { imports = OrganizedImports.organize(e); - - w = createWriter(e); + w = new TrimTrailingSpaceWriter(createWriter(e)); writer = w; writeRootClass(e); } catch (IOException ex) { @@ -145,7 +151,7 @@ write(" {").writeLn(); writeEmptyLn(); - indent(); + indent(1); List staticFields = getStaticFields(e); List instanceFields = getInstanceFields(e); @@ -191,7 +197,7 @@ clazz.accept(this, null); } - dedent(); + dedent(1); write("}"); writeEmptyLn(); } @@ -262,6 +268,14 @@ } else { writeModifiers(f.getModifiers()); write(typeSimpleName(f.asType())); + + if (f.getEnclosingElement().getKind() == ElementKind.METHOD) { + ExecutableElement method = (ExecutableElement) f.getEnclosingElement(); + if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) { + write("..."); + } + } + write(" "); write(f.getSimpleName()); if (init != null) { @@ -474,9 +488,9 @@ writeLn(";"); } else if (e.getBodyTree() != null) { writeLn(" {"); - indent(); + indent(1); e.getBodyTree().acceptCodeElementScanner(this, p); - dedent(); + dedent(1); writeLn("}"); } else if (e.getBody() != null) { write(" {"); @@ -509,11 +523,11 @@ } break; case INDENT: - indent(); + indent(1); for (CodeTree tree : e.getEnclosedElements()) { tree.acceptCodeElementScanner(this, p); } - dedent(); + dedent(1); break; case NEW_LINE: writeLn(); @@ -565,25 +579,28 @@ } } - private static final String LN = "\n"; - - protected void indent() { - indent++; + protected void indent(int count) { + indent += count; } - protected void dedent() { - indent--; + protected void dedent(int count) { + indent -= count; } protected void writeLn() { - write(LN); - newLine = true; + 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() { @@ -596,10 +613,23 @@ private AbstractCodeWriter write(String m) { try { + lineLength += m.length(); if (newLine && m != LN) { writeIndent(); newLine = false; } + if (lineLength > LINE_LENGTH && m.length() > 0) { + char firstChar = m.charAt(0); + if (Character.isAlphabetic(firstChar)) { + if (!lineWrapping) { + indent(LINE_WRAP_INDENTS); + } + lineWrapping = true; + lineLength = 0; + write(LN); + writeIndent(); + } + } writer.write(m); } catch (IOException e) { throw new RuntimeException(e); @@ -609,7 +639,57 @@ private void writeIndent() throws IOException { for (int i = 0; i < indent; i++) { - writer.write(" "); + lineLength += IDENT_STRING.length(); + writer.write(IDENT_STRING); } } + + 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 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java Tue Feb 26 11:55:00 2013 +0100 @@ -63,19 +63,71 @@ } public String useImport(TypeMirror type) { - String simpleName = getSimpleName(type); - TypeMirror usedByType = simpleNamesUsed.get(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((DeclaredType) type); + case ARRAY: + return useImport(((ArrayType) type).getComponentType()) + "[]"; + case WILDCARD: + return createWildcardName((WildcardType) type); + case TYPEVAR: + return "?"; + default: + throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type); + } + } + + private String createWildcardName(WildcardType type) { + StringBuilder b = new StringBuilder(); + if (type.getExtendsBound() != null) { + b.append("? extends ").append(useImport(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("? super ").append(useImport(type.getExtendsBound())); + } + return b.toString(); + } + + private String createDeclaredTypeName(DeclaredType type) { + String name = type.asElement().getSimpleName().toString(); + + TypeMirror usedByType = simpleNamesUsed.get(name); if (usedByType == null) { - simpleNamesUsed.put(simpleName, type); + simpleNamesUsed.put(name, type); usedByType = type; - } else if (!typeEquals(type, usedByType)) { - // we need a qualified name - return getQualifiedName(type); } - // we can use the simple name - addUsage(type, importUsage); - return simpleName; + if (typeEquals(type, usedByType)) { + addUsage(type, importUsage); + } else { + 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(useImport(type.getTypeArguments().get(i))); + if (i < type.getTypeArguments().size() - 1) { + b.append(", "); + } + } + } + b.append(">"); + return b.toString(); } public String useStaticFieldImport(TypeMirror type, String fieldName) { diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Tue Feb 26 11:55:00 2013 +0100 @@ -31,6 +31,7 @@ import javax.lang.model.type.*; import javax.lang.model.util.*; +import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.ast.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; @@ -69,7 +70,8 @@ private static String specializationId(SpecializationData specialization) { String name = ""; - if (specialization.getNode().getSpecializations().length > 1) { + NodeData node = specialization.getNode(); + if (node.getSpecializations().length > 1) { name = specialization.getMethodName(); if (name.startsWith("do")) { name = name.substring(2); @@ -82,8 +84,8 @@ return field.getName() + "Value"; } - private static String valueName(TemplateMethod method, ActualParameter param) { - NodeData node = (NodeData) method.getTemplate(); + private static String valueName(ActualParameter param) { + NodeData node = (NodeData) param.getMethod().getTemplate(); NodeFieldData field = node.findField(param.getSpecification().getName()); if (field != null) { return valueName(field); @@ -92,6 +94,14 @@ } } + private static String castValueName(ActualParameter parameter) { + return valueName(parameter) + "Cast"; + } + + private static String castValueName(NodeFieldData field) { + return valueName(field) + "Cast"; + } + private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { if (forceFrame) { method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame")); @@ -101,7 +111,7 @@ if (forceFrame && spec.getName().equals("frame")) { continue; } - method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter))); + method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter))); } } @@ -118,21 +128,28 @@ if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) { builder.string("ex.getResult()"); } else { - builder.string(valueName(specialization, parameter)); + builder.string(valueName(parameter)); } } } - private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization) { - for (ActualParameter param : specialization.getParameters()) { - TypeData typeData = param.getActualTypeData(specialization.getNode().getTypeSystem()); - if (typeData == null || typeData.isGeneric()) { - body.string(valueName(specialization, param)); + private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) { + NodeData node = targetSpecialization.getNode(); + TypeSystemData typeSystem = node.getTypeSystem(); + + for (ActualParameter targetParameter : targetSpecialization.getParameters()) { + ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getSpecification().getName()); + TypeData targetType = targetParameter.getActualTypeData(typeSystem); + + TypeData valueType = null; + if (valueParameter != null) { + valueType = valueParameter.getActualTypeData(typeSystem); + } + + if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) { + body.string(valueName(targetParameter)); } else { - String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); - startCallTypeSystemMethod(context, body, specialization.getNode(), methodName); - body.string(valueName(specialization, param)); - body.end().end(); + body.string(castValueName(targetParameter)); } } } @@ -173,6 +190,14 @@ return prefix; } + private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + startCallTypeSystemMethod(context, builder, node, methodName); + builder.string(value); + builder.end().end(); + return builder.getRoot(); + } + private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); assert singleton != null; @@ -182,44 +207,205 @@ body.string(".").startCall(methodName); } - private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { - TypeSystemData typeSystem = specialization.getNode().getTypeSystem(); - // Implict guards based on method signature - String andOperator = prefix; - if (needsCast) { - for (NodeFieldData field : specialization.getNode().getFields()) { - ActualParameter param = specialization.findParameter(field.getName()); - TypeData type = param.getActualTypeData(typeSystem); - if (type == null || type.isGeneric()) { - continue; - } + private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization, + CodeTree guardedStatements, CodeTree elseStatements) { + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, valueSpecialization, guardedSpecialization); + CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, valueSpecialization, guardedSpecialization, onSpecialization); + + int ifCount = 0; - body.string(andOperator); - startCallTypeSystemMethod(context, body, specialization.getNode(), TypeSystemCodeGenerator.isTypeMethodName(type)); - body.string(valueName(specialization, param)); - body.end().end(); // call - andOperator = " && "; - } + if (implicitGuards != null) { + builder.startIf(); + builder.tree(implicitGuards); + builder.end(); + builder.startBlock(); + ifCount++; + } + + if (explicitGuards != null || !onSpecialization) { + builder.tree(createCasts(parent, valueSpecialization, guardedSpecialization)); + } + + if (explicitGuards != null) { + builder.startIf(); + builder.tree(explicitGuards); + builder.end(); + builder.startBlock(); + ifCount++; } - if (specialization.getGuards().length > 0) { - // Explicitly specified guards - for (SpecializationGuardData guard : specialization.getGuards()) { - if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { - body.string(andOperator); + if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) { + builder.startIf().string(conditionPrefix).end().startBlock(); + ifCount++; + } + + builder.tree(guardedStatements); + + builder.end(ifCount); + if (ifCount > 0 && elseStatements != null) { + builder.startElseBlock(); + builder.tree(elseStatements); + builder.end(); + } - startCallOperationMethod(body, guard.getGuardDeclaration()); + return builder.getRoot(); + } - if (needsCast) { - addValueParameterNamesWithCasts(context, body, specialization); - } else { - addValueParameterNames(body, specialization, null, false); - } - body.end().end(); // call + private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, + boolean onSpecialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + if (guardedSpecialization.getGuards().length > 0) { + // Explicitly specified guards + for (SpecializationGuardData guard : guardedSpecialization.getGuards()) { + if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { + builder.string(andOperator); + + startCallOperationMethod(builder, guard.getGuardDeclaration()); + addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization); + + builder.end().end(); // call andOperator = " && "; } } } + + return builder.isEmpty() ? null : builder.getRoot(); + } + + private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + NodeData node = guardedSpecialization.getNode(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + // Implict guards based on method signature + for (NodeFieldData field : node.getFields()) { + ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); + ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); + + CodeTree cast = createCast(parent, field, valueParam, guardedParam); + if (cast == null) { + continue; + } + builder.tree(cast); + } + + return builder.getRoot(); + } + + private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { + NodeData node = guardedSpecialization.getNode(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + // Implict guards based on method signature + String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; + for (NodeFieldData field : node.getFields()) { + ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName()); + ActualParameter valueParam = valueSpecialization.findParameter(field.getName()); + + CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); + if (implicitGuard == null) { + continue; + } + + builder.string(andOperator); + builder.tree(implicitGuard); + andOperator = " && "; + } + + return builder.isEmpty() ? null : builder.getRoot(); + } + + private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { + NodeData node = field.getNodeData(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + + TypeData targetType = target.getActualTypeData(node.getTypeSystem()); + TypeData sourceType = source.getActualTypeData(node.getTypeSystem()); + + if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + return null; + } + + builder.startGroup(); + + if (field.isShortCircuit()) { + ActualParameter shortCircuit = target.getPreviousParameter(); + assert shortCircuit != null; + builder.string("("); + builder.string("!").string(valueName(shortCircuit)); + builder.string(" || "); + } + + startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem()))); + builder.string(valueName(field)); + builder.end().end(); // call + + if (field.isShortCircuit()) { + builder.string(")"); + } + + builder.end(); // group + + return builder.getRoot(); + } + + private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { + NodeData node = field.getNodeData(); + TypeSystemData typeSystem = node.getTypeSystem(); + + TypeData sourceType = source.getActualTypeData(typeSystem); + TypeData targetType = target.getActualTypeData(typeSystem); + + if (targetType.equalsType(sourceType) || targetType.isGeneric()) { + return null; + } + + CodeTree condition = null; + if (field.isShortCircuit()) { + ActualParameter shortCircuit = target.getPreviousParameter(); + assert shortCircuit != null; + condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); + } + + CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target)); + + return createLazyAssignment(parent, castValueName(field), target.getActualType(), condition, value); + } + + /** + *
+     * 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(); } @Override @@ -237,11 +423,7 @@ add(factory, node); } - if (node.getSpecializations() == null) { - return; - } - - if (node.needsFactory() || childTypes.size() > 0) { + if (node.needsFactory() || node.getNodeChildren().size() > 0) { add(new NodeFactoryFactory(context, childTypes), node); } } @@ -326,6 +508,15 @@ for (SpecializationData specialization : node.getSpecializations()) { add(new SpecializedNodeFactory(context), specialization); } + + TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); + clazz.getImplements().add(nodeFactory); + clazz.add(createCreateNodeMethod(node)); + clazz.add(createCreateNodeSpecializedMethod(node)); + clazz.add(createGetNodeClassMethod(node)); + clazz.add(createGetNodeSignaturesMethod(node)); + clazz.add(createGetInstanceMethod(node, createVisibility)); + clazz.add(createInstanceConstant(node, clazz.asType())); } for (NodeData childNode : childTypes.keySet()) { @@ -346,9 +537,236 @@ clazz.add(type); } } + + List children = node.getNodeChildren(); + if (node.getParent() == null && children.size() > 0) { + clazz.add(createGetFactories(node)); + } + + } + + private CodeExecutableElement createGetNodeClassMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().typeLiteral(node.getNodeType()).end(); + return method; + } + + private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); + TypeMirror classType = getContext().getType(Class.class); + TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType)); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures"); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn(); + builder.startStaticCall(getContext().getType(Arrays.class), "asList"); + List constructors = findUserConstructors(node); + for (ExecutableElement constructor : constructors) { + builder.startGroup(); + builder.type(getContext().getType(Arrays.class)); + builder.string(".<").type(getContext().getType(Class.class)).string(">"); + builder.startCall("asList"); + for (VariableElement param : constructor.getParameters()) { + builder.typeLiteral(param.asType()); + } + builder.end(); + builder.end(); + } + builder.end(); + builder.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(node); + 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()) { + 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(); + 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 CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) { + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized"); + CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), "thisNode"); + CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); + method.addParameter(nodeParam); + method.addParameter(arguments); + method.setVarArgs(true); + + CodeTreeBuilder builder = method.createBuilder(); + if (!node.needsRewrites(getContext())) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + } else { + builder.startIf(); + builder.string("types.length == 1"); + builder.end(); + builder.startBlock(); + + builder.startReturn().startCall("createSpecialized"); + builder.string("thisNode"); + builder.string("types[0]"); + builder.end().end(); + + builder.end(); + builder.startElseBlock(); + builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); + builder.doubleQuote("Invalid createSpecialized signature."); + builder.end().end(); + builder.end(); + } + + return method; + } + + private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { + Types types = getContext().getEnvironment().getTypeUtils(); + TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); + TypeMirror returnType = types.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.getParent() != 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.getNodeChildren(); + if (node.needsFactory()) { + children.add(node); + } + + List nodeTypesList = new ArrayList<>(); + for (NodeData child : children) { + nodeTypesList.add(child.getTemplateType().asType()); + } + TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); + + Types types = getContext().getEnvironment().getTypeUtils(); + TypeMirror factoryType = getContext().getType(NodeFactory.class); + TypeMirror baseType; + if (children.size() == 1) { + baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); + } else { + baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); + } + TypeMirror listType = types.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.getParent() != null) { + factories.add(childNode); + childNode = childNode.getParent(); + } + 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(node); + for (ExecutableElement constructor : constructors) { + clazz.add(createCreateMethod(node, createVisibility, constructor)); + } + } + + private List findUserConstructors(NodeData node) { + List constructors = new ArrayList<>(); for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) { if (constructor.getModifiers().contains(PRIVATE)) { continue; @@ -358,9 +776,9 @@ if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) { continue; } - - clazz.add(createCreateMethod(node, createVisibility, constructor)); + constructors.add(constructor); } + return constructors; } private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { @@ -436,17 +854,12 @@ SpecializationData specialization = node.getSpecializations()[i]; body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); - if (specialization.isGeneric()) { - body.startIf().string("allowed").end().startBlock(); - } else { - body.startIf().string("allowed"); - emitGuards(getContext(), body, " && ", specialization, true, true); - body.end().startBlock(); - } - body.startReturn().startNew(nodeClassName(specialization)); - body.string(THIS_NODE_LOCAL_VAR_NAME); - body.end().end(); - body.end(); // block + CodeTreeBuilder guarded = new CodeTreeBuilder(body); + guarded.startReturn().startNew(nodeClassName(specialization)); + guarded.string(THIS_NODE_LOCAL_VAR_NAME); + guarded.end().end(); + + body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, true, guarded.getRoot(), null)); } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); @@ -490,24 +903,23 @@ } private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) { + CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder); + emitInvokeDoMethod(invokeMethodBuilder, current, 0); + CodeTree invokeMethod = invokeMethodBuilder.getRoot(); + if (next != null) { - builder.startIf(); - emitGuards(context, builder, "", current, false, true); - builder.end().startBlock(); + invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, null); } - emitInvokeDoMethod(builder, current, 0); + builder.tree(invokeMethod); if (next != null) { builder.end(); - builder.startElseBlock(); builder.startReturn().startCall(generatedGenericMethodName(next)); builder.string(THIS_NODE_LOCAL_VAR_NAME); addValueParameterNames(builder, next, null, true); builder.end().end(); - - builder.end(); } } @@ -518,7 +930,7 @@ builder.startReturn(); startCallOperationMethod(builder, specialization); - addValueParameterNamesWithCasts(context, builder, specialization); + addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization); builder.end().end(); // start call operation builder.end(); // return @@ -625,14 +1037,14 @@ builder.string("// ignore").newLine(); } else { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); + builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); builder.end(); } builder.end(); if (!returnVoid) { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, CodeTreeBuilder.singleString("value"))); + builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value"))); builder.end(); } } else { @@ -640,81 +1052,92 @@ builder.statement(primaryExecuteCall); } else { builder.startReturn(); - builder.tree(castPrimaryExecute(node, castedType, primaryExecuteCall)); + builder.tree(createExpectType(node, castedType, primaryExecuteCall)); builder.end(); } } } - private CodeTree castPrimaryExecute(NodeData node, ExecutableTypeData castedType, CodeTree value) { - if (castedType.getType().isVoid()) { + private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) { + if (castedType == null) { return value; - } - if (castedType.getType().isGeneric()) { + } else if (castedType.getType().isVoid()) { + return value; + } else if (castedType.getType().isGeneric()) { return value; } CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String targetMethodName; if (castedType.hasUnexpectedValue(getContext())) { - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType())); + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()); } else { - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.asTypeMethodName(castedType.getType())); + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()); } + startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); + builder.tree(value); builder.end().end(); return builder.getRoot(); } private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { - NodeData node = specialization.getNode(); - TypeSystemData typeSystem = node.getTypeSystem(); - - for (NodeFieldData field : node.getFields()) { - if (field.getExecutionKind() == ExecutionKind.IGNORE) { - continue; - } + if (specialization.isUninitialized()) { + builder.tree(createDeoptimize(builder)); + } - ActualParameter parameterType = specialization.findParameter(field.getName()); + builder.tree(createExecuteChildren(builder, specialization)); - if (parameterType.getActualTypeData(typeSystem).isGeneric()) { - buildGenericValueExecute(builder, specialization, field, null); - } else { - buildSpecializedValueExecute(builder, specialization, field); - } + if (specialization.isUninitialized()) { + builder.tree(createSpecializeCall(builder, specialization)); } - if (specialization.hasDynamicGuards()) { - builder.startIf(); - emitGuards(getContext(), builder, "", specialization, false, false); - builder.end().startBlock(); + CodeTree executeNode = createExecute(builder, specialization); + + SpecializationData next = specialization.findNextSpecialization(); + CodeTree returnSpecialized = null; + if (next != null) { + returnSpecialized = createReturnSpecializeAndExecute(builder, next, null); } + builder.tree(createGuardAndCast(builder, null, specialization, specialization, false, executeNode, returnSpecialized)); + } + + private CodeTree createDeoptimize(CodeTreeBuilder parent) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startStatement(); + builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); + builder.end(); + return builder.getRoot(); + } + + private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { + NodeData node = specialization.getNode(); + + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + emitSpecializationListeners(builder, node); + + builder.startStatement(); + builder.startCall("replace"); + if (node.needsRewrites(getContext())) { + builder.startCall(factoryClassName(node), "specialize"); + builder.string("this"); + builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); + addValueParameterNames(builder, specialization, null, false); + builder.end(); // call replace, call specialize + } else { + builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); + } + builder.end().end(); + return builder.getRoot(); + } + + private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) { + NodeData node = specialization.getNode(); + CodeTreeBuilder builder = new CodeTreeBuilder(parent); if (specialization.getExceptions().length > 0) { builder.startTryBlock(); } - if (specialization.isUninitialized()) { - for (TemplateMethod listener : node.getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); - builder.end().end(); - builder.end(); // statement - } - - builder.startStatement(); - builder.startCall("replace"); - if (node.needsRewrites(getContext())) { - builder.startCall(factoryClassName(node), "specialize"); - builder.string("this"); - builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); - addValueParameterNames(builder, specialization, null, false); - builder.end(); // call replace, call specialize - } else { - builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); - } - builder.end().end(); - } - if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); builder.string("this"); @@ -736,14 +1159,38 @@ if (specialization.getExceptions().length > 0) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); - buildThrowSpecialize(builder, specialization, exception.getTransitionTo(), null); + builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null)); } builder.end(); } - if (specialization.hasDynamicGuards()) { - builder.end().startElseBlock(); - buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), null); - builder.end(); + return builder.getRoot(); + } + + private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + for (NodeFieldData field : specialization.getNode().getFields()) { + if (field.getExecutionKind() == ExecutionKind.IGNORE) { + continue; + } + + ActualParameter parameterType = specialization.findParameter(field.getName()); + + if (parameterType.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) { + buildGenericValueExecute(builder, specialization, field, null); + } else { + buildSpecializedValueExecute(builder, specialization, field); + } + } + return builder.getRoot(); + } + + private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { + for (TemplateMethod listener : node.getSpecializationListeners()) { + builder.startStatement(); + startCallOperationMethod(builder, listener); + addValueParameterNames(builder, listener, null, false); + builder.end().end(); + builder.end(); // statement } } @@ -758,7 +1205,7 @@ builder.string(" "); } - builder.string(valueName(specialization, specParameter)); + builder.string(valueName(specParameter)); builder.string(" = "); ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), specParameter.getActualTypeData(node.getTypeSystem())); if (genericExecutableType == null) { @@ -794,7 +1241,7 @@ boolean shortCircuit = startShortCircuit(builder, specialization, field, null); if (!shortCircuit) { - builder.startStatement().type(param.getActualType()).string(" ").string(valueName(specialization, param)).end(); + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); } ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); @@ -820,7 +1267,7 @@ execute = true; } } - buildThrowSpecialize(builder, specialization, specialization.findNextSpecialization(), param.getSpecification()); + builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification())); builder.end(); // catch block } @@ -846,7 +1293,7 @@ } } - builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = "); + builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; startCallOperationMethod(builder, shortCircuitData); @@ -855,7 +1302,7 @@ builder.end(); // statement - builder.declaration(parameter.getActualType(), valueName(specialization, parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); + builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); builder.startIf().string(shortCircuitParam.getSpecification().getName()).end(); builder.startBlock(); @@ -868,50 +1315,38 @@ } } - private void buildThrowSpecialize(CodeTreeBuilder builder, SpecializationData currentSpecialization, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { - boolean canThrowUnexpected = Utils.canThrowType(builder.findMethod().getThrownTypes(), getContext().getTruffleTypes().getUnexpectedValueException()); - - CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder(); - specializeCall.startCall("specialize"); + private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { + CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); + specializeCall.startCall("specializeAndExecute"); specializeCall.string(nodeClassName(nextSpecialization) + ".class"); addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); specializeCall.end().end(); - TypeData expectedType = currentSpecialization.getReturnType().getActualTypeData(currentSpecialization.getNode().getTypeSystem()); - if (canThrowUnexpected) { - builder.startReturn(); - startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType)); - builder.tree(specializeCall.getRoot()); - builder.end().end(); - builder.end(); // return - } else { - builder.startReturn(); - if (!expectedType.isVoid() && !expectedType.isGeneric()) { - startCallTypeSystemMethod(context, builder, currentSpecialization.getNode(), TypeSystemCodeGenerator.asTypeMethodName(expectedType)); - builder.tree(specializeCall.getRoot()); - builder.end().end(); - } else { - builder.tree(specializeCall.getRoot()); - } - builder.end(); - } - + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + builder.startReturn(); + builder.tree(specializeCall.getRoot()); + builder.end(); + return builder.getRoot(); } private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { - CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), specialization.getNode().getTypeSystem().getGenericType(), "specialize"); + NodeData node = specialization.getNode(); + TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); + ExecutableTypeData returnExecutableType = node.findExecutableType(returnType); + boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext()); + + CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); + if (canThrowUnexpected) { + method.addThrownType(getUnexpectedValueException()); + } addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); - for (TemplateMethod listener : specialization.getNode().getSpecializationListeners()) { - builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); - builder.end().end(); // call operation - builder.end(); // statement - } + + builder.tree(createDeoptimize(builder)); + emitSpecializationListeners(builder, specialization.getNode()); builder.startStatement(); builder.startCall("replace"); @@ -922,20 +1357,24 @@ builder.end(); // statement String generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization()); - ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); - CodeTreeBuilder genericBuilder = CodeTreeBuilder.createBuilder(); - genericBuilder.startCall(factoryClassName(specialization.getNode()), generatedMethodName); - genericBuilder.string("this"); - addValueParameterNames(genericBuilder, specialization.getNode().getGenericSpecialization(), null, true); - genericBuilder.end(); // call generated generic + CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); + genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); + genericExecute.string("this"); + addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true); + genericExecute.end(); // call generated generic + + CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot()); if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) { - builder.declaration(generatedGeneric.getReturnType(), "genericResult", genericBuilder.getRoot()); - builder.startReturn().string("null").end(); + builder.statement(genericInvocation); + + if (!Utils.isVoid(builder.findMethod().asType())) { + builder.startReturn().defaultValue(returnType.getPrimitiveType()).end(); + } } else { - builder.startReturn().tree(genericBuilder.getRoot()).end(); + builder.startReturn().tree(genericInvocation).end(); } } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Tue Feb 26 11:55:00 2013 +0100 @@ -71,6 +71,17 @@ return !noSpecialization; } + public List getNodeChildren() { + List children = new ArrayList<>(); + for (NodeData child : getDeclaredChildren()) { + if (child.needsFactory()) { + children.add(child); + } + children.addAll(child.getNodeChildren()); + } + return children; + } + void setDeclaredChildren(List declaredChildren) { this.declaredChildren = declaredChildren; diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Tue Feb 26 11:55:00 2013 +0100 @@ -52,6 +52,10 @@ this.executionKind = executionKind; } + public boolean isShortCircuit() { + return executionKind == ExecutionKind.SHORT_CIRCUIT; + } + public VariableElement getFieldElement() { return fieldElement; } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Tue Feb 26 11:55:00 2013 +0100 @@ -94,6 +94,7 @@ if (rootNode != null) { rootNode.setDeclaredChildren(children); } + return rootNode; } @@ -118,20 +119,24 @@ return null; // not a node } + if (type.getModifiers().contains(Modifier.PRIVATE)) { + return null; // not visible + } + List elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); List typeHierarchy = findSuperClasses(new ArrayList(), type); Collections.reverse(typeHierarchy); AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) { - log.error(originalType, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName()); + log.error(type, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName()); return null; } TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); if (typeSystem == null) { - log.error(originalType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); + log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); return null; } @@ -146,8 +151,7 @@ nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()])); - parsedNodes.put(Utils.getQualifiedName(type), nodeData); // node fields will resolve node - // types, to avoid endless loops + parsedNodes.put(Utils.getQualifiedName(type), nodeData); NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy); if (fields == null) { @@ -179,7 +183,7 @@ } if (specializations.size() > 1 && genericSpecialization == null) { - log.error(originalType, "Need a @%s method.", Generic.class.getSimpleName()); + log.error(type, "Need a @%s method.", Generic.class.getSimpleName()); return null; } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Tue Feb 26 11:55:00 2013 +0100 @@ -124,15 +124,4 @@ return false; } - public ActualParameter getPreviousParam(ActualParameter searchParam) { - ActualParameter prev = null; - for (ActualParameter param : getParameters()) { - if (param == searchParam) { - return prev; - } - prev = param; - } - return prev; - } - } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Tue Feb 26 11:55:00 2013 +0100 @@ -30,16 +30,25 @@ private final ParameterSpec specification; private final TypeMirror actualType; + private TemplateMethod method; public ActualParameter(ParameterSpec specification, TypeMirror actualType) { this.specification = specification; this.actualType = actualType; } + void setMethod(TemplateMethod method) { + this.method = method; + } + public ParameterSpec getSpecification() { return specification; } + public TemplateMethod getMethod() { + return method; + } + public TypeMirror getActualType() { return actualType; } @@ -47,4 +56,8 @@ public TypeData getActualTypeData(TypeSystemData typeSystem) { return typeSystem.findTypeData(actualType); } + + public ActualParameter getPreviousParameter() { + return method.getPreviousParam(this); + } } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Tue Feb 26 11:55:00 2013 +0100 @@ -40,15 +40,16 @@ this.markerAnnotation = markerAnnotation; this.returnType = returnType; this.parameters = parameters; + + if (parameters != null) { + for (ActualParameter param : parameters) { + param.setMethod(this); + } + } } public TemplateMethod(TemplateMethod method) { - this.template = method.template; - this.specification = method.specification; - this.method = method.method; - this.markerAnnotation = method.markerAnnotation; - this.returnType = method.returnType; - this.parameters = method.parameters; + this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); } public Template getTemplate() { @@ -101,4 +102,15 @@ public String toString() { return getClass().getSimpleName() + " [method = " + method + "]"; } + + public ActualParameter getPreviousParam(ActualParameter searchParam) { + ActualParameter prev = null; + for (ActualParameter param : getParameters()) { + if (param == searchParam) { + return prev; + } + prev = param; + } + return prev; + } } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java Tue Feb 26 11:55:00 2013 +0100 @@ -162,10 +162,7 @@ continue; } - TypeMirror boxedType = primitiveType; - if (boxedType.getKind().isPrimitive()) { - boxedType = processingEnv.getTypeUtils().boxedClass((PrimitiveType) boxedType).asType(); - } + TypeMirror boxedType = Utils.boxType(context, primitiveType); if (Utils.typeEquals(boxedType, objectType)) { log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain the generic type java.lang.Object."); diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/TernaryTest.java Tue Feb 26 11:55:00 2013 +0100 @@ -0,0 +1,52 @@ +/* + * 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.sl.test; + +import org.junit.*; + +// @formatter:off +public class TernaryTest extends AbstractTest { + + private static String[] INPUT = new String[] { +"function main { " + +" print #(1 < 2) ? 1 : 2;" + +" print #(2 < 1) ? 100000000000000 : 1; ", +" print #(1 < 2) ? 100000000000000 : 1; ", +" print #(2 < 1) ? \"wrong\" : \"true\";", +" print #(2 < 1) ? \"wrong\" : 1;", +"} ", + }; + + private static String[] OUTPUT = new String[] { + "1", + "1", + "100000000000000", + "true", + "1", + }; + + @Test + public void test() { + executeSL(INPUT, OUTPUT, true); + } +} diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java Tue Feb 26 11:55:00 2013 +0100 @@ -127,4 +127,8 @@ StatementNode write = WriteLocalNodeFactory.create(slot, value); return new ReturnNode(write); } + + public TypedNode createTernary(TypedNode condition, TypedNode thenPart, TypedNode elsePart) { + return TernaryNodeFactory.create(condition, thenPart, elsePart); + } } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Tue Feb 26 11:55:00 2013 +0100 @@ -21,10 +21,9 @@ * questions. */ -// The content of this file is automatically generated. DO NOT EDIT. + // The content of this file is automatically generated. DO NOT EDIT. package com.oracle.truffle.sl.parser; - import java.util.*; import com.oracle.truffle.sl.*; @@ -33,11 +32,11 @@ // Checkstyle: stop // @formatter:off public class Parser { - public static final int _EOF = 0; - public static final int _identifier = 1; - public static final int _stringLiteral = 2; - public static final int _numericLiteral = 3; - public static final int maxT = 25; + public static final int _EOF = 0; + public static final int _identifier = 1; + public static final int _stringLiteral = 2; + public static final int _numericLiteral = 3; + public static final int maxT = 28; static final boolean T = true; static final boolean x = false; @@ -50,7 +49,7 @@ public final Scanner scanner; public final Errors errors; private final NodeFactory factory; - + public Parser(Scanner scanner, NodeFactory factory) { this.scanner = scanner; this.factory = factory; @@ -121,226 +120,255 @@ } } - void SimpleLanguage() { - Function(); - while (la.kind == 4) { - Function(); - } - } - - void Function() { - Expect(4); - factory.startFunction(); - Expect(1); - String name = t.val; - StatementNode body = Block(); - factory.createFunction(body, name); - } - - StatementNode Block() { - StatementNode result; - List statements = new ArrayList<>(); - Expect(5); - while (StartOf(1)) { - StatementNode statement = Statement(); - statements.add(statement); - } - Expect(6); - result = factory.createBlock(statements); - return result; - } - - StatementNode Statement() { - StatementNode result; - result = null; - if (la.kind == 7) { - result = WhileStatement(); - } else if (la.kind == 1) { - result = AssignmentStatement(); - } else if (la.kind == 12) { - result = OutputStatement(); - } else if (la.kind == 13) { - result = ReturnStatement(); - } else SynErr(26); - return result; - } - - StatementNode WhileStatement() { - StatementNode result; - Expect(7); - Expect(8); - ConditionNode condition = Expression(); - Expect(9); - StatementNode body = Block(); - result = factory.createWhile(condition, body); - return result; - } - - StatementNode AssignmentStatement() { - StatementNode result; - Expect(1); - String name = t.val; - Expect(10); - TypedNode rvalue = Expression(); - Expect(11); - result = factory.createAssignment(name, rvalue); - return result; - } - - StatementNode OutputStatement() { - StatementNode result; - List expressions = new ArrayList<>(); - Expect(12); - while (StartOf(2)) { - TypedNode value = Expression(); - expressions.add(value); - } - Expect(11); - result = factory.createPrint(expressions); - return result; - } - - StatementNode ReturnStatement() { - StatementNode result; - Expect(13); - TypedNode value = Expression(); - Expect(11); - result = factory.createReturn(value); - return result; - } - - TypedNode Expression() { - TypedNode result; - result = ValueExpression(); - if (StartOf(3)) { - switch (la.kind) { - case 14: { - Get(); - break; - } - case 15: { - Get(); - break; - } - case 16: { - Get(); - break; - } - case 17: { - Get(); - break; - } - case 18: { - Get(); - break; - } - case 19: { - Get(); - break; - } - } - String op = t.val; - TypedNode right = ValueExpression(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode ValueExpression() { - TypedNode result; - result = Term(); - while (la.kind == 20 || la.kind == 21) { - if (la.kind == 20) { - Get(); - } else { - Get(); - } - String op = t.val; - TypedNode right = Term(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode Term() { - TypedNode result; - result = Factor(); - while (la.kind == 22 || la.kind == 23) { - if (la.kind == 22) { - Get(); - } else { - Get(); - } - String op = t.val; - TypedNode right = Factor(); - result = factory.createBinary(op, result, right); - } - return result; - } - - TypedNode Factor() { - TypedNode result; - result = null; - if (la.kind == 24) { - result = TimeRef(); - } else if (la.kind == 1) { - result = VariableRef(); - } else if (la.kind == 2) { - result = StringLiteral(); - } else if (la.kind == 3) { - result = NumericLiteral(); - } else if (la.kind == 8) { - Get(); - result = Expression(); - Expect(9); - } else SynErr(27); - return result; - } - - TypedNode TimeRef() { - TypedNode result; - Expect(24); - result = factory.createTime(); - return result; - } - - TypedNode VariableRef() { - TypedNode result; - Expect(1); - result = factory.createLocal(t.val); - return result; - } - - TypedNode StringLiteral() { - TypedNode result; - Expect(2); - result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); - return result; - } - - TypedNode NumericLiteral() { - TypedNode result; - Expect(3); - result = factory.createNumericLiteral(t.val); - return result; - } - + void SimpleLanguage() { + Function(); + while (la.kind == 4) { + Function(); + } + } + + void Function() { + Expect(4); + factory.startFunction(); + Expect(1); + String name = t.val; + StatementNode body = Block(); + factory.createFunction(body, name); + } + + StatementNode Block() { + StatementNode result; + List statements = new ArrayList<>(); + Expect(5); + while (StartOf(1)) { + StatementNode statement = Statement(); + statements.add(statement); + } + Expect(6); + result = factory.createBlock(statements); + return result; + } + + StatementNode Statement() { + StatementNode result; + result = null; + if (la.kind == 7) { + result = WhileStatement(); + } else if (la.kind == 1) { + result = AssignmentStatement(); + } else if (la.kind == 12) { + result = OutputStatement(); + } else if (la.kind == 13) { + result = ReturnStatement(); + } else SynErr(29); + return result; + } + + StatementNode WhileStatement() { + StatementNode result; + Expect(7); + Expect(8); + ConditionNode condition = Expression(); + Expect(9); + StatementNode body = Block(); + result = factory.createWhile(condition, body); + return result; + } + + StatementNode AssignmentStatement() { + StatementNode result; + Expect(1); + String name = t.val; + Expect(10); + TypedNode rvalue = Expression(); + Expect(11); + result = factory.createAssignment(name, rvalue); + return result; + } + + StatementNode OutputStatement() { + StatementNode result; + List expressions = new ArrayList<>(); + Expect(12); + while (StartOf(2)) { + TypedNode value = Expression(); + expressions.add(value); + } + Expect(11); + result = factory.createPrint(expressions); + return result; + } + + StatementNode ReturnStatement() { + StatementNode result; + Expect(13); + TypedNode value = Expression(); + Expect(11); + result = factory.createReturn(value); + return result; + } + + TypedNode Expression() { + TypedNode result; + result = ValueExpression(); + if (StartOf(3)) { + switch (la.kind) { + case 14: { + Get(); + break; + } + case 15: { + Get(); + break; + } + case 16: { + Get(); + break; + } + case 17: { + Get(); + break; + } + case 18: { + Get(); + break; + } + case 19: { + Get(); + break; + } + } + String op = t.val; + TypedNode right = ValueExpression(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode ValueExpression() { + TypedNode result; + result = Term(); + while (la.kind == 20 || la.kind == 21) { + if (la.kind == 20) { + Get(); + } else { + Get(); + } + String op = t.val; + TypedNode right = Term(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode Term() { + TypedNode result; + result = Factor(); + while (la.kind == 22 || la.kind == 23) { + if (la.kind == 22) { + Get(); + } else { + Get(); + } + String op = t.val; + TypedNode right = Factor(); + result = factory.createBinary(op, result, right); + } + return result; + } + + TypedNode Factor() { + TypedNode result; + result = null; + switch (la.kind) { + case 27: { + result = TimeRef(); + break; + } + case 1: { + result = VariableRef(); + break; + } + case 2: { + result = StringLiteral(); + break; + } + case 3: { + result = NumericLiteral(); + break; + } + case 24: { + result = Ternary(); + break; + } + case 8: { + Get(); + result = Expression(); + Expect(9); + break; + } + default: SynErr(30); break; + } + return result; + } + + TypedNode TimeRef() { + TypedNode result; + Expect(27); + result = factory.createTime(); + return result; + } + + TypedNode VariableRef() { + TypedNode result; + Expect(1); + result = factory.createLocal(t.val); + return result; + } + + TypedNode StringLiteral() { + TypedNode result; + Expect(2); + result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); + return result; + } + + TypedNode NumericLiteral() { + TypedNode result; + Expect(3); + result = factory.createNumericLiteral(t.val); + return result; + } + + TypedNode Ternary() { + TypedNode result; + TypedNode condition, thenPart, elsePart; + Expect(24); + condition = Expression(); + Expect(25); + thenPart = Expression(); + Expect(26); + elsePart = Expression(); + result = factory.createTernary(condition, thenPart, elsePart); + return result; + } + public void Parse() { la = new Token(); la.val = ""; Get(); - SimpleLanguage(); - Expect(0); + SimpleLanguage(); + Expect(0); } private static final boolean[][] set = { - {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x}, - {x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x}, - {x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x} + {T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,x,x, x,x,x,T, x,x,x,x, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x}, + {x,T,T,T, x,x,x,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,T, x,x}, + {x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,T, T,T,T,T, x,x,x,x, x,x,x,x, x,x} }; @@ -388,35 +416,38 @@ public void SynErr(int line, int col, int n) { String s; - switch (n) { - case 0: s = "EOF expected"; break; - case 1: s = "identifier expected"; break; - case 2: s = "stringLiteral expected"; break; - case 3: s = "numericLiteral expected"; break; - case 4: s = "\"function\" expected"; break; - case 5: s = "\"{\" expected"; break; - case 6: s = "\"}\" expected"; break; - case 7: s = "\"while\" expected"; break; - case 8: s = "\"(\" expected"; break; - case 9: s = "\")\" expected"; break; - case 10: s = "\"=\" expected"; break; - case 11: s = "\";\" expected"; break; - case 12: s = "\"print\" expected"; break; - case 13: s = "\"return\" expected"; break; - case 14: s = "\"<\" expected"; break; - case 15: s = "\">\" expected"; break; - case 16: s = "\"<=\" expected"; break; - case 17: s = "\">=\" expected"; break; - case 18: s = "\"==\" expected"; break; - case 19: s = "\"!=\" expected"; break; - case 20: s = "\"+\" expected"; break; - case 21: s = "\"-\" expected"; break; - case 22: s = "\"*\" expected"; break; - case 23: s = "\"/\" expected"; break; - case 24: s = "\"time\" expected"; break; - case 25: s = "??? expected"; break; - case 26: s = "invalid Statement"; break; - case 27: s = "invalid Factor"; break; + switch (n) { + case 0: s = "EOF expected"; break; + case 1: s = "identifier expected"; break; + case 2: s = "stringLiteral expected"; break; + case 3: s = "numericLiteral expected"; break; + case 4: s = "\"function\" expected"; break; + case 5: s = "\"{\" expected"; break; + case 6: s = "\"}\" expected"; break; + case 7: s = "\"while\" expected"; break; + case 8: s = "\"(\" expected"; break; + case 9: s = "\")\" expected"; break; + case 10: s = "\"=\" expected"; break; + case 11: s = "\";\" expected"; break; + case 12: s = "\"print\" expected"; break; + case 13: s = "\"return\" expected"; break; + case 14: s = "\"<\" expected"; break; + case 15: s = "\">\" expected"; break; + case 16: s = "\"<=\" expected"; break; + case 17: s = "\">=\" expected"; break; + case 18: s = "\"==\" expected"; break; + case 19: s = "\"!=\" expected"; break; + case 20: s = "\"+\" expected"; break; + case 21: s = "\"-\" expected"; break; + case 22: s = "\"*\" expected"; break; + case 23: s = "\"/\" expected"; break; + case 24: s = "\"#\" expected"; break; + case 25: s = "\"?\" expected"; break; + case 26: s = "\":\" expected"; break; + case 27: s = "\"time\" expected"; break; + case 28: s = "??? expected"; break; + case 29: s = "invalid Statement"; break; + case 30: s = "invalid Factor"; break; default: s = "error " + n; break; diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java Tue Feb 26 11:55:00 2013 +0100 @@ -311,8 +311,8 @@ static final char EOL = '\n'; static final int eofSym = 0; - static final int maxT = 25; - static final int noSym = 25; + static final int maxT = 28; + static final int noSym = 28; public Buffer buffer; // scanner buffer @@ -339,27 +339,30 @@ for (int i = 65; i <= 90; ++i) start.set(i, 1); for (int i = 97; i <= 122; ++i) start.set(i, 1); for (int i = 49; i <= 57; ++i) start.set(i, 4); - start.set(34, 2); - start.set(48, 5); - start.set(123, 6); - start.set(125, 7); - start.set(40, 8); - start.set(41, 9); - start.set(61, 20); - start.set(59, 10); - start.set(60, 21); - start.set(62, 22); - start.set(33, 14); - start.set(43, 16); - start.set(45, 17); - start.set(42, 18); - start.set(47, 19); + start.set(34, 2); + start.set(48, 5); + start.set(123, 6); + start.set(125, 7); + start.set(40, 8); + start.set(41, 9); + start.set(61, 23); + start.set(59, 10); + start.set(60, 24); + start.set(62, 25); + start.set(33, 14); + start.set(43, 16); + start.set(45, 17); + start.set(42, 18); + start.set(47, 19); + start.set(35, 20); + start.set(63, 21); + start.set(58, 22); start.set(Buffer.EOF, -1); literals.put("function", new Integer(4)); literals.put("while", new Integer(7)); literals.put("print", new Integer(12)); literals.put("return", new Integer(13)); - literals.put("time", new Integer(24)); + literals.put("time", new Integer(27)); } @@ -425,7 +428,7 @@ tval = newBuf; } if (ch != Buffer.EOF) { - tval[tlen++] = (char)ch; + tval[tlen++] = (char)ch; NextCh(); } @@ -484,9 +487,9 @@ } Token NextToken() { - while (ch == ' ' || + while (ch == ' ' || ch >= 9 && ch <= 10 || ch == 13 - ) NextCh(); + ) NextCh(); if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken(); int recKind = noSym; int recEnd = pos; @@ -515,60 +518,66 @@ } // NextCh already done case 1: recEnd = pos; recKind = 1; - if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} + if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;} case 2: - if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} - else if (ch == '"') {AddCh(); state = 3; break;} + if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 2; break;} + else if (ch == '"') {AddCh(); state = 3; break;} else {state = 0; break;} - case 3: + case 3: {t.kind = 2; break loop;} case 4: recEnd = pos; recKind = 3; - if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} + if (ch >= '0' && ch <= '9') {AddCh(); state = 4; break;} else {t.kind = 3; break loop;} - case 5: + case 5: {t.kind = 3; break loop;} - case 6: + case 6: {t.kind = 5; break loop;} - case 7: + case 7: {t.kind = 6; break loop;} - case 8: + case 8: {t.kind = 8; break loop;} - case 9: + case 9: {t.kind = 9; break loop;} - case 10: + case 10: {t.kind = 11; break loop;} - case 11: + case 11: {t.kind = 16; break loop;} - case 12: + case 12: {t.kind = 17; break loop;} - case 13: + case 13: {t.kind = 18; break loop;} case 14: - if (ch == '=') {AddCh(); state = 15; break;} + if (ch == '=') {AddCh(); state = 15; break;} else {state = 0; break;} - case 15: + case 15: {t.kind = 19; break loop;} - case 16: + case 16: {t.kind = 20; break loop;} - case 17: + case 17: {t.kind = 21; break loop;} - case 18: + case 18: {t.kind = 22; break loop;} - case 19: + case 19: {t.kind = 23; break loop;} - case 20: + case 20: + {t.kind = 24; break loop;} + case 21: + {t.kind = 25; break loop;} + case 22: + {t.kind = 26; break loop;} + case 23: recEnd = pos; recKind = 10; - if (ch == '=') {AddCh(); state = 13; break;} + if (ch == '=') {AddCh(); state = 13; break;} else {t.kind = 10; break loop;} - case 21: + case 24: recEnd = pos; recKind = 14; - if (ch == '=') {AddCh(); state = 11; break;} + if (ch == '=') {AddCh(); state = 11; break;} else {t.kind = 14; break loop;} - case 22: + case 25: recEnd = pos; recKind = 15; - if (ch == '=') {AddCh(); state = 12; break;} + if (ch == '=') {AddCh(); state = 12; break;} else {t.kind = 15; break loop;} } diff -r 45bce3579308 -r 3828c6119073 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Mon Feb 25 18:19:53 2013 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Tue Feb 26 11:55:00 2013 +0100 @@ -131,11 +131,19 @@ | NumericLiteral | + Ternary +| "(" Expression ")" -) +) . -TimeRef +Ternary (. TypedNode condition, thenPart, elsePart; .) += +"#" Expression "?" Expression ":" Expression + (. result = factory.createTernary(condition, thenPart, elsePart); .) +. + +TimeRef = "time" (. result = factory.createTime(); .) .