changeset 13821:b16ec83edc73

Documentation and more refactoring of Simple Language
author Christian Wimmer <christian.wimmer@oracle.com>
date Wed, 29 Jan 2014 20:45:43 -0800
parents 20e7727588e8
children 35fc64972250 96d5cb754b68
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java graal/com.oracle.truffle.sl.test/tests/Add.sl graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl graal/com.oracle.truffle.sl.test/tests/Builtins.sl graal/com.oracle.truffle.sl.test/tests/CalcShell.input graal/com.oracle.truffle.sl.test/tests/CalcShell.output graal/com.oracle.truffle.sl.test/tests/CalcShell.sl graal/com.oracle.truffle.sl.test/tests/Call.sl graal/com.oracle.truffle.sl.test/tests/Comparison.output graal/com.oracle.truffle.sl.test/tests/Comparison.sl graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl graal/com.oracle.truffle.sl.test/tests/Div.sl graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl graal/com.oracle.truffle.sl.test/tests/Mul.sl graal/com.oracle.truffle.sl.test/tests/Null.output graal/com.oracle.truffle.sl.test/tests/Null.sl graal/com.oracle.truffle.sl.test/tests/String.output graal/com.oracle.truffle.sl.test/tests/String.sl graal/com.oracle.truffle.sl.test/tests/Sub.sl graal/com.oracle.truffle.sl.test/tests/error/TypeError01.output graal/com.oracle.truffle.sl.test/tests/error/TypeError01.sl graal/com.oracle.truffle.sl.test/tests/error/TypeError02.output graal/com.oracle.truffle.sl.test/tests/error/TypeError02.sl graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output graal/com.oracle.truffle.sl.test/tests/error/TypeError05.sl graal/com.oracle.truffle.sl.test/tests/error/TypeError06.output graal/com.oracle.truffle.sl.test/tests/error/TypeError06.sl graal/com.oracle.truffle.sl.test/tests/error/TypeError07.output graal/com.oracle.truffle.sl.test/tests/error/TypeError07.sl graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNanoTimeBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLReadlnBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLTimeBuiltin.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLArgumentsNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLNotEqualNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/ReadLocalNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/WriteLocalNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/ParserUtils.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java
diffstat 96 files changed, 1952 insertions(+), 973 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Wed Jan 29 20:45:43 2014 -0800
@@ -158,6 +158,103 @@
     }
 
     @Test
