changeset 21557:31fc2fce38f3

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 27 May 2015 13:32:18 +0200
parents 48c1ebd24120 (current diff) 93d486d51ab4 (diff)
children d563baeca9df
files graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/JavaTypeProfile.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java mx/suite.py
diffstat 41 files changed, 881 insertions(+), 227 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 27 13:32:18 2015 +0200
@@ -22,33 +22,6 @@
  */
 package com.oracle.graal.java;
 
-import com.oracle.jvmci.code.CodeUtil;
-import com.oracle.jvmci.code.BailoutException;
-import com.oracle.jvmci.code.InfopointReason;
-import com.oracle.jvmci.code.BytecodeFrame;
-import com.oracle.jvmci.code.BytecodePosition;
-import com.oracle.jvmci.meta.ResolvedJavaType;
-import com.oracle.jvmci.meta.LocationIdentity;
-import com.oracle.jvmci.meta.RawConstant;
-import com.oracle.jvmci.meta.ProfilingInfo;
-import com.oracle.jvmci.meta.JavaConstant;
-import com.oracle.jvmci.meta.TriState;
-import com.oracle.jvmci.meta.JavaType;
-import com.oracle.jvmci.meta.MetaAccessProvider;
-import com.oracle.jvmci.meta.JavaMethod;
-import com.oracle.jvmci.meta.ResolvedJavaField;
-import com.oracle.jvmci.meta.JavaField;
-import com.oracle.jvmci.meta.MetaUtil;
-import com.oracle.jvmci.meta.ResolvedJavaMethod;
-import com.oracle.jvmci.meta.JavaTypeProfile;
-import com.oracle.jvmci.meta.Kind;
-import com.oracle.jvmci.meta.DeoptimizationAction;
-import com.oracle.jvmci.meta.LineNumberTable;
-import com.oracle.jvmci.meta.ConstantReflectionProvider;
-import com.oracle.jvmci.meta.ConstantPool;
-import static com.oracle.jvmci.code.TypeCheckHints.*;
-import static com.oracle.jvmci.meta.DeoptimizationAction.*;
-import static com.oracle.jvmci.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.compiler.common.type.StampFactory.*;
@@ -56,7 +29,10 @@
 import static com.oracle.graal.java.GraphBuilderPhase.Options.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.nodes.type.StampTool.*;
+import static com.oracle.jvmci.code.TypeCheckHints.*;
 import static com.oracle.jvmci.common.JVMCIError.*;
+import static com.oracle.jvmci.meta.DeoptimizationAction.*;
+import static com.oracle.jvmci.meta.DeoptimizationReason.*;
 import static java.lang.String.*;
 
 import java.util.*;
@@ -86,9 +62,11 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.jvmci.code.*;
 import com.oracle.jvmci.common.*;
 import com.oracle.jvmci.debug.*;
 import com.oracle.jvmci.debug.Debug.Scope;
+import com.oracle.jvmci.meta.*;
 import com.oracle.jvmci.options.*;
 
 /**
@@ -3091,7 +3069,26 @@
                     JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
                     TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
                     if (typeCheckPlugin == null || !typeCheckPlugin.checkCast(this, object, resolvedType, profile)) {
-                        ValueNode checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
+                        ValueNode checkCastNode = null;
+                        if (profile != null) {
+                            if (profile.getNullSeen().isFalse()) {
+                                object = append(GuardingPiNode.createNullCheck(object));
+                                ResolvedJavaType singleType = profile.asSingleType();
+                                if (singleType != null) {
+                                    LogicNode typeCheck = append(TypeCheckNode.create(singleType, object));
+                                    if (typeCheck.isTautology()) {
+                                        checkCastNode = object;
+                                    } else {
+                                        GuardingPiNode piNode = append(new GuardingPiNode(object, typeCheck, false, DeoptimizationReason.TypeCheckedInliningViolated,
+                                                        DeoptimizationAction.InvalidateReprofile, StampFactory.exactNonNull(singleType)));
+                                        checkCastNode = piNode;
+                                    }
+                                }
+                            }
+                        }
+                        if (checkCastNode == null) {
+                            checkCastNode = append(createCheckCast(resolvedType, object, profile, false));
+                        }
                         frameState.apush(checkCastNode);
                     }
                 } else {
@@ -3108,7 +3105,21 @@
                     JavaTypeProfile profile = getProfileForTypeCheck(resolvedType);
                     TypeCheckPlugin typeCheckPlugin = this.graphBuilderConfig.getPlugins().getTypeCheckPlugin();
                     if (typeCheckPlugin == null || !typeCheckPlugin.instanceOf(this, object, resolvedType, profile)) {
-                        ValueNode instanceOfNode = createInstanceOf(resolvedType, object, profile);
+                        ValueNode instanceOfNode = null;
+                        if (profile != null) {
+                            if (profile.getNullSeen().isFalse()) {
+                                object = append(GuardingPiNode.createNullCheck(object));
+                                ResolvedJavaType singleType = profile.asSingleType();
+                                if (singleType != null) {
+                                    LogicNode typeCheck = append(TypeCheckNode.create(singleType, object));
+                                    append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+                                    instanceOfNode = LogicConstantNode.forBoolean(resolvedType.isAssignableFrom(singleType));
+                                }
+                            }
+                        }
+                        if (instanceOfNode == null) {
+                            instanceOfNode = createInstanceOf(resolvedType, object, profile);
+                        }
                         frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
                     }
                 } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Wed May 27 13:32:18 2015 +0200
@@ -271,6 +271,13 @@
         LoopScope loopScope = new LoopScope(methodScope);
         FixedNode firstNode;
         if (startNode != null) {
+            /*
+             * The start node of a graph can be referenced as the guard for a GuardedNode. We
+             * register the previous block node, so that such guards are correctly anchored when
+             * doing inlining during graph decoding.
+             */
+            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false);
+
             firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID);
             startNode.setNext(firstNode);
             loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID);
@@ -332,6 +339,10 @@
                         ((AbstractMergeNode) node).forwardEndCount() == 1) {
             AbstractMergeNode merge = (AbstractMergeNode) node;
             EndNode singleEnd = merge.forwardEndAt(0);
+
+            /* Nodes that would use this merge as the guard need to use the previous block. */
+            registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
+
             FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET);
             singleEnd.replaceAtPredecessor(next);
 
