# HG changeset patch # User Christian Wimmer # Date 1391133207 28800 # Node ID 64c77f0577bb6fc7b49e74ea342a1fad4b851754 # Parent 67e4e7f56911e9953cc9487664acdbdaf5314d7b More documentation and improvements of Simple Language diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/Break.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Break.output Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,1 @@ +942 diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/Break.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/Break.sl Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,10 @@ +function main() { + i = 0; + while (i < 1000) { + if (i >= 942) { + break; + } + i = i + 1; + } + return i; +} diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/LoopCall.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopCall.output Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/LoopCall.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopCall.sl Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,15 @@ +function add(a, b) { + return a + b; +} + +function loop(n) { + i = 0; + while (i < n) { + i = add(i, 1); + } + return i; +} + +function main() { + println(loop(1000)); +} diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.output --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.output Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,1 @@ +1000 diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.sl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPolymorphic.sl Thu Jan 30 17:53:27 2014 -0800 @@ -0,0 +1,16 @@ +function add(a, b) { + return a + b; +} + +function loop(n) { + i = 0; + while (i < n) { + i = add(i, 1); + } + return i; +} + +function main() { + add("a", "b"); + println(loop(1000)); +} diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl --- a/graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl Thu Jan 30 17:53:27 2014 -0800 @@ -1,7 +1,11 @@ -function main() { +function loop(n) { i = 0; - while (i < 1000) { + while (i < n) { i = i + 1; } - println(i); + return i; } + +function main() { + println(loop(1000)); +} diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Thu Jan 30 17:53:27 2014 -0800 @@ -116,18 +116,21 @@ /** * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup. */ - public static void main(String[] args) { + public static void main(String[] args) throws IOException { + SourceManager sourceManager = new SourceManager(); + + Source source; if (args.length == 0) { - throw new SLException("SL source file must be specified as the first argument"); + source = sourceManager.get("stdin", System.in); + } else { + source = sourceManager.get(args[0]); } - String fileName = args[0]; + int repeats = 1; if (args.length >= 2) { repeats = Integer.parseInt(args[1]); } - SourceManager sourceManager = new SourceManager(); - Source source = sourceManager.get(fileName); SLContext context = new SLContext(sourceManager, new BufferedReader(new InputStreamReader(System.in)), System.out); run(context, source, System.out, repeats); } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -33,7 +33,7 @@ * and setting it in a constructor, we use the Truffle DSL annotation {@link NodeField} that * generates the field and constructor automatically. *

