# HG changeset patch # User Christian Wimmer # Date 1391057143 28800 # Node ID b16ec83edc73307860553bafb17b77a275d96a80 # Parent 20e7727588e8698f85ec962cf66a0da7d8312331 Documentation and more refactoring of Simple Language diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleTreeDumpHandler.java --- 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); } } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- 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(); + } } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- 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 foundCases = new ArrayList<>(); Files.walkFileTree(rootPath, new SimpleFileVisitor() { @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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Add.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Arithmetic.sl --- 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)); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Builtins.sl --- 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(); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/CalcShell.input --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/CalcShell.output --- /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> diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/CalcShell.sl --- /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 + "; }"); + } + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Call.sl --- 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)); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Comparison.output --- 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Comparison.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/DefineFunction.sl --- 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() { diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Div.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Fibonacci.sl --- 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)); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/LoopPrint.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Mul.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Null.output --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Null.sl --- /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"); +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/String.output --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/String.sl --- /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"); +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/Sub.sl --- 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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError01.output --- /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" diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError01.sl --- /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"; +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError02.output --- /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" diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError02.sl --- /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") { } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError05.output --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError05.sl --- /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(); +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError06.output --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError06.sl --- /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); +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError07.output --- /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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl.test/tests/error/TypeError07.sl --- /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(); +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLException.java --- 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java 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. + *

+ * 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. + * + *

+ * Types: + *

    + *
  • 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. + *
  • Boolean: implemented as the Java primitive type {@code boolean}. + *
  • String: implemented as the Java standard type {@link String}. + *
  • Function: implementation type {@link SLFunction}. + *
  • Null (with only one value {@code null}): implemented as the singleton + * {@link SLNull#SINGLETON}. + *
+ * The class {@link SLTypes} lists these types for the Truffle DSL, i.e., for type-specialized + * operations that are specified using Truffle DSL annotations. + * + *

+ * Language concepts: + *

    + *
  • Literals for {@link SLBigIntegerLiteralNode numbers} , {@link SLStringLiteralNode strings}, + * and {@link SLFunctionLiteralNode functions}. + *
  • 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 <=}, >, >=. + *
  • 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. + *
  • Basic control flow statements: {@link SLBlockNode blocks}, {@link SLIfNode if}, + * {@link SLWhileNode while} with {@link SLBreakNode break} and {@link SLContinueNode continue}, + * {@link SLReturnNode return}. + *
  • Function calls: {@link SLCallNode calls} are efficiently implemented with + * {@link SLAbstractDispatchNode polymorphic inline caches}. + *
+ * + *

+ * Syntax and parsing:
+ * 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 http://ssw.jku.at/coco/). 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}. + * + *

+ * Builtin functions:
+ * 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 + *

    + *
  • {@link SLReadlnBuiltin readln}: Read a String from the {@link SLContext#getInput() standard + * input}. + *
  • {@link SLPrintlnBuiltin println}: Write a value to the {@link SLContext#getOutput() standard + * output}. + *
  • {@link SLNanoTimeBuiltin nanoTime}: Returns the value of a high-resolution time, in + * nanoseconds. + *
  • {@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. + *
+ */ 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(); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLBuiltinNode.java 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.
+ * 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. + *

+ * 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(); - } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLDefineFunctionBuiltin.java --- 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; } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLNanoTimeBuiltin.java --- /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(); + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintBuiltin.java --- 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; - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLPrintlnBuiltin.java --- /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; + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLReadlnBuiltin.java --- /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()); + } + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLTimeBuiltin.java --- 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(); - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLBinaryNode.java 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; - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java --- 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); - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- 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 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java --- 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(); - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLTypes.java --- 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); diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java 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. + *

+ * Example of the chain of nodes ({@code C}: {@link SLCallNode}; {@code U}: + * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}: + * {@link SLGenericDispatchNode}): + *

    + *
  1. After parsing: {@code C->U} + *
  2. After execution of function {@code f1}: {@code C->D(f1)->U} + *
  3. After execution of function {@code f2}: {@code C->D(f1)->D(f2)->U} + *
  4. After execution of function {@code f3}: {@code C->G} + *
+ * */ +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); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLArgumentsNode.java --- 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; - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLCallNode.java --- 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()); + } } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java 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. + *