@@ -822,7 +833,13 @@
     protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
         long readerByteIndex = methodScope.reader.getByteIndex();
         Node node = instantiateNode(methodScope, nodeOrderId);
-        assert !(node instanceof FixedNode);
+        if (node instanceof FixedNode) {
+            /*
+             * This is a severe error that will lead to a corrupted graph, so it is better not to
+             * continue decoding at all.
+             */
+            throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
+        }
 
         /* Read the properties of the node. */
         readProperties(methodScope, node);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Wed May 27 13:32:18 2015 +0200
@@ -81,6 +81,15 @@
         this.negated = negateCondition;
     }
 
+    public static ValueNode createNullCheck(ValueNode object) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        if (objectStamp.nonNull()) {
+            return object;
+        } else {
+            return new GuardingPiNode(object);
+        }
+    }
+
     @Override
     public void lower(LoweringTool tool) {
         GuardingNode guard = tool.createGuard(next(), condition, reason, action, negated);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Wed May 27 13:32:18 2015 +0200
@@ -55,4 +55,22 @@
     public static LogicNode or(LogicNode a, boolean negateA, LogicNode b, boolean negateB, double shortCircuitProbability) {
         return a.graph().unique(new ShortCircuitOrNode(a, negateA, b, negateB, shortCircuitProbability));
     }
+
+    public final boolean isTautology() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return logicConstantNode.getValue();
+        }
+
+        return false;
+    }
+
+    public final boolean isContradiction() {
+        if (this instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) this;
+            return !logicConstantNode.getValue();
+        }
+
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 27 13:32:18 2015 +0200
@@ -132,7 +132,7 @@
                 return LogicConstantNode.contradiction();
             } else {
                 boolean superType = inputType.isAssignableFrom(type);
-                if (!superType && !isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)) {
+                if (!superType && (type.asExactType() != null || (!isInterfaceOrArrayOfInterface(inputType) && !isInterfaceOrArrayOfInterface(type)))) {
                     return LogicConstantNode.contradiction();
                 }
                 // since the subtype comparison was only performed on a declared type we don't
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed May 27 13:32:18 2015 +0200
@@ -166,7 +166,7 @@
             if (objectType != null) {
                 ResolvedJavaType instanceofType = type;
                 if (instanceofType.equals(objectType)) {
-                    if (objectStamp.nonNull()) {
+                    if (objectStamp.nonNull() && (objectStamp.isExactType() || objectType.isFinal())) {
                         return TriState.TRUE;
                     }
                 } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.replacements.test;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.memory.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.memory.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.*;
+import com.oracle.jvmci.debug.*;
+import com.oracle.jvmci.meta.*;
+
+public class PEGraphDecoderTest extends GraalCompilerTest {
+
+    /**
+     * This method is intrinsified to a node with a guard dependency on the block it is in. The
+     * various tests ensure that this guard is correctly updated when blocks are merged during
+     * inlining.
+     */
+    private static native int readInt(Object obj, long offset);
+
+    private static boolean flag;
+    private static int value;
+
+    private static void invokeSimple() {
+        value = 111;
+    }
+
+    private static void invokeComplicated() {
+        if (flag) {
+            value = 0;
+        } else {
+            value = 42;
+        }
+    }
+
+    private static int readInt1(Object obj) {
+        return readInt(obj, 16);
+    }
+
+    private static int readInt2(Object obj) {
+        invokeSimple();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt3(Object obj) {
+        invokeComplicated();
+        return readInt(obj, 16);
+    }
+
+    private static int readInt4(Object obj, int n) {
+        if (n > 0) {
+            invokeComplicated();
+        }
+        return readInt(obj, 16);
+    }
+
+    public static int doTest(Object obj) {
+        int result = 0;
+        result += readInt1(obj);
+        result += readInt2(obj);
+        result += readInt3(obj);
+        result += readInt4(obj, 2);
+        return result;
+    }
+
+    private static void registerPlugins(InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, PEGraphDecoderTest.class);
+        r.register2("readInt", Object.class, long.class, new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode obj, ValueNode offset) {
+                LocationNode location = b.add(new ConstantLocationNode(LocationIdentity.any(), offset.asJavaConstant().asLong()));
+                ReadNode read = b.addPush(Kind.Int, new ReadNode(obj, location, StampFactory.forKind(Kind.Int), BarrierType.NONE));
+                read.setGuard(AbstractBeginNode.prevBegin(read));
+                return true;
+            }
+        });
+    }
+
+    class InlineAll implements InlineInvokePlugin {
+        @Override
+        public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+            return new InlineInfo(method, false);
+        }
+    }
+
+    @Test
+    public void test() {
+        ResolvedJavaMethod testMethod = getResolvedJavaMethod(PEGraphDecoderTest.class, "doTest", Object.class);
+        StructuredGraph targetGraph = null;
+        try (Debug.Scope scope = Debug.scope("GraphPETest", testMethod)) {
+            GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getEagerDefault(getDefaultGraphBuilderPlugins());
+            registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins());
+            CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, getTarget().arch);
+
+            targetGraph = new StructuredGraph(testMethod, AllowAssumptions.YES);
+            decoder.decode(targetGraph, testMethod, null, null, new InlineAll(), null);
+            Debug.dump(targetGraph, "Target Graph");
+            targetGraph.verify();
+
+            PhaseContext context = new PhaseContext(getProviders());
+            new CanonicalizerPhase().apply(targetGraph, context);
+            targetGraph.verify();
+
+        } catch (Throwable ex) {
+            if (targetGraph != null) {
+                Debug.dump(targetGraph, ex.toString());
+            }
+            Debug.handle(ex);
+        }
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Wed May 27 13:32:18 2015 +0200
@@ -39,7 +39,8 @@
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType);
         if (inlineInfo == null) {
-            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+            if (InlineDuringParsing.getValue() && method.hasBytecodes() && !method.isSynchronized() && method.getCode().length <= TrivialInliningSize.getValue() &&
+                            b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
                 return new InlineInfo(method, false);
             }
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java	Wed May 27 13:32:18 2015 +0200
@@ -390,7 +390,7 @@
             if (graphBuilderContext.lastInstr != null) {
                 registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
                 invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
-                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData));
+                graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr)));
             } else {
                 assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
                 invoke.asNode().replaceAtUsages(null);
@@ -469,16 +469,16 @@
         ValueNode returnValue;
         List<ReturnNode> returnNodes = inlineScope.returnNodes;
         if (!returnNodes.isEmpty()) {
-            FixedNode n;
-            n = nodeAfterInvoke(methodScope, loopScope, invokeData);
             if (returnNodes.size() == 1) {
                 ReturnNode returnNode = returnNodes.get(0);
                 returnValue = returnNode.result();
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
                 returnNode.replaceAndDelete(n);
             } else {
                 AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
                 merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
                 returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
+                FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
                 merge.setNext(n);
             }
         } else {
@@ -508,9 +508,11 @@
         return true;
     }
 
-    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
+    public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) {
+        assert lastBlock.isAlive();
         FixedNode n;
         if (invokeData.invoke instanceof InvokeWithExceptionNode) {
+            registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false);
             n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
         } else {
             n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
--- a/graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/JavaTypeProfile.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/JavaTypeProfile.java	Wed May 27 13:32:18 2015 +0200
@@ -174,4 +174,22 @@
         }
         return buf.append(String.format("], notRecorded:%.6f>", getNotRecordedProbability())).toString();
     }
