changeset 22066:78c3d3d8d86e

Clearly separating the TruffleLanguage definition from context used during its execution. TruffleLanguage now has to have public static field INSTANCE and override createContext method.
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Thu, 06 Aug 2015 08:31:49 +0200
parents 503529c65456
children e206ebd965f2
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.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.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/AccessorTest.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/debug/Debugger.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.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/SymbolInvoker.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java
diffstat 21 files changed, 294 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java	Thu Aug 06 08:31:49 2015 +0200
@@ -30,11 +30,11 @@
 import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 
-public final class TestingLanguage extends TruffleLanguage {
-    public static final TruffleLanguage INSTANCE = new TestingLanguage();
+public final class TestingLanguage extends TruffleLanguage<Object> {
+    public static final TestingLanguage INSTANCE = new TestingLanguage();
 
     private TestingLanguage() {
-        super(null);
+        super();
     }
 
     @Override
@@ -43,12 +43,12 @@
     }
 
     @Override
-    protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+    protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
         return null;
     }
 
     @Override
-    protected Object getLanguageGlobal() {
+    protected Object getLanguageGlobal(Object context) {
         return null;
     }
 
@@ -67,4 +67,8 @@
         return null;
     }
 
+    @Override
+    protected Object createContext(Env env) {
+        return null;
+    }
 }
--- a/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Thu Aug 06 08:31:49 2015 +0200
@@ -48,11 +48,11 @@
     public static final class MyLangNoSubclass {
     }
 
-    @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter")
+    @ExpectError("Language class must have public static final singleton field called INSTANCE")
     @TruffleLanguage.Registration(name = "myLangNoCnstr", version = "0", mimeType = "text/x-my")
-    public static final class MyLangWrongConstr extends TruffleLanguage {
+    public static final class MyLangWrongConstr extends TruffleLanguage<Object> {
         private MyLangWrongConstr() {
-            super(null);
+            super();
         }
 
         @Override
@@ -61,12 +61,12 @@
         }
 
         @Override
-        protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+        protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
             return null;
         }
 
         @Override
-        protected Object getLanguageGlobal() {
+        protected Object getLanguageGlobal(Object context) {
             return null;
         }
 
@@ -85,13 +85,18 @@
             return null;
         }
 
+        @Override
+        protected Object createContext(Env env) {
+            throw new UnsupportedOperationException();
+        }
+
     }
 
-    @ExpectError("Language must have a public constructor accepting TruffleLanguage.Env as parameter")
-    @TruffleLanguage.Registration(name = "myLangNoCnstr", version = "0", mimeType = "text/x-my")
-    public static final class MyLangNoConstr extends TruffleLanguage {
-        public MyLangNoConstr() {
-            super(null);
+    @ExpectError("Language class must have public static final singleton field called INSTANCE")
+    @TruffleLanguage.Registration(name = "myLangNoField", version = "0", mimeType = "text/x-my")
+    public static final class MyLangNoField extends TruffleLanguage<Object> {
+        public MyLangNoField() {
+            super();
         }
 
         @Override
@@ -100,12 +105,12 @@
         }
 
         @Override
-        protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+        protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
             return null;
         }
 
         @Override
-        protected Object getLanguageGlobal() {
+        protected Object getLanguageGlobal(Object context) {
             return null;
         }
 
@@ -124,21 +129,28 @@
             return null;
         }
 
+        @Override
+        protected Object createContext(Env env) {
+            throw new UnsupportedOperationException();
+        }
+
     }
 
     @TruffleLanguage.Registration(name = "myLangGood", version = "0", mimeType = "text/x-my")
-    public static final class MyLangGood extends TruffleLanguage {
-        public MyLangGood(TruffleLanguage.Env env) {
-            super(env);
+    public static final class MyLangGood extends TruffleLanguage<Object> {
+        private MyLangGood() {
+            super();
         }
 
+        public static final MyLangGood INSTANCE = new MyLangGood();
+
         @Override
-        protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+        protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
             return null;
         }
 
         @Override
-        protected Object getLanguageGlobal() {
+        protected Object getLanguageGlobal(Object context) {
             return null;
         }
 
@@ -162,5 +174,10 @@
             throw new IOException();
         }
 
+        @Override
+        protected Object createContext(Env env) {
+            return env;
+        }
+
     }
 }