- * The builitin functions are registered in {@link SLContext#installBuiltins}. Every builtin node + * The builtin functions are registered in {@link SLContext#installBuiltins}. Every builtin node * subclass is instantiated there, wrapped into a function, and added to the * {@link SLFunctionRegistry}. This ensures that builtin functions can be called like user-defined * functions; there is no special function lookup or call node for builtin functions. diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,8 +26,8 @@ /** * Utility base class for operations that take two arguments (per convention called "left" and - * "right). For concrete subclassses of this class, the Truffle DSL creates two child fields, and - * the necessary constructors and logic to set them. + * "right). For concrete subclasses of this class, the Truffle DSL creates two child fields, and the + * necessary constructors and logic to set them. */ @NodeChildren({@NodeChild("leftNode"), @NodeChild("rightNode")}) public abstract class SLBinaryNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,7 +28,7 @@ /** * Before a call is executed the first time, the dispatch node is a - * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymprphic + * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymorphic * inline cache, i.e., a chain of {@link SLDirectDispatchNode}s. The chain is terminated by a * {@link SLUninitializedDispatchNode}. If the chain gets too long (longer than * {@link #INLINE_CACHE_SIZE}), i.e., if the call is too polymorphic, the whole chain is replaced by diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -96,7 +96,7 @@ } catch (InvalidAssumptionException ex) { /* - * The function has been redefined. Remove ourselfs from the polymorphic inline + * The function has been redefined. Remove ourself from the polymorphic inline * cache, so that we fail the check only once. Note that this replacement has subtle * semantics: we are changing a node in the tree that is currently executed. This is * only safe because we know that after the call to replace(), there is no more code diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -65,13 +65,13 @@ /* Extend the inline cache. Allocate the new cache entry, and the new end of the cache. */ SLAbstractDispatchNode next = new SLUninitializedDispatchNode(); SLAbstractDispatchNode direct = new SLDirectDispatchNode(next, function); - /* Replace ourselfs with the new cache entry. */ + /* Replace ourself with the new cache entry. */ specialized = replace(direct); } else { /* Cache size exceeded, fall back to a single generic dispatch node. */ SLAbstractDispatchNode generic = new SLGenericDispatchNode(); - /* Replace the whole chain, not just ourselfs, with the new generic node. */ + /* Replace the whole chain, not just ourself, with the new generic node. */ specialized = callNode.dispatchNode.replace(generic); } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,15 +26,32 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * A statement node that just executes a list of other statements. + */ @NodeInfo(shortName = "block") public class SLBlockNode extends SLStatementNode { + /** + * The array of child nodes. The annotation {@link com.oracle.truffle.api.nodes.Node.Children + * Children} informs Truffle that the field contains multiple children. It is a Truffle + * requirement that the field is {@code final} and an array of nodes. + */ @Children private final SLStatementNode[] bodyNodes; public SLBlockNode(SLStatementNode[] bodyNodes) { + /* + * It is a Truffle requirement to call adoptChildren(), which performs all the necessary + * steps to add the new children to the node tree. + */ this.bodyNodes = adoptChildren(bodyNodes); } + /** + * Execute all child statements. The annotation {@link ExplodeLoop} triggers full unrolling of + * the loop during compilation. This allows the {@link SLStatementNode#executeVoid} method of + * all children to be inlined. + */ @Override @ExplodeLoop public void executeVoid(VirtualFrame frame) { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java Thu Jan 30 17:53:27 2014 -0800 @@ -24,12 +24,18 @@ import com.oracle.truffle.api.nodes.*; +/** + * Exception thrown by the {@link SLBreakNode break statement} and caught by the {@link SLWhileNode + * loop statement}. Since the exception is stateless, i.e., has no instance fields, we can use a + * {@link #SINGLETON} to avoid memory allocation during interpretation. + */ public final class SLBreakException extends ControlFlowException { public static final SLBreakException SINGLETON = new SLBreakException(); private static final long serialVersionUID = -91013036379258890L; + /* Prevent instantiation from outside. */ private SLBreakException() { } } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,12 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Implementation of the SL break statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLBreakNode} and the {@link SLWhileNode} of the loop we are + * breaking out. This is done by throwing an {@link SLBreakException exception} that is caught by + * the {@link SLWhileNode#executeVoid loop node}. + */ @NodeInfo(shortName = "break") public final class SLBreakNode extends SLStatementNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java Thu Jan 30 17:53:27 2014 -0800 @@ -24,12 +24,18 @@ import com.oracle.truffle.api.nodes.*; +/** + * Exception thrown by the {@link SLContinueNode continue statement} and caught by the + * {@link SLWhileNode loop statement}. Since the exception is stateless, i.e., has no instance + * fields, we can use a {@link #SINGLETON} to avoid memory allocation during interpretation. + */ public final class SLContinueException extends ControlFlowException { public static final SLContinueException SINGLETON = new SLContinueException(); private static final long serialVersionUID = 5329687983726237188L; + /* Prevent instantiation from outside. */ private SLContinueException() { } } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,12 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Implementation of the SL continue statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLContinueNode} and the {@link SLWhileNode} of the loop we + * are continuing. This is done by throwing an {@link SLContinueException exception} that is caught + * by the {@link SLWhileNode#executeVoid loop node}. + */ @NodeInfo(shortName = "continue") public final class SLContinueNode extends SLStatementNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,27 +28,57 @@ import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.runtime.*; +/** + * The body of a user-defined SL function. This is the node references by a {@link SLRootNode} for + * user-defined functions. It handles the return value of a function: the {@link SLReturnNode return + * statement} throws an {@link SLReturnException exception} with the return value. This node catches + * the exception. If the method ends without an explicit {@code return}, return the + * {@link SLNull#SINGLETON default null value}. + */ @NodeInfo(shortName = "body") public class SLFunctionBodyNode extends SLExpressionNode { + /** The body of the function. */ @Child private SLStatementNode bodyNode; + /** + * Profiling information, collected by the interpreter, capturing whether the function had an + * {@link SLReturnNode explicit return statement}. This allows the compiler to generate better + * code. + */ private final BranchProfile exceptionTaken = new BranchProfile(); private final BranchProfile nullTaken = new BranchProfile(); public SLFunctionBodyNode(SLStatementNode bodyNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ this.bodyNode = adoptChild(bodyNode); } @Override public Object executeGeneric(VirtualFrame frame) { try { + /* Execute the function body. */ bodyNode.executeVoid(frame); + } catch (SLReturnException ex) { + /* + * In the interpreter, record profiling information that the function has an explicit + * return. + */ exceptionTaken.enter(); + /* The exception transports the actual return value. */ return ex.getResult(); } + + /* + * In the interpreter, record profiling information that the function ends without an + * explicit return. + */ nullTaken.enter(); + /* Return the default null value. */ return SLNull.SINGLETON; } } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -30,14 +30,33 @@ @NodeInfo(shortName = "if") public class SLIfNode extends SLStatementNode { + + /** + * The condition of the {@code if}. This in a {@link SLExpressionNode} because we require a + * result value. We do not have a node type that can only return a {@code boolean} value, so + * {@link #evaluateCondition executing the condition} can lead to a type error. + */ @Child private SLExpressionNode conditionNode; + + /** Statement (or {@SLBlockNode block}) executed when the condition is true. */ @Child private SLStatementNode thenPartNode; + + /** Statement (or {@SLBlockNode block}) executed when the condition is false. */ @Child private SLStatementNode elsePartNode; + /** + * Profiling information, collected by the interpreter, capturing whether the then-branch was + * used (analogously for the {@link #elseTaken else-branch}). This allows the compiler to + * generate better code for conditions that are always true or always false. + */ private final BranchProfile thenTaken = new BranchProfile(); private final BranchProfile elseTaken = new BranchProfile(); public SLIfNode(SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ this.conditionNode = adoptChild(conditionNode); this.thenPartNode = adoptChild(thenPartNode); this.elsePartNode = adoptChild(elsePartNode); @@ -46,11 +65,15 @@ @Override public void executeVoid(VirtualFrame frame) { if (evaluateCondition(frame)) { + /* In the interpreter, record profiling information that the then-branch was used. */ thenTaken.enter(); + /* Execute the then-branch. */ thenPartNode.executeVoid(frame); } else { + /* In the interpreter, record profiling information that the else-branch was used. */ + elseTaken.enter(); + /* Execute the else-branch (which is optional according to the SL syntax). */ if (elsePartNode != null) { - elseTaken.enter(); elsePartNode.executeVoid(frame); } } @@ -59,8 +82,8 @@ private boolean evaluateCondition(VirtualFrame frame) { try { /* - * The condition must evaluate to a boolean value, so we call boolean-specialized - * method. + * The condition must evaluate to a boolean value, so we call the boolean-specialized + * execute method. */ return conditionNode.executeBoolean(frame); } catch (UnexpectedResultException ex) { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java Thu Jan 30 17:53:27 2014 -0800 @@ -24,6 +24,11 @@ import com.oracle.truffle.api.nodes.*; +/** + * Exception thrown by the {@link SLReturnNode return statement} and caught by the + * {@link SLFunctionBodyNode function body}. The exception transports the return value in its + * {@link #result} field. + */ public final class SLReturnException extends ControlFlowException { private static final long serialVersionUID = 4073191346281369231L; diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -27,6 +27,13 @@ import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.runtime.*; +/** + * Implementation of the SL return statement. We need to unwind an unknown number of interpreter + * frames that are between this {@link SLReturnNode} and the {@link SLFunctionBodyNode} of the + * method we are exiting. This is done by throwing an {@link SLReturnException exception} that is + * caught by the {@link SLFunctionBodyNode#executeGeneric function body}. The exception transports + * the return value. + */ @NodeInfo(shortName = "return") public class SLReturnNode extends SLStatementNode { @@ -42,6 +49,7 @@ if (valueNode != null) { result = valueNode.executeGeneric(frame); } else { + /* Return statement that was not followed by an expression, so return the SL null value. */ result = SLNull.SINGLETON; } throw new SLReturnException(result); diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -32,13 +32,29 @@ @NodeInfo(shortName = "while") public class SLWhileNode extends SLStatementNode { + /** + * The condition of the loop. This in a {@link SLExpressionNode} because we require a result + * value. We do not have a node type that can only return a {@code boolean} value, so + * {@link #evaluateCondition executing the condition} can lead to a type error. + */ @Child private SLExpressionNode conditionNode; + + /** Statement (or {@SLBlockNode block}) executed as long as the condition is true. */ @Child private SLStatementNode bodyNode; + /** + * Profiling information, collected by the interpreter, capturing whether a {@code continue} + * statement was used in this loop. This allows the compiler to generate better code for loops + * without a {@code continue}. + */ private final BranchProfile continueTaken = new BranchProfile(); private final BranchProfile breakTaken = new BranchProfile(); public SLWhileNode(SLExpressionNode conditionNode, SLStatementNode bodyNode) { + /* + * It is a Truffle requirement to call adoptChild(), which performs all the necessary steps + * to add the new child to the node tree. + */ this.conditionNode = adoptChild(conditionNode); this.bodyNode = adoptChild(bodyNode); } @@ -49,28 +65,31 @@ try { while (evaluateCondition(frame)) { try { + /* Execute the loop body. */ bodyNode.executeVoid(frame); + if (CompilerDirectives.inInterpreter()) { + /* In the interpreter, profile the the number of loop iteration. */ count++; } } catch (SLContinueException ex) { + /* In the interpreter, record profiling information that the loop uses continue. */ continueTaken.enter(); /* Fall through to next loop iteration. */ } } } catch (SLBreakException ex) { + /* In the interpreter, record profiling information that the loop uses break. */ breakTaken.enter(); /* Done executing this loop, exit method to execute statement following the loop. */ + } finally { if (CompilerDirectives.inInterpreter()) { /* - * Report the loop count to the Truffle system. It is used for compilation and - * inlining decisions. + * In the interpreter, report the loop count to the Truffle system. It is used for + * compilation and inlining decisions. */ - RootNode root = getRootNode(); - if (root.getCallTarget() instanceof LoopCountReceiver) { - ((LoopCountReceiver) root.getCallTarget()).reportLoopCount(count); - } + getRootNode().reportLoopCount(count); } } } @@ -78,8 +97,8 @@ private boolean evaluateCondition(VirtualFrame frame) { try { /* - * The condition must evaluate to a boolean value, so we call boolean-specialized - * method. + * The condition must evaluate to a boolean value, so we call the boolean-specialized + * execute method. */ return conditionNode.executeBoolean(frame); } catch (UnexpectedResultException ex) { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -29,29 +29,81 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * SL node that performs the "+" operation, which performs addition on arbitrary precision numbers, + * as well as String concatenation if one of the operands is a String. + *

+ * Type specialization on the input values is essential for the performance. This is achieved via + * node rewriting: specialized subclasses handle just a single type, so that the generic node that + * can handle all types is used only in cases where different types were encountered. The subclasses + * are automatically generated by the Truffle DSL. In addition, a {@link SLAddNodeFactory factory + * class} is generated that provides, e.g., {@link SLAddNodeFactory#create node creation}. + */ @NodeInfo(shortName = "+") public abstract class SLAddNode extends SLBinaryNode { + /** + * Specialization for primitive {@code long} values. This is the fast path of the + * arbitrary-precision arithmetic. We need to check for overflows of the addition, and switch to + * the {@link #add(BigInteger, BigInteger) slow path}. Therefore, we use an + * {@link ExactMath#addExact(long, long) addition method that throws an exception on overflow}. + * The {@code rewriteOn} attribute on the {@link Specialization} annotation automatically + * triggers the node rewriting on the exception. + *

+ * In compiled code, {@link ExactMath#addExact(long, long) addExact} is compiled to efficient + * machine code that uses the processor's overflow flag. Therefore, this method is compiled to + * only two machine code instructions on the fast path. + *

+ * This specialization is automatically selected by the Truffle DSL if both the left and right + * operand are {@code long} values. + */ @Specialization(rewriteOn = ArithmeticException.class) protected long add(long left, long right) { return ExactMath.addExact(left, right); } + /** + * This is the slow path of the arbitrary-precision arithmetic. The {@link BigInteger} type of + * Java is doing everything we need. + *

+ * This specialization is automatically selected by the Truffle DSL if both the left and right + * operand are {@link BigInteger} values. Because the type system defines an + * {@link ImplicitCast implicit conversion} from {@code long} to {@link BigInteger} in + * {@link SLTypes#castBigInteger(long)}, this specialization is also taken if the left or the + * right operand is a {@code long} value. + */ @Specialization protected BigInteger add(BigInteger left, BigInteger right) { return left.add(right); } + /** + * Specialization for String concatenation. This specialization is not strictly necessary, since + * {@link #add(Object, Object)} covers this case too. But it leads to slightly better code, + * since we do not require the {@link Object#toString()} calls in this specialization. + */ @Specialization protected String add(String left, String right) { return left + right; } + /** + * Specialization for String concatenation. The SL specification says that String concatenation + * works if either the left or the right operand is a String. The non-string operand is + * converted then automatically converted to a String. + *

+ * To implement these semantics, we tell the Truffle DSL to use a custom guard. The guard + * function is defined in {@link #isString this class}, but could also be in any superclass. + */ @Specialization(guards = "isString") protected String add(Object left, Object right) { return left.toString() + right.toString(); } + /** + * Guard for String concatenation: returns true if either the left or the right operand is a + * {@link String}. + */ protected boolean isString(Object a, Object b) { return a instanceof String || b instanceof String; } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,6 +28,10 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Constant literal for a arbitrary-precision number that exceeds the range of + * {@link SLLongLiteralNode}. + */ @NodeInfo(shortName = "const") public final class SLBigIntegerLiteralNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,6 +28,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the extensively documented {@link SLAddNode}. + */ @NodeInfo(shortName = "/") public abstract class SLDivNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -29,6 +29,16 @@ import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.runtime.*; +/** + * The {@code ==} operator of SL is defined on all types. Therefore, we need a (@link + * {@link #equal(Object, Object) generic implementation} that can handle all possible types. But + * since {@code ==} can only return {@code true} when the type of the left and right operand are the + * same, the specializations already cover all possible cases that can return {@code true} and the + * generic case is trivial. + *

+ * Note that we do not need the analogous {@code =!} operator, because we can just + * {@link SLLogicalNotNode negate} the {@code ==} operator. + */ @NodeInfo(shortName = "==") public abstract class SLEqualNode extends SLBinaryNode { @@ -67,6 +77,11 @@ return left == right; } + /** + * The {@link Generic} annotation informs that Truffle DSL that this method should be executed + * when no {@link Specialization specialized method} matches. The operand types must be + * {@link Object}. + */ @Generic protected boolean equal(Object left, Object right) { /* diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -22,11 +22,18 @@ */ package com.oracle.truffle.sl.nodes.expression; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.runtime.*; +/** + * Constant literal for a {@link SLFunction function} value, created when a function name occurs as + * a literal in SL source code. Note that function redefinition can change the {@link CallTarget + * call target} that is executed when calling the function, but the {@link SLFunction} for a name + * never changes. This is guaranteed by the {@link SLFunctionRegistry}. + */ @NodeInfo(shortName = "func") public final class SLFunctionLiteralNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,6 +28,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the {@link SLLessThanNode}. + */ @NodeInfo(shortName = "<=") public abstract class SLLessOrEqualNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -28,6 +28,10 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the extensively documented {@link SLAddNode}. The only difference: the + * specialized methods return {@code boolean} instead of the input types. + */ @NodeInfo(shortName = "<") public abstract class SLLessThanNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,15 +26,32 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class declares specializations similar to the extensively documented {@link SLAddNode}. It + * uses one additional feature of the Truffle DSL: {@link ShortCircuit}. + *

+ * Logical operations in SL use short circuit evaluation: if the evaluation of the left operand + * already decides the result of the operation, the right operand must not be executed. This is + * expressed in the Truffle DSL via a method annotated with {@link ShortCircuit}, which returns + * whether a child needs to be executed based on the result of already executed children. + */ @NodeInfo(shortName = "&&") @SuppressWarnings("unused") public abstract class SLLogicalAndNode extends SLBinaryNode { + /** + * This method is called after the left child was evaluated, but before the right child is + * evaluated. The right child is only evaluated when the return value is {code true}. + */ @ShortCircuit("rightNode") protected boolean needsRightNode(boolean left) { return left; } + /** + * Similar to {@link #needsRightNode(boolean)}, but for generic cases where the type of the left + * child is not known. + */ @ShortCircuit("rightNode") protected boolean needsRightNode(Object left) { return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,10 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Example of a simple unary node that uses type specialization. See {@link SLAddNode} for + * information on specializations. + */ @NodeChild("valueNode") @NodeInfo(shortName = "!") public abstract class SLLogicalNotNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the {@link SLLogicalAndNode}. + */ @NodeInfo(shortName = "||") @SuppressWarnings("unused") public abstract class SLLogicalOrNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,11 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Constant literal for a primitive {@code long} value. The unboxed value can be returned when the + * parent expects a long value and calls {@link SLLongLiteralNode#executeLong}. In the generic case, + * the primitive value is automatically boxed by Java. + */ @NodeInfo(shortName = "const") public final class SLLongLiteralNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -29,6 +29,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the extensively documented {@link SLAddNode}. + */ @NodeInfo(shortName = "*") public abstract class SLMulNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,6 +26,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * Constant literal for a String value. + */ @NodeInfo(shortName = "const") public final class SLStringLiteralNode extends SLExpressionNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -29,6 +29,9 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.sl.nodes.*; +/** + * This class is similar to the extensively documented {@link SLAddNode}. + */ @NodeInfo(shortName = "-") public abstract class SLSubNode extends SLBinaryNode { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -22,15 +22,31 @@ */ package com.oracle.truffle.sl.nodes.local; +import com.oracle.truffle.api.*; import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.sl.nodes.*; +import com.oracle.truffle.sl.parser.*; import com.oracle.truffle.sl.runtime.*; +/** + * Reads a function argument. Arguments are passed in as a {@link SLArguments} object, which + * encapsulates an {@link SLArguments#getFromFrame Object[] array}. Language-defined subclasses of + * {@link Arguments} are the standard Truffle way to pass values between function. + *

+ * Arguments are not type-specialized. To ensure that repeated accesses within a method are + * specialized and can, e.g., accessed without unboxing, all arguments are loaded into local + * variables {@link SLNodeFactory#addFormalParameter in the method prologue}. + */ public class SLReadArgumentNode extends SLExpressionNode { + /** The argument number, i.e., the index into the array of arguments. */ private final int index; + /** + * Profiling information, collected by the interpreter, capturing whether the function was + * called with fewer actual arguments than formal arguments. + */ private final BranchProfile outOfBoundsTaken = new BranchProfile(); public SLReadArgumentNode(int index) { @@ -43,7 +59,9 @@ if (index < args.length) { return args[index]; } else { + /* In the interpreter, record profiling information that the branch was used. */ outOfBoundsTaken.enter(); + /* Use the default null value. */ return SLNull.SINGLETON; } } diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -26,10 +26,21 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.sl.nodes.*; +/** + * Node to read a local variable from a function's {@link VirtualFrame frame}. The Truffle frame API + * allows to store primitive values of all Java primitive types, and Object values. This means that + * all SL types that are objects are handled by the {@link #readObject} method. When a local + * variable changes its type, the frame access method throws an {@link FrameSlotTypeException}, + * which causes not rewriting. The rewriting code is generated by the Truffle DSL. + */ @PolymorphicLimit(1) @NodeField(name = "slot", type = FrameSlot.class) public abstract class SLReadLocalVariableNode extends SLExpressionNode { + /** + * Returns the descriptor of the accessed local variable. The implementation of this method is + * created by the Truffle DSL based on the {@link NodeField} annotation on the class. + */ protected abstract FrameSlot getSlot(); @Specialization(rewriteOn = {FrameSlotTypeException.class}) diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java Thu Jan 30 17:53:27 2014 -0800 @@ -27,12 +27,25 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.sl.nodes.*; +/** + * Node to write a local variable to a function's {@link VirtualFrame frame}. The Truffle frame API + * allows to store primitive values of all Java primitive types, and Object values. + */ @NodeChild(value = "valueNode") @NodeField(name = "slot", type = FrameSlot.class) public abstract class SLWriteLocalVariableNode extends SLExpressionNode { + /** + * Returns the descriptor of the accessed local variable. The implementation of this method is + * created by the Truffle DSL based on the {@link NodeField} annotation on the class. + */ protected abstract FrameSlot getSlot(); + /** + * Specialized method to write a primitive {@code long} value}. This is only possible if the + * local variable also has currently the type {@code long}, therefore a Truffle DSL + * {@link #isLongKind() custom guard} is specified. + */ @Specialization(guards = "isLongKind") protected long write(VirtualFrame frame, long value) { frame.setLong(getSlot(), value); @@ -45,9 +58,24 @@ return value; } + /** + * Generic write method that works for all possible types. + *

+ * Why is this method annotated with {@link Specialization} and not {@link Generic}? For a + * {@link Generic} method, the Truffle DSL generated code would try all other specializations + * first before calling this method. We know that all these specializations would fail their + * guards, so there is no point in calling them. Since this method takes a value of type + * {@link Object}, it is guaranteed to never fail, i.e., once we are in this specialization the + * node will never be re-specialized. + */ @Specialization protected Object write(VirtualFrame frame, Object value) { if (getSlot().getKind() != FrameSlotKind.Object) { + /* + * The local variable has still a primitive type, we need to change it to Object. Since + * the variable type is important when the compiler optimizes a method, we also discard + * compiled code. + */ CompilerDirectives.transferToInterpreterAndInvalidate(); getSlot().setKind(FrameSlotKind.Object); } @@ -55,6 +83,9 @@ return value; } + /** + * Guard function that the local variable has the type {@code long}. + */ protected boolean isLongKind() { return isKind(FrameSlotKind.Long); } @@ -65,12 +96,22 @@ private boolean isKind(FrameSlotKind kind) { if (getSlot().getKind() == kind) { + /* Success: the frame slot has the expected kind. */ return true; } else if (getSlot().getKind() == FrameSlotKind.Illegal) { + /* + * This is the first write to this local variable. We can set the type to the one we + * expect. Since the variable type is important when the compiler optimizes a method, we + * also discard compiled code. + */ CompilerDirectives.transferToInterpreterAndInvalidate(); getSlot().setKind(kind); return true; } else { + /* + * Failure: the frame slot has the wrong kind, the Truffle DSL generated code will + * choose a different specialization. + */ return false; } } diff -r 67e4e7f56911 -r 64c77f0577bb 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 Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java Thu Jan 30 17:53:27 2014 -0800 @@ -145,17 +145,17 @@ } } Expect(7); - SLStatementNode body = Block(); + SLStatementNode body = Block(false); factory.finishFunction(body); } - SLStatementNode Block() { + SLStatementNode Block(boolean inLoop) { SLStatementNode result; factory.startBlock(); List body = new ArrayList<>(); Expect(8); while (StartOf(1)) { - SLStatementNode s = Statement(); + SLStatementNode s = Statement(inLoop); body.add(s); } Expect(9); @@ -163,7 +163,7 @@ return result; } - SLStatementNode Statement() { + SLStatementNode Statement(boolean inLoop) { SLStatementNode result; result = null; switch (la.kind) { @@ -173,18 +173,18 @@ } case 10: { Get(); - result = factory.createBreak(t); + if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } Expect(11); break; } case 12: { Get(); - result = factory.createContinue(t); + if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } Expect(11); break; } case 14: { - result = IfStatement(); + result = IfStatement(inLoop); break; } case 16: { @@ -208,23 +208,23 @@ Token whileToken = t; SLExpressionNode condition = Expression(); Expect(7); - SLStatementNode body = Block(); + SLStatementNode body = Block(true); result = factory.createWhile(whileToken, condition, body); return result; } - SLStatementNode IfStatement() { + SLStatementNode IfStatement(boolean inLoop) { SLStatementNode result; Expect(14); Expect(5); Token ifToken = t; SLExpressionNode condition = Expression(); Expect(7); - SLStatementNode thenPart = Block(); + SLStatementNode thenPart = Block(inLoop); SLStatementNode elsePart = null; if (la.kind == 15) { Get(); - elsePart = Block(); + elsePart = Block(inLoop); } result = factory.createIf(ifToken, condition, thenPart, elsePart); return result; diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java Thu Jan 30 17:53:27 2014 -0800 @@ -36,8 +36,17 @@ import com.oracle.truffle.sl.nodes.local.*; import com.oracle.truffle.sl.runtime.*; +/** + * Helper class used by the SL {@link Parser} to create nodes. The code is factored out of the + * automatically generated parser to keep the attributed grammar of SL small. + */ public class SLNodeFactory { + /** + * Local variable names that are visible in the current block. Variables are not visible outside + * of their defining block, to prevent the usage of undefined variables. Because of that, we can + * decide during parsing if a name references a local variable or is a function name. + */ static class LexicalScope { protected final LexicalScope outer; protected final Map locals; diff -r 67e4e7f56911 -r 64c77f0577bb 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 Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg Thu Jan 30 17:53:27 2014 -0800 @@ -70,34 +70,34 @@ } ] ")" -Block (. factory.finishFunction(body); .) +Block (. factory.finishFunction(body); .) . -Block +Block = (. factory.startBlock(); List body = new ArrayList<>(); .) "{" { - Statement (. body.add(s); .) + Statement (. body.add(s); .) } "}" (. result = factory.finishBlock(body); .) . -Statement +Statement = (. result = null; .) ( WhileStatement | - "break" (. result = factory.createBreak(t); .) + "break" (. if (inLoop) { result = factory.createBreak(t); } else { SemErr("break used outside of loop"); } .) ";" | - "continue" (. result = factory.createContinue(t); .) + "continue" (. if (inLoop) { result = factory.createContinue(t); } else { SemErr("continue used outside of loop"); } .) ";" | - IfStatement + IfStatement | ReturnStatement | @@ -112,20 +112,20 @@ "(" (. Token whileToken = t; .) Expression ")" -Block (. result = factory.createWhile(whileToken, condition, body); .) +Block (. result = factory.createWhile(whileToken, condition, body); .) . -IfStatement +IfStatement = "if" "(" (. Token ifToken = t; .) Expression ")" -Block (. SLStatementNode elsePart = null; .) +Block (. SLStatementNode elsePart = null; .) [ "else" - Block + Block ] (. result = factory.createIf(ifToken, condition, thenPart, elsePart); .) . diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Thu Jan 30 17:53:27 2014 -0800 @@ -89,7 +89,7 @@ } /** - * Adds all builitin functions to the {@link SLFunctionRegistry}. This method lists all + * Adds all builtin functions to the {@link SLFunctionRegistry}. This method lists all * {@link SLBuiltinNode builtin implementation classes}. */ private void installBuiltins() { diff -r 67e4e7f56911 -r 64c77f0577bb graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Thu Jan 30 17:52:24 2014 -0800 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Thu Jan 30 17:53:27 2014 -0800 @@ -27,12 +27,12 @@ /** * Represents a SL function. On the Truffle level, a callable element is represented by a - * {@link RootCallTarget call target}. This class encapsulates a call target, and adds versioning + * {@link RootCallTarget call target}. This class encapsulates a call target, and adds version * support: functions in SL can be redefined, i.e. changed at run time. When a function is * redefined, the call target managed by this function object is changed (and {@link #callTarget} is * therefore not a final field). *

- * Function redefinition is expected to be rare, therefore optimzied call nodes want to speculate + * Function redefinition is expected to be rare, therefore optimized call nodes want to speculate * that the call target is stable. This is possible with the help of a Truffle {@link Assumption}: a * call node can keep the call target returned by {@link #getCallTarget()} cached until the * assumption returned by {@link #getCallTargetStable()} is valid.