changeset 22046:e7c2d36daf72

TruffleLanguage.parse method to convert a source to CallTarget. Basic caching to make sure the code is shared among tenants in one JVM.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Thu, 30 Jul 2015 17:36:34 +0200
parents ffbc7f472438
children 227ed03852de
files truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java
diffstat 17 files changed, 294 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java	Thu Jul 30 17:36:34 2015 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.truffle.api.dsl.test;
 
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.debug.DebugSupportProvider;
 import com.oracle.truffle.api.instrument.ToolSupportProvider;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 
@@ -36,7 +39,7 @@
     }
 
     @Override
-    protected Object eval(Source code) throws IOException {
+    protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
         throw new IOException();
     }
 
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Thu Jul 30 17:36:34 2015 +0200
@@ -28,6 +28,7 @@
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.dsl.test.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.*;
 
 public class LanguageRegistrationTest {
@@ -55,8 +56,8 @@
         }
 
         @Override
-        protected Object eval(Source code) throws IOException {
-            return null;
+        protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+            throw new IOException();
         }
 
         @Override
@@ -94,8 +95,8 @@
         }
 
         @Override
-        protected Object eval(Source code) throws IOException {
-            return null;
+        protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+            throw new IOException();
         }
 
         @Override
@@ -132,11 +133,6 @@
         }
 
         @Override
-        protected Object eval(Source code) throws IOException {
-            return null;
-        }
-
-        @Override
         protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
             return null;
         }
@@ -161,5 +157,10 @@
             return null;
         }
 
+        @Override
+        protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+            throw new IOException();
+        }
+
     }
 }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java	Thu Jul 30 17:36:34 2015 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.truffle.api.test;
 
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.RootCallTarget;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.debug.DebugSupportProvider;
 import com.oracle.truffle.api.instrument.ToolSupportProvider;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 
@@ -36,7 +39,7 @@
     }
 
     @Override
-    protected Object eval(Source code) throws IOException {
+    protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
         throw new IOException();
     }
 
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Thu Jul 30 17:36:34 2015 +0200
@@ -32,6 +32,8 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.api.nodes.RootNode;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.vm.*;
 
@@ -115,28 +117,8 @@
         private final Map<String, String> implicit = new HashMap<>();
 
         @Override
-        protected Object eval(Source code) throws IOException {
-            Properties p = new Properties();
-            try (Reader r = code.getReader()) {
-                p.load(r);
-            }
-            Enumeration<Object> en = p.keys();
-            while (en.hasMoreElements()) {
-                Object n = en.nextElement();
-                if (n instanceof String) {
-                    String k = (String) n;
-                    if (k.startsWith("explicit.")) {
-                        explicit.put(k.substring(9), p.getProperty(k));
-                    }
-                    if (k.startsWith("implicit.")) {
-                        implicit.put(k.substring(9), p.getProperty(k));
-                    }
-                    if (k.equals("return")) {
-                        return env().importSymbol(p.getProperty(k));
-                    }
-                }
-            }
-            return null;
+        protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+            return new ValueCallTarget(code, getClass());
         }
 
         @Override
@@ -150,6 +132,10 @@
             return null;
         }
 
