# HG changeset patch # User Jaroslav Tulach # Date 1438270594 -7200 # Node ID e7c2d36daf72b4bac18806199aceed17bb0c8914 # Parent ffbc7f472438044ca1134d803605cbcd03679a5b TruffleLanguage.parse method to convert a source to CallTarget. Basic caching to make sure the code is shared among tenants in one JVM. diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestingLanguage.java --- 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(); } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java --- 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(); + } + } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TestingLanguage.java --- 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(); } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/ImplicitExplicitExportTest.java --- 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 implicit = new HashMap<>(); @Override - protected Object eval(Source code) throws IOException { - Properties p = new Properties(); - try (Reader r = code.getReader()) { - p.load(r); - } - Enumeration 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 findContext(Class 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 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 language; + + private ValueCallTarget(Source code, Class 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"; diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- 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 + * @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 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 findContext(Class 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 COMPILED = Collections.synchronizedMap(new WeakHashMap()); + @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 languageClass) { + return super.findLanguage(vm, languageClass); + } + + @Override protected Object languageGlobal(TruffleLanguage l) { return l.getLanguageGlobal(); } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- 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 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 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) { diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- 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); } - } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java --- 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; } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- 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"; + } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLLanguage.java --- 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 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() { diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/factory/SLContextFactory.java --- 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); - } -} diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java --- 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; - } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java --- 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); } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java --- 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); } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- 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 factory) { + public void installBuiltin(NodeFactory 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) { diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/MaxMinObject.java --- 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); } } diff -r ffbc7f472438 -r e7c2d36daf72 truffle/com.oracle.truffle.tck/src/com/oracle/truffle/tck/TruffleTCK.java --- 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 1, the second + * 2 and so on. The returned values are expected to be instances of {@link Number}. + *

+ * 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!";