+
+    /**
+     * Returns {@code true} if all types seen at this location have been recorded in the profile.
+     */
+    public boolean allTypesRecorded() {
+        return this.getNotRecordedProbability() == 0.0;
+    }
+
+    /**
+     * Returns the single monormorphic type representing this profile or {@code null} if no such
+     * type exists.
+     */
+    public ResolvedJavaType asSingleType() {
+        if (allTypesRecorded() && this.getTypes().length == 1) {
+            return getTypes()[0].getType();
+        }
+        return null;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.dsl.test;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation is internally known by the dsl processor and used to expect errors for testing
+ * purposes. This is not part of public API.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ExpectError {
+
+    String[] value();
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java	Wed May 27 13:32:18 2015 +0200
@@ -105,7 +105,6 @@
         }
 
         @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"})
-        @ExplodeLoop
         double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) {
             doPowCachedExponent++;
             double result = 1.0;
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java	Wed May 27 13:32:18 2015 +0200
@@ -25,7 +25,7 @@
 import java.io.*;
 
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.*;
 import com.oracle.truffle.api.source.*;
 
 public class LanguageRegistrationTest {
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java	Wed May 27 13:32:18 2015 +0200
@@ -31,7 +31,7 @@
 
 import org.junit.*;
 
-import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.verify.*;
 
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java	Wed May 27 00:36:16 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.dsl;
-
-import java.lang.annotation.*;
-
-/**
- * This annotation is internally known by the dsl processor and used to expect errors for testing
- * purposes. This is not part of public API.
- */
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ExpectError {
-
-    String[] value();
-
-}
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java	Wed May 27 13:32:18 2015 +0200
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import org.junit.*;
+
 import com.oracle.truffle.api.vm.*;
 
 /**
@@ -31,10 +33,10 @@
  * requirements of the Truffle infrastructure and tooling. Subclass, implement abstract methods and
  * include in your test suite.
  */
-public abstract class TruffleTCK {
-    private TruffleVM vm;
+public class TruffleTCK { // abstract
+    private TruffleVM tckVM;
 
-    protected TruffleTCK() {
+    public TruffleTCK() { // protected
     }
 
     /**
@@ -46,8 +48,11 @@
      * for internal testing.
      *
      * @return initialized Truffle virtual machine
+     * @throws java.lang.Exception thrown when the VM preparation fails
      */
-    protected abstract TruffleVM prepareVM() throws Exception;
+    protected TruffleVM prepareVM() throws Exception { // abstract
+        return null;
+    }
 
     /**
      * Name of function which will return value 42 as a number. The return value of the method
@@ -56,7 +61,9 @@
      *
      * @return name of globally exported symbol
      */
-    protected abstract String fourtyTwo();
+    protected String fourtyTwo() { // abstract
+        return null;
+    }
 
     /**
      * Name of function to add two integer values together. The symbol will be invoked with two
@@ -65,20 +72,26 @@
      *
      * @return name of globally exported symbol
      */
-    protected abstract String plusInt();
+    protected String plusInt() {  // abstract
+        return null;
+    }
 
     private TruffleVM vm() throws Exception {
-        if (vm == null) {
-            vm = prepareVM();
+        if (tckVM == null) {
+            tckVM = prepareVM();
         }
-        return vm;
+        return tckVM;
     }
 
     //
     // The tests
     //
 
+    @Test
     public void testFortyTwo() throws Exception {
+        if (getClass() == TruffleTCK.class) {
+            return;
+        }
         TruffleVM.Symbol fourtyTwo = findGlobalSymbol(fourtyTwo());
 
         Object res = fourtyTwo.invoke(null);
@@ -90,7 +103,11 @@
         assert 42 == n.intValue() : "The value is 42 =  " + n.intValue();
     }
 
+    @Test
     public void testPlusWithInts() throws Exception {
+        if (getClass() == TruffleTCK.class) {
+            return;
+        }
         Random r = new Random();
         int a = r.nextInt(100);
         int b = r.nextInt(100);
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java	Wed May 27 13:32:18 2015 +0200
@@ -34,10 +34,11 @@
 
     @Before
     public void initInDifferentThread() throws InterruptedException {
+        final TruffleVM.Builder b = TruffleVM.newVM();
         Thread t = new Thread("Initializer") {
             @Override
             public void run() {
-                tvm = TruffleVM.create();
+                tvm = b.build();
             }
         };
         t.start();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java	Wed May 27 13:32:18 2015 +0200
@@ -133,13 +133,19 @@
     public static final class Env {
         private final TruffleVM vm;
         private final TruffleLanguage lang;
+        private final Reader in;
+        private final Writer err;
+        private final Writer out;
 
-        Env(TruffleVM vm, Constructor<?> langConstructor) {
+        Env(TruffleVM vm, Constructor<?> langConstructor, Writer out, Writer err, Reader in) {
             this.vm = vm;
+            this.in = in;
+            this.err = err;
+            this.out = out;
             try {
                 this.lang = (TruffleLanguage) langConstructor.newInstance(this);
             } catch (Exception ex) {
-                throw new IllegalStateException("Cannot construct language " + langConstructor.getClass().getName(), ex);
+                throw new IllegalStateException("Cannot construct language " + langConstructor.getDeclaringClass().getName(), ex);
             }
         }
 
@@ -155,15 +161,41 @@
         public Object importSymbol(String globalName) {
             return API.importSymbol(vm, lang, globalName);
         }
+
+        /**
+         * Input associated with this {@link TruffleVM}.
+         *
+         * @return reader, never <code>null</code>
+         */
+        public Reader stdIn() {
+            return in;
+        }
+
+        /**
+         * Standard output writer for this {@link TruffleVM}.
+         *
+         * @return writer, never <code>null</code>
+         */
+        public Writer stdOut() {
+            return out;
+        }
+
+        /**
+         * Standard error writer for this {@link TruffleVM}.
+         *
+         * @return writer, never <code>null</code>
+         */
+        public Writer stdErr() {
+            return err;
+        }
     }
 
     private static final AccessAPI API = new AccessAPI();
 
     private static final class AccessAPI extends Accessor {
-
         @Override
-        protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz) {
-            Env env = new Env(vm, langClazz);
+        protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+            Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn);
             return env.lang;
         }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java	Wed May 27 13:32:18 2015 +0200
@@ -77,8 +77,8 @@
         }
     }
 
-    protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz) {
-        return API.attachEnv(vm, langClazz);
+    protected TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+        return API.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
     }
 
     protected Object eval(TruffleLanguage l, Source s) throws IOException {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java	Wed May 27 13:32:18 2015 +0200
@@ -38,10 +38,10 @@
 import com.oracle.truffle.api.source.*;
 
 /**
- * Virtual machine for Truffle based languages. Use {@link #create()} to instantiate new isolated
- * virtual machine ready for execution of various languages. All the languages in a single virtual
- * machine see each other exported global symbols and can co-operate. Use {@link #create()} multiple
- * times to create different, isolated virtual machines completely separated from each other.
+ * Virtual machine for Truffle based languages. Use {@link #newVM()} to create new isolated virtual
+ * machine ready for execution of various languages. All the languages in a single virtual machine
+ * see each other exported global symbols and can co-operate. Use {@link #newVM()} multiple times to
+ * create different, isolated virtual machines completely separated from each other.
  * <p>
  * Once instantiated use {@link #eval(java.net.URI)} with a reference to a file or URL or directly
  * pass code snippet into the virtual machine via {@link #eval(java.lang.String, java.lang.String)}.
@@ -50,17 +50,41 @@
  * initialized, it remains so, until the virtual machine isn't garbage collected.
  * <p>
  * The <code>TruffleVM</code> is single-threaded and tries to enforce that. It records the thread it
- * has been {@link #create() created} by and checks that all subsequent calls are coming from the
- * same thread.
+ * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from
+ * the same thread.
  */
 public final class TruffleVM {
     private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName());
     private static final SPIAccessor SPI = new SPIAccessor();
     private final Thread initThread;
     private final Map<String, Language> langs;
+    private final Reader in;
+    private final Writer err;
+    private final Writer out;
 
+    /**
+     * Private & temporary only constructor.
+     */
     private TruffleVM() {
-        initThread = Thread.currentThread();
+        this.initThread = null;
+        this.in = null;
+        this.err = null;
+        this.out = null;
+        this.langs = null;
+    }
+
+    /**
+     * Real constructor used from the builder.
+     *
+     * @param out stdout
+     * @param err stderr
+     * @param in stdin
+     */
+    private TruffleVM(Writer out, Writer err, Reader in) {
+        this.out = out;
+        this.err = err;
+        this.in = in;
+        this.initThread = Thread.currentThread();
         this.langs = new HashMap<>();
         Enumeration<URL> en;
         try {
@@ -96,14 +120,105 @@
     }
 
     /**
-     * Creates new Truffle virtual machine. It searches for {@link Registration languages
-     * registered} in the system class loader and makes them available for later evaluation via
+     * Creation of new Truffle virtual machine. Use the {@link Builder} methods to configure your
+     * virtual machine and then create one using {@link Builder#build()}:
+     *
+     * <pre>
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * </pre>
+     *
+     * It searches for {@link Registration languages registered} in the system class loader and
+     * makes them available for later evaluation via
      * {@link #eval(java.lang.String, java.lang.String)} methods.
      *
      * @return new, isolated virtual machine with pre-registered languages
      */
-    public static TruffleVM create() {
-        return new TruffleVM();
+    public static TruffleVM.Builder newVM() {
+        // making Builder non-static inner class is a
+        // nasty trick to avoid the Builder class to appear
+        // in Javadoc next to TruffleVM class
+        TruffleVM vm = new TruffleVM();
+        return vm.new Builder();
+    }
+
+    /**
+     * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the
+     * end create new {@link TruffleVM virtual machine}:
+     *
+     * <pre>
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * </pre>
+     */
+    public final class Builder {
+        private Writer out;
+        private Writer err;
+        private Reader in;
+
+        Builder() {
+        }
+
+        /**
+         * Changes the defaut output for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
+         *
+         * @param w the writer to use as output
+         * @return instance of this builder
+         */
+        public Builder stdOut(Writer w) {
+            out = w;
+            return this;
+        }
+
+        /**
+         * Changes the error output for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#err}.
+         *
+         * @param w the writer to use as output
+         * @return instance of this builder
+         */
+        public Builder stdErr(Writer w) {
+            err = w;
+            return this;
+        }
+
+        /**
+         * Changes the defaut input for languages running in <em>to be created</em>
+         * {@link TruffleVM virtual machine}. The default is to use {@link System#out}.
+         *
+         * @param r the reader to use as input
+         * @return instance of this builder
+         */
+        public Builder stdIn(Reader r) {
+            in = r;
+            return this;
+        }
+
+        /**
+         * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from
+         * values passed into configuration methods in this class.
+         *
+         * @return new, isolated virtual machine with pre-registered languages
+         */
+        public TruffleVM build() {
+            if (out == null) {
+                out = new OutputStreamWriter(System.out);
+            }
+            if (err == null) {
+                err = new OutputStreamWriter(System.err);
+            }
+            if (in == null) {
+                in = new InputStreamReader(System.in);
+            }
+            return new TruffleVM(out, err, in);
+        }
     }
 
     /**
@@ -321,7 +436,7 @@
                 try {
                     Class<?> langClazz = Class.forName(n, true, loader());
                     Constructor<?> constructor = langClazz.getConstructor(Env.class);
-                    impl = SPI.attachEnv(TruffleVM.this, constructor);
+                    impl = SPI.attachEnv(TruffleVM.this, constructor, out, err, in);
                 } catch (Exception ex) {
                     throw new IllegalStateException("Cannot initialize " + getName() + " language with implementation " + n, ex);
                 }
@@ -353,8 +468,8 @@
         }
 
         @Override
-        public TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz) {
-            return super.attachEnv(vm, langClazz);
+        public TruffleLanguage attachEnv(TruffleVM vm, Constructor<?> langClazz, Writer stdOut, Writer stdErr, Reader stdIn) {
+            return super.attachEnv(vm, langClazz, stdOut, stdErr, stdIn);
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Truffle Virtual Machine</title>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    </head>
+    <body>
+        <div>Central place to control <a href="TruffleVM.html">Truffle Virtual Machine</a> and
+        all languages hosted in it.</div>
+    </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.dsl.processor;
+
+import java.util.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.element.*;
+import javax.tools.Diagnostic.*;
+
+public class ExpectError {
+
+    public static void assertNoErrorExpected(ProcessingEnvironment processingEnv, Element element) {
+        TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME);
+        if (eee != null) {
+            for (AnnotationMirror am : element.getAnnotationMirrors()) {
+                if (am.getAnnotationType().asElement().equals(eee)) {
+                    processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", element);
+                }
+            }
+        }
+    }
+
+    public static boolean isExpectedError(ProcessingEnvironment processingEnv, Element element, String message) {
+        TypeElement eee = processingEnv.getElementUtils().getTypeElement(TruffleTypes.EXPECT_ERROR_CLASS_NAME);
+        if (eee != null) {
+            for (AnnotationMirror am : element.getAnnotationMirrors()) {
+                if (am.getAnnotationType().asElement().equals(eee)) {
+                    Map<? extends ExecutableElement, ? extends AnnotationValue> vals = am.getElementValues();
+                    if (vals.size() == 1) {
+                        AnnotationValue av = vals.values().iterator().next();
+                        if (av.getValue() instanceof List) {
+                            List<?> arr = (List<?>) av.getValue();
+                            for (Object o : arr) {
+                                if (o instanceof AnnotationValue) {
+                                    AnnotationValue ov = (AnnotationValue) o;
+                                    if (message.equals(ov.getValue())) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java	Wed May 27 13:32:18 2015 +0200
@@ -34,7 +34,6 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.TruffleLanguage.Registration;
-import com.oracle.truffle.api.dsl.*;
 
 @SupportedAnnotationTypes("com.oracle.truffle.api.*")
 public final class LanguageRegistrationProcessor extends AbstractProcessor {
@@ -112,35 +111,14 @@
     }
 
     void assertNoErrorExpected(Element e) {
-        TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName());
-        for (AnnotationMirror am : e.getAnnotationMirrors()) {
-            if (am.getAnnotationType().asElement().equals(eee)) {
-                processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", e);
-            }
-        }
+        ExpectError.assertNoErrorExpected(processingEnv, e);
     }
 
     void emitError(String msg, Element e) {
-        TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName());
-        for (AnnotationMirror am : e.getAnnotationMirrors()) {
-            if (am.getAnnotationType().asElement().equals(eee)) {
-                Map<? extends ExecutableElement, ? extends AnnotationValue> vals = am.getElementValues();
-                if (vals.size() == 1) {
-                    AnnotationValue av = vals.values().iterator().next();
-                    if (av.getValue() instanceof List) {
-                        List<?> arr = (List<?>) av.getValue();
-                        for (Object o : arr) {
-                            if (o instanceof AnnotationValue) {
-                                AnnotationValue ov = (AnnotationValue) o;
-                                if (msg.equals(ov.getValue())) {
-                                    return;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+        if (ExpectError.isExpectedError(processingEnv, e, msg)) {
+            return;
         }
         processingEnv.getMessager().printMessage(Kind.ERROR, msg, e);
     }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Wed May 27 13:32:18 2015 +0200
@@ -44,6 +44,8 @@
  */
 public final class TruffleTypes {
 
+    public static final String EXPECT_ERROR_CLASS_NAME = "com.oracle.truffle.api.dsl.test.ExpectError";
+
     private final DeclaredType node;
     private final ArrayType nodeArray;
     private final TypeMirror unexpectedValueException;
@@ -94,7 +96,7 @@
         nodeFactory = getRequired(context, NodeFactory.class);
         nodeFactoryBase = getRequired(context, NodeFactoryBase.class);
         dslMetadata = getRequired(context, DSLMetadata.class);
-        expectError = (TypeElement) getRequired(context, ExpectError.class).asElement();
+        expectError = getOptional(context, EXPECT_ERROR_CLASS_NAME);
         generateNodeFactory = getRequired(context, GenerateNodeFactory.class);
     }
 
@@ -158,6 +160,10 @@
         return (DeclaredType) type;
     }
 
+    private static TypeElement getOptional(ProcessorContext context, String name) {
+        return context.getEnvironment().getElementUtils().getTypeElement(name);
+    }
+
     public TypeMirror getInvalidAssumption() {
         return invalidAssumption;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Wed May 27 13:32:18 2015 +0200
@@ -37,7 +37,7 @@
 @DSLOptions
 public class TypeSystemParser extends AbstractParser<TypeSystemData> {
 
-    public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class);
+    public static final List<Class<TypeSystem>> ANNOTATIONS = Arrays.asList(TypeSystem.class);
 
     @Override
     public Class<? extends Annotation> getAnnotationType() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java	Wed May 27 13:32:18 2015 +0200
@@ -34,8 +34,8 @@
 import javax.tools.Diagnostic.Kind;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.Node.Child;
+import com.oracle.truffle.dsl.processor.*;
 
 @SupportedAnnotationTypes({"com.oracle.truffle.api.CompilerDirectives.TruffleBoundary", "com.oracle.truffle.api.nodes.Node.Child"})
 public class VerifyTruffleProcessor extends AbstractProcessor {
@@ -125,37 +125,15 @@
         return false;
     }
 
-    void assertNoErrorExpected(Element e) {
-        TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName());
-        for (AnnotationMirror am : e.getAnnotationMirrors()) {
-            if (am.getAnnotationType().asElement().equals(eee)) {
-                processingEnv.getMessager().printMessage(Kind.ERROR, "Expected an error, but none found!", e);
-            }
-        }
+    void assertNoErrorExpected(Element element) {
+        ExpectError.assertNoErrorExpected(processingEnv, element);
     }
 
-    void emitError(String msg, Element e) {
-        TypeElement eee = processingEnv.getElementUtils().getTypeElement(ExpectError.class.getName());
-        for (AnnotationMirror am : e.getAnnotationMirrors()) {
-            if (am.getAnnotationType().asElement().equals(eee)) {
-                Map<? extends ExecutableElement, ? extends AnnotationValue> vals = am.getElementValues();
-                if (vals.size() == 1) {
-                    AnnotationValue av = vals.values().iterator().next();
-                    if (av.getValue() instanceof List) {
-                        List<?> arr = (List<?>) av.getValue();
-                        for (Object o : arr) {
-                            if (o instanceof AnnotationValue) {
-                                AnnotationValue ov = (AnnotationValue) o;
-                                if (msg.equals(ov.getValue())) {
-                                    return;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+    void emitError(String message, Element element) {
+        if (ExpectError.isExpectedError(processingEnv, element, message)) {
+            return;
         }
-        processingEnv.getMessager().printMessage(Kind.ERROR, msg, e);
+        processingEnv.getMessager().printMessage(Kind.ERROR, message, element);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.test;
+
+import com.oracle.truffle.api.test.vm.TruffleTCK;
+import com.oracle.truffle.api.vm.TruffleVM;
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+/**
+ * This is the way to verify your language implementation is compatible.
+ *
+ */
+public class SLTckTest extends TruffleTCK {
+    @Test
+    public void testVerifyPresence() {
+        TruffleVM vm = TruffleVM.newVM().build();
+        assertTrue("Our language is present", vm.getLanguages().containsKey("application/x-sl"));
+    }
+
+    @Override
+    protected TruffleVM prepareVM() throws Exception {
+        TruffleVM vm = TruffleVM.newVM().build();
+        vm.eval("application/x-sl", // your langage
+                        "function fourtyTwo() {\n" + // your script
+                                        "  return 42;\n" + //
+                                        "}\n" + //
+                                        "function plus(a, b) {\n" + //
+                                        "  return a + b;\n" + //
+                                        "}\n" //
+        );
+        return vm;
+    }
+
+    @Override
+    protected String fourtyTwo() {
+        return "fourtyTwo";
+    }
+
+    @Override
+    protected String plusInt() {
+        return "plus";
+    }
+}
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java	Wed May 27 13:32:18 2015 +0200
@@ -37,11 +37,9 @@
 import org.junit.runners.model.*;
 
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.source.*;
+import com.oracle.truffle.api.vm.*;
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
-import com.oracle.truffle.sl.factory.*;
-import com.oracle.truffle.sl.runtime.*;
 import com.oracle.truffle.sl.test.SLTestRunner.TestCase;
 
 public final class SLTestRunner extends ParentRunner<TestCase> {
@@ -167,22 +165,16 @@
         ByteArrayOutputStream out = new ByteArrayOutputStream();
         PrintWriter printer = new PrintWriter(out);
         try {
-            SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer);
-            for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
-                context.installBuiltin(builtin);
-            }
-            /*
-             * TruffleVM vm = TruffleVM.create(); String script = readAllLines(testCase.path); for
-             * (int i = 0; i < repeats; i++) { vm.eval("application/x-sl", script); }
-             */
-            final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName);
-            SLMain.run(context, source, null, repeats);
+            TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build();
+
+            String script = readAllLines(testCase.path);
+            SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins);
 
             printer.flush();
             String actualOutput = new String(out.toByteArray());
-            Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput);
+            Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput);
         } catch (Throwable ex) {
-            notifier.fireTestFailure(new Failure(testCase.name, ex));
+            notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex)));
         } finally {
             notifier.fireTestFinished(testCase.name);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,1 @@
+Undefined function: foo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,3 @@
+function main() {  
+  foo();
+}  
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed May 27 13:32:18 2015 +0200
@@ -24,6 +24,8 @@
 
 import java.io.*;
 import java.math.*;
+import java.net.*;
+import java.util.*;
 import java.util.Scanner;
 
 import com.oracle.truffle.api.*;
@@ -33,6 +35,7 @@
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.tools.*;
 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.*;
@@ -132,11 +135,17 @@
  */
 @TruffleLanguage.Registration(name = "sl", mimeType = "application/x-sl")
 public class SLMain extends TruffleLanguage {
+    private static SLMain LAST;
+    private static List<NodeFactory<? extends SLBuiltinNode>> builtins = Collections.emptyList();
     private final SLContext context;
 
     public SLMain(Env env) {
         super(env);
-        this.context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), new PrintWriter(System.out));
+        context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true));
+        LAST = this;
+        for (NodeFactory<? extends SLBuiltinNode> builtin : builtins) {
+            context.installBuiltin(builtin);
+        }
     }
 
     /* Demonstrate per-type tabulation of node execution counts */
@@ -150,7 +159,7 @@
      * The main entry point. Use the mx command "mx sl" to run it with the correct class path setup.
      */
     public static void main(String[] args) throws IOException {
-        TruffleVM vm = TruffleVM.create();
+        TruffleVM vm = TruffleVM.newVM().build();
         assert vm.getLanguages().containsKey("application/x-sl");
 
         int repeats = 1;
@@ -158,12 +167,17 @@
             repeats = Integer.parseInt(args[1]);
         }
 
+        if (args.length == 0) {
+            vm.eval("application/x-sl", new InputStreamReader(System.in));
+        } else {
+            vm.eval(new File(args[0]).toURI());
+        }
+        Symbol main = vm.findGlobalSymbol("main");
+        if (main == null) {
+            throw new SLException("No function main() defined in SL source file.");
+        }
         while (repeats-- > 0) {
-            if (args.length == 0) {
-                vm.eval("application/x-sl", new InputStreamReader(System.in));
-            } else {
-                vm.eval(new File(args[0]).toURI());
-            }
+            main.invoke(null);
         }
     }
 
@@ -171,7 +185,9 @@
      * Parse and run the specified SL source. Factored out in a separate method so that it can also
      * be used by the unit test harness.
      */
-    public static long run(SLContext context, Source source, PrintWriter logOutput, int repeats) {
+    public static long run(TruffleVM context, URI source, PrintWriter logOutput, PrintWriter out, int repeats, List<NodeFactory<? extends SLBuiltinNode>> currentBuiltins) throws IOException {
+        builtins = currentBuiltins;
+
         if (logOutput != null) {
             logOutput.println("== running on " + Truffle.getRuntime().getName());
             // logOutput.println("Source = " + source.getCode());
@@ -200,11 +216,14 @@
         }
 
         /* Parse the SL source file. */
-        Parser.parseSL(context, source);
+        Object result = context.eval(source);
+        if (result != null) {
+            out.println(result);
+        }
 
         /* Lookup our main entry point, which is per definition always named "main". */
-        SLFunction main = context.getFunctionRegistry().lookup("main");
-        if (main.getCallTarget() == null) {
+        Symbol main = context.findGlobalSymbol("main");
+        if (main == null) {
             throw new SLException("No function main() defined in SL source file.");
         }
 
@@ -215,19 +234,21 @@
         /* Change to dump the AST to IGV over the network. */
         boolean dumpASTToIGV = false;
 
-        printScript("before execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
+        printScript("before execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
         long totalRuntime = 0;
         try {
             for (int i = 0; i < repeats; i++) {
                 long start = System.nanoTime();
                 /* Call the main entry point, without any arguments. */
                 try {
-                    Object result = main.getCallTarget().call();
+                    result = main.invoke(null);
                     if (result != SLNull.SINGLETON) {
-                        context.getOutput().println(result);
+                        out.println(result);
                     }
                 } catch (UnsupportedSpecializationException ex) {
-                    context.getOutput().println(formatTypeError(ex));
+                    out.println(formatTypeError(ex));
+                } catch (SLUndefinedFunctionException ex) {
+                    out.println(String.format("Undefined function: %s", ex.getFunctionName()));
                 }
                 long end = System.nanoTime();
                 totalRuntime += end - start;
@@ -238,7 +259,7 @@
             }
 
         } finally {
-            printScript("after execution", context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
+            printScript("after execution", LAST.context, logOutput, printASTToLog, printSourceAttributionToLog, dumpASTToIGV);
         }
         if (nodeExecCounter != null) {
             nodeExecCounter.print(System.out);
@@ -307,7 +328,7 @@
         if (ex.getNode() != null && ex.getNode().getSourceSection() != null) {
             SourceSection ss = ex.getNode().getSourceSection();
             if (ss != null && !(ss instanceof NullSourceSection)) {
-                result.append(" at ").append(ss.getSource().getName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn());
+                result.append(" at ").append(ss.getSource().getShortName()).append(" line ").append(ss.getStartLine()).append(" col ").append(ss.getStartColumn());
             }
         }
         result.append(": operation");
@@ -356,17 +377,22 @@
 
     @Override
     protected Object findExportedSymbol(String globalName) {
+        for (SLFunction f : context.getFunctionRegistry().getFunctions()) {
+            if (globalName.equals(f.getName())) {
+                return f;
+            }
+        }
         return null;
     }
 
     @Override
     protected Object getLanguageGlobal() {
-        return null;
+        return context;
     }
 
     @Override
     protected boolean isObjectOfLanguage(Object object) {
-        return false;
+        return object instanceof SLFunction;
     }
 
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java	Wed May 27 13:32:18 2015 +0200
@@ -52,20 +52,22 @@
         StringBuilder str = new StringBuilder();
 
         Truffle.getRuntime().iterateFrames(frameInstance -> {
-            dumpFrame(str, frameInstance.getCallTarget(), frameInstance.getFrame(FrameAccess.READ_ONLY, true));
+            CallTarget callTarget = frameInstance.getCallTarget();
+            Frame frame = frameInstance.getFrame(FrameAccess.READ_ONLY, true);
+            RootNode rn = ((RootCallTarget) callTarget).getRootNode();
+            if (rn.getClass().getName().contains("SLFunctionForeignAccess")) {
+                return 1;
+            }
+            if (str.length() > 0) {
+                str.append(System.getProperty("line.separator"));
+            }
+            str.append("Frame: ").append(rn.toString());
+            FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
+            frameDescriptor.getSlots().stream().forEach((s) -> {
+                str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s));
+            });
             return null;
         });
         return str.toString();
     }
-
-    private static void dumpFrame(StringBuilder str, CallTarget callTarget, Frame frame) {
-        if (str.length() > 0) {
-            str.append(System.getProperty("line.separator"));
-        }
-        str.append("Frame: ").append(((RootCallTarget) callTarget).getRootNode().toString());
-        FrameDescriptor frameDescriptor = frame.getFrameDescriptor();
-        for (FrameSlot s : frameDescriptor.getSlots()) {
-            str.append(", ").append(s.getIdentifier()).append("=").append(frame.getValue(s));
-        }
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Wed May 27 13:32:18 2015 +0200
@@ -34,6 +34,11 @@
 
     public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments);
 
+    @Specialization(guards = "function.getCallTarget() == null")
+    protected Object doUndefinedFunction(SLFunction function, @SuppressWarnings("unused") Object[] arguments) {
+        throw new SLUndefinedFunctionException(function.getName());
+    }
+
     /**
      * Inline cached specialization of the dispatch.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.nodes.call;
+
+public class SLUndefinedFunctionException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final String functionName;
+
+    public SLUndefinedFunctionException(String functionName) {
+        this.functionName = functionName;
+    }
+
+    public String getFunctionName() {
+        return functionName;
+    }
+
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed May 27 13:32:18 2015 +0200
@@ -52,7 +52,7 @@
         return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue());
     }
 
-    @Specialization(rewriteOn = RuntimeException.class)
+    @Specialization
     protected boolean doBoolean(boolean left, boolean hasRight, boolean right) {
         return left || right;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Wed May 27 13:32:18 2015 +0200
@@ -30,7 +30,6 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
 import com.oracle.truffle.api.source.*;
-import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.local.*;
@@ -158,12 +157,6 @@
      */
     public void executeMain(Source source) {
         Parser.parseSL(this, source);
-        SLFunction main = getFunctionRegistry().lookup("main");
-        if (main.getCallTarget() == null) {
-            throw new SLException("No function main() defined in SL source file.");
-        }
-        main.getCallTarget().call();
-        output.flush();
     }
 
     public DynamicObject createObject() {
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Wed May 27 00:36:16 2015 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java	Wed May 27 13:32:18 2015 +0200
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.runtime;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.interop.*;
 import com.oracle.truffle.api.utilities.*;
 
 /**
@@ -41,7 +42,7 @@
  * per name exists, the {@link SLFunctionRegistry} creates an instance also when performing name
  * lookup. A function that has been looked up, i.e., used, but not defined, has no call target.
  */
-public final class SLFunction {
+public final class SLFunction implements TruffleObject {
 
     /** The name of the function. */
     private final String name;
@@ -90,4 +91,14 @@
     public String toString() {
         return name;
     }
+
+    /**
+     * In case you want some of your objects to co-operate with other languages, you need to make
+     * them implement {@link TruffleObject} and provide additional {@link SLFunctionForeignAccess
+     * foreign access implementation}.
+     */
+    @Override
+    public ForeignAccessFactory getForeignAccessFactory() {
+        return SLFunctionForeignAccess.INSTANCE;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java	Wed May 27 13:32:18 2015 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.sl.runtime;
+
+import com.oracle.truffle.api.CallTarget;
+import com.oracle.truffle.api.Truffle;
+import com.oracle.truffle.api.frame.VirtualFrame;
+import com.oracle.truffle.api.interop.ForeignAccessFactory;
+import com.oracle.truffle.api.interop.InteropPredicate;
+import com.oracle.truffle.api.interop.exception.UnsupportedMessageException;
+import com.oracle.truffle.api.interop.messages.Message;
+import com.oracle.truffle.api.nodes.RootNode;
+import com.oracle.truffle.interop.ForeignAccessArguments;
+import com.oracle.truffle.interop.messages.Execute;
+import com.oracle.truffle.interop.messages.Receiver;
+import com.oracle.truffle.sl.nodes.call.SLDispatchNode;
+import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen;
+import java.math.BigInteger;
+
+/**
+ * Implementation of foreing access for {@link SLFunction}.
+ */
+final class SLFunctionForeignAccess implements ForeignAccessFactory {
+    public static final ForeignAccessFactory INSTANCE = new SLFunctionForeignAccess();
+
+    private SLFunctionForeignAccess() {
+    }
+
+    @Override
+    public InteropPredicate getLanguageCheck() {
+        return (com.oracle.truffle.api.interop.TruffleObject o) -> o instanceof SLFunction;
+    }
+
+    @Override
+    public CallTarget getAccess(Message tree) {
+        if (Execute.create(Receiver.create(), 0).matchStructure(tree)) {
+            return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode());
+        } else {
+            throw new UnsupportedMessageException(tree.toString() + " not supported");
+        }
+    }
+
+    private static class SLForeignCallerRootNode extends RootNode {
+        @Child private SLDispatchNode dispatch = SLDispatchNodeGen.create();
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            SLFunction function = (SLFunction) ForeignAccessArguments.getReceiver(frame.getArguments());
+            // the calling convention of interop passes the receiver of a
+            // function call (the this object)
+            // as an implicit 1st argument; we need to ignore this argument for SL
+            Object[] arguments = ForeignAccessArguments.extractUserArguments(1, frame.getArguments());
+            for (int i = 0; i < arguments.length; i++) {
+                if (arguments[i] instanceof Long) {
+                    continue;
+                }
+                if (arguments[i] instanceof BigInteger) {
+                    continue;
+                }
+                if (arguments[i] instanceof Number) {
+                    arguments[i] = ((Number) arguments[i]).longValue();
+                }
+            }
+
+            return dispatch.executeDispatch(frame, function, arguments);
+        }
+
+    }
+
+}
--- a/mx/mx_graal_makefile.py	Wed May 27 00:36:16 2015 +0200
+++ b/mx/mx_graal_makefile.py	Wed May 27 13:32:18 2015 +0200
@@ -84,8 +84,9 @@
 """.format(**props)
 
 def createDistributionRule(dist):
-    depDirs = ' '.join(['$(TARGET)/' + i.name for i in dist.sorted_deps(False, True)])
-    depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in dist.sorted_deps(False, True)])
+    sorted_deps = set(dist.sorted_deps(False, True))
+    depDirs = ' '.join(['$(TARGET)/' + i.name for i in sorted_deps])
+    depDirsStar = ' '.join(['$(TARGET)/' + i.name + '/*' for i in sorted_deps])
     jarPath = os.path.relpath(dist.path, dist.suite.dir)
     jarDir = os.path.dirname(jarPath)
     props = {
--- a/mx/suite.py	Wed May 27 00:36:16 2015 +0200
+++ b/mx/suite.py	Wed May 27 13:32:18 2015 +0200
@@ -1084,6 +1084,7 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "com.oracle.truffle.api.dsl",
+        "com.oracle.truffle.interop",
         "com.oracle.truffle.api.object",
         "FINDBUGS"
       ],
@@ -1097,8 +1098,8 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.truffle.sl",
-        "JUNIT",
+        "com.oracle.truffle.api.test",
+        "com.oracle.truffle.sl"
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
--- a/mxtool/mx.py	Wed May 27 00:36:16 2015 +0200
+++ b/mxtool/mx.py	Wed May 27 13:32:18 2015 +0200
@@ -2759,7 +2759,7 @@
         # N.B. Limiting to a suite only affects the starting set of projects. Dependencies in other suites will still be compiled
         sortedProjects = sorted_project_deps(projects, includeAnnotationProcessors=True)
 
-    if args.java:
+    if args.java and jdtJar:
         ideinit([], refreshOnly=True, buildProcessorJars=False)
 
     tasks = {}
@@ -2937,7 +2937,7 @@
                 log('Compiling {0} failed'.format(t.proj.name))
             abort('{0} Java compilation tasks failed'.format(len(failed)))
 
-    if args.java:
+    if args.java and not args.only:
         files = []
         for dist in sorted_dists():
             if dist not in updatedAnnotationProcessorDists:
@@ -4430,6 +4430,8 @@
     out.element('arg', {'value' : 'build'})
     out.element('arg', {'value' : '--only'})
     out.element('arg', {'value' : p.name})
+    out.element('arg', {'value' : '--force-javac'})
+    out.element('arg', {'value' : '--no-native'})
     out.close('exec')
     out.close('target')
     out.open('target', {'name' : 'jar', 'depends' : 'compile'})