+ * 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java --- 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedCallNode.java --- 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); - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java --- /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); + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakException.java 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBreakNode.java 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueException.java 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLContinueNode.java 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLFunctionBodyNode.java 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLIfNode.java 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()); + } + } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnException.java 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 diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLReturnNode.java 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLWhileNode.java 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()); } } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java 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; + } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLDivNode.java 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java 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; - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java 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; - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java 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()); - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java --- /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; + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java 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()); - } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLongLiteralNode.java 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLMulNode.java 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLNotEqualNode.java --- 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); - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLSubNode.java 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/ReadLocalNode.java --- 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); - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadArgumentNode.java 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; } } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLReadLocalVariableNode.java --- /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()); + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java --- /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; + } + } +} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/WriteLocalNode.java --- 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; - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Copyright.frame --- 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. diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.frame --- 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(); } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Parser.java 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 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 statements = new ArrayList<>(); + List 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 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; diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/ParserUtils.java --- 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); - } -} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java 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 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 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 statements) { + public SLStatementNode finishBlock(List bodyNodes) { lexicalScope = lexicalScope.outer; - List flattened = new ArrayList<>(statements.size()); - flattenBlocks(statements, flattened); - if (flattened.size() == 1) { - return flattened.get(0); + List 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 statements, List flattened) { - for (Node statement : statements) { - if (statement instanceof SLBlockNode) { - flattenBlocks(statement.getChildren(), flattened); + private void flattenBlocks(Iterable bodyNodes, List flattenedNodes) { + for (Node n : bodyNodes) { + if (n instanceof SLBlockNode) { + flattenBlocks(n.getChildren(), flattenedNodes); } else { - flattened.add((SLStatementNode) statement); + flattenedNodes.add((SLStatementNode) n); } } } - private 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 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 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 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/Scanner.java 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;} diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SimpleLanguage.atg 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 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 (. factory.finishFunction(body); .) . @@ -54,12 +77,12 @@ Block = (. factory.startBlock(); - List statements = new ArrayList<>(); .) + List body = new ArrayList<>(); .) "{" { - Statement (. statements.add(statement); .) + Statement (. body.add(s); .) } -"}" (. result = factory.finishBlock(statements); .) +"}" (. result = factory.finishBlock(body); .) . @@ -68,10 +91,10 @@ ( WhileStatement | - "break" (. result = factory.createBreak(); .) + "break" (. result = factory.createBreak(t); .) ";" | - "continue" (. result = factory.createContinue(); .) + "continue" (. result = factory.createContinue(t); .) ";" | IfStatement @@ -83,34 +106,38 @@ . +WhileStatement += +"while" +"(" (. Token whileToken = t; .) +Expression +")" +Block (. result = factory.createWhile(whileToken, condition, body); .) +. + + IfStatement = "if" -"(" +"(" (. Token ifToken = t; .) Expression ")" Block (. SLStatementNode elsePart = null; .) [ "else" Block -] (. result = factory.createIf(condition, thenPart, elsePart); .) -. - - -WhileStatement -= -"while" -"(" -Expression -")" -Block (. result = factory.createWhile(condition, body); .) +] (. result = factory.createIf(ifToken, condition, thenPart, elsePart); .) . ReturnStatement = -"return" -Expression ";" (. result = factory.createReturn(value); .) +"return" (. Token returnToken = t; + SLExpressionNode value = null; .) +[ + Expression +] (. result = factory.createReturn(returnToken, value); .) +";" . @@ -118,7 +145,7 @@ = LogicTerm { - "||" (. String op = t.val; .) + "||" (. Token op = t; .) LogicTerm (. result = factory.createBinary(op, result, right); .) } . @@ -128,7 +155,7 @@ = LogicFactor { - "&&" (. String op = t.val; .) + "&&" (. Token op = t; .) LogicFactor (. result = factory.createBinary(op, result, right); .) } . @@ -138,7 +165,7 @@ = Arithmetic [ - ("<" | "<=" | "==" | "!=" ) (. String op = t.val; .) + ("<" | "<=" | ">" | ">=" | "==" | "!=" ) (. Token op = t; .) Arithmetic (. result = factory.createBinary(op, result, right); .) ] . @@ -148,7 +175,7 @@ = Term { - ("+" | "-") (. String op = t.val; .) + ("+" | "-") (. Token op = t; .) Term (. result = factory.createBinary(op, result, right); .) } . @@ -158,7 +185,7 @@ = Factor { - ("*" | "/") (. String op = t.val; .) + ("*" | "/") (. Token op = t; .) Factor (. result = factory.createBinary(op, result, right); .) } . @@ -167,7 +194,7 @@ Factor = (. result = null; .) ( - identifier (. String name = t.val; .) + identifier (. Token nameToken = t; .) ( "(" (. List parameters = new ArrayList<>(); SLExpressionNode parameter; .) @@ -177,18 +204,18 @@ "," Expression (. parameters.add(parameter); .) } - ] (. result = factory.createCall(factory.createRead(name), parameters); .) + ] (. result = factory.createCall(nameToken, parameters); .) ")" | "=" - Expression (. result = factory.createAssignment(name, value); .) + Expression (. 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 ")" ) diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLArguments.java --- 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java 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}. + *

+ * 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 factory, String name) { - getFunctionRegistry().register(name, SLRootNode.createBuiltin(this, factory, name)); + private void installBuiltin(NodeFactory 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); } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java 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). + *

+ * 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. + *

+ * 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; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionRegistry.java --- 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 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 getFunctions() { - return functions.values(); + /** + * Returns the sorted list of all functions, for printing purposes only. + */ + public List getFunctions() { + List result = new ArrayList<>(functions.values()); + Collections.sort(result, new Comparator() { + public int compare(SLFunction f1, SLFunction f2) { + return f1.toString().compareTo(f2.toString()); + } + }); + return result; } } diff -r 20e7727588e8 -r b16ec83edc73 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java --- 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"; + } }