# HG changeset patch # User Doug Simon # Date 1432726338 -7200 # Node ID 31fc2fce38f3cf27e9392730f3a85bac91b2d6ac # Parent 48c1ebd2412012b65dcd76d99ed7a5016d1376fd# Parent 93d486d51ab48f91d8697d94793e208e01e44559 Merge. diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- 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 { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java --- 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); diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java --- 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); diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java --- 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; + } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- 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 diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java --- 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 { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PEGraphDecoderTest.java --- /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); + } + } +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java --- 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); } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/PEGraphDecoder.java --- 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 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); diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.jvmci.meta/src/com/oracle/jvmci/meta/JavaTypeProfile.java --- 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; + } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExpectError.java --- /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(); + +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java --- 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; diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/LanguageRegistrationTest.java --- 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 { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/processor/TruffleProcessorTest.java --- 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.*; diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ExpectError.java --- 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(); - -} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java 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); diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleVMSingleThreadedTest.java 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(); diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleLanguage.java 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 null + */ + public Reader stdIn() { + return in; + } + + /** + * Standard output writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdOut() { + return out; + } + + /** + * Standard error writer for this {@link TruffleVM}. + * + * @return writer, never null + */ + public Writer stdErr() { + return err; + } } private static final AccessAPI API = new AccessAPI(); private static final class AccessAPI extends Accessor { - @Override - protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz) { - Env env = new Env(vm, langClazz); + protected TruffleLanguage attachEnv(TruffleVM vm, Constructor langClazz, Writer stdOut, Writer stdErr, Reader stdIn) { + Env env = new Env(vm, langClazz, stdOut, stdErr, stdIn); return env.lang; } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/Accessor.java 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 { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/TruffleVM.java 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. *

* 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. *