--- a/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.interop/src/com/oracle/truffle/api/interop/impl/SymbolInvokerImpl.java	Thu Aug 06 08:31:49 2015 +0200
@@ -37,8 +37,9 @@
 public final class SymbolInvokerImpl extends SymbolInvoker {
     static final FrameDescriptor UNUSED_FRAMEDESCRIPTOR = new FrameDescriptor();
 
+    @SuppressWarnings("unchecked")
     @Override
-    protected Object invoke(TruffleLanguage lang, Object symbol, Object... arr) throws IOException {
+    protected Object invoke(TruffleLanguage<?> lang, Object symbol, Object... arr) throws IOException {
         if (symbol instanceof String) {
             return symbol;
         }
@@ -48,8 +49,9 @@
         if (symbol instanceof Boolean) {
             return symbol;
         }
+        Class<? extends TruffleLanguage<?>> type = (Class<? extends TruffleLanguage<?>>) lang.getClass();
         Node executeMain = Message.createExecute(arr.length).createNode();
-        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, executeMain, (TruffleObject) symbol, arr));
+        CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(type, executeMain, (TruffleObject) symbol, arr));
         VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR);
         Object ret = callTarget.call(frame);
         if (ret instanceof TruffleObject) {
@@ -57,20 +59,20 @@
             Object isBoxedResult;
             try {
                 Node isBoxed = Message.IS_BOXED.createNode();
-                CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isBoxed, tret));
+                CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(type, isBoxed, tret));
                 isBoxedResult = isBoxedTarget.call(frame);
             } catch (IllegalArgumentException ex) {
                 isBoxedResult = false;
             }
             if (Boolean.TRUE.equals(isBoxedResult)) {
                 Node unbox = Message.UNBOX.createNode();
-                CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, unbox, tret));
+                CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(type, unbox, tret));
                 Object unboxResult = unboxTarget.call(frame);
                 return unboxResult;
             } else {
                 try {
                     Node isNull = Message.IS_NULL.createNode();
-                    CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(lang, isNull, tret));
+                    CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(type, isNull, tret));
                     Object isNullResult = isNullTarget.call(frame);
                     if (Boolean.TRUE.equals(isNullResult)) {
                         return null;
@@ -88,8 +90,8 @@
         private final TruffleObject function;
         private final Object[] args;
 
-        public TemporaryRoot(TruffleLanguage lang, Node foreignAccess, TruffleObject function, Object... args) {
-            super(lang.getClass(), null, null);
+        public TemporaryRoot(Class<? extends TruffleLanguage<?>> lang, Node foreignAccess, TruffleObject function, Object... args) {
+            super(lang, null, null);
             this.foreignAccess = foreignAccess;
             this.function = function;
             this.args = args;
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java	Thu Aug 06 08:31:49 2015 +0200
@@ -30,11 +30,10 @@
 import com.oracle.truffle.api.source.Source;
 import java.io.IOException;
 
-public final class TestingLanguage extends TruffleLanguage {
-    public static final TruffleLanguage INSTANCE = new TestingLanguage();
+public final class TestingLanguage extends TruffleLanguage<Object> {
+    public static final TestingLanguage INSTANCE = new TestingLanguage();
 
     private TestingLanguage() {
-        super(null);
     }
 
     @Override
@@ -43,12 +42,12 @@
     }
 
     @Override
-    protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+    protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
         return null;
     }
 
     @Override
-    protected Object getLanguageGlobal() {
+    protected Object getLanguageGlobal(Object context) {
         return null;
     }
 
@@ -67,4 +66,9 @@
         return null;
     }
 
+    @Override
+    protected Object createContext(Env env) {
+        return null;
+    }
+
 }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/AccessorTest.java	Thu Aug 06 08:31:49 2015 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.truffle.api.test.vm;
 
+import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.impl.Accessor;
 import com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.ExportImportLanguage1;
 import static com.oracle.truffle.api.test.vm.ImplicitExplicitExportTest.L1;
@@ -54,13 +55,18 @@
 
         Object afterInitialization = findLanguageByClass(vm);
         assertNotNull("Language found", afterInitialization);
-        assertTrue("Right instance", afterInitialization instanceof ExportImportLanguage1);
+        assertTrue("Right instance: " + afterInitialization, afterInitialization instanceof ExportImportLanguage1);
     }
 
-    Object findLanguageByClass(TruffleVM vm) throws IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
+    Object findLanguageByClass(TruffleVM vm) throws IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
         Method find = Accessor.class.getDeclaredMethod("findLanguage", TruffleVM.class, Class.class);
         find.setAccessible(true);
-        Object language1 = find.invoke(API, vm, ExportImportLanguage1.class);
-        return language1;
+        TruffleLanguage.Env env = (TruffleLanguage.Env) find.invoke(API, vm, ExportImportLanguage1.class);
+        Field f = env.getClass().getDeclaredField("langCtx");
+        f.setAccessible(true);
+        Object langCtx = f.get(env);
+        f = langCtx.getClass().getDeclaredField("lang");
+        f.setAccessible(true);
+        return f.get(langCtx);
     }
 }
--- a/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java	Thu Aug 06 08:31:49 2015 +0200
@@ -30,6 +30,7 @@
 import org.junit.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.Node;
@@ -108,36 +109,41 @@
         assertEquals("Global symbol is also 43", "43", vm.findGlobalSymbol("ahoj").invoke(null));
     }
 
