# HG changeset patch # User Thomas Wuerthinger # Date 1432664602 -7200 # Node ID fac827422011f66231c05a56e42ac2306aa62a16 # Parent f9031351b2bdb1d51b99bd9554e33b6d68ac9720# Parent 3286fb5fea4a2adefab1d110dd93cdf859945e79 Merge. diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Tue May 26 20:23:22 2015 +0200 @@ -24,16 +24,17 @@ import com.oracle.truffle.api.vm.TruffleVM; import java.util.Random; +import org.junit.Test; /** * A collection of tests that can certify language implementaiton to be complient with most recent * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and * include in your test suite. */ -public abstract class TruffleTCK { - private TruffleVM vm; +public class TruffleTCK { // abstract + private TruffleVM tckVM; - protected TruffleTCK() { + public TruffleTCK() { // protected } /** @@ -45,8 +46,11 @@ * for internal testing. * * @return initialized Truffle virtual machine + * @throws java.lang.Exception thrown when the VM preparation fails */ - protected abstract TruffleVM prepareVM() throws Exception; + protected TruffleVM prepareVM() throws Exception { // abstract + return null; + } /** * Name of function which will return value 42 as a number. The return value of the method @@ -55,7 +59,9 @@ * * @return name of globally exported symbol */ - protected abstract String fourtyTwo(); + protected String fourtyTwo() { // abstract + return null; + } /** * Name of function to add two integer values together. The symbol will be invoked with two @@ -64,20 +70,26 @@ * * @return name of globally exported symbol */ - protected abstract String plusInt(); + protected String plusInt() { // abstract + return null; + } private TruffleVM vm() throws Exception { - if (vm == null) { - vm = prepareVM(); + if (tckVM == null) { + tckVM = prepareVM(); } - return vm; + return tckVM; } // // The tests // + @Test public void testFortyTwo() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } TruffleVM.Symbol fourtyTwo = findGlobalSymbol(fourtyTwo()); Object res = fourtyTwo.invoke(null); @@ -89,7 +101,11 @@ assert 42 == n.intValue() : "The value is 42 = " + n.intValue(); } + @Test public void testPlusWithInts() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } Random r = new Random(); int a = r.nextInt(100); int b = r.nextInt(100); diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java Tue May 26 20:23:22 2015 +0200 @@ -35,10 +35,11 @@ @Before public void initInDifferentThread() throws InterruptedException { + final TruffleVM.Builder b = TruffleVM.newVM(); Thread t = new Thread("Initializer") { @Override public void run() { - tvm = TruffleVM.create(); + tvm = b.build(); } }; t.start(); diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java Tue May 26 20:23:22 2015 +0200 @@ -29,6 +29,8 @@ import com.oracle.truffle.api.vm.TruffleVM; import com.oracle.truffle.api.vm.TruffleVM.Language; import java.io.IOException; +import java.io.Reader; +import java.io.Writer; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -135,13 +137,19 @@ public static final class Env { private final TruffleVM vm; private final TruffleLanguage lang; + private final Reader in; + private final Writer err; + private final Writer out; - Env(TruffleVM vm, Constructor langConstructor) { + Env(TruffleVM vm, Constructor langConstructor, Writer out, Writer err, Reader in) { this.vm = vm; + this.in = in; + this.err = err; + this.out = out; try { this.lang = (TruffleLanguage) langConstructor.newInstance(this); } catch (Exception ex) { - throw new IllegalStateException("Cannot construct language " + langConstructor.getClass().getName(), ex); + throw new IllegalStateException("Cannot construct language " + langConstructor.getDeclaringClass().getName(), ex); } } @@ -157,15 +165,41 @@ public Object importSymbol(String globalName) { return API.importSymbol(vm, lang, globalName); } + + /** + * Input associated with this {@link TruffleVM}. + * + * @return reader, never null + */ + public Reader stdIn() { + return in; + } + + /** + * Standard output writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdOut() { + return out; + } + + /** + * Standard error writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdErr() { + return err; + } } private static final AccessAPI API = new AccessAPI(); private static final class AccessAPI extends Accessor { - @Override - protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz) { - Env env = new Env(vm, langClazz); + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn); return env.lang; } diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java Tue May 26 20:23:22 2015 +0200 @@ -29,6 +29,8 @@ import com.oracle.truffle.api.source.Source; import java.io.IOException; import java.lang.reflect.Constructor; +import java.io.Reader; +import java.io.Writer; import java.util.ServiceLoader; /** @@ -76,8 +78,8 @@ } } - protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz) { - return API.attachEnv(vm, langClazz); + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); } protected Object eval(TruffleLanguage l, Source s) throws IOException { diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java Tue May 26 20:23:22 2015 +0200 @@ -32,8 +32,11 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; import java.io.Reader; import java.lang.reflect.Constructor; +import java.io.Writer; import java.net.URI; import java.net.URL; import java.net.URLConnection; @@ -53,10 +56,10 @@ import java.util.logging.Logger; /** - * Virtual machine for Truffle based languages. Use {@link #create()} to instantiate new isolated - * virtual machine ready for execution of various languages. All the languages in a single virtual - * machine see each other exported global symbols and can co-operate. Use {@link #create()} multiple - * times to create different, isolated virtual machines completely separated from each other. + * Virtual machine for Truffle based languages. Use {@link #newVM()} to create new isolated virtual + * machine ready for execution of various languages. All the languages in a single virtual machine + * see each other exported global symbols and can co-operate. Use {@link #newVM()} multiple times to + * create different, isolated virtual machines completely separated from each other. *