+        public static <Language extends TruffleLanguage> Language findContext(Class<Language> type) {
+            return TruffleLanguage.findContext(type);
+        }
+
         @Override
         protected Object getLanguageGlobal() {
             return null;
@@ -169,6 +155,53 @@
         protected DebugSupportProvider getDebugSupport() {
             return null;
         }
+
+        private Object importExport(Source code) {
+            Properties p = new Properties();
+            try (Reader r = code.getReader()) {
+                p.load(r);
+            } catch (IOException ex) {
+                throw new IllegalStateException(ex);
+            }
+            Enumeration<Object> en = p.keys();
+            while (en.hasMoreElements()) {
+                Object n = en.nextElement();
+                if (n instanceof String) {
+                    String k = (String) n;
+                    if (k.startsWith("explicit.")) {
+                        explicit.put(k.substring(9), p.getProperty(k));
+                    }
+                    if (k.startsWith("implicit.")) {
+                        implicit.put(k.substring(9), p.getProperty(k));
+                    }
+                    if (k.equals("return")) {
+                        return env().importSymbol(p.getProperty(k));
+                    }
+                }
+            }
+            return null;
+        }
+    }
+
+    private static final class ValueCallTarget implements RootCallTarget {
+        private final Source code;
+        private final Class<? extends AbstractExportImportLanguage> language;
+
+        private ValueCallTarget(Source code, Class<? extends AbstractExportImportLanguage> language) {
+            this.code = code;
+            this.language = language;
+        }
+
+        @Override
+        public RootNode getRootNode() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Object call(Object... arguments) {
+            AbstractExportImportLanguage context = AbstractExportImportLanguage.findContext(language);
+            return context.importExport(code);
+        }
     }
 
     static final String L1 = "application/x-test-import-export-1";
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Thu Jul 30 17:36:34 2015 +0200
@@ -31,9 +31,13 @@
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.api.vm.TruffleVM.Language;
+import java.util.Collections;
+import java.util.Map;
+import java.util.WeakHashMap;
 
 /**
  * An entry point for everyone who wants to implement a Truffle based language. By providing
@@ -98,7 +102,24 @@
         return this.env;
     }
 
-    protected abstract Object eval(Source code) throws IOException;
+    /**
+     * Parses the provided source and generates appropriate AST. The parsing should execute no user
+     * code, it should only create the {@link Node} tree to represent the source. The parsing may be
+     * performed in a context (specified as another {@link Node}) or without context. The
+     * {@code argumentNames} may contain symbolic names for actual parameters of the call to the
+     * returned value. The result should be a call target with method
+     * {@link CallTarget#call(java.lang.Object...)} that accepts as many arguments as were provided
+     * via the {@code argumentNames} array.
+     *
+     * @param code source code to parse
+     * @param context a {@link Node} defining context for the parsing
+     * @param argumentNames symbolic names for parameters of
+     *            {@link CallTarget#call(java.lang.Object...)}
+     * @return a call target to invoke which also keeps in memory the {@link Node} tree representing
+     *         just parsed <code>code</code>
+     * @throws IOException thrown when I/O or parsing goes wrong
+     */
+    protected abstract CallTarget parse(Source code, Node context, String... argumentNames) throws IOException;
 
     /**
      * Called when some other language is seeking for a global symbol. This method is supposed to do
@@ -150,6 +171,18 @@
     protected abstract DebugSupportProvider getDebugSupport();
 
     /**
+     * Finds the currently executing context for current thread.
+     *
+     * @param <Language> type of language making the query
+     * @param language the language class
+     * @return the context associated with current execution
+     * @throws IllegalStateException if no context is associated with the execution
+     */
+    protected static <Language extends TruffleLanguage> Language findContext(Class<Language> language) {
+        return language.cast(API.findLanguage(null, language));
+    }
+
+    /**
      * Represents execution environment of the {@link TruffleLanguage}. Each active
      * {@link TruffleLanguage} receives instance of the environment before any code is executed upon
      * it. The environment has knowledge of all active languages and can exchange symbols between
@@ -229,9 +262,23 @@
             return super.importSymbol(vm, queryingLang, globalName);
         }
 
+        private static final Map<Source, CallTarget> COMPILED = Collections.synchronizedMap(new WeakHashMap<Source, CallTarget>());
+
         @Override
-        protected Object eval(TruffleLanguage l, Source s) throws IOException {
-            return l.eval(s);
+        protected Object eval(TruffleLanguage language, Source source) throws IOException {
+            CallTarget target = COMPILED.get(source);
+            if (target == null) {
+                target = language.parse(source, null);
+                if (target == null) {
+                    throw new IOException("Parsing has not produced a CallTarget for " + source);
+                }
+                COMPILED.put(source, target);
+            }
+            try {
+                return target.call();
+            } catch (Exception ex) {
+                throw new IOException(ex);
+            }
         }
 
         @Override
@@ -240,6 +287,11 @@
         }
 
         @Override
+        protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+            return super.findLanguage(vm, languageClass);
+        }
+
+        @Override
         protected Object languageGlobal(TruffleLanguage l) {
             return l.getLanguageGlobal();
         }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Thu Jul 30 17:36:34 2015 +0200
@@ -45,15 +45,11 @@
     private static Accessor NODES;
     private static Accessor INSTRUMENT;
     private static Accessor DEBUG;
+    private static final ThreadLocal<TruffleVM> CURRENT_VM = new ThreadLocal<>();
 
     static {
         TruffleLanguage lng = new TruffleLanguage(null) {
             @Override
-            protected Object eval(Source code) throws IOException {
-                return null;
-            }
-
-            @Override
             protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
                 return null;
             }
@@ -77,6 +73,11 @@
             protected DebugSupportProvider getDebugSupport() {
                 return null;
             }
+
+            @Override
+            protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+                throw new IOException();
+            }
         };
         lng.hashCode();
         new Node(null) {
@@ -162,11 +163,27 @@
     }
 
     protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+        if (vm == null) {
+            vm = CURRENT_VM.get();
+            if (vm == null) {
+                throw new IllegalStateException();
+            }
+        }
         return SPI.findLanguage(vm, languageClass);
     }
 
     protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
-        return DEBUG.executionStart(vm, fillIn, s);
+        final Closeable debugClose = DEBUG.executionStart(vm, fillIn, s);
+        final TruffleVM prev = CURRENT_VM.get();
+        CURRENT_VM.set(vm);
+        class ContextCloseable implements Closeable {
+            @Override
+            public void close() throws IOException {
+                CURRENT_VM.set(prev);
+                debugClose.close();
+            }
+        }
+        return new ContextCloseable();
     }
 
     protected void dispatchEvent(TruffleVM vm, Object event) {
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Jul 30 17:36:34 2015 +0200
@@ -164,5 +164,4 @@
         }
         return new DefaultLoopNode(repeating);
     }
-
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu Jul 30 17:36:34 2015 +0200
@@ -814,7 +814,7 @@
 
         @Override
         public int hashCode() {
-            return description.hashCode();
+            return description.hashCode() * code.hashCode();
         }
 
         @Override
@@ -827,7 +827,7 @@
             }
             if (obj instanceof LiteralSource) {
                 LiteralSource other = (LiteralSource) obj;
-                return description.equals(other.description);
+                return description.equals(other.description) && code.equals(other.code);
             }
             return false;
         }
--- a/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Thu Jul 30 17:36:34 2015 +0200
@@ -70,6 +70,14 @@
             "function apply(f) {\n" +
             "  return f(18, 32) + 10;\n" +
             "}\n" +
+            "function cnt() {\n" +
+            "  return 0;\n" +
+            "}\n" +
+            "function count() {\n" +
+            "  n = cnt() + 1;\n" +
+            "  defineFunction(\"function cnt() { return \" + n + \"; }\");\n" +
+            "  return n;\n" +
+            "}\n" +
             "function null() {\n" +
             "}\n"
         );
@@ -111,4 +119,9 @@
             "}\n";
         // @formatter:on
     }
+
+    @Override
+    protected String countInvocations() {
+        return "count";
+    }
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Thu Jul 30 17:36:34 2015 +0200
@@ -56,7 +56,6 @@
 import com.oracle.truffle.api.vm.*;
 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.nodes.*;
 import com.oracle.truffle.sl.nodes.call.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
@@ -164,10 +163,10 @@
 
     public SLLanguage(Env env) {
         super(env);
-        context = SLContextFactory.create(this, new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
+        context = new SLContext(this, new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
         LAST = this;
         for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
-            context.installBuiltin(builtin);
+            context.installBuiltin(builtin, true);
         }
     }
 
@@ -381,14 +380,43 @@
         return result.toString();
     }
 
+    public static SLLanguage find() {
+        return SLLanguage.findContext(SLLanguage.class);
+    }
+
     @Override
-    protected Object eval(Source code) throws IOException {
+    protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
+        final SLContext c = new SLContext(this);
+        final Exception[] failed = {null};
         try {
-            context.evalSource(code);
+            c.evalSource(code);
+            failed[0] = null;
         } catch (Exception e) {
-            throw new IOException(e);
+            failed[0] = e;
         }
-        return null;
+        return new CallTarget() {
+            @Override
+            public Object call(Object... arguments) {
+                if (failed[0] instanceof RuntimeException) {
+                    throw (RuntimeException) failed[0];
+                }
+                if (failed[0] != null) {
+                    throw new IllegalStateException(failed[0]);
+                }
+                SLLanguage current = SLLanguage.find();
+                SLContext fillIn = current.context;
+                final SLFunctionRegistry functionRegistry = fillIn.getFunctionRegistry();
+                for (SLFunction f : c.getFunctionRegistry().getFunctions()) {
+                    RootCallTarget callTarget = f.getCallTarget();
+                    if (callTarget == null) {
+                        continue;
+                    }
+                    functionRegistry.lookup(f.getName());
+                    functionRegistry.register(f.getName(), (SLRootNode) f.getCallTarget().getRootNode());
+                }
+                return null;
+            }
+        };
     }
 
     @Override
@@ -465,6 +493,10 @@
         }
     }
 
+    public SLContext getContext() {
+        return context;
+    }
+
     private final class SLDebugProvider implements DebugSupportProvider {
 
         public SLDebugProvider() {
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java	Thu Jul 30 17:16:59 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * The Universal Permissive License (UPL), Version 1.0
- * 
- * Subject to the condition set forth below, permission is hereby granted to any
- * person obtaining a copy of this software, associated documentation and/or
- * data (collectively the "Software"), free of charge and under any and all
- * copyright rights in the Software, and any and all patent rights owned or
- * freely licensable by each licensor hereunder covering either (i) the
- * unmodified Software as contributed to or provided by such licensor, or (ii)
- * the Larger Works (as defined below), to deal in both
- * 
- * (a) the Software, and
- * 
- * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
- * one is included with the Software each a "Larger Work" to which the Software
- * is contributed by such licensors),
- * 
- * without restriction, including without limitation the rights to copy, create
- * derivative works of, display, perform, and distribute the Software and make,
- * use, sell, offer for sale, import, export, have made, and have sold the
- * Software and the Larger Work(s), and to sublicense the foregoing rights on
- * either these or other terms.
- * 
- * This license is subject to the following condition:
- * 
- * The above copyright notice and either this complete permission notice or at a
- * minimum a reference to the UPL must be included in all copies or substantial
- * portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-package com.oracle.truffle.sl.factory;
-
-import com.oracle.truffle.sl.SLLanguage;
-import java.io.*;
-
-import com.oracle.truffle.sl.runtime.*;
-
-public final class SLContextFactory {
-
-    private SLContextFactory() {
-    }
-
-    public static SLContext create(SLLanguage sl, BufferedReader input, PrintWriter output) {
-        return new SLContext(sl, input, output);
-    }
-}
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Thu Jul 30 17:36:34 2015 +0200
@@ -65,16 +65,12 @@
     /** The name of the function, for printing purposes only. */
     private final String name;
 