+    public void testMergeAllocationsInt() {
+        testEscapeAnalysis("testMergeAllocationsIntSnippet", Constant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsIntSnippet(int a) {
+        TestClassInt obj;
+        if (a < 0) {
+            obj = new TestClassInt(1, 2);
+            notInlineable();
+        } else {
+            obj = new TestClassInt(1, 2);
+            notInlineable();
+        }
+        return obj.x <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testMergeAllocationsObj() {
+        testEscapeAnalysis("testMergeAllocationsObjSnippet", Constant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsObjSnippet(int a) {
+        TestClassObject obj;
+        Integer one = 1;
+        Integer two = 2;
+        Integer three = 3;
+        if (a < 0) {
+            obj = new TestClassObject(one, two);
+            notInlineable();
+        } else {
+            obj = new TestClassObject(one, three);
+            notInlineable();
+        }
+        return ((Integer) obj.x).intValue() <= 3 ? 1 : 0;
+    }
+
+    @Test
+    public void testMergeAllocationsObjCirc() {
+        testEscapeAnalysis("testMergeAllocationsObjCircSnippet", Constant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsObjCircSnippet(int a) {
+        TestClassObject obj;
+        Integer one = 1;
+        Integer two = 2;
+        Integer three = 3;
+        if (a < 0) {
+            obj = new TestClassObject(one);
+            obj.y = obj;
+            obj.y = two;
+            notInlineable();
+        } else {
+            obj = new TestClassObject(one);
+            obj.y = obj;
+            obj.y = three;
+            notInlineable();
+        }
+        return ((Integer) obj.x).intValue() <= 3 ? 1 : 0;
+    }
+
+    static class MyException extends RuntimeException {
+
+        private static final long serialVersionUID = 0L;
+
+        protected Integer value;
+
+        public MyException(Integer value) {
+            super((Throwable) null);
+            this.value = value;
+        }
+
+        @SuppressWarnings("sync-override")
+        @Override
+        public final Throwable fillInStackTrace() {
+            return null;
+        }
+    }
+
+    @Test
+    public void testMergeAllocationsException() {
+        testEscapeAnalysis("testMergeAllocationsExceptionSnippet", Constant.forInt(1), false);
+    }
+
+    public int testMergeAllocationsExceptionSnippet(int a) {
+        MyException obj;
+        Integer one = 1;
+        if (a < 0) {
+            obj = new MyException(one);
+            notInlineable();
+        } else {
+            obj = new MyException(one);
+            notInlineable();
+        }
+        return obj.value <= 3 ? 1 : 0;
+    }
+
+    @Test
     public void testCheckCast() {
         testEscapeAnalysis("testCheckCastSnippet", Constant.forObject(TestClassObject.class), false);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java	Wed Jan 29 20:45:43 2014 -0800
@@ -33,7 +33,7 @@
         if (object instanceof RootCallTarget) {
             RootCallTarget callTarget = (RootCallTarget) object;
             if (callTarget.getRootNode() != null) {
-                new GraphPrintVisitor().beginGroup(callTarget.toString()).beginGraph(message).visit(callTarget.getRootNode()).printToNetwork();
+                new GraphPrintVisitor().beginGroup(callTarget.toString()).beginGraph(message).visit(callTarget.getRootNode()).printToNetwork(false);
             }
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java	Wed Jan 29 20:45:43 2014 -0800
@@ -169,7 +169,7 @@
         }
     }
 
-    public void printToNetwork() {
+    public void printToNetwork(boolean ignoreErrors) {
         try {
             Transformer tr = TransformerFactory.newInstance().newTransformer();
             tr.setOutputProperty(OutputKeys.METHOD, "xml");
@@ -178,7 +178,9 @@
             BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000);
             tr.transform(new DOMSource(dom), new StreamResult(stream));
         } catch (TransformerException | IOException e) {
-            e.printStackTrace();
+            if (!ignoreErrors) {
+                e.printStackTrace();
+            }
         }
     }
 
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Wed Jan 29 20:45:43 2014 -0800
@@ -46,20 +46,24 @@
 
     private static final int REPEATS = 10;
 
-    private static final String INPUT_SUFFIX = ".sl";
+    private static final String SOURCE_SUFFIX = ".sl";
+    private static final String INPUT_SUFFIX = ".input";
     private static final String OUTPUT_SUFFIX = ".output";
 
     private static final String LF = System.getProperty("line.separator");
 
-    public static final class TestCase {
-        private final Source input;
-        private final String expectedOutput;
-        private final Description name;
+    static class TestCase {
+        protected final Description name;
+        protected final Source source;
+        protected final String testInput;
+        protected final String expectedOutput;
+        protected String actualOutput;
 
-        public TestCase(Class<?> testClass, String name, Source input, String expectedOutput) {
-            this.input = input;
+        protected TestCase(Class<?> testClass, String name, Source source, String testInput, String expectedOutput) {
+            this.name = Description.createTestDescription(testClass, name);
+            this.source = source;
+            this.testInput = testInput;
             this.expectedOutput = expectedOutput;
-            this.name = Description.createTestDescription(testClass, name);
         }
     }
 
@@ -114,23 +118,24 @@
         final List<TestCase> foundCases = new ArrayList<>();
         Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
             @Override
-            public FileVisitResult visitFile(Path inputFile, BasicFileAttributes attrs) throws IOException {
-                String name = inputFile.getFileName().toString();
-                if (name.endsWith(INPUT_SUFFIX)) {
-                    String baseName = name.substring(0, name.length() - INPUT_SUFFIX.length());
+            public FileVisitResult visitFile(Path sourceFile, BasicFileAttributes attrs) throws IOException {
+                String sourceName = sourceFile.getFileName().toString();
+                if (sourceName.endsWith(SOURCE_SUFFIX)) {
+                    String baseName = sourceName.substring(0, sourceName.length() - SOURCE_SUFFIX.length());
 
-                    Path outputFile = inputFile.resolveSibling(baseName + OUTPUT_SUFFIX);
-                    if (!Files.exists(outputFile)) {
-                        throw new Error("Output file does not exist: " + outputFile);
+                    Path inputFile = sourceFile.resolveSibling(baseName + INPUT_SUFFIX);
+                    String testInput = "";
+                    if (Files.exists(inputFile)) {
+                        testInput = readAllLines(inputFile);
                     }
 
-                    // fix line feeds for non unix os
-                    StringBuilder outFile = new StringBuilder();
-                    for (String line : Files.readAllLines(outputFile, Charset.defaultCharset())) {
-                        outFile.append(line);
-                        outFile.append(LF);
+                    Path outputFile = sourceFile.resolveSibling(baseName + OUTPUT_SUFFIX);
+                    String expectedOutput = "";
+                    if (Files.exists(outputFile)) {
+                        expectedOutput = readAllLines(outputFile);
                     }
-                    foundCases.add(new TestCase(c, baseName, sourceManager.get(inputFile.toString()), outFile.toString()));
+
+                    foundCases.add(new TestCase(c, baseName, sourceManager.get(sourceName, readAllLines(sourceFile)), testInput, expectedOutput));
                 }
                 return FileVisitResult.CONTINUE;
             }
@@ -138,27 +143,30 @@
         return foundCases;
     }
 
+    private static String readAllLines(Path file) throws IOException {
+        // fix line feeds for non unix os
+        StringBuilder outFile = new StringBuilder();
+        for (String line : Files.readAllLines(file, Charset.defaultCharset())) {
+            outFile.append(line).append(LF);
+        }
+        return outFile.toString();
+    }
+
     @Override
     protected void runChild(TestCase testCase, RunNotifier notifier) {
         notifier.fireTestStarted(testCase.name);
 
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         PrintStream printer = new PrintStream(out);
-        PrintStream origErr = System.err;
         try {
-            System.setErr(printer);
-            SLContext context = new SLContext(sourceManager, printer);
-            SLMain.run(context, testCase.input, null, REPEATS);
+            SLContext context = new SLContext(sourceManager, new BufferedReader(new StringReader(repeat(testCase.testInput, REPEATS))), printer);
+            SLMain.run(context, testCase.source, null, REPEATS);
 
             String actualOutput = new String(out.toByteArray());
-
             Assert.assertEquals(repeat(testCase.expectedOutput, REPEATS), actualOutput);
-        } catch (AssertionError e) {
-            notifier.fireTestFailure(new Failure(testCase.name, e));
         } catch (Throwable ex) {
             notifier.fireTestFailure(new Failure(testCase.name, ex));
         } finally {
-            System.setErr(origErr);
             notifier.fireTestFinished(testCase.name);
         }
     }
--- a/graal/com.oracle.truffle.sl.test/tests/Add.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Add.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,9 +1,9 @@
 function main() {  
-  print(3 + 4);  
-  print(3 + "4");  
-  print("3" + 4);  
-  print("3" + "4");  
-  print(3 + 4000000000000);  
-  print(3000000000000 + 4);  
-  print(3000000000000 + 4000000000000);  
+  println(3 + 4);  
+  println(3 + "4");  
+  println("3" + 4);  
+  println("3" + "4");  
+  println(3 + 4000000000000);  
+  println(3000000000000 + 4);  
+  println(3000000000000 + 4000000000000);  
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,12 +1,12 @@
 function main() {  
-  print(3 + 4 - 2);  
-  print(3 - 4 + 2);  
-  print(3 - 4 - 2);  
-  print(3 * 4 + 2);  
-  print(3 + 4 * 2);  
-  print(3 + (4 - 2));  
-  print(3 - (4 + 2));  
-  print(3 - (4 - 2));  
-  print(3 * (4 + 2));  
-  print(3 + (4 * 2));  
+  println(3 + 4 - 2);  
+  println(3 - 4 + 2);  
+  println(3 - 4 - 2);  
+  println(3 * 4 + 2);  
+  println(3 + 4 * 2);  
+  println(3 + (4 - 2));  
+  println(3 - (4 + 2));  
+  println(3 - (4 - 2));  
+  println(3 * (4 + 2));  
+  println(3 + (4 * 2));  
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/Builtins.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Builtins.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,4 +1,4 @@
 function main() {  
-  print("Hello World!");  
-  time();  
+  println("Hello World!");  
+  nanoTime();  
 }  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.input	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,15 @@
+i
+80
+c
+return cur + i;
+r
+c
+if (i <= 2) { return 1; } else { return prev + cur; }
+r
+i
+100
+r
+c
+if (i == 0) { return 1; } else { return cur * i; }
+r
+x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,35 @@
+available commands:
+x: exit
+c: define the calculation function with the parameters prev, cur, and i
+   prev and cur start with 0; i is the loop variable from 0 to n
+     example: 'return cur + i;' computes the sum of 1 to n
+     example: 'if (i == 0) { return 1; } else { return cur * i; }' computes the factorial of i
+     example: 'if (i <= 2) { return 1; } else { return prev + cur; }' computes the nth Fibonacci number
+i: define the number of iterations, i.e, the number n in the examples above
+r: Run the calculation loop often, and print the first and last result
+t: Run the calculation loop a couple of time, and print timing information for each run
+h: Print this help message
+
+cmd>
+n>
+cmd>
+function>
+cmd>
+** first: 3240
+** last:  3240
+cmd>
+function>
+cmd>
+** first: 23416728348467685
+** last:  23416728348467685
+cmd>
+n>
+cmd>
+** first: 354224848179261915075
+** last:  354224848179261915075
+cmd>
+function>
+cmd>
+** first: 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
+** last:  93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
+cmd>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/CalcShell.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,89 @@
+function iterations() {
+  return 80;
+}
+
+function calcLoop(n) {
+  i = 0;
+  prev = cur = 0;
+  while (i <= n) {
+    next = calc(prev, cur, i);
+    prev = cur;
+    cur = next;  
+    i = i + 1;
+  }  
+  return cur;  
+}
+
+function timing(n) {
+  i = 0;
+  while (i < 20) {
+    start = nanoTime();
+    calcLoop(n);
+    end = nanoTime();
+    i = i + 1;
+
+    println("** run " + i + ": " + (end - start) + " ns");
+  }
+}
+
+function run(n) {
+  firstResult = calcLoop(n);
+  println("** first: " + firstResult);
+  i = 0;
+  while (i < 100) {
+    calcLoop(n);
+    i = i + 1;
+  }
+  lastResult = calcLoop(n);
+  println("** last:  " + lastResult);
+  
+  if (firstResult != lastResult) {
+    println("ERROR: result not stable");
+  }
+}  
+
+function help() {
+  println("available commands:");
+  println("x: exit");
+  println("c: define the calculation function with the parameters prev, cur, and i");
+  println("   prev and cur start with 0; i is the loop variable from 0 to n");
+  println("     example: 'return cur + i;' computes the sum of 1 to n"); 
+  println("     example: 'if (i == 0) { return 1; } else { return cur * i; }' computes the factorial of i"); 
+  println("     example: 'if (i <= 2) { return 1; } else { return prev + cur; }' computes the nth Fibonacci number");
+  println("i: define the number of iterations, i.e, the number n in the examples above");
+  println("r: Run the calculation loop often, and print the first and last result");
+  println("t: Run the calculation loop a couple of time, and print timing information for each run");
+  println("h: Print this help message");
+  println("");
+}
+
+function main() {
+  help();
+  
+  while (1 == 1) {
+    println("cmd>");
+    cmd = readln();
+    if (cmd == "x" || cmd == "") {
+      return;
+    }
+    if (cmd == "h") {
+      help();
+    }
+    if (cmd == "c") {
+      println("function>");
+      code = readln();
+      defineFunction("function calc(prev, cur, i) { " + code + "}");
+    }
+    if (cmd == "t") {
+      timing(iterations());
+    }
+    if (cmd == "r") {
+      run(iterations());
+    }
+    if (cmd == "i") {
+      println("n>");
+      n = readln();
+      defineFunction("function iterations() { return " + n + "; }");
+    }
+  }
+}  
--- a/graal/com.oracle.truffle.sl.test/tests/Call.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Call.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -5,12 +5,12 @@
 function call(f, v) { return f(v); }
  
 function main() {  
-  print(ret(42));
-  print(dub(21));
-  print(inc(41));
-  print(dec(43));
-  print(call(ret, 42));
-  print(call(dub, 21));
-  print(call(inc, 41));
-  print(call(dec, 43));
+  println(ret(42));
+  println(dub(21));
+  println(inc(41));
+  println(dec(43));
+  println(call(ret, 42));
+  println(call(dub, 21));
+  println(call(inc, 41));
+  println(call(dec, 43));
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/Comparison.output	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Comparison.output	Wed Jan 29 20:45:43 2014 -0800
@@ -1,7 +1,54 @@
+<
+true
+false
+false
+true
+false
 true
 false
 false
+<=
+true
+false
+true
+true
+false
+true
+false
+true
+>
+false
+true
+false
 false
 true
 false
 true
+false
+>=
+false
+true
+true
+false
+true
+false
+true
+true
+==
+false
+false
+true
+false
+false
+false
+false
+true
+!=
+true
+true
+false
+true
+true
+true
+true
+false
--- a/graal/com.oracle.truffle.sl.test/tests/Comparison.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Comparison.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,9 +1,61 @@
 function main() {  
-  print(4 < 20);  
-  print(4 < "20");  
-  print("4" < 20);  
-  print("4" < "20");  
-  print(4 < 20000000000000);  
-  print(4000000000000 < 20);  
-  print(4000000000000 < 20000000000000);  
+  println("<");
+  println(4 < 20);  
+  println(40 < 2);  
+  println(4 < 4);  
+  println(4 < 200000000000000000000000000);  
+  println(40000000000000000000000000 < 20);  
+  println(40000000000000000000000000 < 200000000000000000000000000);  
+  println(400000000000000000000000000 < 20000000000000000000000000);  
+  println(40000000000000000000000000 < 40000000000000000000000000);  
+
+  println("<=");
+  println(4 <= 20);  
+  println(40 <= 2);  
+  println(4 <= 4);  
+  println(4 <= 200000000000000000000000000);  
+  println(40000000000000000000000000 <= 20);  
+  println(40000000000000000000000000 <= 200000000000000000000000000);  
+  println(400000000000000000000000000 <= 20000000000000000000000000);  
+  println(40000000000000000000000000 <= 40000000000000000000000000);  
+
+  println(">");
+  println(4 > 20);  
+  println(40 > 2);  
+  println(4 > 4);  
+  println(4 > 200000000000000000000000000);  
+  println(40000000000000000000000000 > 20);  
+  println(40000000000000000000000000 > 200000000000000000000000000);  
+  println(400000000000000000000000000 > 20000000000000000000000000);  
+  println(40000000000000000000000000 > 40000000000000000000000000);  
+
+  println(">=");
+  println(4 >= 20);  
+  println(40 >= 2);  
+  println(4 >= 4);  
+  println(4 >= 200000000000000000000000000);  
+  println(40000000000000000000000000 >= 20);  
+  println(40000000000000000000000000 >= 200000000000000000000000000);  
+  println(400000000000000000000000000 >= 20000000000000000000000000);  
+  println(40000000000000000000000000 >= 40000000000000000000000000);  
+
+  println("==");
+  println(4 == 20);  
+  println(40 == 2);  
+  println(4 == 4);  
+  println(4 == 200000000000000000000000000);  
+  println(40000000000000000000000000 == 20);  
+  println(40000000000000000000000000 == 200000000000000000000000000);  
+  println(400000000000000000000000000 == 20000000000000000000000000);  
+  println(40000000000000000000000000 == 40000000000000000000000000);  
+
+  println("!=");
+  println(4 != 20);  
+  println(40 != 2);  
+  println(4 != 4);  
+  println(4 != 200000000000000000000000000);  
+  println(40000000000000000000000000 != 20);  
+  println(40000000000000000000000000 != 200000000000000000000000000);  
+  println(400000000000000000000000000 != 20000000000000000000000000);  
+  println(40000000000000000000000000 != 40000000000000000000000000);  
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 function foo() {
-  print(test(40, 2));
+  println(test(40, 2));
 }
 
 function main() {
--- a/graal/com.oracle.truffle.sl.test/tests/Div.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Div.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,6 +1,6 @@
 function main() {  
-  print(4 / 2);  
-  print(4 / 4000000000000);  
-  print(3000000000000 / 3);  
-  print(3000000000000 / 3000000000000);  
+  println(4 / 2);  
+  println(4 / 4000000000000);  
+  println(3000000000000 / 3);  
+  println(3000000000000 / 3000000000000);  
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -13,5 +13,5 @@
 }
 
 function main() {  
-  print(fib(42));
+  println(fib(42));
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -3,5 +3,5 @@
   while (i < 1000) {  
     i = i + 1;  
   }  
-  print(i);  
+  println(i);  
 }  
--- a/graal/com.oracle.truffle.sl.test/tests/Mul.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Mul.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,6 +1,6 @@
 function main() {  
-  print(3 * 4);  
-  print(3 * 4000000000000);  
-  print(3000000000000 * 4);  
-  print(3000000000000 * 4000000000000);  
+  println(3 * 4);  
+  println(3 * 4000000000000);  
+  println(3000000000000 * 4);  
+  println(3000000000000 * 4000000000000);  
 }  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/Null.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,7 @@
+null
+true
+false
+false
+true
+false
+true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/Null.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,13 @@
+/* The easiest way to generate null: a function without a return statement implicitly returns null. */
+function null() {
+}
+
+function main() {  
+  println(null());  
+  println(null() == null());  
+  println(null() != null());  
+  println(null() == 42);  
+  println(null() != 42);  
+  println(null() == "42");  
+  println(null() != "42");  
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/String.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,8 @@
+snull
+snull
+sbar
+sfoo
+nulls
+nulls
+bars
+foos
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/String.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,18 @@
+function null() {
+}
+
+function foo() {
+  return "bar";
+}
+
+function main() {  
+  println("s" + null());  
+  println("s" + null);  
+  println("s" + foo());  
+  println("s" + foo);
+    
+  println(null() + "s");  
+  println(null() + "s");  
+  println(foo() + "s");  
+  println(foo + "s");
+}  
--- a/graal/com.oracle.truffle.sl.test/tests/Sub.sl	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl.test/tests/Sub.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -1,6 +1,6 @@
 function main() {  
-  print(3 - 4);  
-  print(3 - 4000000000000);  
-  print(3000000000000 - 4);  
-  print(3000000000000 - 4000000000000);  
+  println(3 - 4);  
+  println(3 - 4000000000000);  
+  println(3000000000000 - 4);  
+  println(3000000000000 - 4000000000000);  
 }  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError01.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,1 @@
+Type error at TypeError01.sl line 2 col 5: operation "-" not defined for Number 3, String "4"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError01.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,3 @@
+function main() {  
+  3 - "4";  
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError02.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,1 @@
+Type error at TypeError02.sl line 2 col 6: operation "if" not defined for String "4"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError02.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,3 @@
+function main() {  
+  if ("4") { }  
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,1 @@
+Type error at TypeError05.sl line 3 col 3: operation "call" not defined for Boolean true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError05.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,4 @@
+function main() {
+  f = 1 < 2;
+  f();  
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError06.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,1 @@
+Type error: operation "defineFunction" not defined for Number 3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError06.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,3 @@
+function main() {
+  defineFunction(3);
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError07.output	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,1 @@
+Type error: operation "defineFunction" not defined for NULL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/TypeError07.sl	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,3 @@
+function main() {
+  defineFunction();
+}  
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java	Wed Jan 29 20:45:43 2014 -0800
@@ -22,6 +22,11 @@
  */
 package com.oracle.truffle.sl;
 
+/**
+ * SL does not need a sophisticated error checking and reporting mechanism, so all unexpected
+ * conditions just abort execution. This exception class is used when we abort from within the SL
+ * implementation.
+ */
 public class SLException extends RuntimeException {
     private static final long serialVersionUID = -6799734410727348507L;
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,65 +23,223 @@
 package com.oracle.truffle.sl;
 
 import java.io.*;
+import java.math.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.sl.builtins.*;
+import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.call.*;
+import com.oracle.truffle.sl.nodes.controlflow.*;
+import com.oracle.truffle.sl.nodes.expression.*;
+import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.parser.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as
+ * simple and clean as possible in order to help understanding the ideas and concepts of Truffle.
+ * The language has first class functions, but no object model.
+ * <p>
+ * SL is dynamically typed, i.e., there are no type names specified by the programmer. SL is
+ * strongly typed, i.e., there is no automatic conversion between types. If an operation is not
+ * available for the types encountered at run time, a type error is reported and execution is
+ * stopped. For example, {@code 4 - "2"} results in a type error because subtraction is only defined
+ * for numbers.
+ * 
+ * <p>
+ * <b>Types:</b>
+ * <ul>
+ * <li>Number: arbitrary precision integer numbers. The implementation uses the Java primitive type
+ * {@code long} to represent numbers that fit into the 64 bit range, and {@link BigInteger} for
+ * numbers that exceed the range. Using a primitive type such as {@code long} is crucial for
+ * performance.
+ * <li>Boolean: implemented as the Java primitive type {@code boolean}.
+ * <li>String: implemented as the Java standard type {@link String}.
+ * <li>Function: implementation type {@link SLFunction}.
+ * <li>Null (with only one value {@code null}): implemented as the singleton
+ * {@link SLNull#SINGLETON}.
+ * </ul>
+ * The class {@link SLTypes} lists these types for the Truffle DSL, i.e., for type-specialized
+ * operations that are specified using Truffle DSL annotations.
+ * 
+ * <p>
+ * <b>Language concepts:</b>
+ * <ul>
+ * <li>Literals for {@link SLBigIntegerLiteralNode numbers} , {@link SLStringLiteralNode strings},
+ * and {@link SLFunctionLiteralNode functions}.
+ * <li>Basic arithmetic, logical, and comparison operations: {@link SLAddNode +}, {@link SLSubNode
+ * -}, {@link SLMulNode *}, {@link SLDivNode /}, {@link SLLogicalAndNode logical and},
+ * {@link SLLogicalOrNode logical or}, {@link SLEqualNode ==}, !=, {@link SLLessThanNode <},
+ * {@link SLLessOrEqualNode <=}, >, >=.
+ * <li>Local variables: local variables must be defined (via a {@link SLWriteLocalVariableNode
+ * write}) before they can be used (by a {@link SLReadLocalVariableNode read}). Local variables are
+ * not visible outside of the block where they were first defined.
+ * <li>Basic control flow statements: {@link SLBlockNode blocks}, {@link SLIfNode if},
+ * {@link SLWhileNode while} with {@link SLBreakNode break} and {@link SLContinueNode continue},
+ * {@link SLReturnNode return}.
+ * <li>Function calls: {@link SLCallNode calls} are efficiently implemented with
+ * {@link SLAbstractDispatchNode polymorphic inline caches}.
+ * </ul>
+ * 
+ * <p>
+ * <b>Syntax and parsing:</b><br>
+ * The syntax is described as an attributed grammar. The {@link Parser} and {@link Scanner} are
+ * automatically generated by the parser generator Coco/R (available from <a
+ * href="http://ssw.jku.at/coco/">http://ssw.jku.at/coco/</a>). The grammar contains semantic
+ * actions that build the AST for a method. To keep these semantic actions short, they are mostly
+ * calls to the {@link SLNodeFactory} that performs the actual node creation. All functions found in
+ * the SL source are added to the {@link SLFunctionRegistry}, which is accessible from the
+ * {@link SLContext}.
+ * 
+ * <p>
+ * <b>Builtin functions:</b><br>
+ * Library functions that are available to every SL source without prior definition are called
+ * builtin functions. They are added to the {@link SLFunctionRegistry} when the {@link SLContext} is
+ * created. There current builtin functions are
+ * <ul>
+ * <li>{@link SLReadlnBuiltin readln}: Read a String from the {@link SLContext#getInput() standard
+ * input}.
+ * <li>{@link SLPrintlnBuiltin println}: Write a value to the {@link SLContext#getOutput() standard
+ * output}.
+ * <li>{@link SLNanoTimeBuiltin nanoTime}: Returns the value of a high-resolution time, in
+ * nanoseconds.
+ * <li>{@link SLDefineFunctionBuiltin defineFunction}: Parses the functions provided as a String
+ * argument and adds them to the function registry. Functions that are already defined are replaced
+ * with the new version.
+ * </ul>
+ */
 public class SLMain {
 
-    private static final Object[] NO_ARGUMENTS = new Object[0];
+    /**
+     * 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) {
+        if (args.length == 0) {
+            throw new SLException("SL source file must be specified as the first argument");
+        }
+        String fileName = args[0];
+        int repeats = 1;
+        if (args.length >= 2) {
+            repeats = Integer.parseInt(args[1]);
+        }
 
-    public static void main(String[] args) {
         SourceManager sourceManager = new SourceManager();
-        Source source = sourceManager.get(args[0]);
-        SLContext context = new SLContext(sourceManager, System.err);
-        run(context, source, System.out, 1);
+        Source source = sourceManager.get(fileName);
+        SLContext context = new SLContext(sourceManager, new BufferedReader(new InputStreamReader(System.in)), System.out);
+        run(context, source, System.out, repeats);
     }
 
+    /**
+     * Parse and run the specified SL source. Factored out in a separate method so that it can also
+     * be used by the unit test harness.
+     */
     public static void run(SLContext context, Source source, PrintStream logOutput, int repeats) {
         if (logOutput != null) {
             logOutput.println("== running on " + Truffle.getRuntime().getName());
         }
 
+        /* Parse the SL source file. */
         Parser.parseSL(context, source);
+        /* Lookup our main entry point, which is per definition always named "main". */
         SLFunction main = context.getFunctionRegistry().lookup("main");
         if (main.getCallTarget() == null) {
-            throw new SLException("No function main() found.");
+            throw new SLException("No function main() defined in SL source file.");
         }
 
-        if (logOutput != null) {
-            printScript(context, logOutput);
-        }
+        /* Change to true if you want to see the AST on the console. */
+        boolean printASTToLog = false;
+
+        printScript("before execution", context, logOutput, printASTToLog);
         try {
             for (int i = 0; i < repeats; i++) {
                 long start = System.nanoTime();
-                Object result = main.getCallTarget().call(null, new SLArguments(NO_ARGUMENTS));
+                /* Call the main entry point, without any arguments. */
+                try {
+                    Object result = main.getCallTarget().call(null, new SLArguments(new Object[0]));
+                    if (result != SLNull.SINGLETON) {
+                        context.getOutput().println(result);
+                    }
+                } catch (UnsupportedSpecializationException ex) {
+                    context.getOutput().println(formatTypeError(ex));
+                }
                 long end = System.nanoTime();
 
-                if (result != SLNull.INSTANCE) {
-                    context.getPrintOutput().println(result);
-                }
-                if (logOutput != null) {
-                    logOutput.printf("== iteration %d: %.3f ms\n", (i + 1), (end - start) / 1000000.0);
+                if (logOutput != null && repeats > 1) {
+                    logOutput.println("== iteration " + (i + 1) + ": " + ((end - start) / 1000000) + " ms");
                 }
             }
 
         } finally {
-            if (logOutput != null) {
-                printScript(context, logOutput);
-            }
+            printScript("after execution", context, logOutput, printASTToLog);
         }
     }
 
-    private static void printScript(SLContext context, PrintStream logOutput) {
+    /**
+     * Dumps the AST of all functions to the IGV visualizer, via a socket connection. IGV can be
+     * started with the mx command "mx igv". Optionally, also prints the ASTs to the console.
+     */
+    private static void printScript(String groupName, SLContext context, PrintStream logOutput, boolean printASTToLog) {
+        GraphPrintVisitor graphPrinter = new GraphPrintVisitor();
+        graphPrinter.beginGroup(groupName);
         for (SLFunction function : context.getFunctionRegistry().getFunctions()) {
-            if (function.getCallTarget() != null) {
-                logOutput.println("=== function " + function.getName());
-                NodeUtil.printTree(logOutput, function.getCallTarget().getRootNode());
+            RootCallTarget callTarget = function.getCallTarget();
+            if (callTarget != null) {
+                graphPrinter.beginGraph(function.toString()).visit(callTarget.getRootNode());
+
+                if (logOutput != null && printASTToLog) {
+                    logOutput.println("=== " + function);
+                    NodeUtil.printTree(logOutput, callTarget.getRootNode());
+                }
             }
         }
+        graphPrinter.printToNetwork(true);
+    }
+
+    /**
+     * Provides a user-readable message for run-time type errors. SL is strongly typed, i.e., there
+     * are no automatic type conversions of values. Therefore, Truffle does the type checking for
+     * us: if no matching node specialization for the actual values is found, then we have a type
+     * error. Specialized nodes use the {@link UnsupportedSpecializationException} to report that no
+     * specialization was found. We therefore just have to convert the information encapsulated in
+     * this exception in a user-readable form.
+     */
+    private static String formatTypeError(UnsupportedSpecializationException ex) {
+        StringBuilder result = new StringBuilder();
+        result.append("Type error");
+        if (ex.getNode() != null && ex.getNode().getSourceSection() != null) {
+            SourceSection ss = ex.getNode().getSourceSection();
+            result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn());
+        }
+        result.append(": operation");
+        if (ex.getNode() != null && ex.getNode().getClass().getAnnotation(NodeInfo.class) != null) {
+            result.append(" \"").append(ex.getNode().getClass().getAnnotation(NodeInfo.class).shortName()).append("\"");
+        }
+        result.append(" not defined for");
+
+        String sep = " ";
+        for (Object value : ex.getSuppliedValues()) {
+            if (value != null) {
+                result.append(sep);
+                sep = ", ";
+
+                if (value instanceof Long || value instanceof BigInteger) {
+                    result.append("Number ").append(value);
+                } else if (value instanceof Boolean) {
+                    result.append("Boolean ").append(value);
+                } else if (value instanceof String) {
+                    result.append("String \"").append(value).append("\"");
+                } else if (value instanceof SLFunction) {
+                    result.append("Function ").append(value);
+                } else if (value == SLNull.SINGLETON) {
+                    result.append("NULL");
+                } else {
+                    result.append(value);
+                }
+            }
+        }
+        return result.toString();
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,12 +26,25 @@
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * Base class for all builtin functions. It contains the Truffle DSL annotation {@link NodeChild}
+ * that defines the function arguments.<br>
+ * Builtin functions need access to the {@link SLContext}. Instead of defining a Java field manually
+ * and setting it in a constructor, we use the Truffle DSL annotation {@link NodeField} that
+ * generates the field and constructor automatically.
+ * <p>
+ * The builitin 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.
+ */
+@NodeChild(value = "arguments", type = SLExpressionNode[].class)
 @NodeField(name = "context", type = SLContext.class)
-@NodeChild(value = "arguments", type = SLExpressionNode[].class)
 public abstract class SLBuiltinNode extends SLExpressionNode {
 
+    /**
+     * Accessor for the {@link SLContext}. The implementation of this method is generated
+     * automatically based on the {@link NodeField} annotation on the class.
+     */
     public abstract SLContext getContext();
-
-    public abstract SLExpressionNode[] getArguments();
-
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,13 +24,20 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.parser.*;
 
+/**
+ * Builtin function to define (or redefine) functions. The provided source code is parsed the same
+ * way as the initial source of the script, so the same syntax applies.
+ */
+@NodeInfo(shortName = "defineFunction")
 public abstract class SLDefineFunctionBuiltin extends SLBuiltinNode {
 
     @Specialization
     public String defineFunction(String code) {
-        Source source = getContext().getSourceManager().get("dynamic", code);
+        Source source = getContext().getSourceManager().get("[defineFunction]", code);
+        /* The same parsing code as for parsing the initial source. */
         Parser.parseSL(getContext(), source);
         return code;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNanoTimeBuiltin.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2014, 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.builtins;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Builtin function that returns the value of a high-resolution time, in nanoseconds.
+ */
+@NodeInfo(shortName = "nanoTime")
+public abstract class SLNanoTimeBuiltin extends SLBuiltinNode {
+
+    @Specialization
+    public long nanoTime() {
+        return System.nanoTime();
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintBuiltin.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.builtins;
-
-import com.oracle.truffle.api.dsl.*;
-
-public abstract class SLPrintBuiltin extends SLBuiltinNode {
-
-    @Specialization
-    public long print(long value) {
-        getContext().getPrintOutput().println(value);
-        return value;
-    }
-
-    @Specialization
-    public boolean print(boolean value) {
-        getContext().getPrintOutput().println(value);
-        return value;
-    }
-
-    @Specialization
-    public String print(String value) {
-        getContext().getPrintOutput().println(value);
-        return value;
-    }
-
-    @Specialization
-    public Object print(Object value) {
-        getContext().getPrintOutput().println(value.toString());
-        return value;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2014, 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.builtins;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * Builtin function to write a value to the {@link SLContext#getOutput() standard output}. The
+ * different specialization leverage the typed {@code println} methods available in Java, i.e.,
+ * primitive values are printed without converting them to a {@link String} first.
+ */
+@NodeInfo(shortName = "println")
+public abstract class SLPrintlnBuiltin extends SLBuiltinNode {
+
+    @Specialization
+    public long println(long value) {
+        getContext().getOutput().println(value);
+        return value;
+    }
+
+    @Specialization
+    public boolean println(boolean value) {
+        getContext().getOutput().println(value);
+        return value;
+    }
+
+    @Specialization
+    public String println(String value) {
+        getContext().getOutput().println(value);
+        return value;
+    }
+
+    @Specialization
+    public Object println(Object value) {
+        getContext().getOutput().println(value);
+        return value;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLReadlnBuiltin.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, 2014, 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.builtins;
+
+import java.io.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * Builtin function that reads a String from the {@link SLContext#getInput() standard input}.
+ */
+@NodeInfo(shortName = "readln")
+public abstract class SLReadlnBuiltin extends SLBuiltinNode {
+
+    @Specialization
+    public String readln() {
+        try {
+            String result = getContext().getInput().readLine();
+            if (result == null) {
+                /*
+                 * We do not have a sophisticated end of file handling, so returning an empty string
+                 * is a reasonable alternative. Note that the Java null value should never be used,
+                 * since it can interfere with the specialization logic in generated source code.
+                 */
+                result = "";
+            }
+            return result;
+        } catch (IOException ex) {
+            throw new SLException(ex.getMessage());
+        }
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLTimeBuiltin.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.builtins;
-
-import com.oracle.truffle.api.dsl.*;
-
-public abstract class SLTimeBuiltin extends SLBuiltinNode {
-
-    public static final long START_TIME = System.currentTimeMillis();
-
-    @Specialization
-    public long time() {
-        return System.nanoTime();
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,10 +24,11 @@
 
 import com.oracle.truffle.api.dsl.*;
 
+/**
+ * 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.
+ */
 @NodeChildren({@NodeChild("leftNode"), @NodeChild("rightNode")})
 public abstract class SLBinaryNode extends SLExpressionNode {
-
-    public boolean isString(Object a, Object b) {
-        return a instanceof String || b instanceof String;
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,14 +24,40 @@
 
 import java.math.*;
 
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * Base class for all SL nodes that produce a value and therefore benefit from type specialization.
+ * The annotation {@Link TypeSystemReference} specifies the SL types. Specifying it here
+ * defines the type system for all subclasses.
+ */
+@TypeSystemReference(SLTypes.class)
 public abstract class SLExpressionNode extends SLStatementNode {
 
+    /**
+     * The execute method when no specialization is possible. This is the most general case,
+     * therefore it must be provided by all subclasses.
+     */
     public abstract Object executeGeneric(VirtualFrame frame);
 
+    /**
+     * When we use an expression at places where a {@SLStatmentNode statement} is
+     * already sufficient, the return value is just discarded.
+     */
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        executeGeneric(frame);
+    }
+
+    /*
+     * Execute methods for specialized types. They all follow the same pattern: they call the
+     * generic execution method and then expect a result of their return type. Type-specialized
+     * subclasses overwrite the appropriate methods.
+     */
+
     public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
         return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame));
     }
@@ -52,24 +78,7 @@
         return SLTypesGen.SLTYPES.expectSLFunction(executeGeneric(frame));
     }
 
-    public Object[] executeArray(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.SLTYPES.expectObjectArray(executeGeneric(frame));
-    }
-
     public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
         return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
     }
-
-    public final boolean executeCondition(VirtualFrame frame) {
-        try {
-            return executeBoolean(frame);
-        } catch (UnexpectedResultException ex) {
-            throw new RuntimeException("Illegal type for condition: " + ex.getResult().getClass().getSimpleName());
-        }
-    }
-
-    @Override
-    public void executeVoid(VirtualFrame frame) {
-        executeGeneric(frame);
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,65 +22,53 @@
  */
 package com.oracle.truffle.sl.nodes;
 
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
-import com.oracle.truffle.sl.nodes.local.*;
-import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * The root of all SL execution trees. It is a Truffle requirement that the tree root extends the
+ * class {@link RootNode}. This class is used for both builtin and user-defined functions. For
+ * builtin functions, the {@link #bodyNode} is a subclass of {@link SLBuiltinNode}. For user-defined
+ * functions, the {@link #bodyNode} is a {@link SLFunctionBodyNode}.
+ */
 public final class SLRootNode extends RootNode {
 
-    @Child private SLExpressionNode body;
-
-    private final SLExpressionNode uninitializedBody;
-    private final String name;
-    private final boolean inlineImmediatly;
+    /** The function body that is executed, and specialized during execution. */
+    @Child private SLExpressionNode bodyNode;
 
-    public static RootCallTarget createFunction(String name, FrameDescriptor frameDescriptor, SLStatementNode body) {
-        SLFunctionBodyNode bodyContainer = new SLFunctionBodyNode(frameDescriptor, body);
-        SLRootNode root = new SLRootNode(frameDescriptor, bodyContainer, name, false);
-        return Truffle.getRuntime().createCallTarget(root);
-    }
+    /**
+     * A copy of the uninitialized body. When performing method inlining, it is beneficial to inline
+     * the unspecialized function body, so that it is specialized in the context of the caller. This
+     * makes the specializations of the inlined function more precise.
+     */
+    private final SLExpressionNode uninitializedBodyNode;
 
-    public static RootCallTarget createBuiltin(SLContext context, NodeFactory<? extends SLBuiltinNode> factory, String name) {
-        int argumentCount = factory.getExecutionSignature().size();
-        SLExpressionNode[] arguments = new SLExpressionNode[argumentCount];
-        for (int i = 0; i < arguments.length; i++) {
-            arguments[i] = new SLReadArgumentNode(i);
-        }
-        SLBuiltinNode buitinBody = factory.createNode(arguments, context);
-        SLRootNode root = new SLRootNode(new FrameDescriptor(), buitinBody, name, true);
-        return Truffle.getRuntime().createCallTarget(root);
-    }
+    /** The name of the function, for printing purposes only. */
+    private final String name;
 
-    private SLRootNode(FrameDescriptor frameDescriptor, SLExpressionNode body, String name, boolean inlineImmediatly) {
+    public SLRootNode(FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) {
         super(null, frameDescriptor);
-        this.uninitializedBody = NodeUtil.cloneNode(body);
-        this.body = adoptChild(body);
+        /* Deep copy the body before any specialization occurs during execution. */
+        this.uninitializedBodyNode = NodeUtil.cloneNode(bodyNode);
+        this.bodyNode = adoptChild(bodyNode);
         this.name = name;
-        this.inlineImmediatly = inlineImmediatly;
     }
 
     @Override
     public Object execute(VirtualFrame frame) {
-        return body.executeGeneric(frame);
-    }
-
-    public boolean isInlineImmediatly() {
-        return inlineImmediatly;
+        return bodyNode.executeGeneric(frame);
     }
 
     @Override
     public RootNode inline() {
-        return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBody), name, inlineImmediatly);
+        return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBodyNode), name);
     }
 
     @Override
     public int getInlineNodeCount() {
-        return NodeUtil.countNodes(uninitializedBody);
+        return NodeUtil.countNodes(uninitializedBodyNode);
     }
 
     @Override
@@ -88,12 +76,8 @@
         return true;
     }
 
-    public Node getUninitializedBody() {
-        return uninitializedBody;
-    }
-
     @Override
     public String toString() {
-        return "function " + name;
+        return "root " + name;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,17 +22,18 @@
  */
 package com.oracle.truffle.sl.nodes;
 
-import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
-@TypeSystemReference(SLTypes.class)
+/**
+ * The base class of all Truffle nodes for SL. All nodes (even expressions) can be used as
+ * statements, i.e., without returning a value. The {@link VirtualFrame} provides access to the
+ * local variables.
+ */
 public abstract class SLStatementNode extends Node {
 
+    /**
+     * Execute this node as as statement, where no return value is necessary.
+     */
     public abstract void executeVoid(VirtualFrame frame);
-
-    @Override
-    public String toString() {
-        return getEncapsulatingSourceSection() != null ? getEncapsulatingSourceSection().toString() : super.toString();
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,22 +25,47 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.runtime.*;
 
-@TypeSystem({long.class, BigInteger.class, boolean.class, String.class, SLFunction.class, SLNull.class, Object[].class})
-public class SLTypes {
+/**
+ * The type system of SL, as explained in {@link SLMain}. Based on the annotation {@link TypeSystem}
+ * , the Truffle DSL generates the subclass {@link SLTypesGen} with type test and type conversion
+ * methods for all types. In this class, we only cover types where the automatically generated ones
+ * would not be sufficient.
+ */
+@TypeSystem({long.class, BigInteger.class, boolean.class, String.class, SLFunction.class, SLNull.class})
+public abstract class SLTypes {
 
+    /**
+     * Example of a manually specified type check that replaces the automatically generated type
+     * check that the Truffle DSL would generate. For {@link SLNull}, we do not need an
+     * {@code instanceof} check, because we know that there is only a {@link SLNull#SINGLETON
+     * singleton} instance.
+     */
     @TypeCheck
     public boolean isSLNull(Object value) {
-        return SLNull.INSTANCE == value;
+        return value == SLNull.SINGLETON;
     }
 
+    /**
+     * Example of a manually specified type cast that replaces the automatically generated type cast
+     * that the Truffle DSL would generate. For {@link SLNull}, we do not need an actual cast,
+     * because we know that there is only a {@link SLNull#SINGLETON singleton} instance.
+     */
     @TypeCast
     public SLNull asSLNull(Object value) {
         assert isSLNull(value);
-        return SLNull.INSTANCE;
+        return SLNull.SINGLETON;
     }
 
+    /**
+     * Informs the Truffle DSL that a primitive {@code long} value can used in all specializations
+     * where a {@link BigInteger} is expected. This models the semantic of SL: It only has an
+     * arbitrary precision Number type (implemented as {@link BigInteger}, and {@code long} is only
+     * used as a performance optimization to avoid the costly {@link BigInteger} arithmetic for
+     * values that fit into a 64-bit primitive value.
+     */
     @ImplicitCast
     public BigInteger castBigInteger(long value) {
         return BigInteger.valueOf(value);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -26,9 +26,28 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
-abstract class SLAbstractDispatchNode extends Node {
+/**
+ * Before a call is executed the first time, the dispatch node is a
+ * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymprphic
+ * 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
+ * a single {@link SLGenericDispatchNode}. All this rewriting happens on runtime, based on profiling
+ * feedback of the actual execution.
+ * <p>
+ * Example of the chain of nodes ({@code C}: {@link SLCallNode}; {@code U}:
+ * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}:
+ * {@link SLGenericDispatchNode}):
+ * <ol>
+ * <li>After parsing: {@code C->U}
+ * <li>After execution of function {@code f1}: {@code C->D(f1)->U}
+ * <li>After execution of function {@code f2}: {@code C->D(f1)->D(f2)->U}
+ * <li>After execution of function {@code f3}: {@code C->G}
+ * </ol>
+ * */
+public abstract class SLAbstractDispatchNode extends Node {
 
     protected static final int INLINE_CACHE_SIZE = 2;
 
-    protected abstract Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments);
+    protected abstract Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments);
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLArgumentsNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.call;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.nodes.*;
-
-public final class SLArgumentsNode extends SLExpressionNode {
-
-    @Children private final SLExpressionNode[] arguments;
-
-    public SLArgumentsNode(SLExpressionNode[] arguments) {
-        this.arguments = adoptChildren(arguments);
-    }
-
-    public SLExpressionNode[] getArguments() {
-        return arguments;
-    }
-
-    @Override
-    public Object[] executeGeneric(VirtualFrame frame) {
-        return executeArray(frame);
-    }
-
-    @Override
-    @ExplodeLoop
-    public Object[] executeArray(VirtualFrame frame) {
-        Object[] argumentValues = new Object[arguments.length];
-        for (int i = 0; i < arguments.length; i++) {
-            argumentValues[i] = arguments[i].executeGeneric(frame);
-        }
-        return argumentValues;
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -22,15 +22,24 @@
  */
 package com.oracle.truffle.sl.nodes.call;
 
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * The node for a function call in SL. Since SL has first class functions, the {@link SLFunction
+ * target function} can be computed by an {@link #functionNode arbitrary expression}. This node is
+ * responsible for evaluating this expression, as well as evaluating the {@link #argumentNodes
+ * arguments}. The actual call dispatch is then delegated to a chain of
+ * {@link SLAbstractDispatchNode}s that form a polymorphic inline cache.
+ */
+@NodeInfo(shortName = "call")
 public final class SLCallNode extends SLExpressionNode {
 
     public static SLCallNode create(SLExpressionNode function, SLExpressionNode[] arguments) {
-        return new SLCallNode(function, arguments, new SLUninitializedCallNode());
+        return new SLCallNode(function, arguments, new SLUninitializedDispatchNode());
     }
 
     @Child protected SLExpressionNode functionNode;
@@ -46,12 +55,7 @@
     @Override
     @ExplodeLoop
     public Object executeGeneric(VirtualFrame frame) {
-        SLFunction function;
-        try {
-            function = functionNode.executeFunction(frame);
-        } catch (UnexpectedResultException e) {
-            throw new UnsupportedOperationException("Call to " + e.getMessage() + " not supported.");
-        }
+        SLFunction function = evaluateFunction(frame);
 
         Object[] argumentValues = new Object[argumentNodes.length];
         for (int i = 0; i < argumentNodes.length; i++) {
@@ -59,6 +63,23 @@
         }
         SLArguments arguments = new SLArguments(argumentValues);
 
-        return dispatchNode.executeCall(frame, function, arguments);
+        return dispatchNode.executeDispatch(frame, function, arguments);
+    }
+
+    private SLFunction evaluateFunction(VirtualFrame frame) {
+        try {
+            /*
+             * The function node must evaluate to a SLFunction value, so we call
+             * function-specialized method.
+             */
+            return functionNode.executeFunction(frame);
+        } catch (UnexpectedResultException ex) {
+            /*
+             * The function node evaluated to a non-function result. This is a type error in the SL
+             * program. We report it with the same exception that Truffle DSL generated nodes use to
+             * report type errors.
+             */
+            throw new UnsupportedSpecializationException(this, ex.getResult());
+        }
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -27,40 +27,86 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * An entry in the polymorphic inline cache.
+ */
 final class SLDirectDispatchNode extends SLAbstractDispatchNode {
 
-    protected final SLFunction cachedFunction;
-    protected final RootCallTarget cachedCallTarget;
-    protected final Assumption cachedCallTargetStable;
+    /** The cached function. */
+    private final SLFunction cachedFunction;
 
-    @Child protected CallNode callNode;
-    @Child protected SLAbstractDispatchNode nextNode;
+    /**
+     * {@link CallNode} is part of the Truffle API and handles all the steps necessary for method
+     * inlining: if the call is executed frequently and the callee is small, then the call is
+     * inlined, i.e., the call node is replaced with a copy of the callee's AST.
+     */
+    @Child private CallNode callCachedTargetNode;
+
+    /** Assumption that the {@link #callCachedTargetNode} is still valid. */
+    private final Assumption cachedTargetStable;
+
+    /**
+     * The next entry of the polymorphic inline cache, either another {@link SLDirectDispatchNode}
+     * or a {@link SLUninitializedDispatchNode}.
+     */
+    @Child private SLAbstractDispatchNode nextNode;
 
     protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) {
         this.cachedFunction = cachedFunction;
-        this.cachedCallTarget = cachedFunction.getCallTarget();
-        this.cachedCallTargetStable = cachedFunction.getCallTargetStable();
-        this.callNode = adoptChild(CallNode.create(cachedCallTarget));
+        this.callCachedTargetNode = adoptChild(CallNode.create(cachedFunction.getCallTarget()));
+        this.cachedTargetStable = cachedFunction.getCallTargetStable();
         this.nextNode = adoptChild(next);
     }
 
+    /**
+     * Perform the inline cache check. If it succeeds, execute the cached
+     * {@link #cachedTargetStable call target}; if it fails, defer to the next element in the chain.
+     * <p>
+     * Since SL is a quite simple language, the benefit of the inline cache is quite small: after
+     * checking that the actual function to be executed is the same as the
+     * {@link SLDirectDispatchNode#cachedFunction}, we can safely execute the cached call target.
+     * You can reasonably argue that caching the call target is overkill, since we could just
+     * retrieve it via {@code function.getCallTarget()}. However, in a more complex language the
+     * lookup of the call target is usually much more complicated than in SL. In addition, caching
+     * the call target allows method inlining.
+     */
     @Override
-    protected Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) {
+    protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) {
+        /*
+         * The inline cache check. Note that cachedFunction must be a final field so that the
+         * compiler can optimize the check.
+         */
         if (this.cachedFunction == function) {
+            /* Inline cache hit, we are safe to execute the cached call target. */
             try {
-                cachedCallTargetStable.check();
-                return callNode.call(frame.pack(), arguments);
+                /*
+                 * Support for function redefinition: When a function is redefined, the call target
+                 * maintained by the SLFunction object is change. To avoid a check for that, we use
+                 * an Assumption that is invalidated by the SLFunction when the change is performed.
+                 * Since checking an assumption is a no-op in compiled code, the line below does not
+                 * add any overhead during optimized execution.
+                 */
+                cachedTargetStable.check();
+
+                /*
+                 * Now we are really ready to perform the call. We use a Truffle CallNode for that,
+                 * because it does all the work for method inlining.
+                 */
+                return callCachedTargetNode.call(frame.pack(), arguments);
+
             } catch (InvalidAssumptionException ex) {
                 /*
-                 * Remove ourselfs from the polymorphic inline cache, so that we fail the check only
-                 * once.
+                 * The function has been redefined. Remove ourselfs 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
+                 * that requires that this node is part of the tree.
                  */
                 replace(nextNode);
-                /*
-                 * Execute the next node in the chain by falling out of the if block.
-                 */
+                /* Execute the next node in the chain by falling out of the if block. */
             }
         }
-        return nextNode.executeCall(frame, function, arguments);
+        /* Inline cache miss, defer to the next element in the chain. */
+        return nextNode.executeDispatch(frame, function, arguments);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2014, 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
@@ -25,10 +25,18 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.sl.runtime.*;
 
+/**
+ * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such
+ * calls are not optimized any further, e.g., no method inlining is performed.
+ */
 final class SLGenericDispatchNode extends SLAbstractDispatchNode {
 
     @Override
-    protected Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) {
+    protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) {
+        /*
+         * SL has a quite simple call lookup: just ask the function for the current call target, and
+         * call it.
+         */
         return function.getCallTarget().call(frame.pack(), arguments);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.call;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.sl.runtime.*;
-
-final class SLUninitializedCallNode extends SLAbstractDispatchNode {
-
-    @Override
-    protected Object executeCall(VirtualFrame frame, SLFunction function, SLArguments arguments) {
-        CompilerDirectives.transferToInterpreterAndInvalidate();
-
-        SLAbstractDispatchNode cur = this;
-        int depth = 0;
-        while (cur.getParent() instanceof SLAbstractDispatchNode) {
-            cur = (SLAbstractDispatchNode) cur.getParent();
-            depth++;
-        }
-        SLCallNode callNode = (SLCallNode) cur.getParent();
-
-        SLAbstractDispatchNode specialized;
-        if (depth < INLINE_CACHE_SIZE) {
-            SLAbstractDispatchNode next = new SLUninitializedCallNode();
-            SLAbstractDispatchNode direct = new SLDirectDispatchNode(next, function);
-            specialized = replace(direct);
-        } else {
-            SLAbstractDispatchNode generic = new SLGenericDispatchNode();
-            specialized = callNode.dispatchNode.replace(generic);
-        }
-
-        return specialized.executeCall(frame, function, arguments);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2013, 2014, 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.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * The last entry of a polymorphic inline cache.
+ */
+final class SLUninitializedDispatchNode extends SLAbstractDispatchNode {
+
+    /**
+     * When we reach this method, all the previous cache entries did not match the function. If the
+     * cache is still small enough, we extend it by adding another {@link SLDirectDispatchNode}. If
+     * the cache reached its maximum size, we replace the whole dispatch chain with a
+     * {@link SLGenericDispatchNode}.
+     */
+    @Override
+    protected Object executeDispatch(VirtualFrame frame, SLFunction function, SLArguments arguments) {
+        /* The following code modifies the AST, so compiled code must be invalidated. */
+        CompilerDirectives.transferToInterpreterAndInvalidate();
+
+        /*
+         * Count the number of SLDirectDispatchNodes we already have in the cache. We walk the chain
+         * of parent nodes until we hit the SLCallNode. We know that a SLCallNode is always present.
+         */
+        Node cur = this;
+        int depth = 0;
+        while (cur.getParent() instanceof SLAbstractDispatchNode) {
+            cur = cur.getParent();
+            depth++;
+        }
+        SLCallNode callNode = (SLCallNode) cur.getParent();
+
+        SLAbstractDispatchNode specialized;
+        if (function.getCallTarget() == null) {
+            /* Corner case: the function is not defined, so report an error to the user. */
+            throw new SLException("Call of undefined function: " + function.getName());
+
+        } else if (depth < INLINE_CACHE_SIZE) {
+            /* 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. */
+            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. */
+            specialized = callNode.dispatchNode.replace(generic);
+        }
+
+        /*
+         * Execute the newly created node perform the actual dispatch. That saves us from
+         * duplicating the actual call logic here.
+         */
+        return specialized.executeDispatch(frame, function, arguments);
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,18 +26,19 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "block")
 public class SLBlockNode extends SLStatementNode {
 
-    @Children private final SLStatementNode[] statements;
+    @Children private final SLStatementNode[] bodyNodes;
 
-    public SLBlockNode(SLStatementNode[] statements) {
-        this.statements = adoptChildren(statements);
+    public SLBlockNode(SLStatementNode[] bodyNodes) {
+        this.bodyNodes = adoptChildren(bodyNodes);
     }
 
     @Override
     @ExplodeLoop
     public void executeVoid(VirtualFrame frame) {
-        for (SLStatementNode statement : statements) {
+        for (SLStatementNode statement : bodyNodes) {
             statement.executeVoid(frame);
         }
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,8 +23,10 @@
 package com.oracle.truffle.sl.nodes.controlflow;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "break")
 public final class SLBreakNode extends SLStatementNode {
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,8 +23,10 @@
 package com.oracle.truffle.sl.nodes.controlflow;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "continue")
 public final class SLContinueNode extends SLStatementNode {
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,38 +24,31 @@
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+@NodeInfo(shortName = "body")
 public class SLFunctionBodyNode extends SLExpressionNode {
 
-    @Child private SLStatementNode body;
-
-    private FrameDescriptor frameDescriptor;
+    @Child private SLStatementNode bodyNode;
 
-    public SLFunctionBodyNode(FrameDescriptor frameDescriptor, SLStatementNode body) {
-        this.frameDescriptor = frameDescriptor;
-        this.body = adoptChild(body);
+    private final BranchProfile exceptionTaken = new BranchProfile();
+    private final BranchProfile nullTaken = new BranchProfile();
+
+    public SLFunctionBodyNode(SLStatementNode bodyNode) {
+        this.bodyNode = adoptChild(bodyNode);
     }
 
     @Override
     public Object executeGeneric(VirtualFrame frame) {
         try {
-            body.executeVoid(frame);
+            bodyNode.executeVoid(frame);
         } catch (SLReturnException ex) {
+            exceptionTaken.enter();
             return ex.getResult();
         }
-        return SLNull.INSTANCE;
-    }
-
-    @Override
-    public Node copy() {
-        SLFunctionBodyNode copy = (SLFunctionBodyNode) super.copy();
-        copy.frameDescriptor = frameDescriptor.shallowCopy();
-        return copy;
-    }
-
-    public FrameDescriptor getFrameDescriptor() {
-        return frameDescriptor;
+        nullTaken.enter();
+        return SLNull.SINGLETON;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,10 +22,13 @@
  */
 package com.oracle.truffle.sl.nodes.controlflow;
 
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "if")
 public class SLIfNode extends SLStatementNode {
     @Child private SLExpressionNode conditionNode;
     @Child private SLStatementNode thenPartNode;
@@ -42,7 +45,7 @@
 
     @Override
     public void executeVoid(VirtualFrame frame) {
-        if (conditionNode.executeCondition(frame)) {
+        if (evaluateCondition(frame)) {
             thenTaken.enter();
             thenPartNode.executeVoid(frame);
         } else {
@@ -52,4 +55,21 @@
             }
         }
     }
+
+    private boolean evaluateCondition(VirtualFrame frame) {
+        try {
+            /*
+             * The condition must evaluate to a boolean value, so we call boolean-specialized
+             * method.
+             */
+            return conditionNode.executeBoolean(frame);
+        } catch (UnexpectedResultException ex) {
+            /*
+             * The condition evaluated to a non-boolean result. This is a type error in the SL
+             * program. We report it with the same exception that Truffle DSL generated nodes use to
+             * report type errors.
+             */
+            throw new UnsupportedSpecializationException(this, ex.getResult());
+        }
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,19 +23,27 @@
 package com.oracle.truffle.sl.nodes.controlflow;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
 
+@NodeInfo(shortName = "return")
 public class SLReturnNode extends SLStatementNode {
 
-    @Child private SLExpressionNode expr;
+    @Child private SLExpressionNode valueNode;
 
-    public SLReturnNode(SLExpressionNode expr) {
-        this.expr = adoptChild(expr);
+    public SLReturnNode(SLExpressionNode valueNode) {
+        this.valueNode = adoptChild(valueNode);
     }
 
     @Override
     public void executeVoid(VirtualFrame frame) {
-        Object result = expr.executeGeneric(frame);
+        Object result;
+        if (valueNode != null) {
+            result = valueNode.executeGeneric(frame);
+        } else {
+            result = SLNull.SINGLETON;
+        }
         throw new SLReturnException(result);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,29 +22,37 @@
  */
 package com.oracle.truffle.sl.nodes.controlflow;
 
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.utilities.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "while")
 public class SLWhileNode extends SLStatementNode {
 
-    @Child private SLExpressionNode condition;
-    @Child private SLStatementNode body;
+    @Child private SLExpressionNode conditionNode;
+    @Child private SLStatementNode bodyNode;
 
     private final BranchProfile continueTaken = new BranchProfile();
     private final BranchProfile breakTaken = new BranchProfile();
 
-    public SLWhileNode(SLExpressionNode condition, SLStatementNode body) {
-        this.condition = adoptChild(condition);
-        this.body = adoptChild(body);
+    public SLWhileNode(SLExpressionNode conditionNode, SLStatementNode bodyNode) {
+        this.conditionNode = adoptChild(conditionNode);
+        this.bodyNode = adoptChild(bodyNode);
     }
 
     @Override
     public void executeVoid(VirtualFrame frame) {
+        int count = 0;
         try {
-            while (condition.executeCondition(frame)) {
+            while (evaluateCondition(frame)) {
                 try {
-                    body.executeVoid(frame);
+                    bodyNode.executeVoid(frame);
+                    if (CompilerDirectives.inInterpreter()) {
+                        count++;
+                    }
                 } catch (SLContinueException ex) {
                     continueTaken.enter();
                     /* Fall through to next loop iteration. */
@@ -53,6 +61,34 @@
         } catch (SLBreakException ex) {
             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.
+                 */
+                RootNode root = getRootNode();
+                if (root.getCallTarget() instanceof LoopCountReceiver) {
+                    ((LoopCountReceiver) root.getCallTarget()).reportLoopCount(count);
+                }
+            }
+        }
+    }
+
+    private boolean evaluateCondition(VirtualFrame frame) {
+        try {
+            /*
+             * The condition must evaluate to a boolean value, so we call boolean-specialized
+             * method.
+             */
+            return conditionNode.executeBoolean(frame);
+        } catch (UnexpectedResultException ex) {
+            /*
+             * The condition evaluated to a non-boolean result. This is a type error in the SL
+             * program. We report it with the same exception that Truffle DSL generated nodes use to
+             * report type errors.
+             */
+            throw new UnsupportedSpecializationException(this, ex.getResult());
         }
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,27 +26,33 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "+")
 public abstract class SLAddNode extends SLBinaryNode {
 
     @Specialization(rewriteOn = ArithmeticException.class)
-    long add(long left, long right) {
+    protected long add(long left, long right) {
         return ExactMath.addExact(left, right);
     }
 
     @Specialization
-    BigInteger add(BigInteger left, BigInteger right) {
+    protected BigInteger add(BigInteger left, BigInteger right) {
         return left.add(right);
     }
 
     @Specialization
-    String add(String left, String right) {
+    protected String add(String left, String right) {
         return left + right;
     }
 
     @Specialization(guards = "isString")
-    String add(Object left, Object right) {
+    protected String add(Object left, Object right) {
         return left.toString() + right.toString();
     }
+
+    protected boolean isString(Object a, Object b) {
+        return a instanceof String || b instanceof String;
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,8 +25,10 @@
 import java.math.*;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "const")
 public final class SLBigIntegerLiteralNode extends SLExpressionNode {
 
     private final BigInteger value;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,17 +25,19 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "/")
 public abstract class SLDivNode extends SLBinaryNode {
 
     @Specialization(rewriteOn = ArithmeticException.class)
-    long div(long left, long right) {
+    protected long div(long left, long right) {
         return left / right;
     }
 
     @Specialization
-    BigInteger div(BigInteger left, BigInteger right) {
+    protected BigInteger div(BigInteger left, BigInteger right) {
         return left.divide(right);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,23 +22,58 @@
  */
 package com.oracle.truffle.sl.nodes.expression;
 
+import java.math.*;
+
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
 
+@NodeInfo(shortName = "==")
 public abstract class SLEqualNode extends SLBinaryNode {
 
     @Specialization
-    public boolean equal(long left, long right) {
+    protected boolean equal(long left, long right) {
+        return left == right;
+    }
+
+    @Specialization
+    protected boolean equal(BigInteger left, BigInteger right) {
+        return left.equals(right);
+    }
+
+    @Specialization
+    protected boolean equal(boolean left, boolean right) {
         return left == right;
     }
 
     @Specialization
-    public boolean equal(boolean left, boolean right) {
+    protected boolean equal(String left, String right) {
+        return left.equals(right);
+    }
+
+    @Specialization
+    protected boolean equal(SLFunction left, SLFunction right) {
+        /*
+         * Our function registry maintains one canonical SLFunction object per function name, so we
+         * do not need equals().
+         */
+        return left == right;
+    }
+
+    @Specialization
+    protected boolean equal(SLNull left, SLNull right) {
+        /* There is only the singleton instance of SLNull, so we do not need equals(). */
         return left == right;
     }
 
     @Generic
-    public boolean equal(Object left, Object right) {
-        return left.equals(right);
+    protected boolean equal(Object left, Object right) {
+        /*
+         * We covered all the cases that can return true in specializations. If we compare two
+         * values with different types, no specialization matches and we end up here.
+         */
+        assert !left.equals(right);
+        return false;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,9 +23,11 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
+@NodeInfo(shortName = "func")
 public final class SLFunctionLiteralNode extends SLExpressionNode {
 
     private final SLFunction value;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,22 +25,19 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "<=")
 public abstract class SLLessOrEqualNode extends SLBinaryNode {
 
     @Specialization
-    public boolean lessOrEqual(long left, long right) {
+    protected boolean lessOrEqual(long left, long right) {
         return left <= right;
     }
 
     @Specialization
-    public boolean lessOrEqual(BigInteger left, BigInteger right) {
+    protected boolean lessOrEqual(BigInteger left, BigInteger right) {
         return left.compareTo(right) <= 0;
     }
-
-    @Specialization(guards = "isString")
-    public boolean lessOrEqual(Object left, Object right) {
-        return left.toString().compareTo(right.toString()) <= 0;
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,22 +25,19 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "<")
 public abstract class SLLessThanNode extends SLBinaryNode {
 
     @Specialization
-    public boolean lessThan(long left, long right) {
+    protected boolean lessThan(long left, long right) {
         return left < right;
     }
 
     @Specialization
-    public boolean lessThan(BigInteger left, BigInteger right) {
+    protected boolean lessThan(BigInteger left, BigInteger right) {
         return left.compareTo(right) < 0;
     }
-
-    @Specialization(guards = "isString")
-    public boolean lessThan(Object left, Object right) {
-        return left.toString().compareTo(right.toString()) < 0;
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,28 +23,25 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "&&")
 @SuppressWarnings("unused")
 public abstract class SLLogicalAndNode extends SLBinaryNode {
 
     @ShortCircuit("rightNode")
-    public boolean needsRightNode(boolean left) {
+    protected boolean needsRightNode(boolean left) {
         return left;
     }
 
     @ShortCircuit("rightNode")
-    public boolean needsRightNode(Object left) {
+    protected boolean needsRightNode(Object left) {
         return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue());
     }
 
     @Specialization
-    public boolean doBoolean(boolean left, boolean hasRight, boolean right) {
+    protected boolean doBoolean(boolean left, boolean hasRight, boolean right) {
         return left && right;
     }
-
-    @Generic
-    public Object doGeneric(Object left, boolean hasRight, Object right) {
-        throw new RuntimeException("operation not defined for type " + left.getClass().getSimpleName());
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2014, 2014, 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.nodes.expression;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.nodes.*;
+
+@NodeChild("valueNode")
+@NodeInfo(shortName = "!")
+public abstract class SLLogicalNotNode extends SLExpressionNode {
+
+    @Specialization
+    protected boolean doBoolean(boolean value) {
+        return !value;
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,28 +23,25 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "||")
 @SuppressWarnings("unused")
 public abstract class SLLogicalOrNode extends SLBinaryNode {
 
     @ShortCircuit("rightNode")
-    public boolean needsRightNode(boolean left) {
+    protected boolean needsRightNode(boolean left) {
         return !left;
     }
 
     @ShortCircuit("rightNode")
-    public boolean needsRightNode(Object left) {
+    protected boolean needsRightNode(Object left) {
         return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue());
     }
 
     @Specialization
-    public boolean doBoolean(boolean left, boolean hasRight, boolean right) {
+    protected boolean doBoolean(boolean left, boolean hasRight, boolean right) {
         return left || right;
     }
-
-    @Generic
-    public Object doGeneric(Object left, boolean hasRight, Object right) {
-        throw new RuntimeException("operation not defined for type " + left.getClass().getSimpleName());
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,6 +26,7 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "const")
 public final class SLLongLiteralNode extends SLExpressionNode {
 
     private final long value;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,17 +26,19 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "*")
 public abstract class SLMulNode extends SLBinaryNode {
 
     @Specialization(rewriteOn = ArithmeticException.class)
-    long mul(long left, long right) {
+    protected long mul(long left, long right) {
         return ExactMath.multiplyExact(left, right);
     }
 
     @Specialization
-    BigInteger mul(BigInteger left, BigInteger right) {
+    protected BigInteger mul(BigInteger left, BigInteger right) {
         return left.multiply(right);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLNotEqualNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.expression;
-
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.sl.nodes.*;
-
-public abstract class SLNotEqualNode extends SLBinaryNode {
-
-    @Specialization
-    public boolean notEqual(long left, long right) {
-        return left != right;
-    }
-
-    @Specialization
-    public boolean notEqual(boolean left, boolean right) {
-        return left != right;
-    }
-
-    @Generic
-    public boolean equal(Object left, Object right) {
-        return !left.equals(right);
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -23,8 +23,10 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "const")
 public final class SLStringLiteralNode extends SLExpressionNode {
 
     private final String value;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -26,17 +26,19 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 
+@NodeInfo(shortName = "-")
 public abstract class SLSubNode extends SLBinaryNode {
 
     @Specialization(rewriteOn = ArithmeticException.class)
-    long sub(long left, long right) {
+    protected long sub(long left, long right) {
         return ExactMath.subtractExact(left, right);
     }
 
     @Specialization
-    BigInteger sub(BigInteger left, BigInteger right) {
+    protected BigInteger sub(BigInteger left, BigInteger right) {
         return left.subtract(right);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/ReadLocalNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.local;
-
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.sl.nodes.*;
-
-@PolymorphicLimit(1)
-public abstract class ReadLocalNode extends SLExpressionNode {
-
-    private final FrameSlot slot;
-
-    public ReadLocalNode(FrameSlot slot) {
-        this.slot = slot;
-    }
-
-    public ReadLocalNode(ReadLocalNode specialized) {
-        this(specialized.slot);
-    }
-
-    @Specialization(rewriteOn = {FrameSlotTypeException.class})
-    public long readLong(VirtualFrame frame) throws FrameSlotTypeException {
-        return frame.getLong(slot);
-    }
-
-    @Specialization(rewriteOn = {FrameSlotTypeException.class})
-    public boolean readBoolean(VirtualFrame frame) throws FrameSlotTypeException {
-        return frame.getBoolean(slot);
-    }
-
-    @Specialization(rewriteOn = {FrameSlotTypeException.class})
-    public Object readObject(VirtualFrame frame) throws FrameSlotTypeException {
-        return frame.getObject(slot);
-    }
-
-    @Generic
-    public Object doGeneric(VirtualFrame frame) {
-        return frame.getValue(slot);
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -31,7 +31,7 @@
 
     private final int index;
 
-    private final BranchProfile outOfBounds = new BranchProfile();
+    private final BranchProfile outOfBoundsTaken = new BranchProfile();
 
     public SLReadArgumentNode(int index) {
         this.index = index;
@@ -43,8 +43,8 @@
         if (index < args.length) {
             return args[index];
         } else {
-            outOfBounds.enter();
-            return SLNull.INSTANCE;
+            outOfBoundsTaken.enter();
+            return SLNull.SINGLETON;
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 2014, 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.nodes.local;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.sl.nodes.*;
+
+@PolymorphicLimit(1)
+@NodeField(name = "slot", type = FrameSlot.class)
+public abstract class SLReadLocalVariableNode extends SLExpressionNode {
+
+    protected abstract FrameSlot getSlot();
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    protected long readLong(VirtualFrame frame) throws FrameSlotTypeException {
+        return frame.getLong(getSlot());
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    protected boolean readBoolean(VirtualFrame frame) throws FrameSlotTypeException {
+        return frame.getBoolean(getSlot());
+    }
+
+    @Specialization(rewriteOn = {FrameSlotTypeException.class})
+    protected Object readObject(VirtualFrame frame) throws FrameSlotTypeException {
+        return frame.getObject(getSlot());
+    }
+
+    @Generic
+    protected Object readGeneric(VirtualFrame frame) {
+        return frame.getValue(getSlot());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Wed Jan 29 20:45:43 2014 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, 2014, 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.nodes.local;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.sl.nodes.*;
+
+@NodeChild(value = "valueNode")
+@NodeField(name = "slot", type = FrameSlot.class)
+public abstract class SLWriteLocalVariableNode extends SLExpressionNode {
+
+    protected abstract FrameSlot getSlot();
+
+    @Specialization(guards = "isLongKind")
+    protected long write(VirtualFrame frame, long value) {
+        frame.setLong(getSlot(), value);
+        return value;
+    }
+
+    @Specialization(guards = "isBooleanKind")
+    protected boolean write(VirtualFrame frame, boolean value) {
+        frame.setBoolean(getSlot(), value);
+        return value;
+    }
+
+    @Specialization
+    protected Object write(VirtualFrame frame, Object value) {
+        if (getSlot().getKind() != FrameSlotKind.Object) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getSlot().setKind(FrameSlotKind.Object);
+        }
+        frame.setObject(getSlot(), value);
+        return value;
+    }
+
+    protected boolean isLongKind() {
+        return isKind(FrameSlotKind.Long);
+    }
+
+    protected boolean isBooleanKind() {
+        return isKind(FrameSlotKind.Boolean);
+    }
+
+    private boolean isKind(FrameSlotKind kind) {
+        if (getSlot().getKind() == kind) {
+            return true;
+        } else if (getSlot().getKind() == FrameSlotKind.Illegal) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
+            getSlot().setKind(kind);
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/WriteLocalNode.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.local;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.sl.nodes.*;
-
-@NodeChild(value = "rightNode", type = SLExpressionNode.class)
-public abstract class WriteLocalNode extends SLExpressionNode {
-
-    private final FrameSlot slot;
-
-    public WriteLocalNode(FrameSlot slot) {
-        this.slot = slot;
-    }
-
-    public WriteLocalNode(WriteLocalNode node) {
-        this(node.slot);
-    }
-
-    @Specialization(guards = "isLongKind")
-    protected final long write(VirtualFrame frame, long right) {
-        frame.setLong(slot, right);
-        return right;
-    }
-
-    @Specialization(guards = "isBooleanKind")
-    protected final boolean write(VirtualFrame frame, boolean right) {
-        frame.setBoolean(slot, right);
-        return right;
-    }
-
-    @Specialization(guards = "isObjectKind")
-    protected final Object writeGeneric(VirtualFrame frame, Object right) {
-        frame.setObject(slot, right);
-        return right;
-    }
-
-    protected final boolean isLongKind() {
-        return isKind(FrameSlotKind.Long);
-    }
-
-    protected final boolean isBooleanKind() {
-        return isKind(FrameSlotKind.Boolean);
-    }
-
-    protected final boolean isObjectKind() {
-        if (slot.getKind() != FrameSlotKind.Object) {
-            CompilerDirectives.transferToInterpreter();
-            slot.setKind(FrameSlotKind.Object);
-        }
-        return true;
-    }
-
-    private boolean isKind(FrameSlotKind kind) {
-        return slot.getKind() == kind || initialSetKind(kind);
-    }
-
-    private boolean initialSetKind(FrameSlotKind kind) {
-        if (slot.getKind() == FrameSlotKind.Illegal) {
-            CompilerDirectives.transferToInterpreter();
-            slot.setKind(kind);
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -21,5 +21,4 @@
  * questions.
  */
 
- // The content of this file is automatically generated. DO NOT EDIT.
-
+// The content of this file is automatically generated. DO NOT EDIT.
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame	Wed Jan 29 20:45:43 2014 -0800
@@ -53,7 +53,7 @@
     -->declarations
     public Parser(SLContext context, Source source) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source, this);
+        this.factory = new SLNodeFactory(context, source);
         errors = new Errors();
     }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -55,7 +55,7 @@
     
     public Parser(SLContext context, Source source) {
         this.scanner = new Scanner(source.getInputStream());
-        this.factory = new SLNodeFactory(context, source, this);
+        this.factory = new SLNodeFactory(context, source);
         errors = new Errors();
     }
 
@@ -133,20 +133,18 @@
 	void Function() {
 		Expect(4);
 		Expect(1);
-		String name = t.val; 
+		factory.startFunction(t); 
 		Expect(5);
-		List<String> parameters = new ArrayList<>(); 
 		if (la.kind == 1) {
 			Get();
-			parameters.add(t.val); 
+			factory.addFormalParameter(t); 
 			while (la.kind == 6) {
 				Get();
 				Expect(1);
-				parameters.add(t.val); 
+				factory.addFormalParameter(t); 
 			}
 		}
 		Expect(7);
-		factory.startFunction(name, parameters); 
 		SLStatementNode body = Block();
 		factory.finishFunction(body); 
 	}
@@ -154,14 +152,14 @@
 	SLStatementNode  Block() {
 		SLStatementNode  result;
 		factory.startBlock();
-		List<SLStatementNode> statements = new ArrayList<>(); 
+		List<SLStatementNode> body = new ArrayList<>(); 
 		Expect(8);
 		while (StartOf(1)) {
-			SLStatementNode statement = Statement();
-			statements.add(statement); 
+			SLStatementNode s = Statement();
+			body.add(s); 
 		}
 		Expect(9);
-		result = factory.finishBlock(statements); 
+		result = factory.finishBlock(body); 
 		return result;
 	}
 
@@ -169,23 +167,23 @@
 		SLStatementNode  result;
 		result = null; 
 		switch (la.kind) {
-		case 15: {
+		case 13: {
 			result = WhileStatement();
 			break;
 		}
 		case 10: {
 			Get();
-			result = factory.createBreak(); 
+			result = factory.createBreak(t); 
 			Expect(11);
 			break;
 		}
 		case 12: {
 			Get();
-			result = factory.createContinue(); 
+			result = factory.createContinue(t); 
 			Expect(11);
 			break;
 		}
-		case 13: {
+		case 14: {
 			result = IfStatement();
 			break;
 		}
@@ -205,37 +203,43 @@
 
 	SLStatementNode  WhileStatement() {
 		SLStatementNode  result;
-		Expect(15);
+		Expect(13);
 		Expect(5);
+		Token whileToken = t; 
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode body = Block();
-		result = factory.createWhile(condition, body); 
+		result = factory.createWhile(whileToken, condition, body); 
 		return result;
 	}
 
 	SLStatementNode  IfStatement() {
 		SLStatementNode  result;
-		Expect(13);
+		Expect(14);
 		Expect(5);
+		Token ifToken = t; 
 		SLExpressionNode condition = Expression();
 		Expect(7);
 		SLStatementNode thenPart = Block();
 		SLStatementNode elsePart = null; 
-		if (la.kind == 14) {
+		if (la.kind == 15) {
 			Get();
 			elsePart = Block();
 		}
-		result = factory.createIf(condition, thenPart, elsePart); 
+		result = factory.createIf(ifToken, condition, thenPart, elsePart); 
 		return result;
 	}
 
 	SLStatementNode  ReturnStatement() {
 		SLStatementNode  result;
 		Expect(16);
-		SLExpressionNode value = Expression();
+		Token returnToken = t;
+		SLExpressionNode value = null; 
+		if (StartOf(2)) {
+			value = Expression();
+		}
+		result = factory.createReturn(returnToken, value); 
 		Expect(11);
-		result = factory.createReturn(value); 
 		return result;
 	}
 
@@ -244,7 +248,7 @@
 		result = LogicTerm();
 		while (la.kind == 17) {
 			Get();
-			String op = t.val; 
+			Token op = t; 
 			SLExpressionNode right = LogicTerm();
 			result = factory.createBinary(op, result, right); 
 		}
@@ -256,7 +260,7 @@
 		result = LogicFactor();
 		while (la.kind == 18) {
 			Get();
-			String op = t.val; 
+			Token op = t; 
 			SLExpressionNode right = LogicFactor();
 			result = factory.createBinary(op, result, right); 
 		}
@@ -266,7 +270,7 @@
 	SLExpressionNode  LogicFactor() {
 		SLExpressionNode  result;
 		result = Arithmetic();
-		if (StartOf(2)) {
+		if (StartOf(3)) {
 			switch (la.kind) {
 			case 19: {
 				Get();
@@ -293,7 +297,7 @@
 				break;
 			}
 			}
-			String op = t.val; 
+			Token op = t; 
 			SLExpressionNode right = Arithmetic();
 			result = factory.createBinary(op, result, right); 
 		}
@@ -309,7 +313,7 @@
 			} else {
 				Get();
 			}
-			String op = t.val; 
+			Token op = t; 
 			SLExpressionNode right = Term();
 			result = factory.createBinary(op, result, right); 
 		}
@@ -325,7 +329,7 @@
 			} else {
 				Get();
 			}
-			String op = t.val; 
+			Token op = t; 
 			SLExpressionNode right = Factor();
 			result = factory.createBinary(op, result, right); 
 		}
@@ -337,12 +341,12 @@
 		result = null; 
 		if (la.kind == 1) {
 			Get();
-			String name = t.val; 
+			Token nameToken = t; 
 			if (la.kind == 5) {
 				Get();
 				List<SLExpressionNode> parameters = new ArrayList<>();
 				SLExpressionNode parameter; 
-				if (StartOf(3)) {
+				if (StartOf(2)) {
 					parameter = Expression();
 					parameters.add(parameter); 
 					while (la.kind == 6) {
@@ -351,21 +355,21 @@
 						parameters.add(parameter); 
 					}
 				}
-				result = factory.createCall(factory.createRead(name), parameters); 
+				result = factory.createCall(nameToken, parameters); 
 				Expect(7);
 			} else if (la.kind == 29) {
 				Get();
 				SLExpressionNode value = Expression();
-				result = factory.createAssignment(name, value); 
+				result = factory.createAssignment(nameToken, value); 
 			} else if (StartOf(4)) {
-				result = factory.createRead(name); 
+				result = factory.createRead(nameToken); 
 			} else SynErr(32);
 		} else if (la.kind == 2) {
 			Get();
-			result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); 
+			result = factory.createStringLiteral(t); 
 		} else if (la.kind == 3) {
 			Get();
-			result = factory.createNumericLiteral(t.val); 
+			result = factory.createNumericLiteral(t); 
 		} else if (la.kind == 5) {
 			Get();
 			result = Expression();
@@ -387,9 +391,9 @@
 
     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, x,x,x,x},
-		{x,T,T,T, x,T,x,x, x,x,T,x, T,T,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
+		{x,T,T,T, x,T,x,x, x,x,T,x, T,T,T,x, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x},
+		{x,T,T,T, 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, 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,T,T,T, 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, x,x,T,T, x,x,x,T, x,x,x,x, x,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x}
 
     };
@@ -446,15 +450,15 @@
 			case 10: s = "\"break\" expected"; break;
 			case 11: s = "\";\" expected"; break;
 			case 12: s = "\"continue\" expected"; break;
-			case 13: s = "\"if\" expected"; break;
-			case 14: s = "\"else\" expected"; break;
-			case 15: s = "\"while\" expected"; break;
+			case 13: s = "\"while\" expected"; break;
+			case 14: s = "\"if\" expected"; break;
+			case 15: s = "\"else\" expected"; break;
 			case 16: s = "\"return\" 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 20: s = "\"<=\" expected"; break;
+			case 21: s = "\">\" expected"; break;
 			case 22: s = "\">=\" expected"; break;
 			case 23: s = "\"==\" expected"; break;
 			case 24: s = "\"!=\" expected"; break;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/ParserUtils.java	Wed Jan 29 20:43:28 2014 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.oracle.truffle.sl.parser;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.impl.*;
-
-public class ParserUtils {
-
-    public static SourceSection createSourceSection(Source source, String identifier, Parser p) {
-        Token t = p.t;
-        if (t == null) {
-            t = p.la;
-        }
-        int startLine = -1;
-        int startColumn = -1;
-        int length = 0;
-        if (t != null) {
-            startLine = t.line;
-            startColumn = t.col;
-            length = t.val.length();
-        }
-        return new DefaultSourceSection(source, identifier, startLine, startColumn, 0, length);
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -27,6 +27,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.call.*;
@@ -53,50 +54,56 @@
     /* State while parsing a source unit. */
     private final SLContext context;
     private final Source source;
-    private final Parser parser;
 
     /* State while parsing a function. */
     private String functionName;
+    private int parameterCount;
     private FrameDescriptor frameDescriptor;
     private List<SLStatementNode> methodNodes;
 
     /* State while parsing a block. */
     private LexicalScope lexicalScope;
 
-    public SLNodeFactory(SLContext context, Source source, Parser parser) {
+    public SLNodeFactory(SLContext context, Source source) {
         this.context = context;
         this.source = source;
-        this.parser = parser;
     }
 
-    public void startFunction(String name, List<String> parameters) {
+    public void startFunction(Token nameToken) {
         assert functionName == null;
+        assert parameterCount == 0;
         assert frameDescriptor == null;
         assert lexicalScope == null;
 
-        functionName = name;
+        functionName = nameToken.val;
         frameDescriptor = new FrameDescriptor();
+        methodNodes = new ArrayList<>();
         startBlock();
+    }
 
+    public void addFormalParameter(Token nameToken) {
         /*
          * Method parameters are assigned to local variables at the beginning of the method. This
          * ensures that accesses to parameters are specialized the same way as local variables are
          * specialized.
          */
-        methodNodes = new ArrayList<>(parameters.size());
-        for (int i = 0; i < parameters.size(); i++) {
-            methodNodes.add(createAssignment(parameters.get(i), new SLReadArgumentNode(i)));
-        }
+        SLReadArgumentNode readArg = assignSource(nameToken, new SLReadArgumentNode(parameterCount));
+        methodNodes.add(createAssignment(nameToken, readArg));
+        parameterCount++;
     }
 
-    public void finishFunction(SLStatementNode body) {
-        methodNodes.add(body);
+    public void finishFunction(SLStatementNode bodyNode) {
+        methodNodes.add(bodyNode);
         SLStatementNode methodBlock = finishBlock(methodNodes);
         assert lexicalScope == null : "Wrong scoping of blocks in parser";
 
-        context.getFunctionRegistry().register(functionName, SLRootNode.createFunction(functionName, frameDescriptor, methodBlock));
+        SLFunctionBodyNode functionBodyNode = new SLFunctionBodyNode(methodBlock);
+        SLRootNode rootNode = new SLRootNode(frameDescriptor, functionBodyNode, functionName);
+
+        context.getFunctionRegistry().register(functionName, rootNode);
 
         functionName = null;
+        parameterCount = 0;
         frameDescriptor = null;
         lexicalScope = null;
     }
@@ -105,123 +112,131 @@
         lexicalScope = new LexicalScope(lexicalScope);
     }
 
-    public SLStatementNode finishBlock(List<SLStatementNode> statements) {
+    public SLStatementNode finishBlock(List<SLStatementNode> bodyNodes) {
         lexicalScope = lexicalScope.outer;
 
-        List<SLStatementNode> flattened = new ArrayList<>(statements.size());
-        flattenBlocks(statements, flattened);
-        if (flattened.size() == 1) {
-            return flattened.get(0);
+        List<SLStatementNode> flattenedNodes = new ArrayList<>(bodyNodes.size());
+        flattenBlocks(bodyNodes, flattenedNodes);
+        if (flattenedNodes.size() == 1) {
+            /* A block containing one other node is unnecessary, we can just that other node. */
+            return flattenedNodes.get(0);
         } else {
-            return assignSource(new SLBlockNode(flattened.toArray(new SLStatementNode[flattened.size()])));
+            return new SLBlockNode(flattenedNodes.toArray(new SLStatementNode[flattenedNodes.size()]));
         }
     }
 
-    private void flattenBlocks(Iterable<? extends Node> statements, List<SLStatementNode> flattened) {
-        for (Node statement : statements) {
-            if (statement instanceof SLBlockNode) {
-                flattenBlocks(statement.getChildren(), flattened);
+    private void flattenBlocks(Iterable<? extends Node> bodyNodes, List<SLStatementNode> flattenedNodes) {
+        for (Node n : bodyNodes) {
+            if (n instanceof SLBlockNode) {
+                flattenBlocks(n.getChildren(), flattenedNodes);
             } else {
-                flattened.add((SLStatementNode) statement);
+                flattenedNodes.add((SLStatementNode) n);
             }
         }
     }
 
-    private <T extends Node> T assignSource(T node) {
-        assert functionName != null;
-        node.assignSourceSection(ParserUtils.createSourceSection(source, functionName, parser));
-        return node;
+    public SLStatementNode createBreak(Token t) {
+        return assignSource(t, new SLBreakNode());
+    }
+
+    public SLStatementNode createContinue(Token t) {
+        return assignSource(t, new SLContinueNode());
     }
 
-    public SLExpressionNode createAssignment(String name, SLExpressionNode value) {
-        FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(name);
-        lexicalScope.locals.put(name, frameSlot);
-        return assignSource(WriteLocalNodeFactory.create(frameSlot, value));
+    public SLStatementNode createWhile(Token t, SLExpressionNode conditionNode, SLStatementNode bodyNode) {
+        return assignSource(t, new SLWhileNode(conditionNode, bodyNode));
+    }
+
+    public SLStatementNode createIf(Token t, SLExpressionNode conditionNode, SLStatementNode thenPartNode, SLStatementNode elsePartNode) {
+        return assignSource(t, new SLIfNode(conditionNode, thenPartNode, elsePartNode));
+    }
+
+    public SLStatementNode createReturn(Token t, SLExpressionNode valueNode) {
+        return assignSource(t, new SLReturnNode(valueNode));
     }
 
-    public SLExpressionNode createRead(String name) {
-        FrameSlot frameSlot = lexicalScope.locals.get(name);
-        if (frameSlot != null) {
-            /* Read of a local variable. */
-            return assignSource(ReadLocalNodeFactory.create(frameSlot));
-        } else {
-            /* Read of a global name. In our language, the only global names are functions. */
-            return new SLFunctionLiteralNode(context.getFunctionRegistry().lookup(name));
-        }
-    }
-
-    public SLExpressionNode createNumericLiteral(String value) {
-        try {
-            return assignSource(new SLLongLiteralNode(Long.parseLong(value)));
-        } catch (NumberFormatException ex) {
-            return assignSource(new SLBigIntegerLiteralNode(new BigInteger(value)));
+    public SLExpressionNode createBinary(Token opToken, SLExpressionNode leftNode, SLExpressionNode rightNode) {
+        switch (opToken.val) {
+            case "+":
+                return assignSource(opToken, SLAddNodeFactory.create(leftNode, rightNode));
+            case "*":
+                return assignSource(opToken, SLMulNodeFactory.create(leftNode, rightNode));
+            case "/":
+                return assignSource(opToken, SLDivNodeFactory.create(leftNode, rightNode));
+            case "-":
+                return assignSource(opToken, SLSubNodeFactory.create(leftNode, rightNode));
+            case "<":
+                return assignSource(opToken, SLLessThanNodeFactory.create(leftNode, rightNode));
+            case "<=":
+                return assignSource(opToken, SLLessOrEqualNodeFactory.create(leftNode, rightNode));
+            case ">":
+                return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLLessOrEqualNodeFactory.create(leftNode, rightNode))));
+            case ">=":
+                return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLLessThanNodeFactory.create(leftNode, rightNode))));
+            case "==":
+                return assignSource(opToken, SLEqualNodeFactory.create(leftNode, rightNode));
+            case "!=":
+                return assignSource(opToken, SLLogicalNotNodeFactory.create(assignSource(opToken, SLEqualNodeFactory.create(leftNode, rightNode))));
+            case "&&":
+                return assignSource(opToken, SLLogicalAndNodeFactory.create(leftNode, rightNode));
+            case "||":
+                return assignSource(opToken, SLLogicalOrNodeFactory.create(leftNode, rightNode));
+            default:
+                throw new RuntimeException("unexpected operation: " + opToken.val);
         }
     }
 
-    public SLExpressionNode createStringLiteral(String value) {
-        return assignSource(new SLStringLiteralNode(value));
-    }
-
-    public SLStatementNode createWhile(SLExpressionNode condition, SLStatementNode body) {
-        return assignSource(new SLWhileNode(condition, body));
+    public SLExpressionNode createCall(Token nameToken, List<SLExpressionNode> parameterNodes) {
+        SLExpressionNode functionNode = createRead(nameToken);
+        return assignSource(nameToken, SLCallNode.create(functionNode, parameterNodes.toArray(new SLExpressionNode[parameterNodes.size()])));
     }
 
-    public SLStatementNode createBreak() {
-        return assignSource(new SLBreakNode());
+    public SLExpressionNode createAssignment(Token nameToken, SLExpressionNode valueNode) {
+        FrameSlot frameSlot = frameDescriptor.findOrAddFrameSlot(nameToken.val);
+        lexicalScope.locals.put(nameToken.val, frameSlot);
+        return assignSource(nameToken, SLWriteLocalVariableNodeFactory.create(valueNode, frameSlot));
     }
 
-    public SLStatementNode createContinue() {
-        return assignSource(new SLContinueNode());
-    }
-
-    public SLExpressionNode createCall(SLExpressionNode function, List<SLExpressionNode> parameters) {
-        return assignSource(SLCallNode.create(function, parameters.toArray(new SLExpressionNode[parameters.size()])));
+    public SLExpressionNode createRead(Token nameToken) {
+        FrameSlot frameSlot = lexicalScope.locals.get(nameToken.val);
+        if (frameSlot != null) {
+            /* Read of a local variable. */
+            return assignSource(nameToken, SLReadLocalVariableNodeFactory.create(frameSlot));
+        } else {
+            /* Read of a global name. In our language, the only global names are functions. */
+            return assignSource(nameToken, new SLFunctionLiteralNode(context.getFunctionRegistry().lookup(nameToken.val)));
+        }
     }
 
-    public SLExpressionNode createBinary(String operation, SLExpressionNode left, SLExpressionNode right) {
-        SLExpressionNode binary;
-        switch (operation) {
-            case "+":
-                binary = SLAddNodeFactory.create(left, right);
-                break;
-            case "*":
-                binary = SLMulNodeFactory.create(left, right);
-                break;
-            case "/":
-                binary = SLDivNodeFactory.create(left, right);
-                break;
-            case "-":
-                binary = SLSubNodeFactory.create(left, right);
-                break;
-            case "<":
-                binary = SLLessThanNodeFactory.create(left, right);
-                break;
-            case "<=":
-                binary = SLLessOrEqualNodeFactory.create(left, right);
-                break;
-            case "==":
-                binary = SLEqualNodeFactory.create(left, right);
-                break;
-            case "!=":
-                binary = SLNotEqualNodeFactory.create(left, right);
-                break;
-            case "&&":
-                binary = SLLogicalAndNodeFactory.create(left, right);
-                break;
-            case "||":
-                binary = SLLogicalOrNodeFactory.create(left, right);
-                break;
-            default:
-                throw new RuntimeException("unexpected operation: " + operation);
-        }
-        return assignSource(binary);
+    public SLExpressionNode createStringLiteral(Token literalToken) {
+        /* Remove the trailing and ending " */
+        String literal = literalToken.val;
+        assert literal.length() >= 2 && literal.startsWith("\"") && literal.endsWith("\"");
+        literal = literal.substring(1, literal.length() - 1);
+
+        return assignSource(literalToken, new SLStringLiteralNode(literal));
     }
 
-    public SLStatementNode createReturn(SLExpressionNode value) {
-        return assignSource(new SLReturnNode(value));
+    public SLExpressionNode createNumericLiteral(Token literalToken) {
+        try {
+            /* Try if the literal is small enough to fit into a long value. */
+            return assignSource(literalToken, new SLLongLiteralNode(Long.parseLong(literalToken.val)));
+        } catch (NumberFormatException ex) {
+            /* Overflow of long value, so fall back to BigInteger. */
+            return assignSource(literalToken, new SLBigIntegerLiteralNode(new BigInteger(literalToken.val)));
+        }
     }
 
-    public SLStatementNode createIf(SLExpressionNode condition, SLStatementNode then, SLStatementNode elseNode) {
-        return assignSource(new SLIfNode(condition, then, elseNode));
+    private <T extends Node> T assignSource(Token t, T node) {
+        assert functionName != null;
+        assert t != null;
+
+        int startLine = t.line;
+        int startColumn = t.col;
+        int charLength = t.val.length();
+        SourceSection sourceSection = new DefaultSourceSection(source, functionName, startLine, startColumn, 0, charLength);
+
+        node.assignSourceSection(sourceSection);
+        return node;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -361,9 +361,9 @@
 		literals.put("function", new Integer(4));
 		literals.put("break", new Integer(10));
 		literals.put("continue", new Integer(12));
-		literals.put("if", new Integer(13));
-		literals.put("else", new Integer(14));
-		literals.put("while", new Integer(15));
+		literals.put("while", new Integer(13));
+		literals.put("if", new Integer(14));
+		literals.put("else", new Integer(15));
 		literals.put("return", new Integer(16));
 
     }
@@ -557,7 +557,7 @@
 				case 15:
 					{t.kind = 18; break loop;}
 				case 16:
-					{t.kind = 21; break loop;}
+					{t.kind = 20; break loop;}
 				case 17:
 					{t.kind = 22; break loop;}
 				case 18:
@@ -580,9 +580,9 @@
 					if (ch == '=') {AddCh(); state = 16; break;}
 					else {t.kind = 19; break loop;}
 				case 26:
-					recEnd = pos; recKind = 20;
+					recEnd = pos; recKind = 21;
 					if (ch == '=') {AddCh(); state = 17; break;}
-					else {t.kind = 20; break loop;}
+					else {t.kind = 21; break loop;}
 				case 27:
 					recEnd = pos; recKind = 29;
 					if (ch == '=') {AddCh(); state = 18; break;}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg	Wed Jan 29 20:45:43 2014 -0800
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2012, 2014, 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.
+ */
+
 COMPILER SimpleLanguage
 
 CHARACTERS
@@ -37,16 +60,16 @@
 Function
 =
 "function"                                      
-identifier                                      (. String name = t.val; .)
-"("                                             (. List<String> parameters = new ArrayList<>(); .)
+identifier                                      (. factory.startFunction(t); .)
+"("
 [
-    identifier                                  (. parameters.add(t.val); .)
+    identifier                                  (. factory.addFormalParameter(t); .)
     {
         "," 
-        identifier                              (. parameters.add(t.val); .)
+        identifier                              (. factory.addFormalParameter(t); .)
     }    
 ]
-")"                                             (. factory.startFunction(name, parameters); .)
+")"
 Block<out SLStatementNode body>                 (. factory.finishFunction(body); .)
 .
 
@@ -54,12 +77,12 @@
 
 Block<out SLStatementNode result>
 =                                               (. factory.startBlock();
-                                                   List<SLStatementNode> statements = new ArrayList<>(); .)
+                                                   List<SLStatementNode> body = new ArrayList<>(); .)
 "{" 
 {
-    Statement<out SLStatementNode statement>    (. statements.add(statement); .)
+    Statement<out SLStatementNode s>            (. body.add(s); .)
 }
-"}"                                             (. result = factory.finishBlock(statements); .)
+"}"                                             (. result = factory.finishBlock(body); .)
 .
 
 
@@ -68,10 +91,10 @@
 (
     WhileStatement<out result>
 |
-    "break"                                     (. result = factory.createBreak(); .)
+    "break"                                     (. result = factory.createBreak(t); .)
     ";"
 |
-    "continue"                                  (. result = factory.createContinue(); .)
+    "continue"                                  (. result = factory.createContinue(t); .)
     ";"
 |   
     IfStatement<out result>
@@ -83,34 +106,38 @@
 .
 
 
+WhileStatement<out SLStatementNode result>
+=
+"while"
+"("                                             (. Token whileToken = t; .)
+Expression<out SLExpressionNode condition>
+")" 
+Block<out SLStatementNode body>                 (. result = factory.createWhile(whileToken, condition, body); .)
+.
+
+
 IfStatement<out SLStatementNode result>
 =
 "if" 
-"(" 
+"("                                             (. Token ifToken = t; .)
 Expression<out SLExpressionNode condition> 
 ")"
 Block<out SLStatementNode thenPart>             (. SLStatementNode elsePart = null; .)                             
 [
     "else" 
     Block<out elsePart>
-]                                               (. result = factory.createIf(condition, thenPart, elsePart); .)
-.
-
-
-WhileStatement<out SLStatementNode result>
-=
-"while"
-"("
-Expression<out SLExpressionNode condition>
-")" 
-Block<out SLStatementNode body>                 (. result = factory.createWhile(condition, body); .)
+]                                               (. result = factory.createIf(ifToken, condition, thenPart, elsePart); .)
 .
 
 
 ReturnStatement<out SLStatementNode result>
 =
-"return"
-Expression<out SLExpressionNode value> ";"      (. result = factory.createReturn(value); .)
+"return"                                        (. Token returnToken = t;
+                                                   SLExpressionNode value = null; .)
+[
+    Expression<out value>
+]                                               (. result = factory.createReturn(returnToken, value); .)
+";"
 .
 
 
@@ -118,7 +145,7 @@
 =
 LogicTerm<out result>
 {
-    "||"                                        (. String op = t.val; .)
+    "||"                                        (. Token op = t; .)
     LogicTerm<out SLExpressionNode right>       (. result = factory.createBinary(op, result, right); .)
 }
 .
@@ -128,7 +155,7 @@
 =
 LogicFactor<out result>
 {
-    "&&"                                        (. String op = t.val; .)
+    "&&"                                        (. Token op = t; .)
     LogicFactor<out SLExpressionNode right>     (. result = factory.createBinary(op, result, right); .)
 }
 .
@@ -138,7 +165,7 @@
 =
 Arithmetic<out result>
 [
-    ("<" | "<=" | "==" | "!=" )    (.  String op = t.val; .)
+    ("<" | "<=" | ">" | ">=" | "==" | "!=" )    (. Token op = t; .)
     Arithmetic<out SLExpressionNode right>      (.  result = factory.createBinary(op, result, right); .)
 ]
 .
@@ -148,7 +175,7 @@
 =
 Term<out result>
 {
-    ("+" | "-")                                 (. String op = t.val; .)
+    ("+" | "-")                                 (. Token op = t; .)
     Term<out SLExpressionNode right>            (. result = factory.createBinary(op, result, right); .)
 }
 .
@@ -158,7 +185,7 @@
 =
 Factor<out result>
 {
-    ("*" | "/")                                 (. String op = t.val; .)
+    ("*" | "/")                                 (. Token op = t; .)
     Factor<out SLExpressionNode right>          (. result = factory.createBinary(op, result, right); .)
 }
 .
@@ -167,7 +194,7 @@
 Factor<out SLExpressionNode result>
 =                                               (. result = null; .)
 (
-    identifier                                  (. String name = t.val; .)
+    identifier                                  (. Token nameToken = t; .)
     (
         "("                                     (. List<SLExpressionNode> parameters = new ArrayList<>();
                                                    SLExpressionNode parameter; .)
@@ -177,18 +204,18 @@
                 "," 
                 Expression<out parameter>       (. parameters.add(parameter); .)
             }                                               
-        ]                                       (. result = factory.createCall(factory.createRead(name), parameters); .) 
+        ]                                       (. result = factory.createCall(nameToken, parameters); .) 
         ")"
     |
         "=" 
-        Expression<out SLExpressionNode value>  (. result = factory.createAssignment(name, value); .)
+        Expression<out SLExpressionNode value>  (. result = factory.createAssignment(nameToken, value); .)
     |
-                                                (. result = factory.createRead(name); .)
+                                                (. result = factory.createRead(nameToken); .)
     )
 |
-    stringLiteral                               (. result = factory.createStringLiteral(t.val.substring(1, t.val.length() - 1)); .)
+    stringLiteral                               (. result = factory.createStringLiteral(t); .)
 |
-    numericLiteral                              (. result = factory.createNumericLiteral(t.val); .)
+    numericLiteral                              (. result = factory.createNumericLiteral(t); .)
 |
     "(" Expression<out result> ")"
 ) 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -24,16 +24,28 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.sl.nodes.call.*;
+import com.oracle.truffle.sl.nodes.local.*;
 
+/**
+ * Encapsulation of SL function arguments, as required by the Truffle API. An instance of this class
+ * is allocated by the caller, and read by the callee.
+ */
 public final class SLArguments extends Arguments {
 
-    private final Object[] arguments;
+    private final Object[] argumentValues;
 
+    /**
+     * Used by the caller, i.e., the {@link SLCallNode node that performs a function call}.
+     */
     public SLArguments(Object[] arguments) {
-        this.arguments = arguments;
+        this.argumentValues = arguments;
     }
 
+    /**
+     * Used by the callee, i.e., the {@link SLReadArgumentNode note that reads a function argument}.
+     */
     public static Object[] getFromFrame(VirtualFrame frame) {
-        return frame.getArguments(SLArguments.class).arguments;
+        return frame.getArguments(SLArguments.class).argumentValues;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,42 +25,104 @@
 import java.io.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.local.*;
+import com.oracle.truffle.sl.parser.*;
 
+/**
+ * The run-time state of SL during execution. One context is instantiated before any source code is
+ * parsed, and this context is passed around to all methods that need access to it. For example, the
+ * context is used during {@link SLNodeFactory parsing} and by {@link SLBuiltinNode#getContext()
+ * builtin functions}.
+ * <p>
+ * It would be an error to have two different context instances at the same. From a software
+ * engineering point of view, it is better to pass around this encapsulated context object instead
+ * of storing the data in static Java fields.
+ */
 public final class SLContext {
     private final SourceManager sourceManager;
+    private final BufferedReader input;
     private final PrintStream output;
     private final SLFunctionRegistry functionRegistry;
 
-    public SLContext(SourceManager sourceManager, PrintStream output) {
+    public SLContext(SourceManager sourceManager, BufferedReader input, PrintStream output) {
         this.sourceManager = sourceManager;
+        this.input = input;
         this.output = output;
         this.functionRegistry = new SLFunctionRegistry();
 
         installBuiltins();
     }
 
+    /**
+     * Returns the source manger that controls all SL source code that is executed.
+     */
     public SourceManager getSourceManager() {
         return sourceManager;
     }
 
-    public PrintStream getPrintOutput() {
+    /**
+     * Returns the default input, i.e., the source for the {@link SLReadlnBuiltin}. To allow unit
+     * testing, we do not use {@link System#in} directly.
+     */
+    public BufferedReader getInput() {
+        return input;
+    }
+
+    /**
+     * The default default, i.e., the output for the {@link SLPrintlnBuiltin}. To allow unit
+     * testing, we do not use {@link System#out} directly.
+     */
+    public PrintStream getOutput() {
         return output;
     }
 
+    /**
+     * Returns the registry of all functions that are currently defined.
+     */
     public SLFunctionRegistry getFunctionRegistry() {
         return functionRegistry;
     }
 
+    /**
+     * Adds all builitin functions to the {@link SLFunctionRegistry}. This method lists all
+     * {@link SLBuiltinNode builtin implementation classes}.
+     */
     private void installBuiltins() {
-        installBuiltin(SLPrintBuiltinFactory.getInstance(), "print");
-        installBuiltin(SLTimeBuiltinFactory.getInstance(), "time");
-        installBuiltin(SLDefineFunctionBuiltinFactory.getInstance(), "defineFunction");
+        installBuiltin(SLReadlnBuiltinFactory.getInstance());
+        installBuiltin(SLPrintlnBuiltinFactory.getInstance());
+        installBuiltin(SLNanoTimeBuiltinFactory.getInstance());
+        installBuiltin(SLDefineFunctionBuiltinFactory.getInstance());
     }
 
-    private void installBuiltin(NodeFactory<? extends SLBuiltinNode> factory, String name) {
-        getFunctionRegistry().register(name, SLRootNode.createBuiltin(this, factory, name));
+    private void installBuiltin(NodeFactory<? extends SLBuiltinNode> factory) {
+        /*
+         * The builtin node factory is a class that is automatically generated by the Truffle DSL.
+         * The signature returned by the factory reflects the signature of the @Specialization
+         * methods in the builtin classes.
+         */
+        int argumentCount = factory.getExecutionSignature().size();
+        SLExpressionNode[] argumentNodes = new SLExpressionNode[argumentCount];
+        /*
+         * Builtin functions are like normal functions, i.e., the arguments are passed in as an
+         * Object[] array encapsulated in SLArguments. A SLReadArgumentNode extracts a parameter
+         * from this array.
+         */
+        for (int i = 0; i < argumentCount; i++) {
+            argumentNodes[i] = new SLReadArgumentNode(i);
+        }
+        /* Instantiate the builtin node. This node performs the actual functionality. */
+        SLBuiltinNode builtinBodyNode = factory.createNode(argumentNodes, this);
+        /* The name of the builtin function is specified via an annotation on the node class. */
+        String name = builtinBodyNode.getClass().getAnnotation(NodeInfo.class).shortName();
+        /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */
+        SLRootNode rootNode = new SLRootNode(new FrameDescriptor(), builtinBodyNode, name);
+
+        /* Register the builtin function in our function registry. */
+        getFunctionRegistry().register(name, rootNode);
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Wed Jan 29 20:45:43 2014 -0800
@@ -25,10 +25,35 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.utilities.*;
 
+/**
+ * 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
+ * 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).
+ * <p>
+ * Function redefinition is expected to be rare, therefore optimzied 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.
+ * <p>
+ * The {@link #callTarget} can be {@code null}. To ensure that only one {@link SLFunction} instance
+ * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name
+ * lookup. A function that has been looked up, i.e., used, but not defined, has no call target.
+ */
 public final class SLFunction {
 
+    /** The name of the function. */
     private final String name;
+
+    /** The current implementation of this function. */
     private RootCallTarget callTarget;
+
+    /**
+     * Manages the assumption that the {@link #callTarget} is stable. We use the utility class
+     * {@link CyclicAssumption}, which automatically creates a new {@link Assumption} when the old
+     * one gets invalidated.
+     */
     private final CyclicAssumption callTargetStable;
 
     protected SLFunction(String name) {
@@ -42,6 +67,10 @@
 
     protected void setCallTarget(RootCallTarget callTarget) {
         this.callTarget = callTarget;
+        /*
+         * We have a new call target. Invalidate all code that speculated that the old call target
+         * was stable.
+         */
         callTargetStable.invalidate();
     }
 
@@ -53,8 +82,12 @@
         return callTargetStable.getAssumption();
     }
 
+    /**
+     * This method is, e.g., called when using a function literal in a string concatenation. So
+     * changing it has an effect on SL programs.
+     */
     @Override
     public String toString() {
-        return "function " + name;
+        return name;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -25,11 +25,19 @@
 import java.util.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.sl.nodes.*;
 
+/**
+ * Manages the mapping from function names to {@link SLFunction function objects}.
+ */
 public final class SLFunctionRegistry {
 
     private final Map<String, SLFunction> functions = new HashMap<>();
 
+    /**
+     * Returns the canonical {@link SLFunction} object for the given name. If it does not exist yet,
+     * it is created.
+     */
     public SLFunction lookup(String name) {
         SLFunction result = functions.get(name);
         if (result == null) {
@@ -39,12 +47,27 @@
         return result;
     }
 
-    public void register(String name, RootCallTarget callTarget) {
+    /**
+     * Associates the {@link SLFunction} with the given name with the given implementation root
+     * node. If the function did not exist before, it defines the function. If the function existed
+     * before, it redefines the function and the old implementation is discarded.
+     */
+    public void register(String name, SLRootNode rootNode) {
         SLFunction function = lookup(name);
+        RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(rootNode);
         function.setCallTarget(callTarget);
     }
 
-    public Collection<SLFunction> getFunctions() {
-        return functions.values();
+    /**
+     * Returns the sorted list of all functions, for printing purposes only.
+     */
+    public List<SLFunction> getFunctions() {
+        List<SLFunction> result = new ArrayList<>(functions.values());
+        Collections.sort(result, new Comparator<SLFunction>() {
+            public int compare(SLFunction f1, SLFunction f2) {
+                return f1.toString().compareTo(f2.toString());
+            }
+        });
+        return result;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Wed Jan 29 20:43:28 2014 -0800
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java	Wed Jan 29 20:45:43 2014 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2014, 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
@@ -22,11 +22,34 @@
  */
 package com.oracle.truffle.sl.runtime;
 
+/**
+ * The SL type for a {@code null} (i.e., undefined) value. In Truffle, it is generally discouraged
+ * to use the Java {@code null} value to represent the guest language {@code null} value. It is not
+ * possible to specialize on Java {@code null} (since you cannot ask it for the Java class), and
+ * there is always the danger of a spurious {@link NullPointerException}. Representing the guest
+ * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended
+ * practice.
+ * */
 public final class SLNull {
 
-    public static final SLNull INSTANCE = new SLNull();
+    /**
+     * The canonical value to represent {@code null} in SL.
+     */
+    public static final SLNull SINGLETON = new SLNull();
 
+    /**
+     * Disallow instantiation from outside to ensure that the {@link #SINGLETON} is the only
+     * instance.
+     */
     private SLNull() {
     }
 
+    /**
+     * This method is, e.g., called when using the {@code null} value in a string concatenation. So
+     * changing it has an effect on SL programs.
+     */
+    @Override
+    public String toString() {
+        return "null";
+    }
 }