* Once instantiated use {@link #eval(java.net.URI)} with a reference to a file or URL or directly * pass code snippet into the virtual machine via {@link #eval(java.lang.String, java.lang.String)}. @@ -65,17 +68,41 @@ * initialized, it remains so, until the virtual machine isn't garbage collected. *

* The TruffleVM is single-threaded and tries to enforce that. It records the thread it - * has been {@link #create() created} by and checks that all subsequent calls are coming from the - * same thread. + * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from + * the same thread. */ public final class TruffleVM { private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName()); private static final SPIAccessor SPI = new SPIAccessor(); private final Thread initThread; private final Map langs; + private final Reader in; + private final Writer err; + private final Writer out; + /** + * Private & temporary only constructor. + */ private TruffleVM() { - initThread = Thread.currentThread(); + this.initThread = null; + this.in = null; + this.err = null; + this.out = null; + this.langs = null; + } + + /** + * Real constructor used from the builder. + * + * @param out stdout + * @param err stderr + * @param in stdin + */ + private TruffleVM(Writer out, Writer err, Reader in) { + this.out = out; + this.err = err; + this.in = in; + this.initThread = Thread.currentThread(); this.langs = new HashMap<>(); Enumeration en; try { @@ -111,14 +138,105 @@ } /** - * Creates new Truffle virtual machine. It searches for {@link Registration languages - * registered} in the system class loader and makes them available for later evaluation via + * Creation of new Truffle virtual machine. Use the {@link Builder} methods to configure your + * virtual machine and then create one using {@link Builder#build()}: + * + *

+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ * + * It searches for {@link Registration languages registered} in the system class loader and + * makes them available for later evaluation via * {@link #eval(java.lang.String, java.lang.String)} methods. * * @return new, isolated virtual machine with pre-registered languages */ - public static TruffleVM create() { - return new TruffleVM(); + public static TruffleVM.Builder newVM() { + // making Builder non-static inner class is a + // nasty trick to avoid the Builder class to appear + // in Javadoc next to TruffleVM class + TruffleVM vm = new TruffleVM(); + return vm.new Builder(); + } + + /** + * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the + * end create new {@link TruffleVM virtual machine}: + * + *
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ */ + public final class Builder { + private Writer out; + private Writer err; + private Reader in; + + Builder() { + } + + /** + * Changes the defaut output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdOut(Writer w) { + out = w; + return this; + } + + /** + * Changes the error output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#err}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdErr(Writer w) { + err = w; + return this; + } + + /** + * Changes the defaut input for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param r the reader to use as input + * @return instance of this builder + */ + public Builder stdIn(Reader r) { + in = r; + return this; + } + + /** + * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from + * values passed into configuration methods in this class. + * + * @return new, isolated virtual machine with pre-registered languages + */ + public TruffleVM build() { + if (out == null) { + out = new OutputStreamWriter(System.out); + } + if (err == null) { + err = new OutputStreamWriter(System.err); + } + if (in == null) { + in = new InputStreamReader(System.in); + } + return new TruffleVM(out, err, in); + } } /** @@ -336,7 +454,7 @@ try { Class langClazz = Class.forName(n, true, loader()); Constructor constructor = langClazz.getConstructor(Env.class); - impl = SPI.attachEnv(TruffleVM.this, constructor); + impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in); } catch (Exception ex) { throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + n, ex); } @@ -368,8 +486,8 @@ } @Override - public TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz) { - return super.attachEnv(vm, langClazz); + public TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn); } @Override diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html Tue May 26 20:23:22 2015 +0200 @@ -0,0 +1,12 @@ + + + + Truffle Virtual Machine + + + + +
Central place to control Truffle Virtual Machine and + all languages hosted in it.
+ + diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Tue May 26 20:23:22 2015 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, 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.test; + +import com.oracle.truffle.api.test.vm.TruffleTCK; +import com.oracle.truffle.api.vm.TruffleVM; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * This is the way to verify your language implementation is compatible. + * + */ +public class SLTckTest extends TruffleTCK { + @Test + public void testVerifyPresence() { + TruffleVM vm = TruffleVM.newVM().build(); + assertTrue("Our language is present", vm.getLanguages().containsKey("application/x-sl")); + } + + @Override + protected TruffleVM prepareVM() throws Exception { + TruffleVM vm = TruffleVM.newVM().build(); + vm.eval("application/x-sl", // your langage + "function fourtyTwo() {\n" + // your script + " return 42;\n" + // + "}\n" + // + "function plus(a, b) {\n" + // + " return a + b;\n" + // + "}\n" // + ); + return vm; + } + + @Override + protected String fourtyTwo() { + return "fourtyTwo"; + } + + @Override + protected String plusInt() { + return "plus"; + } +} diff -r f9031351b2bd -r fac827422011 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 Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java Tue May 26 20:23:22 2015 +0200 @@ -37,11 +37,9 @@ import org.junit.runners.model.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.vm.TruffleVM; import com.oracle.truffle.sl.SLMain; import com.oracle.truffle.sl.builtins.*; -import com.oracle.truffle.sl.factory.*; -import com.oracle.truffle.sl.runtime.*; import com.oracle.truffle.sl.test.SLTestRunner.TestCase; public final class SLTestRunner extends ParentRunner { @@ -167,22 +165,16 @@ ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintWriter printer = new PrintWriter(out); try { - SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer); - for (NodeFactory builtin : builtins) { - context.installBuiltin(builtin); - } - /* - * TruffleVM vm = TruffleVM.create(); String script = readAllLines(testCase.path); for - * (int i = 0; i < repeats; i++) { vm.eval("application/x-sl", script); } - */ - final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); - SLMain.run(context, source, null, repeats); + TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build(); + + String script = readAllLines(testCase.path); + SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins); printer.flush(); String actualOutput = new String(out.toByteArray()); - Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput); + Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput); } catch (Throwable ex) { - notifier.fireTestFailure(new Failure(testCase.name, ex)); + notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex))); } finally { notifier.fireTestFinished(testCase.name); } diff -r f9031351b2bd -r fac827422011 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 Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Tue May 26 20:23:22 2015 +0200 @@ -33,8 +33,9 @@ import com.oracle.truffle.api.source.*; import com.oracle.truffle.api.tools.*; import com.oracle.truffle.api.vm.TruffleVM; +import com.oracle.truffle.api.vm.TruffleVM.Symbol; import com.oracle.truffle.sl.builtins.*; -import com.oracle.truffle.sl.factory.*; +import com.oracle.truffle.sl.factory.SLContextFactory; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.nodes.call.*; import com.oracle.truffle.sl.nodes.controlflow.*; @@ -43,6 +44,9 @@ import com.oracle.truffle.sl.nodes.local.*; import com.oracle.truffle.sl.parser.*; import com.oracle.truffle.sl.runtime.*; +import java.net.URI; +import java.util.Collections; +import java.util.List; /** * SL is a simple language to demonstrate and showcase features of Truffle. The implementation is as @@ -132,11 +136,17 @@ */ @TruffleLanguage.Registration(name = "sl", mimeType = "application/x-sl") public class SLMain extends TruffleLanguage { + private static SLMain LAST; + private static List> builtins = Collections.emptyList(); private final SLContext context; public SLMain(Env env) { super(env); - this.context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), new PrintWriter(System.out)); + context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true)); + LAST = this; + for (NodeFactory builtin : builtins) { + context.installBuiltin(builtin); + } } /* Demonstrate per-type tabulation of node execution counts */ @@ -150,7 +160,7 @@ * 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) throws IOException { - TruffleVM vm = TruffleVM.create(); + TruffleVM vm = TruffleVM.newVM().build(); assert vm.getLanguages().containsKey("application/x-sl"); int repeats = 1; @@ -158,12 +168,17 @@ repeats = Integer.parseInt(args[1]); } + if (args.length == 0) { + vm.eval("application/x-sl", new InputStreamReader(System.in)); + } else { + vm.eval(new File(args[0]).toURI()); + } + Symbol main = vm.findGlobalSymbol("main"); + if (main == null) { + throw new SLException("No function main() defined in SL source file."); + } while (repeats-- > 0) { - if (args.length == 0) { - vm.eval("application/x-sl", new InputStreamReader(System.in)); - } else { - vm.eval(new File(args[0]).toURI()); - } + main.invoke(null); } } @@ -171,7 +186,9 @@ * 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 long run(SLContext context, Source source, PrintWriter logOutput, int repeats) { + public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List> currentBuiltins) throws IOException { + builtins = currentBuiltins; + if (logOutput != null) { logOutput.println("== running on " + Truffle.getRuntime().getName()); // logOutput.println("Source = " + source.getCode()); @@ -200,11 +217,14 @@ } /* Parse the SL source file. */ - Parser.parseSL(context, source); + Object result = context.eval(source); + if (result != null) { + out.println(result); + } /* Lookup our main entry point, which is per definition always named "main". */ - SLFunction main = context.getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { + Symbol main = context.findGlobalSymbol("main"); + if (main == null) { throw new SLException("No function main() defined in SL source file."); } @@ -215,19 +235,19 @@ /* Change to dump the AST to IGV over the network. */ boolean dumpASTToIGV = false; - printScript("before execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("before execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); long totalRuntime = 0; try { for (int i = 0; i < repeats; i++) { long start = System.nanoTime(); /* Call the main entry point, without any arguments. */ try { - Object result = main.getCallTarget().call(); + result = main.invoke(null); if (result != SLNull.SINGLETON) { - context.getOutput().println(result); + out.println(result); } } catch (UnsupportedSpecializationException ex) { - context.getOutput().println(formatTypeError(ex)); + out.println(formatTypeError(ex)); } long end = System.nanoTime(); totalRuntime += end - start; @@ -238,7 +258,7 @@ } } finally { - printScript("after execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); + printScript("after execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV); } if (nodeExecCounter != null) { nodeExecCounter.print(System.out); @@ -307,7 +327,7 @@ if (ex.getNode() != null && ex.getNode().getSourceSection() != null) { SourceSection ss = ex.getNode().getSourceSection(); if (ss != null && !(ss instanceof NullSourceSection)) { - result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); + result.append(" at ").append(ss.getSource().getShortName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn()); } } result.append(": operation"); @@ -356,17 +376,22 @@ @Override protected Object findExportedSymbol(String globalName) { + for (SLFunction f : context.getFunctionRegistry().getFunctions()) { + if (globalName.equals(f.getName())) { + return f; + } + } return null; } @Override protected Object getLanguageGlobal() { - return null; + return context; } @Override protected boolean isObjectOfLanguage(Object object) { - return false; + return object instanceof SLFunction; } } diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java Tue May 26 20:23:22 2015 +0200 @@ -52,20 +52,22 @@ StringBuilder str = new StringBuilder(); Truffle.getRuntime().iterateFrames(frameInstance -> { - dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true)); + CallTarget callTarget = frameInstance.getCallTarget(); + Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY, true); + RootNode rn = ((RootCallTarget) callTarget).getRootNode(); + if (rn.getClass().getName().contains("SLFunctionForeignAccess")) { + return 1; + } + if (str.length() > 0) { + str.append(System.getProperty("line.separator")); + } + str.append("Frame: ").append(rn.toString()); + FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); + frameDescriptor.getSlots().stream().forEach((s) -> { + str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); + }); return null; }); return str.toString(); } - - private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame) { - if (str.length() > 0) { - str.append(System.getProperty("line.separator")); - } - str.append("Frame: ").append(((RootCallTarget) callTarget).getRootNode().toString()); - FrameDescriptor frameDescriptor = frame.getFrameDescriptor(); - for (FrameSlot s : frameDescriptor.getSlots()) { - str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s)); - } - } } diff -r f9031351b2bd -r fac827422011 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 Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java Tue May 26 20:23:22 2015 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.object.*; import com.oracle.truffle.api.source.*; -import com.oracle.truffle.sl.*; import com.oracle.truffle.sl.builtins.*; import com.oracle.truffle.sl.nodes.*; import com.oracle.truffle.sl.nodes.local.*; @@ -158,12 +157,6 @@ */ public void executeMain(Source source) { Parser.parseSL(this, source); - SLFunction main = getFunctionRegistry().lookup("main"); - if (main.getCallTarget() == null) { - throw new SLException("No function main() defined in SL source file."); - } - main.getCallTarget().call(); - output.flush(); } public DynamicObject createObject() { diff -r f9031351b2bd -r fac827422011 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 Tue May 26 20:23:11 2015 +0200 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java Tue May 26 20:23:22 2015 +0200 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.runtime; import com.oracle.truffle.api.*; +import com.oracle.truffle.api.interop.*; import com.oracle.truffle.api.utilities.*; /** @@ -41,7 +42,7 @@ * 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 { +public final class SLFunction implements TruffleObject { /** The name of the function. */ private final String name; @@ -90,4 +91,14 @@ public String toString() { return name; } + + /** + * In case you want some of your objects to co-operate with other languages, you need to make + * them implement {@link TruffleObject} and provide additional {@link SLFunctionForeignAccess + * foreign access implementation}. + */ + @Override + public ForeignAccessFactory getForeignAccessFactory() { + return SLFunctionForeignAccess.INSTANCE; + } } diff -r f9031351b2bd -r fac827422011 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java Tue May 26 20:23:22 2015 +0200 @@ -0,0 +1,90 @@ +/* + * 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.runtime; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ForeignAccessFactory; +import com.oracle.truffle.api.interop.InteropPredicate; +import com.oracle.truffle.api.interop.exception.UnsupportedMessageException; +import com.oracle.truffle.api.interop.messages.Message; +import com.oracle.truffle.api.nodes.RootNode; +import com.oracle.truffle.interop.ForeignAccessArguments; +import com.oracle.truffle.interop.messages.Execute; +import com.oracle.truffle.interop.messages.Receiver; +import com.oracle.truffle.sl.nodes.call.SLDispatchNode; +import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen; +import java.math.BigInteger; + +/** + * Implementation of foreing access for {@link SLFunction}. + */ +final class SLFunctionForeignAccess implements ForeignAccessFactory { + public static final ForeignAccessFactory INSTANCE = new SLFunctionForeignAccess(); + + private SLFunctionForeignAccess() { + } + + @Override + public InteropPredicate getLanguageCheck() { + return (com.oracle.truffle.api.interop.TruffleObject o) -> o instanceof SLFunction; + } + + @Override + public CallTarget getAccess(Message tree) { + if (Execute.create(Receiver.create(), 0).matchStructure(tree)) { + return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode()); + } else { + throw new UnsupportedMessageException(tree.toString() + " not supported"); + } + } + + private static class SLForeignCallerRootNode extends RootNode { + @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create(); + + @Override + public Object execute(VirtualFrame frame) { + SLFunction function = (SLFunction) ForeignAccessArguments.getReceiver(frame.getArguments()); + // the calling convention of interop passes the receiver of a + // function call (the this object) + // as an implicit 1st argument; we need to ignore this argument for SL + Object[] arguments = ForeignAccessArguments.extractUserArguments(1, frame.getArguments()); + for (int i = 0; i < arguments.length; i++) { + if (arguments[i] instanceof Long) { + continue; + } + if (arguments[i] instanceof BigInteger) { + continue; + } + if (arguments[i] instanceof Number) { + arguments[i] = ((Number) arguments[i]).longValue(); + } + } + + return dispatch.executeDispatch(frame, function, arguments); + } + + } + +} diff -r f9031351b2bd -r fac827422011 mx/suite.py --- a/mx/suite.py Tue May 26 20:23:11 2015 +0200 +++ b/mx/suite.py Tue May 26 20:23:22 2015 +0200 @@ -1047,6 +1047,7 @@ "sourceDirs" : ["src"], "dependencies" : [ "com.oracle.truffle.api.dsl", + "com.oracle.truffle.interop", "com.oracle.truffle.api.object", "FINDBUGS" ], @@ -1060,8 +1061,8 @@ "subDir" : "graal", "sourceDirs" : ["src"], "dependencies" : [ - "com.oracle.truffle.sl", - "JUNIT", + "com.oracle.truffle.api.test", + "com.oracle.truffle.sl" ], "checkstyle" : "com.oracle.graal.graph", "javaCompliance" : "1.8",