changeset 19301:a79a3e467245

Truffle-DSL: move examples package into test package for the project canonicalizer.
author Christian Humer <christian.humer@gmail.com>
date Wed, 11 Feb 2015 19:01:35 +0100
parents 67ab244ab689
children 45a24e9ba03b
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleNode.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/ExampleTypes.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/FunctionCall.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/Interop.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/MathPow.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/RubyCall.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/examples/StableDispatch.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleNode.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/ExampleTypes.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/FunctionCall.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/Interop.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/MathPow.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/StableDispatch.java
diffstat 14 files changed, 948 insertions(+), 948 deletions(-) [+]
line wrap: on
line diff
--- 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> 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 + "]";
-        }
-
-    }
-
-}
--- 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;
-    }
-
-}
--- 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;
-        }
-    }
-
-}
--- 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;
-                }
-            };
-        }
-    }
-
-}
--- 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);
-        }
-    }
-
-}
--- 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<Object, InternalMethod> 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() + "]";
-        }
-
-    }
-
-}
--- 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();
-        }
-    }
-
-}
--- /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> 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 + "]";
+        }
+
+    }
+
+}
--- /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;
+    }
+
+}
--- /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;
+        }
+    }
+
+}
--- /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;
+                }
+            };
+        }
+    }
+
+}
--- /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);
+        }
+    }
+
+}
--- /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<Object, InternalMethod> 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() + "]";
+        }
+
+    }
+
+}
--- /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();
+        }
+    }
+
+}