-    private abstract static class AbstractExportImportLanguage extends TruffleLanguage {
-        protected AbstractExportImportLanguage(Env env) {
-            super(env);
+    private static final class Ctx {
+        final Map<String, String> explicit = new HashMap<>();
+        final Map<String, String> implicit = new HashMap<>();
+        final Env env;
+
+        public Ctx(Env env) {
+            this.env = env;
         }
+    }
 
-        private final Map<String, String> explicit = new HashMap<>();
-        private final Map<String, String> implicit = new HashMap<>();
+    private abstract static class AbstractExportImportLanguage extends TruffleLanguage<Ctx> {
+
+        @Override
+        protected Ctx createContext(Env env) {
+            return new Ctx(env);
+        }
 
         @Override
         protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
-            return new ValueCallTarget(code, getClass());
+            return new ValueCallTarget(code, this);
         }
 
         @Override
-        protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
-            if (explicit.containsKey(globalName)) {
-                return explicit.get(globalName);
+        protected Object findExportedSymbol(Ctx context, String globalName, boolean onlyExplicit) {
+            if (context.explicit.containsKey(globalName)) {
+                return context.explicit.get(globalName);
             }
-            if (!onlyExplicit && implicit.containsKey(globalName)) {
-                return implicit.get(globalName);
+            if (!onlyExplicit && context.implicit.containsKey(globalName)) {
+                return context.implicit.get(globalName);
             }
             return null;
         }
 
-        public static <Language extends TruffleLanguage> Language findContext(Class<Language> type) {
-            return TruffleLanguage.findContext(type);
-        }
-
         @Override
-        protected Object getLanguageGlobal() {
+        protected Object getLanguageGlobal(Ctx context) {
             return null;
         }
 
@@ -157,6 +163,7 @@
         }
 
         private Object importExport(Source code) {
+            Ctx ctx = findContext();
             Properties p = new Properties();
             try (Reader r = code.getReader()) {
                 p.load(r);
@@ -169,13 +176,13 @@
                 if (n instanceof String) {
                     String k = (String) n;
                     if (k.startsWith("explicit.")) {
-                        explicit.put(k.substring(9), p.getProperty(k));
+                        ctx.explicit.put(k.substring(9), p.getProperty(k));
                     }
                     if (k.startsWith("implicit.")) {
-                        implicit.put(k.substring(9), p.getProperty(k));
+                        ctx.implicit.put(k.substring(9), p.getProperty(k));
                     }
                     if (k.equals("return")) {
-                        return env().importSymbol(p.getProperty(k));
+                        return ctx.env.importSymbol(p.getProperty(k));
                     }
                 }
             }
@@ -185,9 +192,9 @@
 
     private static final class ValueCallTarget implements RootCallTarget {
         private final Source code;
-        private final Class<? extends AbstractExportImportLanguage> language;
+        private final AbstractExportImportLanguage language;
 
-        private ValueCallTarget(Source code, Class<? extends AbstractExportImportLanguage> language) {
+        private ValueCallTarget(Source code, AbstractExportImportLanguage language) {
             this.code = code;
             this.language = language;
         }
@@ -199,8 +206,7 @@
 
         @Override
         public Object call(Object... arguments) {
-            AbstractExportImportLanguage context = AbstractExportImportLanguage.findContext(language);
-            return context.importExport(code);
+            return language.importExport(code);
         }
     }
 
@@ -210,22 +216,25 @@
 
     @TruffleLanguage.Registration(mimeType = L1, name = "ImportExport1", version = "0")
     public static final class ExportImportLanguage1 extends AbstractExportImportLanguage {
-        public ExportImportLanguage1(Env env) {
-            super(env);
+        public static final AbstractExportImportLanguage INSTANCE = new ExportImportLanguage1();
+
+        public ExportImportLanguage1() {
         }
     }
 
     @TruffleLanguage.Registration(mimeType = L2, name = "ImportExport2", version = "0")
     public static final class ExportImportLanguage2 extends AbstractExportImportLanguage {
-        public ExportImportLanguage2(Env env) {
-            super(env);
+        public static final AbstractExportImportLanguage INSTANCE = new ExportImportLanguage2();
+
+        public ExportImportLanguage2() {
         }
     }
 
     @TruffleLanguage.Registration(mimeType = L3, name = "ImportExport3", version = "0")
     public static final class ExportImportLanguage3 extends AbstractExportImportLanguage {
-        public ExportImportLanguage3(Env env) {
-            super(env);
+        public static final AbstractExportImportLanguage INSTANCE = new ExportImportLanguage3();
+
+        private ExportImportLanguage3() {
         }
     }
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Thu Aug 06 08:31:49 2015 +0200
@@ -26,7 +26,6 @@
 
 import java.io.*;
 import java.lang.annotation.*;
-import java.lang.reflect.*;
 
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.impl.*;
@@ -45,18 +44,16 @@
  * language becomes accessible to users of the {@link TruffleVM Truffle virtual machine} - all they
  * will need to do is to include your JAR into their application and all the Truffle goodies (multi
  * language support, multitenant hosting, debugging, etc.) will be made available to them.
+ * 
+ * @param <C> internal state of the language associated with every thread that is executing program
+ *            {@link #parse(com.oracle.truffle.api.source.Source, com.oracle.truffle.api.nodes.Node, java.lang.String...)
+ *            parsed} by the language
  */
-public abstract class TruffleLanguage {
-    private final Env env;
-
+public abstract class TruffleLanguage<C> {
     /**
      * Constructor to be called by subclasses.
-     *
-     * @param env language environment that will be available via {@link #env()} method to
-     *            subclasses.
      */
-    protected TruffleLanguage(Env env) {
-        this.env = env;
+    protected TruffleLanguage() {
     }
 
     /**
@@ -95,12 +92,18 @@
         String[] mimeType();
     }
 
-    protected final Env env() {
-        if (this.env == null) {
-            throw new NullPointerException("Accessing env before initialization is finished");
-        }
-        return this.env;
-    }
+    /**
+     * Creates internal representation of the executing context suitable for given environment. Each
+     * time the {@link TruffleLanguage language} is used by a new {@link TruffleVM} or in a new
+     * thread, the system calls this method to let the {@link TruffleLanguage language} prepare for
+     * <em>execution</em>. The returned execution context is completely language specific; it is
+     * however expected it will contain reference to here-in provided <code>env</code> and adjust
+     * itself according to parameters provided by the <code>env</code> object.
+     * 
+     * @param env the environment the language is supposed to operate in
+     * @return internal data of the language in given environment
+     */
+    protected abstract C createContext(Env env);
 
     /**
      * Parses the provided source and generates appropriate AST. The parsing should execute no user
@@ -145,7 +148,7 @@
      * @return an exported object or <code>null</code>, if the symbol does not represent anything
      *         meaningful in this language
      */
-    protected abstract Object findExportedSymbol(String globalName, boolean onlyExplicit);
+    protected abstract Object findExportedSymbol(C context, String globalName, boolean onlyExplicit);
 
     /**
      * Returns global object for the language.
@@ -156,7 +159,7 @@
      *
      * @return the global object or <code>null</code> if the language does not support such concept
      */
-    protected abstract Object getLanguageGlobal();
+    protected abstract Object getLanguageGlobal(C context);
 
     /**
      * Checks whether the object is provided by this language.
@@ -171,15 +174,37 @@
     protected abstract DebugSupportProvider getDebugSupport();
 
     /**
-     * Finds the currently executing context for current thread.
+     * Finds the currently executing context for this language and current thread. Obtains data
+     * previously created by {@link #createContext(com.oracle.truffle.api.TruffleLanguage.Env)}
+     * method.
      *
-     * @param <Lang> 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 <Lang extends TruffleLanguage> Lang findContext(Class<Lang> language) {
-        return language.cast(API.findLanguage(null, language));
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected final C findContext() {
+        final Class<? extends TruffleLanguage> c = getClass();
+        final Env env = API.findLanguage(null, c);
+        assert env.langCtx.lang == this;
+        return (C) env.langCtx.ctx;
+    }
+
+    private static final class LangCtx<C> {
+        final TruffleLanguage<C> lang;
+        final C ctx;
+
+        public LangCtx(TruffleLanguage<C> lang, Env env) {
+            this.lang = lang;
+            this.ctx = lang.createContext(env);
+        }
+
+        Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+            return lang.findExportedSymbol(ctx, globalName, onlyExplicit);
+        }
+
+        Object getLanguageGlobal() {
+            return lang.getLanguageGlobal(ctx);
+        }
     }
 
     /**
@@ -190,21 +215,17 @@
      */
     public static final class Env {
         private final TruffleVM vm;
-        private final TruffleLanguage lang;
+        private final LangCtx<?> langCtx;
         private final Reader in;
         private final Writer err;
         private final Writer out;
 
-        Env(TruffleVM vm, Constructor<?> langConstructor, Writer out, Writer err, Reader in) {
+        Env(TruffleVM vm, TruffleLanguage<?> lang, 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.getDeclaringClass().getName(), ex);
-            }
+            this.langCtx = new LangCtx<>(lang, this);
         }
 
         /**
@@ -217,7 +238,7 @@
          * @return object representing the symbol or <code>null</code>
          */
         public Object importSymbol(String globalName) {
-            return API.importSymbol(vm, lang, globalName);
+            return API.importSymbol(vm, langCtx.lang, globalName);
         }
 
         /**
@@ -250,22 +271,23 @@
 
     private static final AccessAPI API = new AccessAPI();
 
+    @SuppressWarnings("rawtypes")
     private static final class AccessAPI extends Accessor {
         @Override
-        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;
+        protected Env attachEnv(TruffleVM vm, TruffleLanguage<?> language, Writer stdOut, Writer stdErr, Reader stdIn) {
+            Env env = new Env(vm, language, stdOut, stdErr, stdIn);
+            return env;
         }
 
         @Override
-        public Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) {
+        public Object importSymbol(TruffleVM vm, TruffleLanguage<?> queryingLang, String globalName) {
             return super.importSymbol(vm, queryingLang, globalName);
         }
 
         private static final Map<Source, CallTarget> COMPILED = Collections.synchronizedMap(new WeakHashMap<Source, CallTarget>());
 
         @Override
-        protected Object eval(TruffleLanguage language, Source source) throws IOException {
+        protected Object eval(TruffleLanguage<?> language, Source source) throws IOException {
             CallTarget target = COMPILED.get(source);
             if (target == null) {
                 target = language.parse(source, null);
@@ -282,27 +304,27 @@
         }
 
         @Override
-        protected Object findExportedSymbol(TruffleLanguage l, String globalName, boolean onlyExplicit) {
-            return l.findExportedSymbol(globalName, onlyExplicit);
+        protected Object findExportedSymbol(TruffleLanguage.Env env, String globalName, boolean onlyExplicit) {
+            return env.langCtx.findExportedSymbol(globalName, onlyExplicit);
         }
 
         @Override
-        protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+        protected Env findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
             return super.findLanguage(vm, languageClass);
         }
 
         @Override
-        protected Object languageGlobal(TruffleLanguage l) {
-            return l.getLanguageGlobal();
+        protected Object languageGlobal(TruffleLanguage.Env env) {
+            return env.langCtx.getLanguageGlobal();
         }
 
         @Override
-        protected ToolSupportProvider getToolSupport(TruffleLanguage l) {
+        protected ToolSupportProvider getToolSupport(TruffleLanguage<?> l) {
             return l.getToolSupport();
         }
 
         @Override
-        protected DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+        protected DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
             return l.getDebugSupport();
         }
     }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/Debugger.java	Thu Aug 06 08:31:49 2015 +0200
@@ -117,8 +117,8 @@
             }
         };
 
-        this.lineBreaks = new LineBreakpointFactory(this, breakpointCallback, warningLog);
-        this.tagBreaks = new TagBreakpointFactory(this, breakpointCallback, warningLog);
+        this.lineBreaks = new LineBreakpointFactory(breakpointCallback, warningLog);
+        this.tagBreaks = new TagBreakpointFactory(breakpointCallback, warningLog);
     }
 
     TruffleVM vm() {
@@ -266,10 +266,18 @@
      * @throws IOException if the factory cannot be created, for example if the expression is badly
      *             formed.
      */
-    AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Probe probe, String expr, AdvancedInstrumentResultListener resultListener) throws IOException {
+    @SuppressWarnings("rawtypes")
+    static AdvancedInstrumentRootFactory createAdvancedInstrumentRootFactory(Probe probe, String expr, AdvancedInstrumentResultListener resultListener) throws IOException {
         try {
             Class<? extends TruffleLanguage> langugageClass = ACCESSOR.findLanguage(probe);
-            TruffleLanguage l = ACCESSOR.findLanguage(vm, langugageClass);
+            TruffleLanguage<?> l;
+            try {
+                l = langugageClass.newInstance();
+            } catch (InstantiationException ex) {
+                throw new IllegalStateException(ex);
+            } catch (IllegalAccessException ex) {
+                throw new IllegalStateException(ex);
+            }
             DebugSupportProvider dsp = ACCESSOR.getDebugSupport(l);
             return dsp.createAdvancedInstrumentRootFactory(expr, resultListener);
         } catch (DebugSupportException ex) {
@@ -789,6 +797,7 @@
         debugContext = debugContext.predecessor;
     }
 
+    @SuppressWarnings("rawtypes")
     private static final class AccessorDebug extends Accessor {
         @Override
         protected Closeable executionStart(TruffleVM vm, Debugger[] fillIn, Source s) {
@@ -813,12 +822,12 @@
         }
 
         @Override
-        protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+        protected TruffleLanguage.Env findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
             return super.findLanguage(vm, languageClass);
         }
 
         @Override
-        protected DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+        protected DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
             return super.getDebugSupport(l);
         }
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/LineBreakpointFactory.java	Thu Aug 06 08:31:49 2015 +0200
@@ -90,7 +90,6 @@
         }
     };
 
-    private final Debugger executionSupport;
     private final BreakpointCallback breakpointCallback;
     private final WarningLog warningLog;
 
@@ -113,8 +112,7 @@
     @CompilationFinal private boolean breakpointsActive = true;
     private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
 
-    LineBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
-        this.executionSupport = executionSupport;
+    LineBreakpointFactory(BreakpointCallback breakpointCallback, final WarningLog warningLog) {
         this.breakpointCallback = breakpointCallback;
         this.warningLog = warningLog;
 
@@ -365,7 +363,7 @@
             if (conditionExpr == null) {
                 newInstrument = Instrument.create(new UnconditionalLineBreakInstrumentListener(), BREAKPOINT_NAME);
             } else {
-                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+                newInstrument = Instrument.create(this, Debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
             }
             newProbe.attach(newInstrument);
             instruments.add(newInstrument);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/debug/TagBreakpointFactory.java	Thu Aug 06 08:31:49 2015 +0200
@@ -88,7 +88,6 @@
         }
     };
 
-    private final Debugger executionSupport;
     private final BreakpointCallback breakpointCallback;
     private final WarningLog warningLog;
 
@@ -104,8 +103,7 @@
     @CompilationFinal private boolean breakpointsActive = true;
     private final CyclicAssumption breakpointsActiveUnchanged = new CyclicAssumption(BREAKPOINT_NAME + " globally active");
 
-    TagBreakpointFactory(Debugger executionSupport, BreakpointCallback breakpointCallback, final WarningLog warningLog) {
-        this.executionSupport = executionSupport;
+    TagBreakpointFactory(BreakpointCallback breakpointCallback, final WarningLog warningLog) {
         this.breakpointCallback = breakpointCallback;
         this.warningLog = warningLog;
 
@@ -329,7 +327,7 @@
             if (conditionExpr == null) {
                 newInstrument = Instrument.create(new UnconditionalTagBreakInstrumentListener(), BREAKPOINT_NAME);
             } else {
-                newInstrument = Instrument.create(this, executionSupport.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
+                newInstrument = Instrument.create(this, Debugger.createAdvancedInstrumentRootFactory(newProbe, conditionExpr, this), Boolean.class, BREAKPOINT_NAME);
             }
             newProbe.attach(newInstrument);
             instruments.add(newInstrument);
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Thu Aug 06 08:31:49 2015 +0200
@@ -25,10 +25,10 @@
 package com.oracle.truffle.api.impl;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.TruffleLanguage.Env;
 import com.oracle.truffle.api.debug.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.Node;
@@ -39,6 +39,7 @@
 /**
  * Communication between TruffleVM and TruffleLanguage API/SPI.
  */
+@SuppressWarnings("rawtypes")
 public abstract class Accessor {
     private static Accessor API;
     private static Accessor SPI;
@@ -48,14 +49,14 @@
     private static final ThreadLocal<TruffleVM> CURRENT_VM = new ThreadLocal<>();
 
     static {
-        TruffleLanguage lng = new TruffleLanguage(null) {
+        TruffleLanguage<?> lng = new TruffleLanguage<Object>() {
             @Override
-            protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+            protected Object findExportedSymbol(Object context, String globalName, boolean onlyExplicit) {
                 return null;
             }
 
             @Override
-            protected Object getLanguageGlobal() {
+            protected Object getLanguageGlobal(Object context) {
                 return null;
             }
 
@@ -78,6 +79,11 @@
             protected CallTarget parse(Source code, Node context, String... argumentNames) throws IOException {
                 throw new IOException();
             }
+
+            @Override
+            protected Object createContext(TruffleLanguage.Env env) {
+                return null;
+            }
         };
         lng.hashCode();
         new Node(null) {
@@ -119,35 +125,35 @@
         }
     }
 
-    protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
-        return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
+    protected Env attachEnv(TruffleVM vm, TruffleLanguage<?> language, Writer stdOut, Writer stdErr, Reader stdIn) {
+        return API.attachEnv(vm, language, stdOut, stdErr, stdIn);
     }
 
-    protected Object eval(TruffleLanguage l, Source s) throws IOException {
+    protected Object eval(TruffleLanguage<?> l, Source s) throws IOException {
         return API.eval(l, s);
     }
 
-    protected Object importSymbol(TruffleVM vm, TruffleLanguage queryingLang, String globalName) {
+    protected Object importSymbol(TruffleVM vm, TruffleLanguage<?> queryingLang, String globalName) {
         return SPI.importSymbol(vm, queryingLang, globalName);
     }
 
-    protected Object findExportedSymbol(TruffleLanguage l, String globalName, boolean onlyExplicit) {
-        return API.findExportedSymbol(l, globalName, onlyExplicit);
+    protected Object findExportedSymbol(TruffleLanguage.Env env, String globalName, boolean onlyExplicit) {
+        return API.findExportedSymbol(env, globalName, onlyExplicit);
     }
 
-    protected Object languageGlobal(TruffleLanguage l) {
-        return API.languageGlobal(l);
+    protected Object languageGlobal(TruffleLanguage.Env env) {
+        return API.languageGlobal(env);
     }
 
-    protected ToolSupportProvider getToolSupport(TruffleLanguage l) {
+    protected ToolSupportProvider getToolSupport(TruffleLanguage<?> l) {
         return API.getToolSupport(l);
     }
 
-    protected DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+    protected DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
         return API.getDebugSupport(l);
     }
 
-    protected Object invoke(TruffleLanguage lang, Object obj, Object[] args) throws IOException {
+    protected Object invoke(TruffleLanguage<?> lang, Object obj, Object[] args) throws IOException {
         for (SymbolInvoker si : ServiceLoader.load(SymbolInvoker.class)) {
             return si.invoke(lang, obj, args);
         }
@@ -162,7 +168,7 @@
         return INSTRUMENT.findLanguage(probe);
     }
 
-    protected TruffleLanguage findLanguage(TruffleVM known, Class<? extends TruffleLanguage> languageClass) {
+    protected Env findLanguage(TruffleVM known, Class<? extends TruffleLanguage> languageClass) {
         TruffleVM vm;
         if (known == null) {
             vm = CURRENT_VM.get();
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/SymbolInvoker.java	Thu Aug 06 08:31:49 2015 +0200
@@ -32,5 +32,5 @@
  * associated nodes too much.
  */
 public abstract class SymbolInvoker {
-    protected abstract Object invoke(TruffleLanguage lang, Object symbol, Object... args) throws IOException;
+    protected abstract Object invoke(TruffleLanguage<?> lang, Object symbol, Object... args) throws IOException;
 }
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Aug 06 08:31:49 2015 +0200
@@ -100,6 +100,7 @@
  * @see ProbeListener
  * @see SyntaxTag
  */
+@SuppressWarnings("rawtypes")
 public final class Probe {
     private final Class<? extends TruffleLanguage> language;
 
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Aug 06 08:31:49 2015 +0200
@@ -118,6 +118,7 @@
      * Create a new {@link Probe} associated with, and attached to, a Guest Language specific
      * instance of {@link WrapperNode}.
      */
+    @SuppressWarnings("rawtypes")
     public static Probe insertProbe(WrapperNode wrapper) {
         final SourceSection sourceSection = wrapper.getChild().getSourceSection();
         final ProbeNode probeNode = new ProbeNode(); // private constructor
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Aug 06 08:31:49 2015 +0200
@@ -589,6 +589,7 @@
     }
 
     private static final class AccessorNodes extends Accessor {
+        @SuppressWarnings("rawtypes")
         @Override
         protected Class<? extends TruffleLanguage> findLanguage(RootNode n) {
             return n.language;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Thu Aug 06 08:31:49 2015 +0200
@@ -36,6 +36,7 @@
  * root node can be used to create a call target using
  * {@link TruffleRuntime#createCallTarget(RootNode)}.
  */
+@SuppressWarnings("rawtypes")
 public abstract class RootNode extends Node {
     final Class<? extends TruffleLanguage> language;
     private RootCallTarget callTarget;
--- a/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Thu Aug 06 08:31:49 2015 +0200
@@ -25,7 +25,6 @@
 package com.oracle.truffle.api.vm;
 
 import java.io.*;
-import java.lang.reflect.*;
 import java.net.*;
 import java.nio.file.*;
 import java.util.*;
@@ -55,6 +54,7 @@
  * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from
  * the same thread.
  */
+@SuppressWarnings("rawtypes")
 public final class TruffleVM {
     private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
@@ -289,7 +289,7 @@
             URLConnection conn = url.openConnection();
             mimeType = conn.getContentType();
         }
-        TruffleLanguage l = getTruffleLang(mimeType);
+        TruffleLanguage<?> l = getTruffleLang(mimeType);
         if (l == null) {
             throw new IOException("No language for " + location + " with MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
@@ -307,7 +307,7 @@
      */
     public Object eval(String mimeType, Reader reader) throws IOException {
         checkThread();
-        TruffleLanguage l = getTruffleLang(mimeType);
+        TruffleLanguage<?> l = getTruffleLang(mimeType);
         if (l == null) {
             throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
@@ -325,14 +325,14 @@
      */
     public Object eval(String mimeType, String code) throws IOException {
         checkThread();
-        TruffleLanguage l = getTruffleLang(mimeType);
+        TruffleLanguage<?> l = getTruffleLang(mimeType);
         if (l == null) {
             throw new IOException("No language for MIME type " + mimeType + " found. Supported types: " + langs.keySet());
         }
         return eval(l, Source.fromText(code, mimeType));
     }
 
-    private Object eval(TruffleLanguage l, Source s) throws IOException {
+    private Object eval(TruffleLanguage<?> l, Source s) throws IOException {
         TruffleVM.findDebuggerSupport(l);
         Debugger[] fillIn = {debugger};
         try (Closeable d = SPI.executionStart(this, fillIn, s)) {
@@ -362,25 +362,25 @@
      */
     public Symbol findGlobalSymbol(String globalName) {
         checkThread();
-        TruffleLanguage lang = null;
+        TruffleLanguage<?> lang = null;
         Object obj = null;
         Object global = null;
         for (Language dl : langs.values()) {
-            TruffleLanguage l = dl.getImpl();
-            obj = SPI.findExportedSymbol(l, globalName, true);
+            TruffleLanguage<?> l = dl.getImpl();
+            obj = SPI.findExportedSymbol(dl.env, globalName, true);
             if (obj != null) {
                 lang = l;
-                global = SPI.languageGlobal(l);
+                global = SPI.languageGlobal(dl.env);
                 break;
             }
         }
         if (obj == null) {
             for (Language dl : langs.values()) {
-                TruffleLanguage l = dl.getImpl();
-                obj = SPI.findExportedSymbol(l, globalName, false);
+                TruffleLanguage<?> l = dl.getImpl();
+                obj = SPI.findExportedSymbol(dl.env, globalName, false);
                 if (obj != null) {
                     lang = l;
-                    global = SPI.languageGlobal(l);
+                    global = SPI.languageGlobal(dl.env);
                     break;
                 }
             }
@@ -394,7 +394,7 @@
         }
     }
 
-    private TruffleLanguage getTruffleLang(String mimeType) {
+    private TruffleLanguage<?> getTruffleLang(String mimeType) {
         checkThread();
         Language l = langs.get(mimeType);
         return l == null ? null : l.getImpl();
@@ -434,11 +434,11 @@
      * of the initialized languages in {@link TruffleVM Truffle virtual machine}.
      */
     public class Symbol {
-        private final TruffleLanguage language;
+        private final TruffleLanguage<?> language;
         private final Object obj;
         private final Object global;
 
-        Symbol(TruffleLanguage language, Object obj, Object global) {
+        Symbol(TruffleLanguage<?> language, Object obj, Object global) {
             this.language = language;
             this.obj = obj;
             this.global = global;
@@ -487,7 +487,8 @@
      */
     public final class Language {
         private final Properties props;
-        private TruffleLanguage impl;
+        private TruffleLanguage<?> impl;
+        private TruffleLanguage.Env env;
         private final String prefix;
         private String shortName;
 
@@ -543,13 +544,14 @@
             return shortName;
         }
 
-        TruffleLanguage getImpl() {
+        TruffleLanguage<?> getImpl() {
             if (impl == null) {
                 String n = props.getProperty(prefix + "className");
                 try {
                     Class<?> langClazz = Class.forName(n, true, loader());
-                    Constructor<?> constructor = langClazz.getConstructor(Env.class);
-                    impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in);
+                    TruffleLanguage<?> language = (TruffleLanguage<?>) langClazz.getField("INSTANCE").get(null);
+                    env = SPI.attachEnv(TruffleVM.this, language, out, err, in);
+                    impl = language;
                 } catch (Exception ex) {
                     throw new IllegalStateException("Cannot initialize " + getShortName() + " language with implementation " + n, ex);
                 }
@@ -567,12 +569,8 @@
     // Accessor helper methods
     //
 
-    TruffleLanguage findLanguage(Probe probe) {
+    TruffleLanguage<?> findLanguage(Probe probe) {
         Class<? extends TruffleLanguage> languageClazz = SPI.findLanguage(probe);
-        return findLanguage(languageClazz);
-    }
-
-    TruffleLanguage findLanguage(Class<? extends TruffleLanguage> languageClazz) {
         for (Map.Entry<String, Language> entrySet : langs.entrySet()) {
             Language languageDescription = entrySet.getValue();
             if (languageClazz.isInstance(languageDescription.impl)) {
@@ -582,30 +580,40 @@
         throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs);
     }
 
-    static DebugSupportProvider findDebuggerSupport(TruffleLanguage l) {
+    Env findEnv(Class<? extends TruffleLanguage> languageClazz) {
+        for (Map.Entry<String, Language> entrySet : langs.entrySet()) {
+            Language languageDescription = entrySet.getValue();
+            if (languageClazz.isInstance(languageDescription.impl)) {
+                return languageDescription.env;
+            }
+        }
+        throw new IllegalStateException("Cannot find language " + languageClazz + " among " + langs);
+    }
+
+    static DebugSupportProvider findDebuggerSupport(TruffleLanguage<?> l) {
         return SPI.getDebugSupport(l);
     }
 
     private static class SPIAccessor extends Accessor {
         @Override
-        public Object importSymbol(TruffleVM vm, TruffleLanguage ownLang, String globalName) {
+        public Object importSymbol(TruffleVM vm, TruffleLanguage<?> ownLang, String globalName) {
             Set<Language> uniqueLang = new LinkedHashSet<>(vm.langs.values());
             for (Language dl : uniqueLang) {
-                TruffleLanguage l = dl.getImpl();
+                TruffleLanguage<?> l = dl.getImpl();
                 if (l == ownLang) {
                     continue;
                 }
-                Object obj = SPI.findExportedSymbol(l, globalName, true);
+                Object obj = SPI.findExportedSymbol(dl.env, globalName, true);
                 if (obj != null) {
                     return obj;
                 }
             }
             for (Language dl : uniqueLang) {
-                TruffleLanguage l = dl.getImpl();
+                TruffleLanguage<?> l = dl.getImpl();
                 if (l == ownLang) {
                     continue;
                 }
-                Object obj = SPI.findExportedSymbol(l, globalName, false);
+                Object obj = SPI.findExportedSymbol(dl.env, globalName, false);
                 if (obj != null) {
                     return obj;
                 }
@@ -614,37 +622,37 @@
         }
 
         @Override
-        public TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
-            return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
+        public Env attachEnv(TruffleVM vm, TruffleLanguage<?> language, Writer stdOut, Writer stdErr, Reader stdIn) {
+            return super.attachEnv(vm, language, stdOut, stdErr, stdIn);
         }
 
         @Override
-        public Object eval(TruffleLanguage l, Source s) throws IOException {
+        public Object eval(TruffleLanguage<?> l, Source s) throws IOException {
             return super.eval(l, s);
         }
 
         @Override
-        public Object findExportedSymbol(TruffleLanguage l, String globalName, boolean onlyExplicit) {
-            return super.findExportedSymbol(l, globalName, onlyExplicit);
+        public Object findExportedSymbol(TruffleLanguage.Env env, String globalName, boolean onlyExplicit) {
+            return super.findExportedSymbol(env, globalName, onlyExplicit);
         }
 
         @Override
-        public Object languageGlobal(TruffleLanguage l) {
-            return super.languageGlobal(l);
+        protected Object languageGlobal(TruffleLanguage.Env env) {
+            return super.languageGlobal(env);
         }
 
         @Override
-        protected Object invoke(TruffleLanguage lang, Object obj, Object[] args) throws IOException {
+        protected Object invoke(TruffleLanguage<?> lang, Object obj, Object[] args) throws IOException {
             return super.invoke(lang, obj, args);
         }
 
         @Override
-        public ToolSupportProvider getToolSupport(TruffleLanguage l) {
+        public ToolSupportProvider getToolSupport(TruffleLanguage<?> l) {
             return super.getToolSupport(l);
         }
 
         @Override
-        public DebugSupportProvider getDebugSupport(TruffleLanguage l) {
+        public DebugSupportProvider getDebugSupport(TruffleLanguage<?> l) {
             return super.getDebugSupport(l);
         }
 
@@ -654,8 +662,8 @@
         }
 
         @Override
-        protected TruffleLanguage findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
-            return vm.findLanguage(languageClass);
+        protected Env findLanguage(TruffleVM vm, Class<? extends TruffleLanguage> languageClass) {
+            return vm.findEnv(languageClass);
         }
 
         @Override
--- a/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java	Thu Aug 06 08:31:49 2015 +0200
@@ -93,31 +93,32 @@
                     emitError("Registered language inner-class must be static", e);
                     continue;
                 }
-                TypeMirror truffleLang = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType();
+                TypeMirror truffleLang = processingEnv.getTypeUtils().erasure(processingEnv.getElementUtils().getTypeElement(TruffleLanguage.class.getName()).asType());
                 if (!processingEnv.getTypeUtils().isAssignable(e.asType(), truffleLang)) {
                     emitError("Registered language class must subclass TruffleLanguage", e);
                     continue;
                 }
                 boolean found = false;
                 for (Element mem : e.getEnclosedElements()) {
-                    if (mem.getKind() != ElementKind.CONSTRUCTOR) {
+                    if (!mem.getModifiers().contains(Modifier.PUBLIC)) {
+                        continue;
+                    }
+                    if (mem.getKind() != ElementKind.FIELD) {
                         continue;
                     }
-                    ExecutableElement ee = (ExecutableElement) mem;
-                    if (ee.getParameters().size() != 1) {
+                    if (!mem.getModifiers().contains(Modifier.FINAL)) {
                         continue;
                     }
-                    if (!ee.getModifiers().contains(Modifier.PUBLIC)) {
+                    if (!"INSTANCE".equals(mem.getSimpleName().toString())) {
                         continue;
                     }
-                    TypeMirror env = processingEnv.getElementUtils().getTypeElement(TruffleLanguage.Env.class.getCanonicalName()).asType();
-                    if (processingEnv.getTypeUtils().isSameType(ee.getParameters().get(0).asType(), env)) {
+                    if (processingEnv.getTypeUtils().isAssignable(mem.asType(), truffleLang)) {
                         found = true;
                         break;
                     }
                 }
                 if (!found) {
-                    emitError("Language must have a public constructor accepting TruffleLanguage.Env as parameter", e);
+                    emitError("Language class must have public static final singleton field called INSTANCE", e);
                     continue;
                 }
                 assertNoErrorExpected(e);
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java	Thu Aug 06 08:31:49 2015 +0200
@@ -153,19 +153,24 @@
  *
  */
 @TruffleLanguage.Registration(name = "SL", version = "0.5", mimeType = "application/x-sl")
-public class SLLanguage extends TruffleLanguage {
+public class SLLanguage extends TruffleLanguage<SLContext> {
     private static List<NodeFactory<? extends SLBuiltinNode>> builtins = Collections.emptyList();
     private static Visualizer visualizer = new SLDefaultVisualizer();
     private static ASTProber registeredASTProber; // non-null if prober already registered
-    private final SLContext context;
     private DebugSupportProvider debugSupport;
 
-    public SLLanguage(Env env) {
-        super(env);
-        context = new SLContext(this, new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
+    private SLLanguage() {
+    }
+
+    public static final SLLanguage INSTANCE = new SLLanguage();
+
+    @Override
+    protected SLContext createContext(Env env) {
+        SLContext context = new SLContext(this, new BufferedReader(env.stdIn()), new PrintWriter(env.stdOut(), true));
         for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
             context.installBuiltin(builtin, true);
         }
+        return context;
     }
 
     // TODO (mlvdv) command line options
@@ -378,10 +383,6 @@
         return result.toString();
     }
 
-    public static SLLanguage find() {
-        return SLLanguage.findContext(SLLanguage.class);
-    }
-
     @Override
     protected CallTarget parse(Source code, Node node, String... argumentNames) throws IOException {
         final SLContext c = new SLContext(this);
@@ -401,8 +402,7 @@
                 if (failed[0] != null) {
                     throw new IllegalStateException(failed[0]);
                 }
-                SLLanguage current = SLLanguage.find();
-                SLContext fillIn = current.context;
+                SLContext fillIn = getContext();
                 final SLFunctionRegistry functionRegistry = fillIn.getFunctionRegistry();
                 for (SLFunction f : c.getFunctionRegistry().getFunctions()) {
                     RootCallTarget callTarget = f.getCallTarget();
@@ -418,7 +418,7 @@
     }
 
     @Override
-    protected Object findExportedSymbol(String globalName, boolean onlyExplicit) {
+    protected Object findExportedSymbol(SLContext context, String globalName, boolean onlyExplicit) {
         for (SLFunction f : context.getFunctionRegistry().getFunctions()) {
             if (globalName.equals(f.getName())) {
                 return f;
@@ -428,7 +428,7 @@
     }
 
     @Override
-    protected Object getLanguageGlobal() {
+    protected Object getLanguageGlobal(SLContext context) {
         return context;
     }
 
@@ -492,7 +492,7 @@
     }
 
     public SLContext getContext() {
-        return context;
+        return findContext();
     }
 
     private final class SLDebugProvider implements DebugSupportProvider {
--- a/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Thu Aug 06 08:31:49 2015 +0200
@@ -56,7 +56,6 @@
  */
 @NodeInfo(shortName = "func")
 public final class SLFunctionLiteralNode extends SLExpressionNode {
-
     private final String value;
 
     public SLFunctionLiteralNode(SourceSection src, String value) {
@@ -66,7 +65,6 @@
 
     @Override
     public SLFunction executeGeneric(VirtualFrame frame) {
-        SLLanguage language = SLLanguage.find();
-        return language.getContext().getFunctionRegistry().lookup(value);
+        return SLLanguage.INSTANCE.getContext().getFunctionRegistry().lookup(value);
     }
 }
--- a/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Wed Aug 05 10:19:41 2015 -0700
+++ b/truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java	Thu Aug 06 08:31:49 2015 +0200
@@ -194,9 +194,6 @@
         }
     }
 
-    private abstract class MMLanguage extends TruffleLanguage {
-        public MMLanguage(Env env) {
-            super(env);
-        }
+    private abstract class MMLanguage extends TruffleLanguage<Object> {
     }
 }