-    /** The Simple execution context for this tree. **/
-    private final SLContext context;
-
     @CompilationFinal private boolean isCloningAllowed;
 
     public SLRootNode(SLContext context, FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) {
         super(SLLanguage.class, null, frameDescriptor);
         this.bodyNode = bodyNode;
         this.name = name;
-        this.context = context;
     }
 
     @Override
@@ -108,13 +104,4 @@
     public String toString() {
         return "root " + name;
     }
-
-    public SLContext getSLContext() {
-        return this.context;
-    }
-
-    @Override
-    public ExecutionContext getExecutionContext() {
-        return this.context;
-    }
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Thu Jul 30 17:36:34 2015 +0200
@@ -44,6 +44,7 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.sl.SLLanguage;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
@@ -56,15 +57,16 @@
 @NodeInfo(shortName = "func")
 public final class SLFunctionLiteralNode extends SLExpressionNode {
 
-    private final SLFunction value;
+    private final String value;
 
-    public SLFunctionLiteralNode(SourceSection src, SLFunction value) {
+    public SLFunctionLiteralNode(SourceSection src, String value) {
         super(src);
         this.value = value;
     }
 
     @Override
     public SLFunction executeGeneric(VirtualFrame frame) {
-        return value;
+        SLLanguage language = SLLanguage.find();
+        return language.getContext().getFunctionRegistry().lookup(value);
     }
 }
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Jul 30 17:36:34 2015 +0200
@@ -331,7 +331,7 @@
             return SLReadLocalVariableNodeGen.create(src, frameSlot);
         } else {
             /* Read of a global name. In our language, the only global names are functions. */
-            return new SLFunctionLiteralNode(src, context.getFunctionRegistry().lookup(nameToken.val));
+            return new SLFunctionLiteralNode(src, nameToken.val);
         }
     }
 
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Jul 30 17:36:34 2015 +0200
@@ -74,11 +74,19 @@
     private final Shape emptyShape;
 
     public SLContext(SLLanguage language, BufferedReader input, PrintWriter output) {
+        this(language, input, output, true);
+    }
+
+    public SLContext(SLLanguage language) {
+        this(language, null, null, false);
+    }
+
+    private SLContext(SLLanguage language, BufferedReader input, PrintWriter output, boolean installBuiltins) {
         this.language = language;
         this.input = input;
         this.output = output;
         this.functionRegistry = new SLFunctionRegistry();
-        installBuiltins();
+        installBuiltins(installBuiltins);
 
         this.emptyShape = LAYOUT.createShape(new ObjectType());
     }
