# HG changeset patch # User Christian Humer # Date 1423677695 -3600 # Node ID a79a3e467245dfb9ddfbbd86e58f2775411e5820 # Parent 67ab244ab689fc192dcf319a96332b05938ee131 Truffle-DSL: move examples package into test package for the project canonicalizer. diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleNode.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleNode.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +0,0 @@ -/* - * 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.api.dsl.examples; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.internal.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -@TypeSystemReference(ExampleTypes.class) -@NodeChild(value = "args", type = ExampleNode[].class) -public abstract class ExampleNode extends Node { - - public Object execute(@SuppressWarnings("unused") VirtualFrame frame) { - // will get implemented by the DSL. - throw new UnsupportedOperationException(); - } - - @Override - public String toString() { - if (this instanceof SpecializedNode) { - return ((SpecializedNode) this).getSpecializationNode().toString(); - } else { - return super.toString(); - } - } - - public static CallTarget createTarget(ExampleNode node) { - return Truffle.getRuntime().createCallTarget(new ExampleRootNode(node)); - } - - @SuppressWarnings("unchecked") - public static T getNode(CallTarget target) { - return (T) ((ExampleRootNode) ((RootCallTarget) target).getRootNode()).child; - } - - public static ExampleNode[] createArguments(int count) { - ExampleNode[] nodes = new ExampleNode[count]; - for (int i = 0; i < count; i++) { - nodes[i] = new ExampleArgumentNode(i); - } - return nodes; - } - - private static class ExampleRootNode extends RootNode { - - @Child ExampleNode child; - - public ExampleRootNode(ExampleNode child) { - this.child = child; - } - - @Override - public Object execute(VirtualFrame frame) { - return child.execute(frame); - } - - } - - private static class ExampleArgumentNode extends ExampleNode { - - private final int index; - - public ExampleArgumentNode(int index) { - this.index = index; - } - - @Override - public Object execute(VirtualFrame frame) { - Object[] arguments = frame.getArguments(); - if (index < arguments.length) { - return arguments[index]; - } - return null; - } - } - - public static CallTarget createDummyTarget(int argumentIndex) { - return Truffle.getRuntime().createCallTarget(new DummyCallRootNode(argumentIndex)); - } - - private static class DummyCallRootNode extends RootNode { - - private final int argumentIndex; - - public DummyCallRootNode(int argumentIndex) { - this.argumentIndex = argumentIndex; - } - - @Override - public Object execute(VirtualFrame frame) { - return frame.getArguments()[argumentIndex]; - } - - @Override - public String toString() { - return "DummyRootNode[arg = " + argumentIndex + "]"; - } - - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleTypes.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleTypes.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * 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.api.dsl.examples; - -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.examples.FunctionCall.Function; -import com.oracle.truffle.api.dsl.examples.Interop.TruffleObject; -import com.oracle.truffle.api.dsl.examples.RubyCall.InternalMethod; -import com.oracle.truffle.api.dsl.examples.RubyCall.RubyObject; -import com.oracle.truffle.api.dsl.examples.StableDispatch.SLFunction; - -@TypeSystem({int.class, double.class, boolean.class, TruffleObject.class, SLFunction.class, RubyObject.class, Function.class, InternalMethod.class, int[].class, double[].class, Object[].class}) -public class ExampleTypes { - - @ImplicitCast - public static double castInt(int intValue) { - return intValue; - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/FunctionCall.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/FunctionCall.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * 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.api.dsl.examples; - -import static com.oracle.truffle.api.dsl.examples.ExampleNode.*; -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.examples.FunctionCallFactory.FunctionCallNodeGen; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * This example illustrates how {@link Cached} can be used to implement function calls that use - * local state for its guards. If there are always distinct Function objects with distinct - * CallTargets then we can use the directCallFunctionGuard specialization. If there are two Function - * instances cached with the same CallTarget then we use the directCall cache. We do this because - * the directCallFunctionGuard specialization can use a faster guard. - */ -@SuppressWarnings("unused") -public class FunctionCall { - - @Test - public void testFunctionCall() { - assertEquals(2, FunctionCallNode.CACHE_SIZE); - - CallTarget dummyTarget1 = createDummyTarget(0); - CallTarget dummyTarget2 = createDummyTarget(0); - CallTarget dummyTarget3 = createDummyTarget(0); - - Function dummyFunction1 = new Function(dummyTarget1); - Function dummyFunction2 = new Function(dummyTarget2); - Function dummyFunction3 = new Function(dummyTarget2); // same target as dummyFunction2 - Function dummyFunction4 = new Function(dummyTarget3); - - FunctionCallNode node = FunctionCallNodeGen.create(createArguments(2)); - CallTarget target = createTarget(node); - assertEquals(42, target.call(dummyFunction1, 42)); - assertEquals(43, target.call(dummyFunction2, 43)); - assertEquals(44, target.call(dummyFunction3, 44)); // transition to directCall - assertEquals(2, node.directCallFunctionGuard); - assertEquals(1, node.directCall); - - assertEquals(42, target.call(dummyFunction1, 42)); - assertEquals(43, target.call(dummyFunction2, 43)); - assertEquals(2, node.directCallFunctionGuard); - assertEquals(3, node.directCall); - - assertEquals(44, target.call(dummyFunction4, 44)); // transition to indirectCall - assertEquals(2, node.directCallFunctionGuard); - assertEquals(3, node.directCall); - assertEquals(1, node.indirectCall); - - assertEquals(42, target.call(dummyFunction1, 42)); - assertEquals(43, target.call(dummyFunction2, 43)); - assertEquals(44, target.call(dummyFunction3, 44)); - assertEquals(2, node.directCallFunctionGuard); - assertEquals(3, node.directCall); - assertEquals(4, node.indirectCall); - } - - public static class FunctionCallNode extends ExampleNode { - - public static final int CACHE_SIZE = 2; - - private CallTarget[] cachedTargets = new CallTarget[CACHE_SIZE]; - - private int directCallFunctionGuard; - private int directCall; - private int indirectCall; - - @Specialization(limit = "CACHE_SIZE", guards = {"function == cachedFunction", "!cacheFunctionTarget(cachedFunction)"}) - public Object directCallFunctionGuard(VirtualFrame frame, Function function, Object argument, // - @Cached("function") Function cachedFunction, // - @Cached("create(cachedFunction.getTarget())") DirectCallNode callNode) { - directCallFunctionGuard++; - return callNode.call(frame, new Object[]{argument}); - } - - protected final boolean cacheFunctionTarget(Function function) { - CompilerAsserts.neverPartOfCompilation(); - if (cachedTargets != null) { - CallTarget target = function.getTarget(); - for (int i = 0; i < cachedTargets.length; i++) { - CallTarget cachedTarget = cachedTargets[i]; - if (cachedTarget == target) { - cachedTargets = null; - return true; - } else if (cachedTarget == null) { - cachedTargets[i] = target; - return false; - } - } - } - return false; - } - - @Specialization(limit = "CACHE_SIZE", contains = "directCallFunctionGuard", guards = {"function.getTarget() == cachedTarget"}) - protected Object directCall(VirtualFrame frame, Function function, Object argument, // - @Cached("function.getTarget()") CallTarget cachedTarget, // - @Cached("create(cachedTarget)") DirectCallNode callNode) { - directCall++; - return callNode.call(frame, new Object[]{argument}); - } - - @Specialization(contains = "directCall") - protected Object indirectCall(VirtualFrame frame, Function function, Object argument, // - @Cached("create()") IndirectCallNode callNode) { - indirectCall++; - return callNode.call(frame, function.getTarget(), new Object[]{argument}); - } - } - - public static class Function { - - private final CallTarget target; - - public Function(CallTarget target) { - this.target = target; - } - - public CallTarget getTarget() { - return target; - } - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/Interop.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/Interop.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * 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.api.dsl.examples; - -import static com.oracle.truffle.api.dsl.examples.ExampleNode.*; -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.examples.InteropFactory.UseInteropNodeGen; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; - -/** - * This example aims to illustrate how the {@link Cached} annotation can be used to implement a - * cache for a simplified language interoperability pattern. - */ -public class Interop { - - @Test - public void testInterop() { - UseInterop node = UseInteropNodeGen.create(createArguments(2)); - CallTarget target = createTarget(node); - TruffleObject o1 = new TruffleObject(); - TruffleObject o2 = new TruffleObject(); - TruffleObject o3 = new TruffleObject(); - TruffleObject o4 = new TruffleObject(); - assertEquals(42, target.call(o1, 42)); - assertEquals(43, target.call(o2, 43)); - assertEquals(44, target.call(o3, 44)); - assertEquals(3, node.cached); - assertEquals(0, node.generic); - assertEquals(45, target.call(o4, 45)); // operation gets generic - assertEquals(42, target.call(o1, 42)); - assertEquals(43, target.call(o2, 43)); - assertEquals(44, target.call(o3, 44)); - assertEquals(3, node.cached); - assertEquals(4, node.generic); - } - - public static class UseInterop extends ExampleNode { - - int cached = 0; - int generic = 0; - - @Specialization(guards = "operation.accept(target)") - protected Object interopCached(VirtualFrame frame, TruffleObject target, Object value, // - @Cached("target.createOperation()") TruffleObjectOperation operation) { - cached++; - return operation.execute(frame, target, value); - } - - @Specialization(contains = "interopCached") - protected Object interopGeneric(VirtualFrame frame, TruffleObject target, Object value) { - generic++; - return target.createOperation().execute(frame, target, value); - } - } - - public abstract static class TruffleObjectOperation extends Node { - - public abstract boolean accept(TruffleObject object); - - public abstract Object execute(VirtualFrame frame, Object target, Object value); - - } - - public static class TruffleObject { - - @TruffleBoundary - public TruffleObjectOperation createOperation() { - return new TruffleObjectOperation() { - @Override - public Object execute(VirtualFrame frame, Object target, Object value) { - return value; - } - - @Override - public boolean accept(TruffleObject object) { - return TruffleObject.this == object; - } - }; - } - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/MathPow.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/MathPow.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -/* - * 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.api.dsl.examples; - -import static com.oracle.truffle.api.dsl.examples.ExampleNode.*; -import static org.junit.Assert.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.examples.MathPowFactory.MathPowNodeGen; -import com.oracle.truffle.api.nodes.*; - -/** - * This example shows possible specializations for a simplified math pow node. It demonstrates how - * multiple caches can coexist within in the same node. This example does not show the best possible - * specializations for math.pow. - * - * Note: int values are implicitly casted to double values. - */ -@SuppressWarnings("unused") -public class MathPow extends Node { - - @Test - public void testPow() { - MathPowNode node = MathPowNodeGen.create(createArguments(2)); - CallTarget target = createTarget(node); - - // start with doPowCached - assertEquals(1D, target.call(1D, 1)); - assertEquals(2D, target.call(2D, 1)); - assertEquals(3D, target.call(3D, 1)); - assertEquals(3, node.doPowCached); - assertEquals(0, node.doPowCachedExponent); - - // transition to doPowCachedExponent - assertEquals(4D, target.call(4D, 1)); - assertEquals(5D, target.call(5D, 1)); - assertEquals(6D, target.call(6D, 1)); - assertEquals(16D, target.call(4D, 2)); - assertEquals(125D, target.call(5D, 3)); - assertEquals(5, node.doPowCachedExponent); - assertEquals(0, node.doPowDoubleInt); - - // transition to doPowDoubleInt - assertEquals(4D * 4D * 4D * 4D, target.call(4D, 4)); - assertEquals(5D * 5D * 5D * 5D * 5D, target.call(5D, 5)); - assertEquals(5, node.doPowCachedExponent); - assertEquals(2, node.doPowDoubleInt); - - // transition to doPow - assertEquals(5D, target.call(5D, 1D)); - assertEquals(2D, target.call(2D, 1D)); - - assertEquals(3, node.doPowCached); - assertEquals(5, node.doPowCachedExponent); - assertEquals(2, node.doPowDoubleInt); - assertEquals(2, node.doPow); - } - - public static class MathPowNode extends ExampleNode { - - // test flags - int doPowCached; - int doPowCachedExponent; - int doPowDoubleInt; - int doPow; - - @Specialization(guards = {"base == cachedBase", "exponent == cachedExponent"}) - double doPowCached(double base, int exponent, // - @Cached("base") double cachedBase, // - @Cached("exponent") int cachedExponent, // - @Cached("cachePow(cachedBase, cachedExponent)") double cachedResult) { - doPowCached++; - return cachedResult; - } - - /* - * We could just use the doPow specialization instead. But this makes the number of doPow - * calls more difficult to assert. - */ - protected static double cachePow(double base, int exponent) { - return Math.pow(base, exponent); - } - - @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"}) - @ExplodeLoop - double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) { - doPowCachedExponent++; - double result = 1.0; - for (int i = 0; i < cachedExponent; i++) { - result *= base; - } - return result; - } - - @Specialization(contains = "doPowCachedExponent", guards = "exponent >= 0") - double doPowDoubleInt(double base, int exponent) { - doPowDoubleInt++; - // Uses binary decomposition to limit the number of - // multiplications; see the discussion in "Hacker's Delight" by Henry - // S. Warren, Jr., figure 11-6, page 213. - double b = base; - int e = exponent; - double result = 1; - while (e > 0) { - if ((e & 1) == 1) { - result *= b; - } - e >>= 1; - b *= b; - } - return result; - } - - @Specialization(contains = {"doPowCached", "doPowDoubleInt"}) - double doPow(double base, double exponent) { - doPow++; - return Math.pow(base, exponent); - } - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/RubyCall.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/RubyCall.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,302 +0,0 @@ -/* - * 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.api.dsl.examples; - -import static com.oracle.truffle.api.dsl.examples.ExampleNode.*; -import static org.junit.Assert.*; - -import java.util.*; - -import org.junit.*; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.examples.RubyCallFactory.RubyDispatchNodeGen; -import com.oracle.truffle.api.dsl.examples.RubyCallFactory.RubyHeadNodeGen; -import com.oracle.truffle.api.dsl.examples.RubyCallFactory.RubyLookupNodeGen; -import com.oracle.truffle.api.dsl.internal.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; - -/** - * This example illustrates a simplified version of a Ruby function call semantics (RubyHeadNode). - * The example usage shows how methods can be redefined in this implementation. - */ -@SuppressWarnings("unused") -public class RubyCall { - - @Test - public void testCall() { - RubyHeadNode node = RubyHeadNodeGen.create(createArguments(4)); - CallTarget nodeTarget = createTarget(node); - final Object firstArgument = "someArgument"; - - // dummyMethod is just going to return the some argument of the function - final Object testMethodName = "getSomeArgument"; - // implementation returns first argument - InternalMethod aClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(3)); - // implementation returns second argument - InternalMethod bClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(4)); - // implementation returns third argument - InternalMethod cClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(5)); - - // defines hierarchy C extends B extends A - RubyClass aClass = new RubyClass("A", null); - RubyClass bClass = new RubyClass("B", aClass); - RubyClass cClass = new RubyClass("C", bClass); - - RubyObject aInstance = new RubyObject(aClass); - RubyObject bInstance = new RubyObject(bClass); - RubyObject cInstance = new RubyObject(cClass); - - // undefined method call - assertEquals(RubyObject.NIL, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument})); - - // method defined in a - aClass.addMethod(testMethodName, aClassTestMethod); - assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); - assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{firstArgument})); - assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument})); - - // method redefined in b - bClass.addMethod(testMethodName, bClassTestMethod); - assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); - assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument})); - assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, firstArgument})); - - // method redefined in c - cClass.addMethod(testMethodName, cClassTestMethod); - assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); - assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument})); - assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, null, firstArgument})); - - } - - public static class RubyHeadNode extends ExampleNode { - - @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(null); - @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(null); - - @Specialization - public Object doCall(VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) { - InternalMethod method = lookup.executeLookup(frame, receiverObject, methodName); - - Object[] packedArguments = new Object[argumentsObjects.length + 3]; - packedArguments[0] = method; - packedArguments[1] = receiverObject; - packedArguments[2] = blockObject; - System.arraycopy(argumentsObjects, 0, packedArguments, 3, argumentsObjects.length); - - return dispatch.executeDispatch(frame, method, packedArguments); - } - } - - public abstract static class RubyLookupNode extends ExampleNode { - - public abstract InternalMethod executeLookup(VirtualFrame frame, Object receiverObject, Object methodName); - - @Specialization(guards = "receiver.getRubyClass() == cachedClass", assumptions = "cachedClass.getDependentAssumptions()") - protected static InternalMethod cachedLookup(RubyObject receiver, Object name, // - @Cached("receiver.getRubyClass()") RubyClass cachedClass, // - @Cached("genericLookup(receiver, name)") InternalMethod cachedLookup) { - return cachedLookup; - } - - @Specialization(contains = "cachedLookup") - protected static InternalMethod genericLookup(RubyObject receiver, Object name) { - return receiver.getRubyClass().lookup(name); - } - - } - - @ImportStatic(InternalMethod.class) - public abstract static class RubyDispatchNode extends ExampleNode { - - public abstract Object executeDispatch(VirtualFrame frame, InternalMethod function, Object[] packedArguments); - - /* - * Please note that cachedMethod != METHOD_MISSING is invoked once at specialization - * instantiation. It is never executed on the fast path. - */ - @Specialization(guards = {"method == cachedMethod", "cachedMethod != METHOD_MISSING"}) - protected static Object directCall(VirtualFrame frame, InternalMethod method, Object[] arguments, // - @Cached("method") InternalMethod cachedMethod, // - @Cached("create(cachedMethod.getTarget())") DirectCallNode callNode) { - return callNode.call(frame, arguments); - } - - /* - * The method == METHOD_MISSING can fold if the RubyLookup results just in a single entry - * returning the constant METHOD_MISSING. - */ - @Specialization(guards = "method == METHOD_MISSING") - protected static Object methodMissing(VirtualFrame frame, InternalMethod method, Object[] arguments) { - // a real implementation would do a call to a method named method_missing here - return RubyObject.NIL; - } - - @Specialization(contains = "directCall", guards = "method != METHOD_MISSING") - protected static Object indirectCall(VirtualFrame frame, InternalMethod method, Object[] arguments, // - @Cached("create()") IndirectCallNode callNode) { - return callNode.call(frame, method.getTarget(), arguments); - } - - @Override - public String toString() { - return ((SpecializedNode) this).getSpecializationNode().toString(); - } - } - - public static final class RubyObject { - - public static final RubyObject NIL = new RubyObject(null); - - private final RubyClass rubyClass; - - public RubyObject(RubyClass rubyClass) { - this.rubyClass = rubyClass; - } - - public RubyClass getRubyClass() { - return rubyClass; - } - - @Override - public String toString() { - return "RubyObject[class=" + rubyClass + "]"; - } - - } - - public static final class RubyClass /* this would extend RubyModule */{ - - private final String name; - private final RubyClass parent; // this would be a RubyModule - private final CyclicAssumption unmodified; - private final Map methods = new HashMap<>(); - private Assumption[] cachedDependentAssumptions; - private final int depth; - - public RubyClass(String name, RubyClass parent) { - this.name = name; - this.parent = parent; - this.unmodified = new CyclicAssumption("unmodified class " + name); - - // lookup depth for array allocation - RubyClass clazz = parent; - int currentDepth = 1; - while (clazz != null) { - currentDepth++; - clazz = clazz.parent; - } - this.depth = currentDepth; - } - - @TruffleBoundary - public InternalMethod lookup(Object methodName) { - InternalMethod method = methods.get(methodName); - if (method == null) { - if (parent != null) { - return parent.lookup(methodName); - } else { - return InternalMethod.METHOD_MISSING; - } - } else { - return method; - } - } - - @TruffleBoundary - public void addMethod(Object methodName, InternalMethod method) { - // check for existing method omitted for simplicity - this.methods.put(methodName, method); - this.unmodified.invalidate(); - } - - /* - * Method collects all unmodified assumptions in the class hierarchy. The result is cached - * per class to void recreation per call site. - */ - @TruffleBoundary - public Assumption[] getDependentAssumptions() { - Assumption[] dependentAssumptions = cachedDependentAssumptions; - if (dependentAssumptions != null) { - // we can use the cached dependent assumptions only if they are still valid - for (Assumption assumption : cachedDependentAssumptions) { - if (!assumption.isValid()) { - dependentAssumptions = null; - break; - } - } - } - if (dependentAssumptions == null) { - cachedDependentAssumptions = dependentAssumptions = createDependentAssumptions(); - } - return dependentAssumptions; - } - - @Override - public String toString() { - return "RubyClass[name=" + name + "]"; - } - - private Assumption[] createDependentAssumptions() { - Assumption[] dependentAssumptions; - RubyClass clazz = this; - dependentAssumptions = new Assumption[depth]; - - // populate array - int index = 0; - do { - dependentAssumptions[index] = clazz.unmodified.getAssumption(); - index++; - clazz = clazz.parent; - } while (clazz != null); - return dependentAssumptions; - } - } - - public static final class InternalMethod { - - public static final InternalMethod METHOD_MISSING = new InternalMethod(null); - - private final CallTarget target; - - public InternalMethod(CallTarget target) { - this.target = target; - } - - public CallTarget getTarget() { - return target; - } - - @Override - public String toString() { - return "InternalMethod[target=" + getTarget() + "]"; - } - - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/StableDispatch.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/StableDispatch.java Wed Feb 11 18:33:49 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * 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.api.dsl.examples; - -import com.oracle.truffle.api.*; -import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.frame.*; -import com.oracle.truffle.api.nodes.*; -import com.oracle.truffle.api.utilities.*; - -/** - * This example is based on the SLDispatchNode of SimpleLanguage. It shows how to implement a simple - * inline cache with an assumption that needs to be checked. - * - * Note that if an assumption is invalidated the specialization instantiation is removed. - */ -@SuppressWarnings("unused") -@NodeChildren({@NodeChild("function"), @NodeChild("arguments")}) -public class StableDispatch { - - public static class StableDispatchNode extends ExampleNode { - - @Specialization(guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()") - protected static Object directDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, // - @Cached("function") SLFunction cachedFunction, // - @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) { - return callNode.call(frame, arguments); - } - - @Specialization(contains = "directDispatch") - protected static Object indirectDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, // - @Cached("create()") IndirectCallNode callNode) { - return callNode.call(frame, function.getCallTarget(), arguments); - } - } - - public static final class SLFunction { - - private CallTarget callTarget; - private final CyclicAssumption callTargetStable; - - protected SLFunction(String name) { - this.callTargetStable = new CyclicAssumption(name); - } - - protected void setCallTarget(CallTarget callTarget) { - this.callTarget = callTarget; - this.callTargetStable.invalidate(); - } - - public CallTarget getCallTarget() { - return callTarget; - } - - public Assumption getCallTargetStable() { - return callTargetStable.getAssumption(); - } - } - -} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleNode.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/examples/ExampleNode.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,123 @@ +/* + * 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.api.dsl.test.examples; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +@TypeSystemReference(ExampleTypes.class) +@NodeChild(value = "args", type = ExampleNode[].class) +public abstract class ExampleNode extends Node { + + public Object execute(@SuppressWarnings("unused") VirtualFrame frame) { + // will get implemented by the DSL. + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + if (this instanceof SpecializedNode) { + return ((SpecializedNode) this).getSpecializationNode().toString(); + } else { + return super.toString(); + } + } + + public static CallTarget createTarget(ExampleNode node) { + return Truffle.getRuntime().createCallTarget(new ExampleRootNode(node)); + } + + @SuppressWarnings("unchecked") + public static T getNode(CallTarget target) { + return (T) ((ExampleRootNode) ((RootCallTarget) target).getRootNode()).child; + } + + public static ExampleNode[] createArguments(int count) { + ExampleNode[] nodes = new ExampleNode[count]; + for (int i = 0; i < count; i++) { + nodes[i] = new ExampleArgumentNode(i); + } + return nodes; + } + + private static class ExampleRootNode extends RootNode { + + @Child ExampleNode child; + + public ExampleRootNode(ExampleNode child) { + this.child = child; + } + + @Override + public Object execute(VirtualFrame frame) { + return child.execute(frame); + } + + } + + private static class ExampleArgumentNode extends ExampleNode { + + private final int index; + + public ExampleArgumentNode(int index) { + this.index = index; + } + + @Override + public Object execute(VirtualFrame frame) { + Object[] arguments = frame.getArguments(); + if (index < arguments.length) { + return arguments[index]; + } + return null; + } + } + + public static CallTarget createDummyTarget(int argumentIndex) { + return Truffle.getRuntime().createCallTarget(new DummyCallRootNode(argumentIndex)); + } + + private static class DummyCallRootNode extends RootNode { + + private final int argumentIndex; + + public DummyCallRootNode(int argumentIndex) { + this.argumentIndex = argumentIndex; + } + + @Override + public Object execute(VirtualFrame frame) { + return frame.getArguments()[argumentIndex]; + } + + @Override + public String toString() { + return "DummyRootNode[arg = " + argumentIndex + "]"; + } + + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleTypes.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/examples/ExampleTypes.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,40 @@ +/* + * 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.api.dsl.test.examples; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.examples.FunctionCall.Function; +import com.oracle.truffle.api.dsl.test.examples.Interop.TruffleObject; +import com.oracle.truffle.api.dsl.test.examples.RubyCall.InternalMethod; +import com.oracle.truffle.api.dsl.test.examples.RubyCall.RubyObject; +import com.oracle.truffle.api.dsl.test.examples.StableDispatch.SLFunction; + +@TypeSystem({int.class, double.class, boolean.class, TruffleObject.class, SLFunction.class, RubyObject.class, Function.class, InternalMethod.class, int[].class, double[].class, Object[].class}) +public class ExampleTypes { + + @ImplicitCast + public static double castInt(int intValue) { + return intValue; + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/FunctionCall.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/examples/FunctionCall.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,150 @@ +/* + * 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.api.dsl.test.examples; + +import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.examples.FunctionCallFactory.FunctionCallNodeGen; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * This example illustrates how {@link Cached} can be used to implement function calls that use + * local state for its guards. If there are always distinct Function objects with distinct + * CallTargets then we can use the directCallFunctionGuard specialization. If there are two Function + * instances cached with the same CallTarget then we use the directCall cache. We do this because + * the directCallFunctionGuard specialization can use a faster guard. + */ +@SuppressWarnings("unused") +public class FunctionCall { + + @Test + public void testFunctionCall() { + assertEquals(2, FunctionCallNode.CACHE_SIZE); + + CallTarget dummyTarget1 = createDummyTarget(0); + CallTarget dummyTarget2 = createDummyTarget(0); + CallTarget dummyTarget3 = createDummyTarget(0); + + Function dummyFunction1 = new Function(dummyTarget1); + Function dummyFunction2 = new Function(dummyTarget2); + Function dummyFunction3 = new Function(dummyTarget2); // same target as dummyFunction2 + Function dummyFunction4 = new Function(dummyTarget3); + + FunctionCallNode node = FunctionCallNodeGen.create(createArguments(2)); + CallTarget target = createTarget(node); + assertEquals(42, target.call(dummyFunction1, 42)); + assertEquals(43, target.call(dummyFunction2, 43)); + assertEquals(44, target.call(dummyFunction3, 44)); // transition to directCall + assertEquals(2, node.directCallFunctionGuard); + assertEquals(1, node.directCall); + + assertEquals(42, target.call(dummyFunction1, 42)); + assertEquals(43, target.call(dummyFunction2, 43)); + assertEquals(2, node.directCallFunctionGuard); + assertEquals(3, node.directCall); + + assertEquals(44, target.call(dummyFunction4, 44)); // transition to indirectCall + assertEquals(2, node.directCallFunctionGuard); + assertEquals(3, node.directCall); + assertEquals(1, node.indirectCall); + + assertEquals(42, target.call(dummyFunction1, 42)); + assertEquals(43, target.call(dummyFunction2, 43)); + assertEquals(44, target.call(dummyFunction3, 44)); + assertEquals(2, node.directCallFunctionGuard); + assertEquals(3, node.directCall); + assertEquals(4, node.indirectCall); + } + + public static class FunctionCallNode extends ExampleNode { + + public static final int CACHE_SIZE = 2; + + private CallTarget[] cachedTargets = new CallTarget[CACHE_SIZE]; + + private int directCallFunctionGuard; + private int directCall; + private int indirectCall; + + @Specialization(limit = "CACHE_SIZE", guards = {"function == cachedFunction", "!cacheFunctionTarget(cachedFunction)"}) + public Object directCallFunctionGuard(VirtualFrame frame, Function function, Object argument, // + @Cached("function") Function cachedFunction, // + @Cached("create(cachedFunction.getTarget())") DirectCallNode callNode) { + directCallFunctionGuard++; + return callNode.call(frame, new Object[]{argument}); + } + + protected final boolean cacheFunctionTarget(Function function) { + CompilerAsserts.neverPartOfCompilation(); + if (cachedTargets != null) { + CallTarget target = function.getTarget(); + for (int i = 0; i < cachedTargets.length; i++) { + CallTarget cachedTarget = cachedTargets[i]; + if (cachedTarget == target) { + cachedTargets = null; + return true; + } else if (cachedTarget == null) { + cachedTargets[i] = target; + return false; + } + } + } + return false; + } + + @Specialization(limit = "CACHE_SIZE", contains = "directCallFunctionGuard", guards = {"function.getTarget() == cachedTarget"}) + protected Object directCall(VirtualFrame frame, Function function, Object argument, // + @Cached("function.getTarget()") CallTarget cachedTarget, // + @Cached("create(cachedTarget)") DirectCallNode callNode) { + directCall++; + return callNode.call(frame, new Object[]{argument}); + } + + @Specialization(contains = "directCall") + protected Object indirectCall(VirtualFrame frame, Function function, Object argument, // + @Cached("create()") IndirectCallNode callNode) { + indirectCall++; + return callNode.call(frame, function.getTarget(), new Object[]{argument}); + } + } + + public static class Function { + + private final CallTarget target; + + public Function(CallTarget target) { + this.target = target; + } + + public CallTarget getTarget() { + return target; + } + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/Interop.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/examples/Interop.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,109 @@ +/* + * 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.api.dsl.test.examples; + +import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.examples.InteropFactory.UseInteropNodeGen; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * This example aims to illustrate how the {@link Cached} annotation can be used to implement a + * cache for a simplified language interoperability pattern. + */ +public class Interop { + + @Test + public void testInterop() { + UseInterop node = UseInteropNodeGen.create(createArguments(2)); + CallTarget target = createTarget(node); + TruffleObject o1 = new TruffleObject(); + TruffleObject o2 = new TruffleObject(); + TruffleObject o3 = new TruffleObject(); + TruffleObject o4 = new TruffleObject(); + assertEquals(42, target.call(o1, 42)); + assertEquals(43, target.call(o2, 43)); + assertEquals(44, target.call(o3, 44)); + assertEquals(3, node.cached); + assertEquals(0, node.generic); + assertEquals(45, target.call(o4, 45)); // operation gets generic + assertEquals(42, target.call(o1, 42)); + assertEquals(43, target.call(o2, 43)); + assertEquals(44, target.call(o3, 44)); + assertEquals(3, node.cached); + assertEquals(4, node.generic); + } + + public static class UseInterop extends ExampleNode { + + int cached = 0; + int generic = 0; + + @Specialization(guards = "operation.accept(target)") + protected Object interopCached(VirtualFrame frame, TruffleObject target, Object value, // + @Cached("target.createOperation()") TruffleObjectOperation operation) { + cached++; + return operation.execute(frame, target, value); + } + + @Specialization(contains = "interopCached") + protected Object interopGeneric(VirtualFrame frame, TruffleObject target, Object value) { + generic++; + return target.createOperation().execute(frame, target, value); + } + } + + public abstract static class TruffleObjectOperation extends Node { + + public abstract boolean accept(TruffleObject object); + + public abstract Object execute(VirtualFrame frame, Object target, Object value); + + } + + public static class TruffleObject { + + @TruffleBoundary + public TruffleObjectOperation createOperation() { + return new TruffleObjectOperation() { + @Override + public Object execute(VirtualFrame frame, Object target, Object value) { + return value; + } + + @Override + public boolean accept(TruffleObject object) { + return TruffleObject.this == object; + } + }; + } + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.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/examples/MathPow.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,144 @@ +/* + * 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.api.dsl.test.examples; + +import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*; +import static org.junit.Assert.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.examples.MathPowFactory.MathPowNodeGen; +import com.oracle.truffle.api.nodes.*; + +/** + * This example shows possible specializations for a simplified math pow node. It demonstrates how + * multiple caches can coexist within in the same node. This example does not show the best possible + * specializations for math.pow. + * + * Note: int values are implicitly casted to double values. + */ +@SuppressWarnings("unused") +public class MathPow extends Node { + + @Test + public void testPow() { + MathPowNode node = MathPowNodeGen.create(createArguments(2)); + CallTarget target = createTarget(node); + + // start with doPowCached + assertEquals(1D, target.call(1D, 1)); + assertEquals(2D, target.call(2D, 1)); + assertEquals(3D, target.call(3D, 1)); + assertEquals(3, node.doPowCached); + assertEquals(0, node.doPowCachedExponent); + + // transition to doPowCachedExponent + assertEquals(4D, target.call(4D, 1)); + assertEquals(5D, target.call(5D, 1)); + assertEquals(6D, target.call(6D, 1)); + assertEquals(16D, target.call(4D, 2)); + assertEquals(125D, target.call(5D, 3)); + assertEquals(5, node.doPowCachedExponent); + assertEquals(0, node.doPowDoubleInt); + + // transition to doPowDoubleInt + assertEquals(4D * 4D * 4D * 4D, target.call(4D, 4)); + assertEquals(5D * 5D * 5D * 5D * 5D, target.call(5D, 5)); + assertEquals(5, node.doPowCachedExponent); + assertEquals(2, node.doPowDoubleInt); + + // transition to doPow + assertEquals(5D, target.call(5D, 1D)); + assertEquals(2D, target.call(2D, 1D)); + + assertEquals(3, node.doPowCached); + assertEquals(5, node.doPowCachedExponent); + assertEquals(2, node.doPowDoubleInt); + assertEquals(2, node.doPow); + } + + public static class MathPowNode extends ExampleNode { + + // test flags + int doPowCached; + int doPowCachedExponent; + int doPowDoubleInt; + int doPow; + + @Specialization(guards = {"base == cachedBase", "exponent == cachedExponent"}) + double doPowCached(double base, int exponent, // + @Cached("base") double cachedBase, // + @Cached("exponent") int cachedExponent, // + @Cached("cachePow(cachedBase, cachedExponent)") double cachedResult) { + doPowCached++; + return cachedResult; + } + + /* + * We could just use the doPow specialization instead. But this makes the number of doPow + * calls more difficult to assert. + */ + protected static double cachePow(double base, int exponent) { + return Math.pow(base, exponent); + } + + @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"}) + @ExplodeLoop + double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) { + doPowCachedExponent++; + double result = 1.0; + for (int i = 0; i < cachedExponent; i++) { + result *= base; + } + return result; + } + + @Specialization(contains = "doPowCachedExponent", guards = "exponent >= 0") + double doPowDoubleInt(double base, int exponent) { + doPowDoubleInt++; + // Uses binary decomposition to limit the number of + // multiplications; see the discussion in "Hacker's Delight" by Henry + // S. Warren, Jr., figure 11-6, page 213. + double b = base; + int e = exponent; + double result = 1; + while (e > 0) { + if ((e & 1) == 1) { + result *= b; + } + e >>= 1; + b *= b; + } + return result; + } + + @Specialization(contains = {"doPowCached", "doPowDoubleInt"}) + double doPow(double base, double exponent) { + doPow++; + return Math.pow(base, exponent); + } + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.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/examples/RubyCall.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,302 @@ +/* + * 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.api.dsl.test.examples; + +import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*; +import static org.junit.Assert.*; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyDispatchNodeGen; +import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyHeadNodeGen; +import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyLookupNodeGen; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; + +/** + * This example illustrates a simplified version of a Ruby function call semantics (RubyHeadNode). + * The example usage shows how methods can be redefined in this implementation. + */ +@SuppressWarnings("unused") +public class RubyCall { + + @Test + public void testCall() { + RubyHeadNode node = RubyHeadNodeGen.create(createArguments(4)); + CallTarget nodeTarget = createTarget(node); + final Object firstArgument = "someArgument"; + + // dummyMethod is just going to return the some argument of the function + final Object testMethodName = "getSomeArgument"; + // implementation returns first argument + InternalMethod aClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(3)); + // implementation returns second argument + InternalMethod bClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(4)); + // implementation returns third argument + InternalMethod cClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(5)); + + // defines hierarchy C extends B extends A + RubyClass aClass = new RubyClass("A", null); + RubyClass bClass = new RubyClass("B", aClass); + RubyClass cClass = new RubyClass("C", bClass); + + RubyObject aInstance = new RubyObject(aClass); + RubyObject bInstance = new RubyObject(bClass); + RubyObject cInstance = new RubyObject(cClass); + + // undefined method call + assertEquals(RubyObject.NIL, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument})); + + // method defined in a + aClass.addMethod(testMethodName, aClassTestMethod); + assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); + assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{firstArgument})); + assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument})); + + // method redefined in b + bClass.addMethod(testMethodName, bClassTestMethod); + assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); + assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument})); + assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, firstArgument})); + + // method redefined in c + cClass.addMethod(testMethodName, cClassTestMethod); + assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument})); + assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument})); + assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, null, firstArgument})); + + } + + public static class RubyHeadNode extends ExampleNode { + + @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(null); + @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(null); + + @Specialization + public Object doCall(VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) { + InternalMethod method = lookup.executeLookup(frame, receiverObject, methodName); + + Object[] packedArguments = new Object[argumentsObjects.length + 3]; + packedArguments[0] = method; + packedArguments[1] = receiverObject; + packedArguments[2] = blockObject; + System.arraycopy(argumentsObjects, 0, packedArguments, 3, argumentsObjects.length); + + return dispatch.executeDispatch(frame, method, packedArguments); + } + } + + public abstract static class RubyLookupNode extends ExampleNode { + + public abstract InternalMethod executeLookup(VirtualFrame frame, Object receiverObject, Object methodName); + + @Specialization(guards = "receiver.getRubyClass() == cachedClass", assumptions = "cachedClass.getDependentAssumptions()") + protected static InternalMethod cachedLookup(RubyObject receiver, Object name, // + @Cached("receiver.getRubyClass()") RubyClass cachedClass, // + @Cached("genericLookup(receiver, name)") InternalMethod cachedLookup) { + return cachedLookup; + } + + @Specialization(contains = "cachedLookup") + protected static InternalMethod genericLookup(RubyObject receiver, Object name) { + return receiver.getRubyClass().lookup(name); + } + + } + + @ImportStatic(InternalMethod.class) + public abstract static class RubyDispatchNode extends ExampleNode { + + public abstract Object executeDispatch(VirtualFrame frame, InternalMethod function, Object[] packedArguments); + + /* + * Please note that cachedMethod != METHOD_MISSING is invoked once at specialization + * instantiation. It is never executed on the fast path. + */ + @Specialization(guards = {"method == cachedMethod", "cachedMethod != METHOD_MISSING"}) + protected static Object directCall(VirtualFrame frame, InternalMethod method, Object[] arguments, // + @Cached("method") InternalMethod cachedMethod, // + @Cached("create(cachedMethod.getTarget())") DirectCallNode callNode) { + return callNode.call(frame, arguments); + } + + /* + * The method == METHOD_MISSING can fold if the RubyLookup results just in a single entry + * returning the constant METHOD_MISSING. + */ + @Specialization(guards = "method == METHOD_MISSING") + protected static Object methodMissing(VirtualFrame frame, InternalMethod method, Object[] arguments) { + // a real implementation would do a call to a method named method_missing here + return RubyObject.NIL; + } + + @Specialization(contains = "directCall", guards = "method != METHOD_MISSING") + protected static Object indirectCall(VirtualFrame frame, InternalMethod method, Object[] arguments, // + @Cached("create()") IndirectCallNode callNode) { + return callNode.call(frame, method.getTarget(), arguments); + } + + @Override + public String toString() { + return ((SpecializedNode) this).getSpecializationNode().toString(); + } + } + + public static final class RubyObject { + + public static final RubyObject NIL = new RubyObject(null); + + private final RubyClass rubyClass; + + public RubyObject(RubyClass rubyClass) { + this.rubyClass = rubyClass; + } + + public RubyClass getRubyClass() { + return rubyClass; + } + + @Override + public String toString() { + return "RubyObject[class=" + rubyClass + "]"; + } + + } + + public static final class RubyClass /* this would extend RubyModule */{ + + private final String name; + private final RubyClass parent; // this would be a RubyModule + private final CyclicAssumption unmodified; + private final Map methods = new HashMap<>(); + private Assumption[] cachedDependentAssumptions; + private final int depth; + + public RubyClass(String name, RubyClass parent) { + this.name = name; + this.parent = parent; + this.unmodified = new CyclicAssumption("unmodified class " + name); + + // lookup depth for array allocation + RubyClass clazz = parent; + int currentDepth = 1; + while (clazz != null) { + currentDepth++; + clazz = clazz.parent; + } + this.depth = currentDepth; + } + + @TruffleBoundary + public InternalMethod lookup(Object methodName) { + InternalMethod method = methods.get(methodName); + if (method == null) { + if (parent != null) { + return parent.lookup(methodName); + } else { + return InternalMethod.METHOD_MISSING; + } + } else { + return method; + } + } + + @TruffleBoundary + public void addMethod(Object methodName, InternalMethod method) { + // check for existing method omitted for simplicity + this.methods.put(methodName, method); + this.unmodified.invalidate(); + } + + /* + * Method collects all unmodified assumptions in the class hierarchy. The result is cached + * per class to void recreation per call site. + */ + @TruffleBoundary + public Assumption[] getDependentAssumptions() { + Assumption[] dependentAssumptions = cachedDependentAssumptions; + if (dependentAssumptions != null) { + // we can use the cached dependent assumptions only if they are still valid + for (Assumption assumption : cachedDependentAssumptions) { + if (!assumption.isValid()) { + dependentAssumptions = null; + break; + } + } + } + if (dependentAssumptions == null) { + cachedDependentAssumptions = dependentAssumptions = createDependentAssumptions(); + } + return dependentAssumptions; + } + + @Override + public String toString() { + return "RubyClass[name=" + name + "]"; + } + + private Assumption[] createDependentAssumptions() { + Assumption[] dependentAssumptions; + RubyClass clazz = this; + dependentAssumptions = new Assumption[depth]; + + // populate array + int index = 0; + do { + dependentAssumptions[index] = clazz.unmodified.getAssumption(); + index++; + clazz = clazz.parent; + } while (clazz != null); + return dependentAssumptions; + } + } + + public static final class InternalMethod { + + public static final InternalMethod METHOD_MISSING = new InternalMethod(null); + + private final CallTarget target; + + public InternalMethod(CallTarget target) { + this.target = target; + } + + public CallTarget getTarget() { + return target; + } + + @Override + public String toString() { + return "InternalMethod[target=" + getTarget() + "]"; + } + + } + +} diff -r 67ab244ab689 -r a79a3e467245 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/StableDispatch.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/examples/StableDispatch.java Wed Feb 11 19:01:35 2015 +0100 @@ -0,0 +1,80 @@ +/* + * 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.api.dsl.test.examples; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.utilities.*; + +/** + * This example is based on the SLDispatchNode of SimpleLanguage. It shows how to implement a simple + * inline cache with an assumption that needs to be checked. + * + * Note that if an assumption is invalidated the specialization instantiation is removed. + */ +@SuppressWarnings("unused") +@NodeChildren({@NodeChild("function"), @NodeChild("arguments")}) +public class StableDispatch { + + public static class StableDispatchNode extends ExampleNode { + + @Specialization(guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()") + protected static Object directDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, // + @Cached("function") SLFunction cachedFunction, // + @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) { + return callNode.call(frame, arguments); + } + + @Specialization(contains = "directDispatch") + protected static Object indirectDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, // + @Cached("create()") IndirectCallNode callNode) { + return callNode.call(frame, function.getCallTarget(), arguments); + } + } + + public static final class SLFunction { + + private CallTarget callTarget; + private final CyclicAssumption callTargetStable; + + protected SLFunction(String name) { + this.callTargetStable = new CyclicAssumption(name); + } + + protected void setCallTarget(CallTarget callTarget) { + this.callTarget = callTarget; + this.callTargetStable.invalidate(); + } + + public CallTarget getCallTarget() { + return callTarget; + } + + public Assumption getCallTargetStable() { + return callTargetStable.getAssumption(); + } + } + +}