* The TruffleVM is single-threaded and tries to enforce that. It records the thread it - * has been {@link #create() created} by and checks that all subsequent calls are coming from the - * same thread. + * has been {@link Builder#build() created} by and checks that all subsequent calls are coming from + * the same thread. */ public final class TruffleVM { private static final Logger LOG = Logger.getLogger(TruffleVM.class.getName()); private static final SPIAccessor SPI = new SPIAccessor(); private final Thread initThread; private final Map langs; + private final Reader in; + private final Writer err; + private final Writer out; + /** + * Private & temporary only constructor. + */ private TruffleVM() { - initThread = Thread.currentThread(); + this.initThread = null; + this.in = null; + this.err = null; + this.out = null; + this.langs = null; + } + + /** + * Real constructor used from the builder. + * + * @param out stdout + * @param err stderr + * @param in stdin + */ + private TruffleVM(Writer out, Writer err, Reader in) { + this.out = out; + this.err = err; + this.in = in; + this.initThread = Thread.currentThread(); this.langs = new HashMap<>(); Enumeration en; try { @@ -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()}: + * + *

+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ * + * It searches for {@link Registration languages registered} in the system class loader and + * makes them available for later evaluation via * {@link #eval(java.lang.String, java.lang.String)} methods. * * @return new, isolated virtual machine with pre-registered languages */ - public static TruffleVM create() { - return new TruffleVM(); + public static TruffleVM.Builder newVM() { + // making Builder non-static inner class is a + // nasty trick to avoid the Builder class to appear + // in Javadoc next to TruffleVM class + TruffleVM vm = new TruffleVM(); + return vm.new Builder(); + } + + /** + * Builder for a new {@link TruffleVM}. Call various configuration methods in a chain and at the + * end create new {@link TruffleVM virtual machine}: + * + *
+     * {@link TruffleVM} vm = {@link TruffleVM}.{@link TruffleVM#newVM() newVM()}
+     *     .{@link Builder#stdOut(java.io.Writer) stdOut}({@link Writer yourWriter})
+     *     .{@link Builder#stdErr(java.io.Writer) stdErr}({@link Writer yourWriter})
+     *     .{@link Builder#stdIn(java.io.Reader) stdIn}({@link Reader yourReader})
+     *     .{@link Builder#build() build()};
+     * 
+ */ + public final class Builder { + private Writer out; + private Writer err; + private Reader in; + + Builder() { + } + + /** + * Changes the defaut output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdOut(Writer w) { + out = w; + return this; + } + + /** + * Changes the error output for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#err}. + * + * @param w the writer to use as output + * @return instance of this builder + */ + public Builder stdErr(Writer w) { + err = w; + return this; + } + + /** + * Changes the defaut input for languages running in to be created + * {@link TruffleVM virtual machine}. The default is to use {@link System#out}. + * + * @param r the reader to use as input + * @return instance of this builder + */ + public Builder stdIn(Reader r) { + in = r; + return this; + } + + /** + * Creates the {@link TruffleVM Truffle virtual machine}. The configuration is taken from + * values passed into configuration methods in this class. + * + * @return new, isolated virtual machine with pre-registered languages + */ + public TruffleVM build() { + if (out == null) { + out = new OutputStreamWriter(System.out); + } + if (err == null) { + err = new OutputStreamWriter(System.err); + } + if (in == null) { + in = new InputStreamReader(System.in); + } + return new TruffleVM(out, err, in); + } } /** @@ -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 diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/vm/package.html Wed May 27 13:32:18 2015 +0200 @@ -0,0 +1,12 @@ + + + + Truffle Virtual Machine + + + + +
Central place to control Truffle Virtual Machine and + all languages hosted in it.
+ + diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ExpectError.java --- /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 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; + } + +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/LanguageRegistrationProcessor.java --- 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 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); } + } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java --- 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; } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java --- 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 { - public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class, ExpectError.class); + public static final List> ANNOTATIONS = Arrays.asList(TypeSystem.class); @Override public Class getAnnotationType() { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/verify/VerifyTruffleProcessor.java --- 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 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); } /** diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java 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"; + } +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTestRunner.java 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 { @@ -167,22 +165,16 @@ ByteArrayOutputStream out = new ByteArrayOutputStream(); PrintWriter printer = new PrintWriter(out); try { - SLContext context = SLContextFactory.create(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats))), printer); - for (NodeFactory builtin : builtins) { - context.installBuiltin(builtin); - } - /* - * TruffleVM vm = TruffleVM.create(); String script = readAllLines(testCase.path); for - * (int i = 0; i < repeats; i++) { vm.eval("application/x-sl", script); } - */ - final Source source = Source.fromText(readAllLines(testCase.path), testCase.sourceName); - SLMain.run(context, source, null, repeats); + TruffleVM vm = TruffleVM.newVM().stdIn(new BufferedReader(new StringReader(repeat(testCase.testInput, repeats)))).stdOut(printer).build(); + + String script = readAllLines(testCase.path); + SLMain.run(vm, testCase.path.toUri(), null, printer, repeats, builtins); printer.flush(); String actualOutput = new String(out.toByteArray()); - Assert.assertEquals(repeat(testCase.expectedOutput, repeats), actualOutput); + Assert.assertEquals(script, repeat(testCase.expectedOutput, repeats), actualOutput); } catch (Throwable ex) { - notifier.fireTestFailure(new Failure(testCase.name, ex)); + notifier.fireTestFailure(new Failure(testCase.name, new IllegalStateException("Cannot run " + testCase.sourceName, ex))); } finally { notifier.fireTestFinished(testCase.name); } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.output --- /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 diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl.test/tests/error/UndefinedFunction01.sl --- /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(); +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java 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> builtins = Collections.emptyList(); private final SLContext context; public SLMain(Env env) { super(env); - this.context = SLContextFactory.create(new BufferedReader(new InputStreamReader(System.in)), new PrintWriter(System.out)); + context = SLContextFactory.create(new BufferedReader(env().stdIn()), new PrintWriter(env().stdOut(), true)); + LAST = this; + for (NodeFactory builtin : builtins) { + context.installBuiltin(builtin); + } } /* Demonstrate per-type tabulation of node execution counts */ @@ -150,7 +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> 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; } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/builtins/SLStackTraceBuiltin.java 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)); - } - } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java --- 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. * diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUndefinedFunctionException.java --- /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; + } + +} diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- 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; } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java 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() { diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunction.java 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; + } } diff -r 48c1ebd24120 -r 31fc2fce38f3 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java 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); + } + + } + +} diff -r 48c1ebd24120 -r 31fc2fce38f3 mx/mx_graal_makefile.py --- 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 = { diff -r 48c1ebd24120 -r 31fc2fce38f3 mx/suite.py --- 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", diff -r 48c1ebd24120 -r 31fc2fce38f3 mxtool/mx.py --- 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'})