@@ -114,19 +122,19 @@
      * Adds all builtin functions to the {@link SLFunctionRegistry}. This method lists all
      * {@link SLBuiltinNode builtin implementation classes}.
      */
-    private void installBuiltins() {
-        installBuiltin(SLReadlnBuiltinFactory.getInstance());
-        installBuiltin(SLPrintlnBuiltinFactory.getInstance());
-        installBuiltin(SLNanoTimeBuiltinFactory.getInstance());
-        installBuiltin(SLDefineFunctionBuiltinFactory.getInstance());
-        installBuiltin(SLStackTraceBuiltinFactory.getInstance());
-        installBuiltin(SLHelloEqualsWorldBuiltinFactory.getInstance());
-        installBuiltin(SLAssertTrueBuiltinFactory.getInstance());
-        installBuiltin(SLAssertFalseBuiltinFactory.getInstance());
-        installBuiltin(SLNewObjectBuiltinFactory.getInstance());
+    private void installBuiltins(boolean registerRootNodes) {
+        installBuiltin(SLReadlnBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLPrintlnBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLNanoTimeBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLDefineFunctionBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLStackTraceBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLHelloEqualsWorldBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLAssertTrueBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLAssertFalseBuiltinFactory.getInstance(), registerRootNodes);
+        installBuiltin(SLNewObjectBuiltinFactory.getInstance(), registerRootNodes);
     }
 
-    public void installBuiltin(NodeFactory<? extends SLBuiltinNode> factory) {
+    public void installBuiltin(NodeFactory<? extends SLBuiltinNode> factory, boolean registerRootNodes) {
         /*
          * 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
@@ -149,8 +157,13 @@
         /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */
         SLRootNode rootNode = new SLRootNode(this, new FrameDescriptor(), builtinBodyNode, name);
 
-        /* Register the builtin function in our function registry. */
-        getFunctionRegistry().register(name, rootNode);
+        if (registerRootNodes) {
+            /* Register the builtin function in our function registry. */
+            getFunctionRegistry().register(name, rootNode);
+        } else {
+            // make sure the function is known
+            getFunctionRegistry().lookup(name);
+        }
     }
 
     public static NodeInfo lookupNodeInfo(Class<?> clazz) {
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Thu Jul 30 17:36:34 2015 +0200
@@ -47,16 +47,10 @@
 
     @Override
     public ForeignAccess getForeignAccess() {
-        return ForeignAccess.create(MaxMinObject.class, new AF(max));
+        return ForeignAccess.create(MaxMinObject.class, new AF());
     }
 
     static final class AF implements ForeignAccess.Factory10 {
-        private final boolean max;
-
-        public AF(boolean max) {
-            this.max = max;
-        }
-
         @Override
         public CallTarget accessIsNull() {
             return null;
@@ -100,7 +94,7 @@
         @Override
         public CallTarget accessExecute(int argumentsLength) {
             if (argumentsLength == 2) {
-                MaxMinNode maxNode = MaxMinObjectFactory.MaxMinNodeGen.create(max, MaxMinObjectFactory.UnboxNodeGen.create(new ReadArgNode(0)),
+                MaxMinNode maxNode = MaxMinObjectFactory.MaxMinNodeGen.create(new ReadReceiverNode(), MaxMinObjectFactory.UnboxNodeGen.create(new ReadArgNode(0)),
                                 MaxMinObjectFactory.UnboxNodeGen.create(new ReadArgNode(1)));
                 return Truffle.getRuntime().createCallTarget(maxNode);
             }
@@ -130,6 +124,12 @@
         }
     }
 
+    static class ReadReceiverNode extends Node {
+        public Object execute(VirtualFrame frame) {
+            return ForeignAccess.getReceiver(frame);
+        }
+    }
+
     @NodeChildren({@NodeChild(value = "valueNode", type = ReadArgNode.class)})
     abstract static class UnboxNode extends Node {
         @Child private Node unbox;
@@ -171,28 +171,26 @@
 
     }
 
-    @NodeChildren({@NodeChild(value = "firstNode", type = UnboxNode.class), @NodeChild(value = "secondNode", type = UnboxNode.class)})
+    @NodeChildren({@NodeChild(value = "receiver", type = ReadReceiverNode.class), @NodeChild(value = "firstNode", type = UnboxNode.class), @NodeChild(value = "secondNode", type = UnboxNode.class)})
     abstract static class MaxMinNode extends RootNode {
-        private final boolean max;
 
-        MaxMinNode(boolean max) {
+        MaxMinNode() {
             super(MMLanguage.class, null, null);
-            this.max = max;
         }
 
         @Specialization
-        public int execute(int first, int second) {
-            return max ? Math.max(first, second) : Math.min(first, second);
+        public int execute(MaxMinObject receiver, int first, int second) {
+            return receiver.max ? Math.max(first, second) : Math.min(first, second);
         }
 
         @Specialization
-        public long execute(long first, long second) {
-            return max ? Math.max(first, second) : Math.min(first, second);
+        public long execute(MaxMinObject receiver, long first, long second) {
+            return receiver.max ? Math.max(first, second) : Math.min(first, second);
         }
 
         @Specialization
-        public double execute(double first, double second) {
-            return max ? Math.max(first, second) : Math.min(first, second);
+        public double execute(MaxMinObject receiver, double first, double second) {
+            return receiver.max ? Math.max(first, second) : Math.min(first, second);
         }
     }
 
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Thu Jul 30 17:16:59 2015 +0200
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java	Thu Jul 30 17:36:34 2015 +0200
@@ -102,6 +102,19 @@
     protected abstract String applyNumbers();
 
     /**
+     * Name of a function that counts number of its invocations in current {@link TruffleVM}
+     * context. Your function should somehow keep a counter to remember number of its invocations
+     * and always increment it. The first invocation should return <code>1</code>, the second
+     * <code>2</code> and so on. The returned values are expected to be instances of {@link Number}.
+     * <p>
+     * The function will be used to test that two instances of your language can co-exist next to
+     * each other. Without being mutually influenced.
+     *
+     * @return name of globally expected symbol
+     */
+    protected abstract String countInvocations();
+
+    /**
      * Return a code snippet that is invalid in your language. Its
      * {@link TruffleVM#eval(java.lang.String, java.lang.String) evaluation} should fail and yield
      * an exception.
@@ -197,6 +210,33 @@
         assert 28 == n.intValue() : "18 < 32 and plus 10";
     }
 
+    @Test
+    public void testCoExistanceOfMultipleLanguageInstances() throws Exception {
+        final String countMethod = countInvocations();
+        TruffleVM.Symbol count1 = findGlobalSymbol(countMethod);
+        tckVM = null; // clean-up
+        TruffleVM.Symbol count2 = findGlobalSymbol(countMethod);
+
+        int prev1 = 0;
+        int prev2 = 0;
+        Random r = new Random();
+        for (int i = 0; i < 10; i++) {
+            int quantum = r.nextInt(10);
+            for (int j = 0; j < quantum; j++) {
+                Object res = count1.invoke(null);
+                assert res instanceof Number : "expecting number: " + res;
+                assert ((Number) res).intValue() == ++prev1 : "expecting " + prev1 + " but was " + res;
+            }
+            for (int j = 0; j < quantum; j++) {
+                Object res = count2.invoke(null);
+                assert res instanceof Number : "expecting number: " + res;
+                assert ((Number) res).intValue() == ++prev2 : "expecting " + prev2 + " but was " + res;
+            }
+            assert prev1 == prev2 : "At round " + i + " the same number of invocations " + prev1 + " vs. " + prev2;
+        }
+
+    }
+
     private TruffleVM.Symbol findGlobalSymbol(String name) throws Exception {
         TruffleVM.Symbol s = vm().findGlobalSymbol(name);
         assert s != null : "Symbol " + name + " is not found!";