# HG changeset patch # User Christian Haeubl # Date 1355907668 -3600 # Node ID 64f4195d0ecfad62fb34b775950c40888c322d8b # Parent 707e9cca11de7ba144e7987836999c1aa5cd425e# Parent 3463363253372daaabdb34433872870b218d65f1 Merge. diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java --- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DeoptimizationAction.java Wed Dec 19 10:01:08 2012 +0100 @@ -28,6 +28,9 @@ public enum DeoptimizationAction { /** * Do not invalidate the machine code. + * This is typically used when deoptimizing at a point where it's highly likely + * nothing will change the likelihood of the deoptimization happening again. + * For example, a compiled array allocation where the size is negative. */ None, @@ -43,6 +46,9 @@ /** * Invalidate the machine code and immediately schedule a recompilation. + * This is typically used when deoptimizing to resolve an unresolved symbol in + * which case extra profiling is not required to determine that the deoptimization + * will not re-occur. */ InvalidateRecompile, diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -26,7 +26,7 @@ import java.util.*; import java.util.concurrent.*; -import junit.framework.*; +import org.junit.*; import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; @@ -162,8 +162,37 @@ private static int compilationId = 0; + /** + * Compares two given objects for {@linkplain Assert#assertEquals(Object, Object) equality}. + * Does a deep copy equality comparison if {@code expected} is an array. + */ protected void assertEquals(Object expected, Object actual) { - Assert.assertEquals(expected, actual); + if (expected != null && expected.getClass().isArray()) { + Assert.assertTrue(expected != null); + Assert.assertTrue(actual != null); + Assert.assertEquals(expected.getClass(), actual.getClass()); + if (expected instanceof int[]) { + Assert.assertArrayEquals((int[]) expected, (int[]) actual); + } else if (expected instanceof byte[]) { + Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); + } else if (expected instanceof char[]) { + Assert.assertArrayEquals((char[]) expected, (char[]) actual); + } else if (expected instanceof short[]) { + Assert.assertArrayEquals((short[]) expected, (short[]) actual); + } else if (expected instanceof float[]) { + Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); + } else if (expected instanceof long[]) { + Assert.assertArrayEquals((long[]) expected, (long[]) actual); + } else if (expected instanceof double[]) { + Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); + } else if (expected instanceof Object[]) { + Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); + } else { + Assert.fail("non-array value encountered: " + expected); + } + } else { + Assert.assertEquals(expected, actual); + } } protected void testN(int n, final String name, final Object... args) { diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Dec 19 10:01:08 2012 +0100 @@ -369,7 +369,7 @@ NodeList list = getNodeList(node, offsets[index]); return list.get(subIndex); } - return null; + throw new NoSuchElementException(); } @Override diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsagesList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsagesList.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUsagesList.java Wed Dec 19 10:01:08 2012 +0100 @@ -146,16 +146,6 @@ } } - boolean replaceFirst(Node node, Node other) { - for (int i = 0; i < size; i++) { - if (nodes[i] == node) { - nodes[i] = other; - return true; - } - } - return false; - } - @Override public String toString() { StringBuilder str = new StringBuilder(); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java Wed Dec 19 10:01:08 2012 +0100 @@ -53,7 +53,7 @@ } @Override public FilteredNodeIterable nonNull() { - this.predicate = this.predicate.or(NodePredicates.isNotNull()); + this.predicate = this.predicate.and(NodePredicates.isNotNull()); return this; } @Override diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/ArrayCopyIntrinsificationTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.hotspot; + +import static org.junit.Assert.*; + +import java.lang.reflect.*; +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.hotspot.snippets.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.PhasePlan.PhasePosition; + + +/** + * Tests intrinsification of {@link System#arraycopy(Object, int, Object, int, int)}. + */ +public class ArrayCopyIntrinsificationTest extends GraalCompilerTest { + + @Override + protected void editPhasePlan(ResolvedJavaMethod method, StructuredGraph graph, PhasePlan phasePlan) { + phasePlan.addPhase(PhasePosition.HIGH_LEVEL, new IntrinsifyArrayCopyPhase(runtime, new Assumptions(false))); + } + + @Override + protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) { + int nodeCount = graph.getNodeCount(); + InstalledCode result = super.getCode(method, graph); + boolean graphWasProcessed = nodeCount != graph.getNodeCount(); + if (graphWasProcessed) { + if (mustIntrinsify) { + for (Node node: graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + Assert.assertTrue(invoke.callTarget() instanceof DirectCallTargetNode); + DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget(); + Assert.assertTrue(directCall.target() instanceof JavaMethod); + JavaMethod callee = (JavaMethod) directCall.target(); + Assert.assertTrue(callee.getName().equals("")); + Assert.assertTrue(runtime.lookupJavaType(ArrayIndexOutOfBoundsException.class).equals(callee.getDeclaringClass()) || + runtime.lookupJavaType(NullPointerException.class).equals(callee.getDeclaringClass())); + } + } + } else { + boolean found = false; + for (Node node: graph.getNodes()) { + if (node instanceof Invoke) { + Invoke invoke = (Invoke) node; + DirectCallTargetNode directCall = (DirectCallTargetNode) invoke.callTarget(); + JavaMethod callee = (JavaMethod) directCall.target(); + if (callee.getDeclaringClass().equals(runtime.lookupJavaType(System.class)) && callee.getName().equals("arraycopy")) { + found = true; + } else { + fail("found invoke to some method other than arraycopy: " + callee); + } + } + } + Assert.assertTrue("did not find invoke to arraycopy", found); + } + } + return result; + } + + boolean mustIntrinsify = true; + + @Test + public void test0() { + mustIntrinsify = false; // a generic call to arraycopy will not be intrinsified + // Array store checks + test("genericArraycopy", new Object(), 0, new Object[0], 0, 0); + test("genericArraycopy", new Object[0], 0, new Object(), 0, 0); + } + + @Test + public void test1() { + String name = "intArraycopy"; + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + // Null checks + test(name, null, 0, src, 0, 0); + test(name, src, 0, null, 0, 0); + // Bounds checks + test(name, src, 0, src, 0, -1); + test(name, src, 0, src, 0, src.length + 1); + } + + @Test + public void testByte() { + byte[] src = {-1, 0, 1, 2, 3, 4}; + testHelper("byteArraycopy", src); + } + + @Test + public void testChar() { + char[] src = "some string of chars".toCharArray(); + testHelper("charArraycopy", src); + } + + @Test + public void testShort() { + short[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("shortArraycopy", src); + } + + @Test + public void testInt() { + int[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("intArraycopy", src); + } + + @Test + public void testFloat() { + float[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("floatArraycopy", src); + } + + @Test + public void testLong() { + long[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("longArraycopy", src); + } + + @Test + public void testDouble() { + double[] src = {234, 5345, 756, 23, 8, 345, 873, 440}; + testHelper("doubleArraycopy", src); + } + + @Test + public void testObject() { + Object[] src = {"one", "two", "three", new ArrayList<>(), new HashMap<>()}; + testHelper("objectArraycopy", src); + } + + private static Object newArray(Object proto, int length) { + assert proto != null; + assert proto.getClass().isArray(); + return Array.newInstance(proto.getClass().getComponentType(), length); + } + + private void testHelper(String name, Object src) { + int srcLength = Array.getLength(src); + + // Complete array copy + test(name, src, 0, newArray(src, srcLength), 0, srcLength); + + for (int length : new int[] {0, 1, srcLength - 1, srcLength}) { + // Partial array copying + test(name, src, 0, newArray(src, length), 0, length); + test(name, src, srcLength - length, newArray(src, length), 0, length); + test(name, src, 0, newArray(src, srcLength), 0, length); + } + } + + public static Object genericArraycopy(Object src, int srcPos, Object dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static Object[] objectArraycopy(Object[] src, int srcPos, Object[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static boolean[] booleanArraycopy(boolean[] src, int srcPos, boolean[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static byte[] byteArraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static char[] charArraycopy(char[] src, int srcPos, char[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static short[] shortArraycopy(short[] src, int srcPos, short[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static int[] intArraycopy(int[] src, int srcPos, int[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static float[] floatArraycopy(float[] src, int srcPos, float[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static long[] longArraycopy(long[] src, int srcPos, long[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + + public static double[] doubleArraycopy(double[] src, int srcPos, double[] dst, int dstPos, int length) { + System.arraycopy(src, srcPos, dst, dstPos, length); + return dst; + } + +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java Wed Dec 19 10:01:08 2012 +0100 @@ -676,6 +676,8 @@ checkcastSnippets.lower((CheckCastDynamicNode) n); } else if (n instanceof InstanceOfNode) { instanceofSnippets.lower((InstanceOfNode) n, tool); + } else if (n instanceof InstanceOfDynamicNode) { + instanceofSnippets.lower((InstanceOfDynamicNode) n, tool); } else if (n instanceof NewInstanceNode) { newObjectSnippets.lower((NewInstanceNode) n, tool); } else if (n instanceof NewArrayNode) { diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.hotspot.phases; +import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.code.RuntimeCallTarget.*; import com.oracle.graal.api.meta.*; @@ -89,7 +91,7 @@ } while (true); - LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(Kind.Long))); + LocalNode buffer = graph.unique(new LocalNode(0, StampFactory.forKind(wordKind()))); RuntimeCallNode migrationEnd = graph.add(new RuntimeCallNode(OSR_MIGRATION_END, buffer)); FrameState osrState = osr.stateAfter(); migrationEnd.setStateAfter(osrState); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -21,8 +21,11 @@ * questions. */ package com.oracle.graal.hotspot.snippets; +import static com.oracle.graal.api.code.DeoptimizationAction.*; +import static com.oracle.graal.api.meta.DeoptimizationReason.*; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.hotspot.*; import com.oracle.graal.hotspot.nodes.*; @@ -42,7 +45,6 @@ private static final Kind VECTOR_KIND = Kind.Long; private static final long VECTOR_SIZE = arrayIndexScale(Kind.Long); - @Snippet public static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter("baseKind") Kind baseKind) { checkInputs(src, srcPos, dest, destPos, length); int header = arrayBaseOffset(baseKind); @@ -71,13 +73,12 @@ } } - @Snippet public static void checkInputs(Object src, int srcPos, Object dest, int destPos, int length) { if (src == null || dest == null) { throw new NullPointerException(); } if (srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > ArrayLengthNode.arrayLength(src) || destPos + length > ArrayLengthNode.arrayLength(dest)) { - throw new IndexOutOfBoundsException(); + throw new ArrayIndexOutOfBoundsException(); } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -33,7 +33,6 @@ import com.oracle.graal.graph.Node.NodeIntrinsic; import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; @@ -99,7 +98,7 @@ return object; } Word objectHub = loadHub(object); - if (loadWordFromWord(objectHub, superCheckOffset) != hub) { + if (objectHub.readWord(superCheckOffset) != hub) { displayMiss.inc(); DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ClassCastException); } @@ -157,12 +156,12 @@ } static Word loadWordElement(Word metaspaceArray, int index) { - return loadWordFromWord(metaspaceArray, metaspaceArrayBaseOffset() + index * wordSize()); + return metaspaceArray.readWord(metaspaceArrayBaseOffset() + index * wordSize()); } static boolean checkSecondarySubType(Word t, Word s) { // if (S.cache == T) return true - if (loadWordFromWord(s, secondarySuperCacheOffset()) == t) { + if (s.readWord(secondarySuperCacheOffset()) == t) { cacheHit.inc(); return true; } @@ -174,8 +173,8 @@ } // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = loadWordFromWord(s, secondarySupersOffset()); - int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset()); + Word secondarySupers = s.readWord(secondarySupersOffset()); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset()); for (int i = 0; i < length; i++) { if (t == loadWordElement(secondarySupers, i)) { DirectObjectStoreNode.storeWord(s, secondarySuperCacheOffset(), 0, t); @@ -189,11 +188,11 @@ static boolean checkUnknownSubType(Word t, Word s) { // int off = T.offset - int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), Kind.Int); + int superCheckOffset = t.readInt(superCheckOffsetOffset()); boolean primary = superCheckOffset != secondarySuperCacheOffset(); // if (T = S[off]) return true - if (loadWordFromWord(s, superCheckOffset) == t) { + if (s.readWord(superCheckOffset) == t) { if (primary) { cacheHit.inc(); } else { @@ -215,8 +214,8 @@ } // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = loadWordFromWord(s, secondarySupersOffset()); - int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset()); + Word secondarySupers = s.readWord(secondarySupersOffset()); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset()); for (int i = 0; i < length; i++) { if (t == loadWordElement(secondarySupers, i)) { DirectObjectStoreNode.storeWord(s, secondarySuperCacheOffset(), 0, t); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ClassSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -23,9 +23,11 @@ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import java.lang.reflect.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.snippets.*; import com.oracle.graal.snippets.ClassSubstitution.MethodSubstitution; @@ -41,7 +43,7 @@ // Class for primitive type return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC; } else { - return loadIntFromWord(klass, klassModifierFlagsOffset()); + return klass.readInt(klassModifierFlagsOffset()); } } @@ -51,7 +53,7 @@ if (klass == Word.zero()) { return false; } else { - int accessFlags = loadIntFromWord(klass, klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset()); return (accessFlags & Modifier.INTERFACE) != 0; } } @@ -62,7 +64,7 @@ if (klass == Word.zero()) { return false; } else { - int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset()); + int layoutHelper = klass.readInt(klassLayoutHelperOffset()); return (layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0; } } @@ -77,17 +79,17 @@ public static Class getSuperclass(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass != Word.zero()) { - int accessFlags = loadIntFromWord(klass, klassAccessFlagsOffset()); + int accessFlags = klass.readInt(klassAccessFlagsOffset()); if ((accessFlags & Modifier.INTERFACE) == 0) { - int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset()); + int layoutHelper = klass.readInt(klassLayoutHelperOffset()); if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { return Object.class; } else { - Word superKlass = loadWordFromWord(klass, klassSuperKlassOffset()); + Word superKlass = klass.readWord(klassSuperKlassOffset()); if (superKlass == Word.zero()) { return null; } else { - return (Class) loadObjectFromWord(superKlass, classMirrorOffset()); + return unsafeCast(superKlass.readObject(classMirrorOffset()), Class.class, true, true); } } } @@ -99,11 +101,17 @@ public static Class getComponentType(final Class thisObj) { Word klass = loadWordFromObject(thisObj, klassOffset()); if (klass != Word.zero()) { - int layoutHelper = loadIntFromWord(klass, klassLayoutHelperOffset()); + int layoutHelper = klass.readInt(klassLayoutHelperOffset()); if ((layoutHelper & arrayKlassLayoutHelperIdentifier()) != 0) { - return (Class) loadObjectFromWord(klass, arrayKlassComponentMirrorOffset()); + return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset()), Class.class, true, true); } } return null; } + + @MethodSubstitution(isStatic = false) + public static boolean isInstance(final Class thisObj, Object obj) { + return MaterializeNode.isInstance(thisObj, obj); + } + } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/HotSpotSnippetUtils.java Wed Dec 19 10:01:08 2012 +0100 @@ -285,36 +285,16 @@ return HotSpotSnippetUtils.registerAsWord(threadRegister()); } - public static int loadIntFromWord(Word address, int offset) { - Integer value = UnsafeLoadNode.load(address, 0, offset, Kind.Int); - return value; - } - - public static Word loadWordFromWord(Word address, int offset) { - return loadWordFromWordIntrinsic(address, 0, offset, wordKind()); - } - - static Object loadObjectFromWord(Word address, int offset) { - return UnsafeLoadNode.load(address, 0, offset, Kind.Object); - } - public static Word loadWordFromObject(Object object, int offset) { return loadWordFromObjectIntrinsic(object, 0, offset, wordKind()); } - public static Object readFinalObject(Word base, @ConstantNodeParameter int displacement) { - return ReadNode.read(base, displacement, LocationNode.FINAL_LOCATION, Kind.Object); - } - @NodeIntrinsic(value = RegisterNode.class, setStampFromReturnType = true) public static native Word registerAsWord(@ConstantNodeParameter Register register); @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) private static native Word loadWordFromObjectIntrinsic(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); - @NodeIntrinsic(value = UnsafeLoadNode.class, setStampFromReturnType = true) - private static native Word loadWordFromWordIntrinsic(Word address, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind wordKind); - @NodeIntrinsic(value = LoadHubNode.class, setStampFromReturnType = true) static native Word loadHubIntrinsic(Object object, @ConstantNodeParameter Kind word); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/InstanceOfSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -93,7 +93,7 @@ return falseValue; } Word objectHub = loadHub(object); - if (loadWordFromWord(objectHub, superCheckOffset) != hub) { + if (objectHub.readWord(superCheckOffset) != hub) { displayMiss.inc(); return falseValue; } @@ -134,7 +134,7 @@ static boolean checkSecondarySubType(Word t, Word s) { // if (S.cache == T) return true - if (loadWordFromWord(s, secondarySuperCacheOffset()) == t) { + if (s.readWord(secondarySuperCacheOffset()) == t) { cacheHit.inc(); return true; } @@ -146,8 +146,8 @@ } // if (S.scan_s_s_array(T)) { S.cache = T; return true; } - Word secondarySupers = loadWordFromWord(s, secondarySupersOffset()); - int length = loadIntFromWord(secondarySupers, metaspaceArrayLengthOffset()); + Word secondarySupers = s.readWord(secondarySupersOffset()); + int length = secondarySupers.readInt(metaspaceArrayLengthOffset()); for (int i = 0; i < length; i++) { if (t == loadWordElement(secondarySupers, i)) { DirectObjectStoreNode.storeObject(s, secondarySuperCacheOffset(), 0, t); @@ -159,45 +159,83 @@ return false; } + /** + * Type test used when the type being tested against is not known at compile time. + */ + @Snippet + public static Object instanceofDynamic( + @Parameter("mirror") Class mirror, + @Parameter("object") Object object, + @Parameter("trueValue") Object trueValue, + @Parameter("falseValue") Object falseValue, + @ConstantParameter("checkNull") boolean checkNull) { + if (checkNull && object == null) { + isNull.inc(); + return falseValue; + } + + Word hub = loadWordFromObject(mirror, klassOffset()); + Word objectHub = loadHub(object); + if (!checkUnknownSubType(hub, objectHub)) { + return falseValue; + } + return trueValue; + } + public static class Templates extends InstanceOfSnippetsTemplates { private final ResolvedJavaMethod instanceofExact; private final ResolvedJavaMethod instanceofPrimary; private final ResolvedJavaMethod instanceofSecondary; + private final ResolvedJavaMethod instanceofDynamic; public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) { super(runtime, assumptions, target, InstanceOfSnippets.class); instanceofExact = snippet("instanceofExact", Object.class, Word.class, Object.class, Object.class, boolean.class); instanceofPrimary = snippet("instanceofPrimary", Word.class, Object.class, Object.class, Object.class, boolean.class, int.class); instanceofSecondary = snippet("instanceofSecondary", Word.class, Object.class, Object.class, Object.class, Word[].class, boolean.class); + instanceofDynamic = snippet("instanceofDynamic", Class.class, Object.class, Object.class, Object.class, boolean.class); } @Override protected KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool) { - InstanceOfNode instanceOf = replacer.instanceOf; - ValueNode trueValue = replacer.trueValue; - ValueNode falseValue = replacer.falseValue; - ValueNode object = instanceOf.object(); - TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); - final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type(); - ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph()); - boolean checkNull = !object.stamp().nonNull(); - Arguments arguments; - Key key; - if (hintInfo.exact) { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); - assert hints.length == 1; - key = new Key(instanceofExact).add("checkNull", checkNull); - arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); - } else if (type.isPrimaryType()) { - key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); - arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + if (replacer.instanceOf instanceof InstanceOfNode) { + InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf; + ValueNode trueValue = replacer.trueValue; + ValueNode falseValue = replacer.falseValue; + ValueNode object = instanceOf.object(); + TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints); + final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type(); + ConstantNode hub = ConstantNode.forConstant(type.klass(), runtime, instanceOf.graph()); + boolean checkNull = !object.stamp().nonNull(); + Arguments arguments; + Key key; + if (hintInfo.exact) { + ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + assert hints.length == 1; + key = new Key(instanceofExact).add("checkNull", checkNull); + arguments = arguments("object", object).add("exactHub", hints[0]).add("trueValue", trueValue).add("falseValue", falseValue); + } else if (type.isPrimaryType()) { + key = new Key(instanceofPrimary).add("checkNull", checkNull).add("superCheckOffset", type.superCheckOffset()); + arguments = arguments("hub", hub).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + } else { + ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); + key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); + arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + } + return new KeyAndArguments(key, arguments); } else { - ConstantNode[] hints = createHints(hintInfo, runtime, hub.graph()); - key = new Key(instanceofSecondary).add("hints", Varargs.vargargs(new Word[hints.length], StampFactory.forKind(wordKind()))).add("checkNull", checkNull); - arguments = arguments("hub", hub).add("object", object).add("hints", hints).add("trueValue", trueValue).add("falseValue", falseValue); + assert replacer.instanceOf instanceof InstanceOfDynamicNode; + InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf; + ValueNode trueValue = replacer.trueValue; + ValueNode falseValue = replacer.falseValue; + ValueNode object = instanceOf.object(); + ValueNode mirror = instanceOf.mirror(); + boolean checkNull = !object.stamp().nonNull(); + Key key = new Key(instanceofDynamic).add("checkNull", checkNull); + Arguments arguments = arguments("mirror", mirror).add("object", object).add("trueValue", trueValue).add("falseValue", falseValue); + return new KeyAndArguments(key, arguments); } - return new KeyAndArguments(key, arguments); } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/MonitorSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -40,7 +40,6 @@ import com.oracle.graal.hotspot.meta.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind; import com.oracle.graal.nodes.spi.*; @@ -107,7 +106,7 @@ // The bias pattern is present in the object's mark word. Need to check // whether the bias owner and the epoch are both still current. Word hub = loadHub(object); - final Word prototypeMarkWord = loadWordFromWord(hub, prototypeMarkWordOffset()); + final Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); final Word thread = thread(); final Word tmp = prototypeMarkWord.or(thread).xor(mark).and(~ageMaskInPlace()); trace(trace, "prototypeMarkWord: 0x%016lx\n", prototypeMarkWord.toLong()); @@ -293,7 +292,7 @@ final Word lock = CurrentLockNode.currentLock(); // Load displaced mark - final Word displacedMark = loadWordFromWord(lock, lockDisplacedMarkOffset()); + final Word displacedMark = lock.readWord(lockDisplacedMarkOffset()); trace(trace, " displacedMark: 0x%016lx\n", displacedMark.toLong()); if (displacedMark == Word.zero()) { @@ -360,7 +359,7 @@ private static void incCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int); + final int count = counter.readInt(0); DirectObjectStoreNode.storeInt(counter, 0, 0, count + 1); } } @@ -368,7 +367,7 @@ private static void decCounter() { if (CHECK_BALANCED_MONITORS) { final Word counter = MonitorCounterNode.counter(); - final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int); + final int count = counter.readInt(0); DirectObjectStoreNode.storeInt(counter, 0, 0, count - 1); } } @@ -382,7 +381,7 @@ @Snippet private static void checkCounter(String errMsg) { final Word counter = MonitorCounterNode.counter(); - final int count = UnsafeLoadNode.load(counter, 0, 0, Kind.Int); + final int count = counter.readInt(0); if (count != 0) { vmError(errMsg, count); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewObjectSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -59,8 +59,8 @@ @Snippet public static Word allocate(@Parameter("size") int size) { Word thread = thread(); - Word top = loadWordFromWord(thread, threadTlabTopOffset()); - Word end = loadWordFromWord(thread, threadTlabEndOffset()); + Word top = thread.readWord(threadTlabTopOffset()); + Word end = thread.readWord(threadTlabEndOffset()); Word newTop = top.plus(size); // this check might lead to problems if the TLAB is within 16GB of the address space end (checked in c++ code) if (newTop.belowOrEqual(end)) { @@ -187,7 +187,7 @@ * Formats some allocated memory with an object header zeroes out the rest. */ private static void formatObject(Word hub, int size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents) { - Word prototypeMarkWord = useBiasedLocking() ? loadWordFromWord(hub, prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; + Word prototypeMarkWord = useBiasedLocking() ? hub.readWord(prototypeMarkWordOffset()) : compileTimePrototypeMarkWord; storeWord(memory, 0, markOffset(), prototypeMarkWord); storeWord(memory, 0, hubOffset(), hub); if (fillContents) { diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ObjectSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -23,6 +23,7 @@ package com.oracle.graal.hotspot.snippets; import static com.oracle.graal.hotspot.snippets.HotSpotSnippetUtils.*; +import static com.oracle.graal.nodes.extended.UnsafeCastNode.*; import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.snippets.*; @@ -36,7 +37,7 @@ @MethodSubstitution(isStatic = false) public static Class getClass(final Object thisObj) { Word hub = loadHub(thisObj); - return (Class) readFinalObject(hub, classMirrorOffset()); + return unsafeCast(hub.readFinalObject(classMirrorOffset()), Class.class, true, true); } @MethodSubstitution(isStatic = false) diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ThreadSnippets.java Wed Dec 19 10:01:08 2012 +0100 @@ -40,10 +40,10 @@ @MethodSubstitution(isStatic = false) private static boolean isInterrupted(final Thread thisObject, boolean clearInterrupted) { Word rawThread = HotSpotCurrentRawThreadNode.get(); - Thread thread = (Thread) loadObjectFromWord(rawThread, threadObjectOffset()); + Thread thread = (Thread) rawThread.readObject(threadObjectOffset()); if (thisObject == thread) { - Word osThread = loadWordFromWord(rawThread, osThreadOffset()); - boolean interrupted = loadIntFromWord(osThread, osThreadInterruptedOffset()) != 0; + Word osThread = rawThread.readWord(osThreadOffset()); + boolean interrupted = osThread.readInt(osThreadInterruptedOffset()) != 0; if (!interrupted || !clearInterrupted) { return interrupted; } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewArrayStub.java Wed Dec 19 10:01:08 2012 +0100 @@ -70,7 +70,7 @@ @Parameter("length") int length, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int layoutHelper = loadIntFromWord(hub, layoutHelperOffset()); + int layoutHelper = hub.readInt(layoutHelperOffset()); int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask(); int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask(); int elementKind = (layoutHelper >> layoutHelperElementTypeShift()) & layoutHelperElementTypeMask(); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java Wed Dec 19 10:01:08 2012 +0100 @@ -68,12 +68,12 @@ @Parameter("hub") Word hub, @ConstantParameter("intArrayHub") Word intArrayHub, @ConstantParameter("log") boolean log) { - int sizeInBytes = loadIntFromWord(hub, klassInstanceSizeOffset()); + int sizeInBytes = hub.readInt(klassInstanceSizeOffset()); if (!forceSlowPath() && inlineContiguousAllocationSupported()) { - if (loadIntFromWord(hub, klassStateOffset()) == klassStateFullyInitialized()) { + if (hub.readInt(klassStateOffset()) == klassStateFullyInitialized()) { Word memory = refillAllocate(intArrayHub, sizeInBytes, log); if (memory != Word.zero()) { - Word prototypeMarkWord = loadWordFromWord(hub, prototypeMarkWordOffset()); + Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset()); storeWord(memory, 0, markOffset(), prototypeMarkWord); storeWord(memory, 0, hubOffset(), hub); for (int offset = 2 * wordSize(); offset < sizeInBytes; offset += wordSize()) { @@ -100,8 +100,8 @@ int alignmentReserveInBytes = tlabAlignmentReserveInHeapWords() * wordSize(); Word thread = thread(); - Word top = loadWordFromWord(thread, threadTlabTopOffset()); - Word end = loadWordFromWord(thread, threadTlabEndOffset()); + Word top = thread.readWord(threadTlabTopOffset()); + Word end = thread.readWord(threadTlabEndOffset()); // calculate amount of free space Word tlabFreeSpaceInBytes = end.minus(top); @@ -116,14 +116,14 @@ // Retain TLAB and allocate object in shared space if // the amount free in the TLAB is too large to discard. - Word refillWasteLimit = loadWordFromWord(thread, tlabRefillWasteLimitOffset()); + Word refillWasteLimit = thread.readWord(tlabRefillWasteLimitOffset()); if (tlabFreeSpaceInWords.belowOrEqual(refillWasteLimit)) { if (tlabStats()) { // increment number of refills - storeInt(thread, 0, tlabNumberOfRefillsOffset(), loadIntFromWord(thread, tlabNumberOfRefillsOffset()) + 1); - log(log, "thread: %p -- number_of_refills %d\n", thread.toLong(), loadIntFromWord(thread, tlabNumberOfRefillsOffset())); + storeInt(thread, 0, tlabNumberOfRefillsOffset(), thread.readInt(tlabNumberOfRefillsOffset()) + 1); + log(log, "thread: %p -- number_of_refills %d\n", thread.toLong(), thread.readInt(tlabNumberOfRefillsOffset())); // accumulate wastage - Word wastage = loadWordFromWord(thread, tlabFastRefillWasteOffset()).plus(tlabFreeSpaceInWords); + Word wastage = thread.readWord(tlabFastRefillWasteOffset()).plus(tlabFreeSpaceInWords); log(log, "thread: %p -- accumulated wastage %d\n", thread.toLong(), wastage.toLong()); storeWord(thread, 0, tlabFastRefillWasteOffset(), wastage); } @@ -137,13 +137,13 @@ int length = ((alignmentReserveInBytes - headerSize) >>> 2) + tlabFreeSpaceInInts; NewObjectSnippets.formatArray(intArrayHub, -1, length, headerSize, top, intArrayMarkWord, false); - Word allocated = loadWordFromWord(thread, threadAllocatedBytesOffset()); - allocated = allocated.plus(top.minus(loadWordFromWord(thread, threadTlabStartOffset()))); + Word allocated = thread.readWord(threadAllocatedBytesOffset()); + allocated = allocated.plus(top.minus(thread.readWord(threadTlabStartOffset()))); storeWord(thread, 0, threadAllocatedBytesOffset(), allocated); } // refill the TLAB with an eden allocation - Word tlabRefillSizeInWords = loadWordFromWord(thread, threadTlabSizeOffset()); + Word tlabRefillSizeInWords = thread.readWord(threadTlabSizeOffset()); Word tlabRefillSizeInBytes = Word.fromLong(tlabRefillSizeInWords.toLong() * wordSize()); // allocate new TLAB, address returned in top top = edenAllocate(tlabRefillSizeInBytes, log); @@ -165,7 +165,7 @@ log(log, "refillTLAB: retaining TLAB - newRefillWasteLimit=%p\n", newRefillWasteLimit.toLong()); if (tlabStats()) { - storeInt(thread, 0, tlabSlowAllocationsOffset(), loadIntFromWord(thread, tlabSlowAllocationsOffset()) + 1); + storeInt(thread, 0, tlabSlowAllocationsOffset(), thread.readInt(tlabSlowAllocationsOffset()) + 1); } return edenAllocate(Word.fromInt(sizeInBytes), log); @@ -184,13 +184,13 @@ Word heapEndAddress = Word.fromLong(heapEndAddress()); while (true) { - Word heapTop = loadWordFromWord(heapTopAddress, 0); + Word heapTop = heapTopAddress.readWord(0); Word newHeapTop = heapTop.plus(sizeInBytes); if (newHeapTop.belowOrEqual(heapTop)) { return Word.zero(); } - Word heapEnd = loadWordFromWord(heapEndAddress, 0); + Word heapEnd = heapEndAddress.readWord(0); if (newHeapTop.above(heapEnd)) { return Word.zero(); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Wed Dec 19 10:01:08 2012 +0100 @@ -63,7 +63,7 @@ int inFalseBranch = loop.nodesInLoopFrom(ifNode.falseSuccessor(), postDom).cardinality(); int loopTotal = loop.size(); int netDiff = loopTotal - (inTrueBranch + inFalseBranch); - double uncertainty = (0.5 - Math.abs(ifNode.probability(IfNode.TRUE_EDGE) - 0.5)) * 2; + double uncertainty = (0.5 - Math.abs(ifNode.probability(ifNode.trueSuccessor()) - 0.5)) * 2; int maxDiff = GraalOptions.LoopUnswitchMaxIncrease + (int) (GraalOptions.LoopUnswitchUncertaintyBoost * loop.loopBegin().loopFrequency() * uncertainty); Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of if", loop, ifNode, netDiff, maxDiff, (double) (inTrueBranch + inFalseBranch) / loopTotal * 100); return netDiff <= maxDiff; diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java Wed Dec 19 10:01:08 2012 +0100 @@ -96,7 +96,7 @@ StructuredGraph graph = (StructuredGraph) ifNode.graph(); BeginNode tempBegin = graph.add(new BeginNode()); originalLoop.entryPoint().replaceAtPredecessor(tempBegin); - double takenProbability = ifNode.probability(ifNode.blockSuccessorIndex(ifNode.trueSuccessor())); + double takenProbability = ifNode.probability(ifNode.trueSuccessor()); IfNode newIf = graph.add(new IfNode(ifNode.condition(), duplicateLoop.entryPoint(), originalLoop.entryPoint(), takenProbability, ifNode.leafGraphId())); tempBegin.setNext(newIf); ifNode.setCondition(graph.unique(ConstantNode.forBoolean(false, graph))); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -53,7 +53,7 @@ if (LoopPolicies.shouldTryUnswitch(loop)) { IfNode ifNode = LoopTransformations.findUnswitchableIf(loop); if (ifNode != null && LoopPolicies.shouldUnswitch(loop, ifNode)) { - Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(0), ifNode.probability(1)); + Debug.log("Unswitching %s at %s [%f - %f]", loop, ifNode, ifNode.probability(ifNode.trueSuccessor()), ifNode.probability(ifNode.falseSuccessor())); LoopTransformations.unswitch(loop, ifNode); UNSWITCHED.increment(); Debug.dump(graph, "After unswitch %s", loop); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -22,62 +22,16 @@ */ package com.oracle.graal.nodes; -import java.util.*; - -import com.oracle.graal.graph.*; -import com.oracle.graal.graph.iterators.*; import com.oracle.graal.nodes.type.*; /** * The {@code ControlSplitNode} is a base class for all instructions that split the control flow (ie. have more than one successor). */ public abstract class ControlSplitNode extends FixedNode { - @Successor private final NodeSuccessorList blockSuccessors; - protected double[] branchProbability; - public BeginNode blockSuccessor(int index) { - return blockSuccessors.get(index); - } - - public void setBlockSuccessor(int index, BeginNode x) { - blockSuccessors.set(index, x); - } - - public int blockSuccessorCount() { - return blockSuccessors.size(); - } - - public ControlSplitNode(Stamp stamp, BeginNode[] blockSuccessors, double[] branchProbability) { + public ControlSplitNode(Stamp stamp) { super(stamp); - assert branchProbability.length == blockSuccessors.length; - this.blockSuccessors = new NodeSuccessorList<>(this, blockSuccessors); - this.branchProbability = branchProbability; } - public double probability(int successorIndex) { - return branchProbability[successorIndex]; - } - - public void setProbability(int successorIndex, double x) { - branchProbability[successorIndex] = x; - } - - public NodeIterable blockSuccessors() { - return blockSuccessors; - } - - public int blockSuccessorIndex(BeginNode successor) { - int idx = blockSuccessors.indexOf(successor); - if (idx < 0) { - throw new IllegalArgumentException(); - } - return idx; - } - - @Override - public ControlSplitNode clone(Graph into) { - ControlSplitNode csn = (ControlSplitNode) super.clone(into); - csn.branchProbability = Arrays.copyOf(branchProbability, branchProbability.length); - return csn; - } + public abstract double probability(BeginNode successor); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java Wed Dec 19 10:01:08 2012 +0100 @@ -298,10 +298,6 @@ return values.get(localsSize + stackSize + i); } - public MergeNode block() { - return usages().filter(MergeNode.class).first(); - } - public NodeIterable innerFrameStates() { return usages().filter(FrameState.class); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -38,11 +38,11 @@ * comparison. */ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, Negatable { - public static final int TRUE_EDGE = 0; - public static final int FALSE_EDGE = 1; private final long leafGraphId; - + @Successor private BeginNode trueSuccessor; + @Successor private BeginNode falseSuccessor; @Input private BooleanNode condition; + private double takenProbability; public BooleanNode condition() { return condition; @@ -54,9 +54,17 @@ } public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability, long leafGraphId) { - super(StampFactory.forVoid(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability}); + this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), takenProbability, leafGraphId); + } + + public IfNode(BooleanNode condition, BeginNode trueSuccessor, BeginNode falseSuccessor, double takenProbability, long leafGraphId) { + super(StampFactory.forVoid()); this.condition = condition; + this.falseSuccessor = falseSuccessor; + this.takenProbability = takenProbability; this.leafGraphId = leafGraphId; + this.trueSuccessor = trueSuccessor; + } public long leafGraphId() { @@ -69,7 +77,7 @@ * @return the true successor */ public BeginNode trueSuccessor() { - return blockSuccessor(0); + return trueSuccessor; } /** @@ -78,15 +86,17 @@ * @return the false successor */ public BeginNode falseSuccessor() { - return blockSuccessor(1); + return falseSuccessor; } public void setTrueSuccessor(BeginNode node) { - setBlockSuccessor(0, node); + updatePredecessor(trueSuccessor, node); + trueSuccessor = node; } public void setFalseSuccessor(BeginNode node) { - setBlockSuccessor(1, node); + updatePredecessor(falseSuccessor, node); + falseSuccessor = node; } /** @@ -96,7 +106,24 @@ * @return the corresponding successor */ public BeginNode successor(boolean istrue) { - return blockSuccessor(istrue ? 0 : 1); + return istrue ? trueSuccessor : falseSuccessor; + } + + @Override + public Negatable negate() { + BeginNode trueSucc = trueSuccessor(); + BeginNode falseSucc = falseSuccessor(); + setTrueSuccessor(null); + setFalseSuccessor(null); + setTrueSuccessor(falseSucc); + setFalseSuccessor(trueSucc); + takenProbability = 1 - takenProbability; + return this; + } + + @Override + public double probability(BeginNode successor) { + return successor == trueSuccessor ? takenProbability : 1 - takenProbability; } @Override @@ -119,11 +146,11 @@ if (c.asConstant().asBoolean()) { tool.deleteBranch(falseSuccessor()); tool.addToWorkList(trueSuccessor()); - ((StructuredGraph) graph()).removeSplit(this, TRUE_EDGE); + ((StructuredGraph) graph()).removeSplit(this, trueSuccessor()); } else { tool.deleteBranch(trueSuccessor()); tool.addToWorkList(falseSuccessor()); - ((StructuredGraph) graph()).removeSplit(this, FALSE_EDGE); + ((StructuredGraph) graph()).removeSplit(this, falseSuccessor()); } } else if (trueSuccessor().guards().isEmpty() && falseSuccessor().guards().isEmpty()) { if (removeOrMaterializeIf(tool)) { @@ -154,7 +181,7 @@ PhiNode singlePhi = phis.next(); if (!phis.hasNext()) { // one phi at the merge of an otherwise empty if construct: try to convert into a MaterializeNode - boolean inverted = trueEnd == merge.forwardEndAt(FALSE_EDGE); + boolean inverted = trueEnd == merge.forwardEndAt(1); ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0); ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1); if (trueValue.kind() != falseValue.kind()) { @@ -276,8 +303,8 @@ List trueEnds = new ArrayList<>(mergePredecessors.size()); Map phiValues = new HashMap<>(mergePredecessors.size()); - BeginNode falseSuccessor = falseSuccessor(); - BeginNode trueSuccessor = trueSuccessor(); + BeginNode oldFalseSuccessor = falseSuccessor(); + BeginNode oldTrueSuccessor = trueSuccessor(); setFalseSuccessor(null); setTrueSuccessor(null); @@ -294,8 +321,8 @@ } assert !ends.hasNext(); - connectEnds(falseEnds, phiValues, falseSuccessor, merge, tool); - connectEnds(trueEnds, phiValues, trueSuccessor, merge, tool); + connectEnds(falseEnds, phiValues, oldFalseSuccessor, merge, tool); + connectEnds(trueEnds, phiValues, oldTrueSuccessor, merge, tool); GraphUtil.killCFG(merge); @@ -382,20 +409,20 @@ } private void removeEmptyIf(SimplifierTool tool) { - BeginNode trueSuccessor = trueSuccessor(); - BeginNode falseSuccessor = falseSuccessor(); - assert trueSuccessor.next() instanceof EndNode && falseSuccessor.next() instanceof EndNode; + BeginNode originalTrueSuccessor = trueSuccessor(); + BeginNode originalFalseSuccessor = falseSuccessor(); + assert originalTrueSuccessor.next() instanceof EndNode && originalFalseSuccessor.next() instanceof EndNode; - EndNode trueEnd = (EndNode) trueSuccessor.next(); - EndNode falseEnd = (EndNode) falseSuccessor.next(); + EndNode trueEnd = (EndNode) originalTrueSuccessor.next(); + EndNode falseEnd = (EndNode) originalFalseSuccessor.next(); assert trueEnd.merge() == falseEnd.merge(); FixedWithNextNode pred = (FixedWithNextNode) predecessor(); MergeNode merge = trueEnd.merge(); merge.prepareDelete(pred); assert merge.usages().isEmpty(); - trueSuccessor.prepareDelete(); - falseSuccessor.prepareDelete(); + originalTrueSuccessor.prepareDelete(); + originalFalseSuccessor.prepareDelete(); FixedNode next = merge.next(); merge.setNext(null); @@ -403,25 +430,11 @@ setFalseSuccessor(null); pred.setNext(next); safeDelete(); - trueSuccessor.safeDelete(); - falseSuccessor.safeDelete(); + originalTrueSuccessor.safeDelete(); + originalFalseSuccessor.safeDelete(); merge.safeDelete(); trueEnd.safeDelete(); falseEnd.safeDelete(); tool.addToWorkList(next); } - - @Override - public Negatable negate() { - BeginNode trueSucc = trueSuccessor(); - BeginNode falseSucc = falseSuccessor(); - setTrueSuccessor(null); - setFalseSuccessor(null); - setTrueSuccessor(falseSucc); - setFalseSuccessor(trueSucc); - double prop = branchProbability[TRUE_EDGE]; - branchProbability[TRUE_EDGE] = branchProbability[FALSE_EDGE]; - branchProbability[FALSE_EDGE] = prop; - return this; - } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -33,9 +33,8 @@ @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}") public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint, LIRLowerable { - public static final int NORMAL_EDGE = 0; - public static final int EXCEPTION_EDGE = 1; - + @Successor private BeginNode next; + @Successor private DispatchBeginNode exceptionEdge; @Input private final CallTargetNode callTarget; @Input private FrameState stateAfter; private final int bci; @@ -44,7 +43,8 @@ private final long leafGraphId; public InvokeWithExceptionNode(CallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci, long leafGraphId) { - super(callTarget.returnStamp(), new BeginNode[]{null, exceptionEdge}, new double[]{1.0, 0.0}); + super(callTarget.returnStamp()); + this.exceptionEdge = exceptionEdge; this.bci = bci; this.callTarget = callTarget; this.leafGraphId = leafGraphId; @@ -53,19 +53,21 @@ } public DispatchBeginNode exceptionEdge() { - return (DispatchBeginNode) blockSuccessor(EXCEPTION_EDGE); + return exceptionEdge; } - public void setExceptionEdge(BeginNode x) { - setBlockSuccessor(EXCEPTION_EDGE, x); + public void setExceptionEdge(DispatchBeginNode x) { + updatePredecessor(exceptionEdge, x); + exceptionEdge = x; } public BeginNode next() { - return blockSuccessor(NORMAL_EDGE); + return next; } public void setNext(BeginNode x) { - setBlockSuccessor(NORMAL_EDGE, x); + updatePredecessor(next, x); + next = x; } public CallTargetNode callTarget() { @@ -170,9 +172,9 @@ } public void killExceptionEdge() { - BeginNode exceptionEdge = exceptionEdge(); + BeginNode edge = exceptionEdge(); setExceptionEdge(null); - GraphUtil.killCFG(exceptionEdge); + GraphUtil.killCFG(edge); } @Override @@ -187,18 +189,24 @@ } if (node == null) { assert kind() == Kind.Void && usages().isEmpty(); - ((StructuredGraph) graph()).removeSplit(this, NORMAL_EDGE); + ((StructuredGraph) graph()).removeSplit(this, next()); } else if (node instanceof DeoptimizeNode) { this.replaceAtPredecessor(node); this.replaceAtUsages(null); GraphUtil.killCFG(this); return; } else { - ((StructuredGraph) graph()).replaceSplit(this, node, NORMAL_EDGE); + ((StructuredGraph) graph()).replaceSplit(this, node, next()); } call.safeDelete(); if (state.usages().isEmpty()) { state.safeDelete(); } } + + private static final double EXCEPTION_PROBA = 1e-5; + @Override + public double probability(BeginNode successor) { + return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA; + } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MaterializeNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -26,6 +26,7 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.java.*; public final class MaterializeNode extends ConditionalNode { @@ -37,6 +38,10 @@ super(condition, trueValue, falseValue); } + private MaterializeNode(ValueNode type, ValueNode object) { + super(type.graph().add(new InstanceOfDynamicNode(type, object)), ConstantNode.forInt(1, type.graph()), ConstantNode.forInt(0, type.graph())); + } + public static MaterializeNode create(BooleanNode condition, ValueNode trueValue, ValueNode falseValue) { Graph graph = condition.graph(); MaterializeNode result = new MaterializeNode(condition, trueValue, falseValue); @@ -53,4 +58,7 @@ @NodeIntrinsic public static native boolean materialize(@ConstantNodeParameter Condition condition, long x, long y); + + @NodeIntrinsic + public static native boolean isInstance(Class mirror, Object object); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Wed Dec 19 10:01:08 2012 +0100 @@ -241,39 +241,34 @@ node.safeDelete(); } - public void removeSplit(ControlSplitNode node, int survivingSuccessor) { + public void removeSplit(ControlSplitNode node, BeginNode survivingSuccessor) { assert node != null; assert node.usages().isEmpty(); - assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; - BeginNode begin = node.blockSuccessor(survivingSuccessor); - for (int i = 0; i < node.blockSuccessorCount(); i++) { - node.setBlockSuccessor(i, null); - } - node.replaceAtPredecessor(begin); + assert survivingSuccessor != null; + node.clearSuccessors(); + node.replaceAtPredecessor(survivingSuccessor); node.safeDelete(); } - public void removeSplitPropagate(ControlSplitNode node, int survivingSuccessor) { + public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) { assert node != null; assert node.usages().isEmpty(); - assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; - BeginNode begin = node.blockSuccessor(survivingSuccessor); - for (int i = 0; i < node.blockSuccessorCount(); i++) { - BeginNode successor = node.blockSuccessor(i); - node.setBlockSuccessor(i, null); - if (successor != null && successor != begin && successor.isAlive()) { - GraphUtil.killCFG(successor); + assert survivingSuccessor != null; + for (Node successor : node.successors().snapshot()) { + successor.replaceAtPredecessor(null); + if (successor != null && successor != survivingSuccessor && successor.isAlive()) { + GraphUtil.killCFG((BeginNode) successor); } } - if (begin.isAlive()) { - node.replaceAtPredecessor(begin); + if (survivingSuccessor.isAlive()) { + node.replaceAtPredecessor(survivingSuccessor); node.safeDelete(); } else { - assert node.isDeleted() : node + " " + begin; + assert node.isDeleted() : node + " " + survivingSuccessor; } } - public void replaceSplit(ControlSplitNode node, Node replacement, int survivingSuccessor) { + public void replaceSplit(ControlSplitNode node, Node replacement, BeginNode survivingSuccessor) { if (replacement instanceof FixedWithNextNode) { replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor); } else { @@ -283,25 +278,19 @@ } } - public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, int survivingSuccessor) { + public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, BeginNode survivingSuccessor) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; - assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; - BeginNode begin = node.blockSuccessor(survivingSuccessor); - for (int i = 0; i < node.blockSuccessorCount(); i++) { - node.setBlockSuccessor(i, null); - } - replacement.setNext(begin); + assert survivingSuccessor != null; + node.clearSuccessors(); + replacement.setNext(survivingSuccessor); node.replaceAndDelete(replacement); } - public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, int survivingSuccessor) { + public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, BeginNode survivingSuccessor) { assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; - assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node; - BeginNode begin = node.blockSuccessor(survivingSuccessor); - for (int i = 0; i < node.blockSuccessorCount(); i++) { - node.setBlockSuccessor(i, null); - } - node.replaceAtPredecessor(begin); + assert survivingSuccessor != null; + node.clearSuccessors(); + node.replaceAtPredecessor(survivingSuccessor); node.replaceAtUsages(replacement); node.safeDelete(); } @@ -322,7 +311,7 @@ public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) { assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node; assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node; - assert newNode.next() == null; + assert newNode.next() == null : newNode; newNode.setProbability(node.probability()); FixedWithNextNode pred = (FixedWithNextNode) node.predecessor(); pred.setNext(newNode); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -93,7 +93,7 @@ public void simplify(SimplifierTool tool) { if (blockSuccessorCount() == 1) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex()); + ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); } else if (value() instanceof ConstantNode) { int constant = value().asConstant().asInt(); @@ -109,7 +109,7 @@ } } tool.addToWorkList(blockSuccessor(survivingEdge)); - ((StructuredGraph) graph()).removeSplitPropagate(this, survivingEdge); + ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge)); } else if (value() != null) { IntegerStamp stamp = value().integerStamp(); if (!stamp.isUnrestricted()) { @@ -121,7 +121,7 @@ } if (validKeys == 0) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex()); + ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); } else if (validKeys != keys.length) { ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); int[] newKeys = new int[validKeys]; diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -22,6 +22,8 @@ */ package com.oracle.graal.nodes.extended; +import java.util.*; + import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; @@ -31,10 +33,11 @@ * The {@code SwitchNode} class is the base of both lookup and table switches. */ public abstract class SwitchNode extends ControlSplitNode { - + @Successor protected final NodeSuccessorList successors; + protected double[] successorProbabilities; @Input private ValueNode value; - private final double[] keyProbabilities; - private final int[] keySuccessors; + private double[] keyProbabilities; + private int[] keySuccessors; public ValueNode value() { return value; @@ -46,13 +49,26 @@ * @param successors the list of successors of this switch */ public SwitchNode(ValueNode value, BeginNode[] successors, double[] successorProbabilities, int[] keySuccessors, double[] keyProbabilities) { - super(StampFactory.forVoid(), successors, successorProbabilities); + super(StampFactory.forVoid()); + this.successorProbabilities = successorProbabilities; assert keySuccessors.length == keyProbabilities.length; + this.successors = new NodeSuccessorList<>(this, successors); this.value = value; this.keySuccessors = keySuccessors; this.keyProbabilities = keyProbabilities; } + @Override + public double probability(BeginNode successor) { + double sum = 0; + for (int i = 0; i < successors.size(); i++) { + if (successors.get(i) == successor) { + sum += successorProbabilities[i]; + } + } + return sum; + } + /** * The number of distinct keys in this switch. */ @@ -74,7 +90,7 @@ * Returns the successor for the key at the given index. */ public BeginNode keySuccessor(int i) { - return blockSuccessor(keySuccessors[i]); + return successors.get(keySuccessors[i]); } /** @@ -91,6 +107,18 @@ return keySuccessors[keySuccessors.length - 1]; } + public BeginNode blockSuccessor(int i) { + return successors.get(i); + } + + public void setBlockSuccessor(int i, BeginNode s) { + successors.set(i, s); + } + + public int blockSuccessorCount() { + return successors.count(); + } + /** * Gets the successor corresponding to the default (fall through) case. * @return the default successor @@ -99,7 +127,7 @@ if (defaultSuccessorIndex() == -1) { throw new GraalInternalError("unexpected"); } - return defaultSuccessorIndex() == -1 ? null : blockSuccessor(defaultSuccessorIndex()); + return defaultSuccessorIndex() == -1 ? null : successors.get(defaultSuccessorIndex()); } /** @@ -113,4 +141,13 @@ } return probability; } + + @Override + public SwitchNode clone(Graph into) { + SwitchNode newSwitch = (SwitchNode) super.clone(into); + newSwitch.successorProbabilities = Arrays.copyOf(successorProbabilities, successorProbabilities.length); + newSwitch.keyProbabilities = Arrays.copyOf(keyProbabilities, keyProbabilities.length); + newSwitch.keySuccessors = Arrays.copyOf(keySuccessors, keySuccessors.length); + return newSwitch; + } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -99,7 +99,4 @@ @NodeIntrinsic public static native T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter Kind kind); - - @NodeIntrinsic - public static native Object loadObject(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter boolean nonNull); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.nodes.java; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.nodes.type.*; + +/** + * The {@code InstanceOfDynamicNode} represents a type check where the type being checked + * is not known at compile time. + * This is used, for instance, to intrinsify {@link Class#isInstance(Object)}. + */ +public final class InstanceOfDynamicNode extends BooleanNode implements Canonicalizable, Lowerable { + + @Input private ValueNode object; + @Input private ValueNode mirror; + + /** + * Constructs a new InstanceOfNode. + * + * @param mirror the {@link Class} value representing the target target type of the instanceof check + * @param object the object being tested by the instanceof + */ + public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) { + super(StampFactory.condition()); + this.mirror = mirror; + this.object = object; + assert mirror.kind() == Kind.Object; + assert mirror.objectStamp().isExactType(); + assert mirror.objectStamp().type().getName().equals("Ljava/lang/Class;"); + } + + @Override + public void lower(LoweringTool tool) { + tool.getRuntime().lower(this, tool); + } + + @Override + public ValueNode canonical(CanonicalizerTool tool) { + assert object() != null : this; + if (mirror().isConstant()) { + Class clazz = (Class) mirror().asConstant().asObject(); + ResolvedJavaType t = tool.runtime().lookupJavaType(clazz); + return graph().unique(new InstanceOfNode(t, object(), null)); + } + return this; + } + + public ValueNode object() { + return object; + } + + public ValueNode mirror() { + return mirror; + } + + @Override + public boolean verify() { + for (Node usage : usages()) { + assertTrue(usage instanceof IfNode || usage instanceof ConditionalNode, "unsupported usage: ", usage); + } + return super.verify(); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -33,7 +33,7 @@ /** * The {@code InstanceOfNode} represents an instanceof test. */ -public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, LIRLowerable, Virtualizable { +public final class InstanceOfNode extends BooleanNode implements Canonicalizable, Lowerable, Virtualizable { @Input private ValueNode object; private final ResolvedJavaType type; @@ -54,10 +54,6 @@ } @Override - public void generate(LIRGeneratorTool gen) { - } - - @Override public void lower(LoweringTool tool) { tool.getRuntime().lower(this, tool); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -91,7 +91,7 @@ } } tool.addToWorkList(blockSuccessor(survivingEdge)); - ((StructuredGraph) graph()).removeSplitPropagate(this, survivingEdge); + ((StructuredGraph) graph()).removeSplit(this, blockSuccessor(survivingEdge)); } if (value() instanceof LoadHubNode) { ObjectStamp stamp = ((LoadHubNode) value()).object().objectStamp(); @@ -104,7 +104,7 @@ } if (validKeys == 0) { tool.addToWorkList(defaultSuccessor()); - ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessorIndex()); + ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor()); } else if (validKeys != keys.length) { ArrayList newSuccessors = new ArrayList<>(blockSuccessorCount()); ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys]; diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java Wed Dec 19 10:01:08 2012 +0100 @@ -104,7 +104,7 @@ //TTY.println(" Already explored, propagate update"); propagateUpdate(csInfo); } else { - if (csInfo.parentCount() == cs.blockSuccessorCount()) { // all paths leading to this CS have been explored + if (csInfo.parentCount() == cs.successors().count()) { // all paths leading to this CS have been explored //TTY.println(" All parents explored, Enqueue"); toExplore.add(next); speculativeExplore.remove(next); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -244,7 +244,7 @@ } @Override - public void afterSplit(FixedNode node) { + public void afterSplit(BeginNode node) { assert node.predecessor() != null; Node pred = node.predecessor(); if (pred instanceof Invoke) { @@ -255,13 +255,7 @@ } else { assert pred instanceof ControlSplitNode; ControlSplitNode x = (ControlSplitNode) pred; - double sum = 0; - for (int i = 0; i < x.blockSuccessorCount(); i++) { - if (x.blockSuccessor(i) == node) { - sum += x.probability(i); - } - } - probability *= sum; + probability *= x.probability(node); } } } @@ -316,7 +310,7 @@ } @Override - public void afterSplit(FixedNode node) { + public void afterSplit(BeginNode node) { // nothing to do... } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -214,7 +214,7 @@ } @Override - public void afterSplit(FixedNode node) { + public void afterSplit(BeginNode node) { } @Override diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertUnreachedToGuardPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -49,11 +49,11 @@ BeginNode insertGuard = null; BeginNode delete = null; boolean inverted = false; - if (ifNode.probability(IfNode.TRUE_EDGE) == 0) { + if (ifNode.probability(ifNode.trueSuccessor()) == 0) { insertGuard = ifNode.falseSuccessor(); delete = ifNode.trueSuccessor(); inverted = true; - } else if (ifNode.probability(IfNode.FALSE_EDGE) == 0) { + } else if (ifNode.probability(ifNode.falseSuccessor()) == 0) { insertGuard = ifNode.trueSuccessor(); delete = ifNode.falseSuccessor(); } @@ -61,7 +61,7 @@ GuardNode guard = graph.unique(new GuardNode(ifNode.condition(), BeginNode.prevBegin(ifNode), DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, inverted, ifNode.leafGraphId())); graph.addBeforeFixed(ifNode, graph.add(new ValueAnchorNode(guard))); GraphUtil.killCFG(delete); - graph.removeSplit(ifNode, inverted ? IfNode.FALSE_EDGE : IfNode.TRUE_EDGE); + graph.removeSplit(ifNode, inverted ? ifNode.falseSuccessor() : ifNode.trueSuccessor()); } } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -87,7 +87,7 @@ } @Override - public void afterSplit(FixedNode node) { + public void afterSplit(BeginNode node) { } @Override diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -149,7 +149,8 @@ private static boolean eliminateAtControlSplit(ControlSplitNode controlSplit) { Map> conditionToGuard = new HashMap<>(); - for (BeginNode begin : controlSplit.blockSuccessors()) { + for (Node successor : controlSplit.successors()) { + BeginNode begin = (BeginNode) successor; for (GuardNode guard : begin.guards()) { if (guard.dependencies().size() != 1) { continue; @@ -196,7 +197,7 @@ if (leafGraphId < 0) { continue; } - if (begins.size() == controlSplit.blockSuccessors().count()) { + if (begins.size() == controlSplit.successors().count()) { hits = true; Condition condition = entry.getKey(); GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, BeginNode.prevBegin(controlSplit), reason, action, condition.negated, leafGraphId)); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -157,7 +157,7 @@ } @Override - public void afterSplit(FixedNode node) { + public void afterSplit(BeginNode node) { // nothing } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Wed Dec 19 10:01:08 2012 +0100 @@ -576,11 +576,11 @@ assert exceptionMerge != null && exceptionObjectPhi != null; InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; - BeginNode exceptionEdge = invokeWithException.exceptionEdge(); + DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge(); ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); FrameState stateAfterException = exceptionObject.stateAfter(); - BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); + DispatchBeginNode newExceptionEdge = (DispatchBeginNode) exceptionEdge.copyWithInputs(); ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); // set new state (pop old exception object, push new one) newExceptionObject.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionObject)); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java Wed Dec 19 10:01:08 2012 +0100 @@ -31,5 +31,5 @@ boolean merge(MergeNode merge, List withStates); void loopBegin(LoopBeginNode loopBegin); void loopEnds(LoopBeginNode loopBegin, List loopEndStates); - void afterSplit(FixedNode node); + void afterSplit(BeginNode node); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java Wed Dec 19 10:01:08 2012 +0100 @@ -38,7 +38,7 @@ public abstract class PostOrderNodeIterator> { private final NodeBitMap visitedEnds; - private final Deque nodeQueue; + private final Deque nodeQueue; private final IdentityHashMap nodeStates; private final FixedNode start; @@ -109,13 +109,13 @@ for (Node node : successors) { if (node != null) { nodeStates.put((FixedNode) node.predecessor(), state); - nodeQueue.addFirst((FixedNode) node); + nodeQueue.addFirst((BeginNode) node); } } } else { for (Node node : x.successors()) { if (node != null) { - nodeQueue.addFirst((FixedNode) node); + nodeQueue.addFirst((BeginNode) node); } } } @@ -124,7 +124,7 @@ private FixedNode nextQueuedNode() { int maxIterations = nodeQueue.size(); while (maxIterations-- > 0) { - FixedNode node = nodeQueue.removeFirst(); + BeginNode node = nodeQueue.removeFirst(); if (node instanceof MergeNode) { MergeNode merge = (MergeNode) node; state = nodeStates.get(merge.forwardEndAt(0)).clone(); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/InstanceOfDynamicTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.snippets; + +import org.junit.*; + +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.java.*; + +/** + * Tests for {@link InstanceOfDynamicNode}. + */ +public class InstanceOfDynamicTest extends GraalCompilerTest { + + public static int id(int value) { + return value; + } + + @Test + public void test100() { + final Object nul = null; + test("isStringDynamic", nul); + test("isStringDynamic", "object"); + test("isStringDynamic", Object.class); + } + + @Test + public void test101() { + final Object nul = null; + test("isStringIntDynamic", nul); + test("isStringIntDynamic", "object"); + test("isStringIntDynamic", Object.class); + } + + @Test + public void test103() { + test("isInstanceDynamic", String.class, null); + test("isInstanceDynamic", String.class, "object"); + test("isInstanceDynamic", String.class, Object.class); + } + + @Test + public void test104() { + test("isInstanceIntDynamic", String.class, null); + test("isInstanceIntDynamic", String.class, "object"); + test("isInstanceIntDynamic", String.class, Object.class); + } + + public static boolean isStringDynamic(Object o) { + return String.class.isInstance(o); + } + + public static int isStringIntDynamic(Object o) { + if (String.class.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } + + public static boolean isInstanceDynamic(Class c, Object o) { + return c.isInstance(o); + } + + public static int isInstanceIntDynamic(Class c, Object o) { + if (c.isInstance(o)) { + return o.toString().length(); + } + return o.getClass().getName().length(); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/IntrinsificationTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -65,7 +65,7 @@ @Test public void testClassIntrinsics() { test("getModifiersSnippet"); -// test("isInstanceSnippet"); + test("isInstanceSnippet"); test("isInterfaceSnippet"); test("isArraySnippet"); test("isPrimitiveSnippet"); @@ -128,7 +128,6 @@ public void testSystemIntrinsics() { test("systemTimeSnippet"); test("systemIdentityHashCode"); -// test("arraycopySnippet"); } @SuppressWarnings("all") @@ -140,10 +139,6 @@ public static int systemIdentityHashCode(Object obj) { return System.identityHashCode(obj); } - @SuppressWarnings("all") - public static void arraycopySnippet(int[] src, int srcPos, int[] dest, int destPos, int length) { - System.arraycopy(src, srcPos, dest, destPos, length); - } @Test @@ -400,7 +395,7 @@ private StructuredGraph test(final String snippet) { - return Debug.scope("IntrinsificationTest", new DebugDumpScope(snippet), new Callable() { + return Debug.scope("IntrinsificationTest", runtime.lookupJavaMethod(getMethod(snippet)), new Callable() { @Override public StructuredGraph call() { StructuredGraph graph = parse(snippet); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/NewMultiArrayTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -38,32 +38,6 @@ */ public class NewMultiArrayTest extends GraalCompilerTest { - @Override - protected void assertEquals(Object expected, Object actual) { - Assert.assertTrue(expected != null); - Assert.assertTrue(actual != null); - super.assertEquals(expected.getClass(), actual.getClass()); - if (expected instanceof int[]) { - Assert.assertArrayEquals((int[]) expected, (int[]) actual); - } else if (expected instanceof byte[]) { - Assert.assertArrayEquals((byte[]) expected, (byte[]) actual); - } else if (expected instanceof char[]) { - Assert.assertArrayEquals((char[]) expected, (char[]) actual); - } else if (expected instanceof short[]) { - Assert.assertArrayEquals((short[]) expected, (short[]) actual); - } else if (expected instanceof float[]) { - Assert.assertArrayEquals((float[]) expected, (float[]) actual, 0.0f); - } else if (expected instanceof long[]) { - Assert.assertArrayEquals((long[]) expected, (long[]) actual); - } else if (expected instanceof double[]) { - Assert.assertArrayEquals((double[]) expected, (double[]) actual, 0.0d); - } else if (expected instanceof Object[]) { - Assert.assertArrayEquals((Object[]) expected, (Object[]) actual); - } else { - Assert.fail("non-array value encountered: " + expected); - } - } - private static int rank(ResolvedJavaType type) { String name = type.getName(); int dims = 0; diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java --- a/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -53,7 +53,7 @@ @Override protected StructuredGraph parse(Method m) { ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m); - return installer.makeGraph(resolvedMethod, inliningPolicy.get()); + return installer.makeGraph(resolvedMethod, inliningPolicy.get(), false); } @Test diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java Wed Dec 19 10:01:08 2012 +0100 @@ -77,7 +77,8 @@ */ protected abstract KeyAndArguments getKeyAndArguments(InstanceOfUsageReplacer replacer, LoweringTool tool); - public void lower(InstanceOfNode instanceOf, LoweringTool tool) { + public void lower(FloatingNode instanceOf, LoweringTool tool) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; List usages = instanceOf.usages().snapshot(); int nUsages = usages.size(); @@ -107,7 +108,7 @@ * Gets the specific replacer object used to replace the usage of an instanceof node * with the result of an instantiated instanceof snippet. */ - protected InstanceOfUsageReplacer createReplacer(InstanceOfNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { + protected InstanceOfUsageReplacer createReplacer(FloatingNode instanceOf, LoweringTool tool, int nUsages, Instantiation instantiation, Node usage, final StructuredGraph graph) { InstanceOfUsageReplacer replacer; if (usage instanceof IfNode) { replacer = new IfUsageReplacer(instantiation, ConstantNode.forInt(1, graph), ConstantNode.forInt(0, graph), instanceOf, (IfNode) usage, nUsages == 1, tool); @@ -175,15 +176,16 @@ } /** - * Replaces a usage of an {@link InstanceOfNode}. + * Replaces a usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. */ public abstract static class InstanceOfUsageReplacer implements UsageReplacer { public final Instantiation instantiation; - public final InstanceOfNode instanceOf; + public final FloatingNode instanceOf; public final ValueNode trueValue; public final ValueNode falseValue; - public InstanceOfUsageReplacer(Instantiation instantiation, InstanceOfNode instanceOf, ValueNode trueValue, ValueNode falseValue) { + public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) { + assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode; this.instantiation = instantiation; this.instanceOf = instanceOf; this.trueValue = trueValue; @@ -197,7 +199,7 @@ } /** - * Replaces an {@link IfNode} usage of an {@link InstanceOfNode}. + * Replaces an {@link IfNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. */ public static class IfUsageReplacer extends InstanceOfUsageReplacer { @@ -205,7 +207,7 @@ private final IfNode usage; private final boolean sameBlock; - public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { + public IfUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, IfNode usage, boolean solitaryUsage, LoweringTool tool) { super(instantiation, instanceOf, trueValue, falseValue); this.sameBlock = tool.getBlockFor(usage) == tool.getBlockFor(instanceOf); this.solitaryUsage = solitaryUsage; @@ -294,13 +296,13 @@ } /** - * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode}. + * Replaces a {@link ConditionalNode} usage of an {@link InstanceOfNode} or {@link InstanceOfDynamicNode}. */ public static class ConditionalUsageReplacer extends InstanceOfUsageReplacer { public final ConditionalNode usage; - public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, InstanceOfNode instanceOf, ConditionalNode usage) { + public ConditionalUsageReplacer(Instantiation instantiation, ValueNode trueValue, ValueNode falseValue, FloatingNode instanceOf, ConditionalNode usage) { super(instantiation, instanceOf, trueValue, falseValue); this.usage = usage; } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetFrameStateCleanupPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.snippets; + +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.util.*; +import com.oracle.graal.phases.*; + +/** + * Removes frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes in a snippet. + */ +public class SnippetFrameStateCleanupPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + for (Node node : graph.getNodes().filterInterface(StateSplit.class)) { + StateSplit stateSplit = (StateSplit) node; + FrameState frameState = stateSplit.stateAfter(); + if (!stateSplit.hasSideEffect()) { + if (frameState != null) { + stateSplit.setStateAfter(null); + if (frameState.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(frameState); + } + } + } + } + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java Wed Dec 19 10:01:08 2012 +0100 @@ -93,7 +93,7 @@ } ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); assert snippet.getCompilerStorage().get(Graph.class) == null : method; - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), false); //System.out.println("snippet: " + graph); snippet.getCompilerStorage().put(Graph.class, graph); } @@ -131,7 +131,7 @@ throw new RuntimeException("Snippet must not be abstract or native"); } ResolvedJavaMethod snippet = runtime.lookupJavaMethod(method); - StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet)); + StructuredGraph graph = makeGraph(snippet, inliningPolicy(snippet), true); //System.out.println("snippet: " + graph); runtime.lookupJavaMethod(originalMethod).getCompilerStorage().put(Graph.class, graph); } catch (NoSuchMethodException e) { @@ -156,14 +156,28 @@ } } - public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { - StructuredGraph graph = parseGraph(method, policy); + public StructuredGraph makeGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy, final boolean isSubstitutionSnippet) { + return Debug.scope("BuildSnippetGraph", new Object[] {method}, new Callable() { + @Override + public StructuredGraph call() throws Exception { + StructuredGraph graph = parseGraph(method, policy); + + new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); - new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph); + if (isSubstitutionSnippet) { + // TODO (ds) remove the constraint of only processing substitution snippets + // once issues with the arraycopy snippets have been resolved + new SnippetFrameStateCleanupPhase().apply(graph); + new DeadCodeEliminationPhase().apply(graph); + } - Debug.dump(graph, "%s: Final", method.getName()); + new InsertStateAfterPlaceholderPhase().apply(graph); + + Debug.dump(graph, "%s: Final", method.getName()); - return graph; + return graph; + } + }); } private StructuredGraph parseGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { @@ -178,54 +192,47 @@ private StructuredGraph buildGraph(final ResolvedJavaMethod method, final SnippetInliningPolicy policy) { final StructuredGraph graph = new StructuredGraph(method); - return Debug.scope("BuildSnippetGraph", new Object[] {method, graph}, new Callable() { - @Override - public StructuredGraph call() throws Exception { - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); - GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); - graphBuilder.apply(graph); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(); + GraphBuilderPhase graphBuilder = new GraphBuilderPhase(runtime, config, OptimisticOptimizations.NONE); + graphBuilder.apply(graph); - Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); + Debug.dump(graph, "%s: %s", method.getName(), GraphBuilderPhase.class.getSimpleName()); - new SnippetVerificationPhase(runtime).apply(graph); + new SnippetVerificationPhase(runtime).apply(graph); - new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); + new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - for (Invoke invoke : graph.getInvokes()) { - MethodCallTargetNode callTarget = invoke.methodCallTarget(); - ResolvedJavaMethod callee = callTarget.targetMethod(); - if (policy.shouldInline(callee, method)) { - StructuredGraph targetGraph = parseGraph(callee, policy); - InliningUtil.inline(invoke, targetGraph, true); - Debug.dump(graph, "after inlining %s", callee); - if (GraalOptions.OptCanonicalizer) { - new WordTypeRewriterPhase(target.wordKind).apply(graph); - new CanonicalizerPhase(target, runtime, assumptions).apply(graph); - } - } - } - - new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - - new WordTypeRewriterPhase(target.wordKind).apply(graph); - - new DeadCodeEliminationPhase().apply(graph); + for (Invoke invoke : graph.getInvokes()) { + MethodCallTargetNode callTarget = invoke.methodCallTarget(); + ResolvedJavaMethod callee = callTarget.targetMethod(); + if (policy.shouldInline(callee, method)) { + StructuredGraph targetGraph = parseGraph(callee, policy); + InliningUtil.inline(invoke, targetGraph, true); + Debug.dump(graph, "after inlining %s", callee); if (GraalOptions.OptCanonicalizer) { + new WordTypeRewriterPhase(target.wordKind).apply(graph); new CanonicalizerPhase(target, runtime, assumptions).apply(graph); } + } + } - for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { - end.disableSafepoint(); - } + new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph); - new InsertStateAfterPlaceholderPhase().apply(graph); + new WordTypeRewriterPhase(target.wordKind).apply(graph); - if (GraalOptions.ProbabilityAnalysis) { - new DeadCodeEliminationPhase().apply(graph); - new ComputeProbabilityPhase().apply(graph); - } - return graph; - } - }); + new DeadCodeEliminationPhase().apply(graph); + if (GraalOptions.OptCanonicalizer) { + new CanonicalizerPhase(target, runtime, assumptions).apply(graph); + } + + for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) { + end.disableSafepoint(); + } + + if (GraalOptions.ProbabilityAnalysis) { + new DeadCodeEliminationPhase().apply(graph); + new ComputeProbabilityPhase().apply(graph); + } + return graph; } } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -221,7 +221,7 @@ InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, InvokeWithExceptionNode.NORMAL_EDGE); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); } else { graph.removeFixed((InvokeNode) invokeNode); } @@ -381,7 +381,7 @@ InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invokeNode; invokeWithExceptionNode.killExceptionEdge(); - graph.removeSplit(invokeWithExceptionNode, InvokeWithExceptionNode.NORMAL_EDGE); + graph.removeSplit(invokeWithExceptionNode, invokeWithExceptionNode.next()); } else { graph.removeFixed((InvokeNode) invokeNode); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java Wed Dec 19 10:01:08 2012 +0100 @@ -208,7 +208,9 @@ throw new GraalInternalError(e); } } -} + } + + private static final Object UNUSED_PARAMETER = "DEAD PARAMETER"; /** * Determines if any parameter of a given method is annotated with {@link ConstantParameter}. @@ -315,8 +317,12 @@ Parameter p = parameterAnnotations[i]; if (p != null) { LocalNode local = snippetCopy.getLocal(i); - assert local != null; - parameters.put(p.value(), local); + if (local == null) { + // Parameter value was eliminated + parameters.put(p.value(), UNUSED_PARAMETER); + } else { + parameters.put(p.value(), local); + } } } } @@ -431,7 +437,9 @@ /** * The named parameters of this template that must be bound to values during instantiation. - * Each value in this map is either a {@link LocalNode} instance or a {@link LocalNode} array. + * For a parameter that is still live after specialization, the value in this map is either + * a {@link LocalNode} instance or a {@link LocalNode} array. For an eliminated parameter, + * the value is identical to the key. */ private final Map parameters; @@ -477,8 +485,7 @@ Constant constant = Constant.forBoxed(kind, argument); replacements.put((LocalNode) parameter, ConstantNode.forConstant(constant, runtime, replaceeGraph)); } - } else { - assert parameter instanceof LocalNode[]; + } else if (parameter instanceof LocalNode[]) { LocalNode[] locals = (LocalNode[]) parameter; Object array = argument; assert array != null && array.getClass().isArray(); @@ -496,6 +503,8 @@ replacements.put(local, element); } } + } else { + assert parameter == UNUSED_PARAMETER : "unexpected entry for parameter: " + name + " -> " + parameter; } } return replacements; @@ -673,7 +682,9 @@ Object value = e.getValue(); buf.append(sep); sep = ", "; - if (value instanceof LocalNode) { + if (value == UNUSED_PARAMETER) { + buf.append(" ").append(name); + } else if (value instanceof LocalNode) { LocalNode local = (LocalNode) value; buf.append(local.kind().getJavaName()).append(' ').append(name); } else { diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java Wed Dec 19 10:01:08 2012 +0100 @@ -58,6 +58,10 @@ OR, AND, XOR, + READ_INT, + READ_WORD, + READ_OBJECT, + READ_FINAL_OBJECT, BELOW, BELOW_EQUAL, ABOVE, @@ -237,4 +241,20 @@ return new Word(value | other.value, null); } + @Operation(READ_INT) + public native int readInt(int offset); + + @Operation(READ_WORD) + public native Word readWord(int offset); + + @Operation(READ_OBJECT) + public native Object readObject(int offset); + + /** + * Reads an object value from a location that is guaranteed not be to modified after this read. + * + * @param offset the offset from this base address of the location to be read + */ + @Operation(READ_FINAL_OBJECT) + public native Object readFinalObject(int offset); } diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java --- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Tue Dec 18 15:05:58 2012 +0100 +++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java Wed Dec 19 10:01:08 2012 +0100 @@ -212,6 +212,18 @@ break; } + case READ_INT: + case READ_OBJECT: + case READ_WORD: { + replaceRead(graph, arguments, invoke, LocationNode.ANY_LOCATION); + break; + } + + case READ_FINAL_OBJECT: { + replaceRead(graph, arguments, invoke, LocationNode.FINAL_LOCATION); + break; + } + default: { throw new GraalInternalError("Unknown opcode: %s", opcode); } @@ -220,6 +232,17 @@ } } + protected void replaceRead(StructuredGraph graph, NodeInputList arguments, Invoke invoke, Object locationIdentity) { + assert arguments.size() == 2; + ValueNode base = arguments.first(); + IndexedLocationNode location = IndexedLocationNode.create(locationIdentity, invoke.node().kind(), 0, arguments.last(), graph, false); + ReadNode read = graph.add(new ReadNode(base, location, invoke.node().stamp())); + graph.addBeforeFixed(invoke.node(), read); + // The read must not float outside its block otherwise it may float above an explicit zero check on its base address + read.dependencies().add(BeginNode.prevBegin(invoke.node())); + replace(invoke, read); + } + protected void replace(Invoke invoke, ValueNode value) { FixedNode next = invoke.next(); invoke.setNext(null); diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ArgumentsTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + + +/** + *

Passing Arguments

+ * + *

+ * A guest language can pass its own custom arguments when invoking a Truffle method by creating a subclass of + * {@link Arguments}. When invoking a call target with {@link CallTarget#call(Arguments)}, the arguments can be passed. + * A Truffle node can access the arguments passed into the Truffle method by using {@link VirtualFrame#getArguments()}. + *

+ * + *

+ * The arguments class should only contain fields that are declared as final. This allows the Truffle runtime to improve + * optimizations around guest language method calls. Also, the arguments object must never be stored into a field. It + * should be created immediately before invoking {@link CallTarget#call(Arguments)} and no longer be accessed + * afterwards. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.FrameTest}. + *

+ */ +public class ArgumentsTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestRootNode rootNode = new TestRootNode(new TestArgumentNode[]{new TestArgumentNode(0), new TestArgumentNode(1)}); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(new TestArguments(20, 22)); + Assert.assertEquals(42, result); + } + + class TestArguments extends Arguments { + final int[] values; + TestArguments(int... values) { + this.values = values; + } + } + + class TestRootNode extends RootNode { + + @Children private TestArgumentNode[] children; + + TestRootNode(TestArgumentNode[] children) { + this.children = adoptChildren(children); + } + + @Override + public Object execute(VirtualFrame frame) { + int sum = 0; + for (int i = 0; i < children.length; ++i) { + sum += children[i].execute(frame); + } + return sum; + } + } + + class TestArgumentNode extends Node { + private final int index; + + TestArgumentNode(int index) { + this.index = index; + } + + int execute(VirtualFrame frame) { + return ((TestArguments) frame.getArguments()).values[index]; + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/CallTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + + +/** + *

Calling Another Tree

+ * + *

+ * A guest language implementation can create multiple call targets using the {@link TruffleRuntime#createCallTarget(RootNode)} method. + * Those call targets can be passed around as normal Java objects and used for calling guest language methods. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ArgumentsTest}. + *

+ */ +public class CallTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + CallTarget foo = runtime.createCallTarget(new ConstantRootNode(20)); + CallTarget bar = runtime.createCallTarget(new ConstantRootNode(22)); + CallTarget main = runtime.createCallTarget(new DualCallNode(foo, bar)); + Object result = main.call(); + Assert.assertEquals(42, result); + } + + class DualCallNode extends RootNode { + + private final CallTarget firstTarget; + private final CallTarget secondTarget; + + DualCallNode(CallTarget firstTarget, CallTarget secondTarget) { + this.firstTarget = firstTarget; + this.secondTarget = secondTarget; + } + + @Override + public Object execute(VirtualFrame frame) { + return ((Integer) firstTarget.call()) + ((Integer) secondTarget.call()); + } + } + + class ConstantRootNode extends RootNode { + private final int value; + + public ConstantRootNode(int value) { + this.value = value; + } + + @Override + public Object execute(VirtualFrame frame) { + return value; + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node.Child; + +/** + *

Creating a Child Node

+ * + *

+ * Child nodes are stored in the class of the parent node in fields that are marked with the {@link Child} annotation. + * Before such a field is assigned, {@link Node#adoptChild} must be called. This method automatically establishes a link + * from the child to the parent. The {@link Node#getParent()} method allows access to this field. Every node also + * provides the ability to iterate over its children using {@link Node#getChildren()}.

+ * + *

A child node field must be declared private and non-final. It may only be assigned in the constructor of the parent + * node. For changing the structure of the tree at run time, the method {@link Node#replace(Node)} must be used (see + * {@link ReplaceTest}). + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ChildrenNodesTest}. + *

+ */ +public class ChildNodeTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestChildNode leftChild = new TestChildNode(); + TestChildNode rightChild = new TestChildNode(); + TestRootNode rootNode = new TestRootNode(leftChild, rightChild); + Assert.assertEquals(rootNode, leftChild.getParent()); + Assert.assertEquals(rootNode, rightChild.getParent()); + Iterator iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(leftChild, iterator.next()); + Assert.assertEquals(rightChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(); + Assert.assertEquals(42, result); + } + + class TestRootNode extends RootNode { + + @Child private TestChildNode left; + @Child private TestChildNode right; + + public TestRootNode(TestChildNode left, TestChildNode right) { + this.left = adoptChild(left); + this.right = adoptChild(right); + } + + @Override + public Object execute(VirtualFrame frame) { + return left.execute() + right.execute(); + } + } + + class TestChildNode extends Node { + + public int execute() { + return 21; + } + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + *

Creating an Array of Children Nodes

+ * + *

+ * An array of children nodes can be used as a field in a parent node. The field has to be annotated with + * {@link com.oracle.truffle.api.nodes.Node.Children} and must be declared private and final. Before assigning the field + * in the parent node constructor, {@link Node#adoptChildren} must be called in order to update the parent pointers in + * the child nodes. After filling the array with its first values, it must never be changed. It is only possible to call + * {@link Node#replace} on a child node. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.FinalFieldTest}. + *

+ */ +public class ChildrenNodesTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestChildNode firstChild = new TestChildNode(); + TestChildNode secondChild = new TestChildNode(); + TestRootNode rootNode = new TestRootNode(new TestChildNode[]{firstChild, secondChild}); + Assert.assertEquals(rootNode, firstChild.getParent()); + Assert.assertEquals(rootNode, secondChild.getParent()); + Iterator iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(firstChild, iterator.next()); + Assert.assertEquals(secondChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(); + Assert.assertEquals(42, result); + } + + class TestRootNode extends RootNode { + + @Children private final TestChildNode[] children; + + public TestRootNode(TestChildNode[] children) { + this.children = adoptChildren(children); + } + + @Override + public Object execute(VirtualFrame frame) { + int sum = 0; + for (int i = 0; i < children.length; ++i) { + sum += children[i].execute(); + } + return sum; + } + } + + class TestChildNode extends Node { + public int execute() { + return 21; + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FinalFieldTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + *

Using Final Fields in Node Classes

+ * + *

+ * The usage of final fields in node classes is highly encouraged. It is beneficial for performance to declare every + * field that is not pointing to a child node as final. This gives the Truffle runtime an increased opportunity to + * optimize this node. + *

+ * + *

+ * If a node has a value which may change at run time, but will rarely do so, it is recommended to speculate on the + * field being final. This involves starting executing with a node where this field is final and only if this + * turns out to be no longer the case, the node is replaced with an alternative implementation of the operation (see + * {@link ReplaceTest}). + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ReplaceTest}. + *

+ */ +public class FinalFieldTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestRootNode rootNode = new TestRootNode(new TestChildNode[]{new TestChildNode(20), new TestChildNode(22)}); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(); + Assert.assertEquals(42, result); + } + + class TestRootNode extends RootNode { + + @Children TestChildNode[] children; + + public TestRootNode(TestChildNode[] children) { + this.children = adoptChildren(children); + } + + @Override + public Object execute(VirtualFrame frame) { + int sum = 0; + for (int i = 0; i < children.length; ++i) { + sum += children[i].execute(); + } + return sum; + } + } + + class TestChildNode extends Node { + private final int value; + + public TestChildNode(int value) { + this.value = value; + } + + public int execute() { + return value; + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameSlotTypeSpecializationTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + + +/** + *

Specializing Frame Slot Types

+ * + *

+ * Dynamically typed languages can speculate on the type of a frame slot and only fall back at run time to a more + * generic type if necessary. The new type of a frame slot can be set using the {@link FrameSlot#setType(Class)} method. + * It is the responsibility of the language implementor to update the content of currently active frames (using + * {@link Frame#updateToLatestVersion()}). Also, nodes that depend a specific type of a frame slot must be replaced. + * Such node can register a listener that implements {@link FrameSlotTypeListener} using + * {@link FrameSlot#registerOneShotTypeListener(FrameSlotTypeListener)}. The event of a type change on the frame slot + * will fire only once for the next upcoming change. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}. + *

+ */ +public class FrameSlotTypeSpecializationTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + FrameDescriptor frameDescriptor = new FrameDescriptor(); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); + CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); + Assert.assertEquals(Integer.class, slot.getType()); + Object result = target.call(); + Assert.assertEquals("42", result); + Assert.assertEquals(Object.class, slot.getType()); + } + + class TestRootNode extends RootNode { + + @Child TestChildNode left; + @Child TestChildNode right; + + public TestRootNode(TestChildNode left, TestChildNode right) { + this.left = adoptChild(left); + this.right = adoptChild(right); + } + + @Override + public Object execute(VirtualFrame frame) { + left.execute(frame); + return right.execute(frame); + } + } + + abstract class TestChildNode extends Node { + abstract Object execute(VirtualFrame frame); + } + + abstract class FrameSlotNode extends TestChildNode { + protected final FrameSlot slot; + + public FrameSlotNode(FrameSlot slot) { + this.slot = slot; + } + } + + class StringTestChildNode extends TestChildNode { + + @Override + Object execute(VirtualFrame frame) { + return "42"; + } + + } + + class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener { + @Child private TestChildNode value; + + IntAssignLocal(FrameSlot slot, TestChildNode value) { + super(slot); + this.value = adoptChild(value); + slot.registerOneShotTypeListener(this); + } + + @Override + Object execute(VirtualFrame frame) { + Object o = value.execute(frame); + if (o instanceof Integer) { + frame.setInt(slot, (Integer) o); + } else { + slot.setType(Object.class); + frame.updateToLatestVersion(); + frame.setObject(slot, o); + } + return null; + } + + @Override + public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) { + if (changedSlot.getType() == Object.class) { + this.replace(new ObjectAssignLocal(changedSlot, value)); + } + } + } + + class ObjectAssignLocal extends FrameSlotNode { + @Child private TestChildNode value; + + ObjectAssignLocal(FrameSlot slot, TestChildNode value) { + super(slot); + this.value = adoptChild(value); + } + + @Override + Object execute(VirtualFrame frame) { + Object o = value.execute(frame); + frame.setObject(slot, o); + return null; + } + } + + class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener { + IntReadLocal(FrameSlot slot) { + super(slot); + slot.registerOneShotTypeListener(this); + } + + @Override + Object execute(VirtualFrame frame) { + return frame.getInt(slot); + } + + @Override + public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) { + if (changedSlot.getType() == Object.class) { + this.replace(new ObjectReadLocal(changedSlot)); + } + } + } + + class ObjectReadLocal extends FrameSlotNode { + ObjectReadLocal(FrameSlot slot) { + super(slot); + } + + @Override + Object execute(VirtualFrame frame) { + return frame.getObject(slot); + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/FrameTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + *

Storing Values in Frame Slots

+ * + *

+ * The frame is the preferred data structure for passing values between nodes. It can in particular be used for storing + * the values of local variables of the guest language. The {@link FrameDescriptor} represents the current structure of + * the frame. The method {@link FrameDescriptor#addFrameSlot(String, Class)} can be used to create predefined frame + * slots. The setter and getter methods in the {@link Frame} class can be used to access the current value of a + * particular frame slot. + *

+ * + *

+ * There are five primitive types for slots available: {@link java.lang.Boolean}, @{link java.lang.Integer}, + * {@link java.lang.Long}, {@link java.lang.Float}, and {@link java.lang.Double}. It is encouraged to use those types + * whenever possible. Dynamically typed languages can speculate on the type of a value fitting into a primitive (see + * {@link FrameSlotTypeSpecializationTest}). When a frame slot is of one of those particular primitive types, its value + * may only be accessed with the repectively typed getter method ({@link Frame#getBoolean}, {@link Frame#getInt}, + * {@link Frame#getLong}, {@link Frame#getFloat}, or {@link Frame#getDouble}) or setter method ({@link Frame#setBoolean}, + * {@link Frame#setInt}, {@link Frame#setLong}, {@link Frame#setFloat}, or {@link Frame#setDouble}) in the + * {@link Frame} class. + *

+ * + *

+ * The next part of the Truffle API introduction is at + * {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}. + *

+ */ +public class FrameTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + FrameDescriptor frameDescriptor = new FrameDescriptor(); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + TestRootNode rootNode = new TestRootNode(new AssignLocal(slot), new ReadLocal(slot)); + CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); + Object result = target.call(); + Assert.assertEquals(42, result); + } + + class TestRootNode extends RootNode { + + @Child TestChildNode left; + @Child TestChildNode right; + + public TestRootNode(TestChildNode left, TestChildNode right) { + this.left = adoptChild(left); + this.right = adoptChild(right); + } + + @Override + public Object execute(VirtualFrame frame) { + return left.execute(frame) + right.execute(frame); + } + } + + abstract class TestChildNode extends Node { + abstract int execute(VirtualFrame frame); + } + + abstract class FrameSlotNode extends TestChildNode { + protected final FrameSlot slot; + + public FrameSlotNode(FrameSlot slot) { + this.slot = slot; + } + } + + class AssignLocal extends FrameSlotNode { + AssignLocal(FrameSlot slot) { + super(slot); + } + + @Override + int execute(VirtualFrame frame) { + frame.setInt(slot, 42); + return 0; + } + } + + class ReadLocal extends FrameSlotNode { + ReadLocal(FrameSlot slot) { + super(slot); + } + + @Override + int execute(VirtualFrame frame) { + return frame.getInt(slot); + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import static org.junit.Assert.*; + +import java.util.*; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + + +/** + *

Replacing Nodes at Run Time

+ * + *

+ * The structure of the Truffle tree can be changed at run time by replacing nodes using the {@link Node#replace(Node)} + * method. This method will automatically change the child pointer in the parent of the node and replace it with a + * pointer to the new node. + *

+ * + *

+ * Replacing nodes is a costly operation, so it should not happen too often. The convention is that the implementation + * of the Truffle nodes should ensure that there are maximal a small (and constant) number of node replacements per + * Truffle node. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.CallTest}. + *

+ */ +public class ReplaceTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + UnresolvedNode leftChild = new UnresolvedNode("20"); + UnresolvedNode rightChild = new UnresolvedNode("22"); + TestRootNode rootNode = new TestRootNode(new ValueNode[]{leftChild, rightChild}); + assertEquals(rootNode, leftChild.getParent()); + assertEquals(rootNode, rightChild.getParent()); + Iterator iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(leftChild, iterator.next()); + Assert.assertEquals(rightChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(); + assertEquals(42, result); + assertEquals(42, target.call()); + iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(ResolvedNode.class, iterator.next().getClass()); + Assert.assertEquals(ResolvedNode.class, iterator.next().getClass()); + Assert.assertFalse(iterator.hasNext()); + iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(rootNode, iterator.next().getParent()); + Assert.assertEquals(rootNode, iterator.next().getParent()); + Assert.assertFalse(iterator.hasNext()); + } + + class TestRootNode extends RootNode { + + @Children private ValueNode[] children; + + public TestRootNode(ValueNode[] children) { + this.children = adoptChildren(children); + } + + @Override + public Object execute(VirtualFrame frame) { + int sum = 0; + for (int i = 0; i < children.length; ++i) { + sum += children[i].execute(); + } + return sum; + } + } + + abstract class ValueNode extends Node { + abstract int execute(); + } + + class UnresolvedNode extends ValueNode { + private final String value; + + public UnresolvedNode(String value) { + this.value = value; + } + + @Override + int execute() { + int intValue = Integer.parseInt(value); + ResolvedNode newNode = this.replace(new ResolvedNode(intValue)); + return newNode.execute(); + } + } + + class ResolvedNode extends ValueNode { + private final int value; + + ResolvedNode(int value) { + this.value = value; + } + + @Override + int execute() { + return value; + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + *

Specializing Return Types

+ * + *

+ * In order to avoid boxing and/or type casts on the return value of a node, the return value the method for executing a + * node can have a specific type and need not be of type {@link java.lang.Object}. For dynamically typed languages, this + * return type is something that should be speculated on. When the speculation fails and the child node cannot return + * the appropriate type of value, it can use an {@link UnexpectedResultException} to still pass the result to the + * caller. In such a case, the caller must rewrite itself to a more general version in oder to avoid future failures of + * this kind. + *

+ */ +public class ReturnTypeSpecializationTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + FrameDescriptor frameDescriptor = new FrameDescriptor(); + FrameSlot slot = frameDescriptor.addFrameSlot("localVar", Integer.class); + TestRootNode rootNode = new TestRootNode(new IntAssignLocal(slot, new StringTestChildNode()), new IntReadLocal(slot)); + CallTarget target = runtime.createCallTarget(rootNode, frameDescriptor); + Assert.assertEquals(Integer.class, slot.getType()); + Object result = target.call(); + Assert.assertEquals("42", result); + Assert.assertEquals(Object.class, slot.getType()); + } + + class TestRootNode extends RootNode { + + @Child TestChildNode left; + @Child TestChildNode right; + + public TestRootNode(TestChildNode left, TestChildNode right) { + this.left = adoptChild(left); + this.right = adoptChild(right); + } + + @Override + public Object execute(VirtualFrame frame) { + left.execute(frame); + return right.execute(frame); + } + } + + abstract class TestChildNode extends Node { + abstract Object execute(VirtualFrame frame); + + int executeInt(VirtualFrame frame) throws UnexpectedResultException { + Object result = execute(frame); + if (result instanceof Integer) { + return (Integer) result; + } + throw new UnexpectedResultException(result); + } + } + + abstract class FrameSlotNode extends TestChildNode { + protected final FrameSlot slot; + + public FrameSlotNode(FrameSlot slot) { + this.slot = slot; + } + } + + class StringTestChildNode extends TestChildNode { + + @Override + Object execute(VirtualFrame frame) { + return "42"; + } + + } + + class IntAssignLocal extends FrameSlotNode implements FrameSlotTypeListener { + @Child private TestChildNode value; + + IntAssignLocal(FrameSlot slot, TestChildNode value) { + super(slot); + this.value = adoptChild(value); + slot.registerOneShotTypeListener(this); + } + + @Override + Object execute(VirtualFrame frame) { + try { + frame.setInt(slot, value.executeInt(frame)); + } catch (UnexpectedResultException e) { + slot.setType(Object.class); + frame.updateToLatestVersion(); + frame.setObject(slot, e.getResult()); + } + return null; + } + + @Override + public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) { + if (changedSlot.getType() == Object.class) { + this.replace(new ObjectAssignLocal(changedSlot, value)); + } + } + } + + class ObjectAssignLocal extends FrameSlotNode { + @Child private TestChildNode value; + + ObjectAssignLocal(FrameSlot slot, TestChildNode value) { + super(slot); + this.value = adoptChild(value); + } + + @Override + Object execute(VirtualFrame frame) { + Object o = value.execute(frame); + frame.setObject(slot, o); + return null; + } + } + + class IntReadLocal extends FrameSlotNode implements FrameSlotTypeListener { + IntReadLocal(FrameSlot slot) { + super(slot); + slot.registerOneShotTypeListener(this); + } + + @Override + Object execute(VirtualFrame frame) { + return executeInt(frame); + } + + @Override + int executeInt(VirtualFrame frame) { + return frame.getInt(slot); + } + + @Override + public void typeChanged(FrameSlot changedSlot, Class< ? > oldType) { + if (changedSlot.getType() == Object.class) { + this.replace(new ObjectReadLocal(changedSlot)); + } + } + } + + class ObjectReadLocal extends FrameSlotNode { + ObjectReadLocal(FrameSlot slot) { + super(slot); + } + + @Override + Object execute(VirtualFrame frame) { + return frame.getObject(slot); + } + } +} + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/RootNodeTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + *

Creating a Root Node

+ * + *

+ * A Truffle root node is the entry point into a Truffle tree that represents a guest language method. It contains a + * {@link RootNode#execute(VirtualFrame)} method that can return a {@link java.lang.Object} value as the result of the + * guest language method invocation. This method must however never be called directly. Instead, the Truffle runtime + * must be used to create a {@link CallTarget} object from a root node using the + * {@link TruffleRuntime#createCallTarget(RootNode)} method. This call target object can then be executed using the + * {@link CallTarget#call()} method or one of its overloads. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.ChildNodeTest}. + *

+ */ +public class RootNodeTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestRootNode rootNode = new TestRootNode(); + CallTarget target = runtime.createCallTarget(rootNode); + Object result = target.call(); + Assert.assertEquals(42, result); + } + + class TestRootNode extends RootNode { + + @Override + public Object execute(VirtualFrame frame) { + return 42; + } + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import org.junit.*; + +import com.oracle.truffle.api.*; + +/** + *

Accessing the Truffle Runtime

+ * + *

+ * The Truffle runtime can be accessed at any point in time globally using the static method + * {@link Truffle#getRuntime()}. This method is guaranteed to return a non-null Truffle runtime object with an + * identifying name. A Java Virtual Machine implementation can chose to replace the default implementation of the + * {@link TruffleRuntime} interface with its own implementation for providing improved performance. + *

+ * + *

+ * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.RootNodeTest}. + *

+ */ +public class TruffleRuntimeTest { + + @Test + public void test() { + TruffleRuntime runtime = Truffle.getRuntime(); + Assert.assertNotNull(runtime); + Assert.assertNotNull(runtime.getName()); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/package-info.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ +/** + *

This package contains basic tests of the Truffle API and serves at the same + * time as an introduction to the Truffle API for language implementors. Every test gives an example on how to use the construct explained in the class description.

+ * + *

+ * Truffle is a language implementation framework. A guest language method is represented as a tree of executable nodes. + * The framework provides mechanisms for those trees to call each other. Additionally it contains dedicated data structures for storing data local to a tree invocation. + *

+ * + *

+ * This introduction to Truffle contains items in the following recommended order: + * + *

    + *
  • How to get access to the Truffle runtime? {@link com.oracle.truffle.api.test.TruffleRuntimeTest}
  • + *
  • How to create a root node? {@link com.oracle.truffle.api.test.RootNodeTest}
  • + *
  • How to create a child node and link it with its parent? {@link com.oracle.truffle.api.test.ChildNodeTest}
  • + *
  • How to create an array of child nodes? {@link com.oracle.truffle.api.test.ChildrenNodesTest}
  • + *
  • Why are final fields in node classes important? {@link com.oracle.truffle.api.test.FinalFieldTest}
  • + *
  • How to replace one node with another node and what for? {@link com.oracle.truffle.api.test.ReplaceTest}
  • + *
  • How to let one Truffle tree invoke another one? {@link com.oracle.truffle.api.test.CallTest}
  • + *
  • How to pass arguments when executing a tree? {@link com.oracle.truffle.api.test.ArgumentsTest}
  • + *
  • How to use frames and frame slots to store values local to an activation? {@link com.oracle.truffle.api.test.FrameTest}
  • + *
  • How to use type specialization and speculation for frame slots? {@link com.oracle.truffle.api.test.FrameSlotTypeSpecializationTest}
  • + *
  • How to use type specialization and speculation for node return values? {@link com.oracle.truffle.api.test.ReturnTypeSpecializationTest}
  • + *
+ * + *

+ * + */ +package com.oracle.truffle.api.test; + + diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Arguments.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Arguments.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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; + +/** + * Base class for arguments passed to guest language methods via the + * {@link CallTarget#call(com.oracle.truffle.api.frame.PackedFrame, Arguments)} method. A guest language create a + * subclass with immutable fields representing the arguments passed to a guest language method. The {@link Arguments} + * object must be created immediately before a method call and it must not be stored in a field or cast to + * {@link java.lang.Object}. + */ +public class Arguments { + + /** + * Constant that can be used as an argument to + * {@link CallTarget#call(com.oracle.truffle.api.frame.PackedFrame, Arguments)} in case no arguments should be + * supplied. + */ + public static final Arguments EMPTY_ARGUMENTS = new Arguments(); + + /** + * Constructs an empty {@link Arguments} instance. Guest languages should create a subclass to specify their own arguments. + */ + protected Arguments() { + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CallTarget.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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; + +import com.oracle.truffle.api.frame.*; + +/** + * Represents the target of a call. Instances of this interface can be created using the + * {@link TruffleRuntime#createCallTarget(com.oracle.truffle.api.nodes.RootNode, FrameDescriptor)} method. + */ +public abstract class CallTarget { + + /** + * Calls this target as a root method and without arguments. + * @return the return result of the call + */ + public final Object call() { + return call(null, Arguments.EMPTY_ARGUMENTS); + } + + /** + * Calls this target with a caller frame and no arguments. + * @param caller the caller frame + * @return the return result of the call + */ + public final Object call(PackedFrame caller) { + return call(caller, Arguments.EMPTY_ARGUMENTS); + } + + /** + * Calls this target as a root method passing arguments. + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public final Object call(Arguments arguments) { + return call(null, arguments); + } + + /** + * Calls this target passing a caller frame and arguments. + * @param caller the caller frame + * @param arguments the arguments that should be passed to the callee + * @return the return result of the call + */ + public abstract Object call(PackedFrame caller, Arguments arguments); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/Truffle.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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; + +import com.oracle.truffle.api.impl.*; + +/** + * Class for obtaining the Truffle runtime singleton object of this virtual machine. + */ +public class Truffle { + + private static TruffleRuntime runtime; + + private static native TruffleRuntime initializeRuntime(); + + public static TruffleRuntime getRuntime() { + return runtime; + } + + static { + try { + runtime = initializeRuntime(); + } catch (UnsatisfiedLinkError e) { + runtime = new DefaultTruffleRuntime(); + } + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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; + +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Interface representing a Truffle runtime object. The runtime is responsible for creating call targets and performing optimizations for them. + */ +public interface TruffleRuntime { + /** + * Name describing this runtime implementation for debugging purposes. + * @return the name as a String + */ + String getName(); + + /** + * Creates a new call target for a given root node. + * @param rootNode the root node whose {@link RootNode#execute(com.oracle.truffle.api.frame.VirtualFrame)} method represents the entry point + * @return the new call target object + */ + CallTarget createCallTarget(RootNode rootNode); + + /** + * Creates a new call target for a given root node and a given frame descriptor. + * @param rootNode the root node whose {@link RootNode#execute(com.oracle.truffle.api.frame.VirtualFrame)} method represents the entry point + * @param frameDescriptor the descriptor used for creating a new frame at each invocation + * @return the new call target object + */ + CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/DefaultTypeConversion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/DefaultTypeConversion.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Default type conversion semantics where a conversion is without changing any data. + */ +public final class DefaultTypeConversion implements TypeConversion { + + private static DefaultTypeConversion instance = new DefaultTypeConversion(); + + public static TypeConversion getInstance() { + return instance; + } + + private DefaultTypeConversion() { + + } + + @Override + public Class< ? > getTopType() { + return Object.class; + } + + @Override + public Object convertTo(Class< ? > targetType, Object value) { + return value; + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +import com.oracle.truffle.api.*; + +/** + * Represents a frame containing values of local variables of the guest language. Instances of this type must not be + * stored in a field or cast to {@link java.lang.Object}. + */ +public interface Frame { + + /** + * @return the arguments used when calling this method + */ + Arguments getArguments(); + + /** + * Read access to a local variable of type {@link Object}. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + Object getObject(FrameSlot slot); + + /** + * Write access to a local variable of type {@link Object}. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setObject(FrameSlot slot, Object value); + + /** + * Read access to a local variable of type boolean. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + boolean getBoolean(FrameSlot slot); + + /** + * Write access to a local variable of type boolean. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setBoolean(FrameSlot slot, boolean value); + + /** + * Read access to a local variable of type int. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + int getInt(FrameSlot slot); + + /** + * Write access to a local variable of type int. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setInt(FrameSlot slot, int value); + + /** + * Read access to a local variable of type long. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + long getLong(FrameSlot slot); + + /** + * Write access to a local variable of type long. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setLong(FrameSlot slot, long value); + + /** + * Read access to a local variable of type float. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + float getFloat(FrameSlot slot); + + /** + * Write access to a local variable of type float. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setFloat(FrameSlot slot, float value); + + /** + * Read access to a local variable of type double. + * + * @param slot the slot of the local variable + * @return the current value of the local variable + */ + double getDouble(FrameSlot slot); + + /** + * Write access to a local variable of type double. + * + * @param slot the slot of the local variable + * @param value the new value of the local variable + */ + void setDouble(FrameSlot slot, double value); + + void updateToLatestVersion(); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameDescriptor.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +import java.util.*; + +/** + * Descriptor of the slots of frame objects. Multiple frame instances are associated with one such descriptor. + */ +public final class FrameDescriptor { + + protected final TypeConversion typeConversion; + private final ArrayList slots; + private FrameVersionImpl lastVersion; + private final HashMap nameToSlotMap; + + public FrameDescriptor() { + this(DefaultTypeConversion.getInstance()); + } + + public FrameDescriptor(TypeConversion typeConversion) { + this.typeConversion = typeConversion; + slots = new ArrayList<>(); + nameToSlotMap = new HashMap<>(); + lastVersion = new FrameVersionImpl(); + } + + public FrameSlot addFrameSlot(String name) { + return addFrameSlot(name, typeConversion.getTopType()); + } + + public FrameSlot addFrameSlot(String name, Class type) { + assert !nameToSlotMap.containsKey(name); + FrameSlotImpl slot = new FrameSlotImpl(this, name, slots.size(), type); + slots.add(slot); + nameToSlotMap.put(name, slot); + return slot; + } + + public FrameSlot findFrameSlot(String name) { + return nameToSlotMap.get(name); + } + + public FrameSlot findOrAddFrameSlot(String name) { + FrameSlot result = findFrameSlot(name); + if (result != null) { + return result; + } + return addFrameSlot(name); + } + + public FrameVersion getCurrentVersion() { + return lastVersion; + } + + public int getSize() { + return slots.size(); + } + + public List< ? extends FrameSlot> getSlots() { + return Collections.unmodifiableList(slots); + } + + protected void appendVersion(FrameVersionImpl newVersion) { + lastVersion.next = newVersion; + lastVersion = newVersion; + } +} + +class FrameVersionImpl implements FrameVersion { + + protected FrameVersionImpl next; + + @Override + public final FrameVersion getNext() { + return next; + } +} + +class TypeChangeFrameVersionImpl extends FrameVersionImpl implements FrameVersion.TypeChange { + + private final FrameSlotImpl slot; + private final Class< ? > oldType; + private final Class< ? > newType; + + protected TypeChangeFrameVersionImpl(FrameSlotImpl slot, Class< ? > oldType, Class< ? > newType) { + this.slot = slot; + this.oldType = oldType; + this.newType = newType; + } + + @Override + public final void applyTransformation(Frame frame) { + Object value = slot.getValue(oldType, frame); + slot.setValue(newType, frame, value); + } +} + +class FrameSlotImpl implements FrameSlot { + + private final FrameDescriptor descriptor; + private final String name; + private final int index; + private Class< ? > type; + private ArrayList listeners; + + protected FrameSlotImpl(FrameDescriptor descriptor, String name, int index, Class< ? > type) { + this.descriptor = descriptor; + this.name = name; + this.index = index; + this.type = type; + assert type != null; + } + + public String getName() { + return name; + } + + public int getIndex() { + return index; + } + + public Class< ? > getType() { + return type; + } + + protected Object getValue(Class< ? > accessType, Frame frame) { + if (accessType == Integer.class) { + return frame.getInt(this); + } else if (accessType == Long.class) { + return frame.getLong(this); + } else if (accessType == Float.class) { + return frame.getFloat(this); + } else if (accessType == Double.class) { + return frame.getDouble(this); + } else { + return frame.getObject(this); + } + } + + protected void setValue(Class< ? > accessType, Frame frame, Object value) { + Object newValue = descriptor.typeConversion.convertTo(accessType, value); + if (accessType == Integer.class) { + frame.setInt(this, (Integer) newValue); + } else if (accessType == Long.class) { + frame.setLong(this, (Long) newValue); + } else if (accessType == Float.class) { + frame.setFloat(this, (Float) newValue); + } else if (accessType == Double.class) { + frame.setDouble(this, (Double) newValue); + } else { + frame.setObject(this, newValue); + } + } + + public void setType(final Class< ? > type) { + final Class< ? > oldType = this.type; + this.type = type; + ArrayList oldListeners = this.listeners; + this.listeners = null; + if (oldListeners != null) { + for (FrameSlotTypeListener listener : oldListeners) { + listener.typeChanged(this, oldType); + } + } + descriptor.appendVersion(new TypeChangeFrameVersionImpl(this, oldType, type)); + } + + @Override + public String toString() { + return "[" + index + "," + name + "]"; + } + + @Override + public void registerOneShotTypeListener(FrameSlotTypeListener listener) { + if (listeners == null) { + listeners = new ArrayList<>(); + } + listeners.add(listener); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlot.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * A slot in a frame that can store a value of a given type. + */ +public interface FrameSlot { + String getName(); + int getIndex(); + Class< ? > getType(); + void setType(Class< ? > type); + void registerOneShotTypeListener(FrameSlotTypeListener listener); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotTypeListener.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Listener for the event of a type change of a frame slot. + */ +public interface FrameSlotTypeListener { + void typeChanged(FrameSlot slot, Class< ? > oldType); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameVersion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameVersion.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Represents a specific version of a frame. + */ +public interface FrameVersion { + + FrameVersion getNext(); + + public interface Resize { + + int getNewSize(); + } + + public interface TypeChange { + + void applyTransformation(Frame frame); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/MaterializedFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Represents a materialized frame containing values of local variables of the guest language. It can be created using + * the {@link VirtualFrame#materialize()} method. Instances of this type are the only frame instances that may be stored + * in fields or cast to {@link java.lang.Object}. In contrast to a {@link VirtualFrame}, a {@link MaterializedFrame} can + * no longer be packed and it also does not provide access to the caller frame. + */ +public interface MaterializedFrame extends Frame { +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +import com.oracle.truffle.api.*; + +/** + * Represents a native frame without any local variables. Instances of this type must not be stored in a field or cast + * to {@link java.lang.Object}. + */ +public class NativeFrame implements VirtualFrame, PackedFrame { + + private PackedFrame caller; + private Arguments arguments; + + public NativeFrame(PackedFrame caller, Arguments arguments) { + this.caller = caller; + this.arguments = arguments; + } + + @Override + public Arguments getArguments() { + return arguments; + } + + @Override + public Object getObject(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setObject(FrameSlot slot, Object value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public boolean getBoolean(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setBoolean(FrameSlot slot, boolean value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public int getInt(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setInt(FrameSlot slot, int value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public long getLong(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setLong(FrameSlot slot, long value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public float getFloat(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setFloat(FrameSlot slot, float value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public double getDouble(FrameSlot slot) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public void setDouble(FrameSlot slot, double value) { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public PackedFrame pack() { + return this; + } + + @Override + public PackedFrame getCaller() { + return caller; + } + + @Override + public MaterializedFrame materialize() { + throw new UnsupportedOperationException("native frame"); + } + + @Override + public VirtualFrame unpack() { + return this; + } + + @Override + public void updateToLatestVersion() { + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/PackedFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/PackedFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Represents a packed frame that represents a virtual frame. A packed frame instance can be retrieved with the + * {@link VirtualFrame#pack()} method. It can be converted back into a virtual frame using {@link PackedFrame#unpack()}. + * Instances of this type must not be stored in a field or cast to {@link java.lang.Object}. + */ +public interface PackedFrame { + + /** + * Unpacks this frame and converts it back to a virtual frame. + * @return the virtual frame that was the content of this packed frame + */ + VirtualFrame unpack(); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/TypeConversion.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/TypeConversion.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +/** + * Interface for defining type conversions for frame slot values. + */ +public interface TypeConversion { + Class getTopType(); + + Object convertTo(Class targetType, Object value); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/VirtualFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/VirtualFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.frame; + +import com.oracle.truffle.api.*; + +/** + * Represents a frame containing values of local variables of the guest language. Instances of this type must not be + * stored in a field or cast to {@link java.lang.Object}. If this is necessary, the frame must be explicitly converted + * into a materialized frame using the {@link VirtualFrame#materialize()} method. Whenever fast access to the local + * variables of a frame is no longer necessary, a virtual frame should be converted into a packed frame using the + * {@link VirtualFrame#pack()} method. + */ +public interface VirtualFrame extends Frame { + + /** + * Converts this virtual frame into a packed frame that has no longer direct access to the local variables. This + * packing is an important hint to the Truffle optimizer and therefore passing around a {@link PackedFrame} should + * be preferred over passing around a {@link VirtualFrame} when the probability that an unpacking will occur is low. + * + * @return the packed frame + */ + PackedFrame pack(); + + /** + * Accesses the caller frame passed in via {@link CallTarget#call}. To get full access, it must be first unpacked + * using {@link PackedFrame#unpack()}. + * + * @return the caller frame or null if this was a root method call + */ + PackedFrame getCaller(); + + /** + * Materializes this frame, which allows it to be stored in a field or cast to {@link java.lang.Object}. The frame + * however looses the ability to be packed or to access the caller frame. + * + * @return the new materialized frame + */ + MaterializedFrame materialize(); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +final class DefaultCallTarget extends CallTarget { + + protected final RootNode rootNode; + protected final FrameDescriptor frameDescriptor; + + DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) { + this.rootNode = function; + this.frameDescriptor = frameDescriptor; + } + + @Override + public String toString() { + return "DefaultCallTarget " + rootNode; + } + + @Override + public Object call(PackedFrame caller, Arguments args) { + VirtualFrame frame = new DefaultVirtualFrame(frameDescriptor, caller, args); + return rootNode.execute(frame); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; + +final class DefaultMaterializedFrame implements MaterializedFrame { + private final DefaultVirtualFrame wrapped; + + protected DefaultMaterializedFrame(DefaultVirtualFrame wrapped) { + this.wrapped = wrapped; + } + + @Override + public Arguments getArguments() { + return wrapped.getArguments(); + } + + @Override + public Object getObject(FrameSlot slot) { + return wrapped.getObject(slot); + } + + @Override + public void setObject(FrameSlot slot, Object value) { + wrapped.setObject(slot, value); + } + + @Override + public boolean getBoolean(FrameSlot slot) { + return wrapped.getBoolean(slot); + } + + @Override + public void setBoolean(FrameSlot slot, boolean value) { + wrapped.setBoolean(slot, value); + } + + @Override + public int getInt(FrameSlot slot) { + return wrapped.getInt(slot); + } + + @Override + public void setInt(FrameSlot slot, int value) { + wrapped.setInt(slot, value); + } + + @Override + public long getLong(FrameSlot slot) { + return wrapped.getLong(slot); + } + + @Override + public void setLong(FrameSlot slot, long value) { + wrapped.setLong(slot, value); + } + + @Override + public float getFloat(FrameSlot slot) { + return wrapped.getFloat(slot); + } + + @Override + public void setFloat(FrameSlot slot, float value) { + wrapped.setFloat(slot, value); + } + + @Override + public double getDouble(FrameSlot slot) { + return wrapped.getDouble(slot); + } + + @Override + public void setDouble(FrameSlot slot, double value) { + wrapped.setDouble(slot, value); + } + + @Override + public void updateToLatestVersion() { + wrapped.updateToLatestVersion(); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultPackedFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.impl; + +import com.oracle.truffle.api.frame.*; + +final class DefaultPackedFrame implements PackedFrame { + private final DefaultVirtualFrame wrapped; + + protected DefaultPackedFrame(DefaultVirtualFrame wrapped) { + this.wrapped = wrapped; + } + + @Override + public VirtualFrame unpack() { + return wrapped; + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.impl; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; +import com.oracle.truffle.api.nodes.*; + +/** + * Default implementation of the Truffle runtime if the virtual machine does not provide a better performing alternative. + */ +public final class DefaultTruffleRuntime implements TruffleRuntime { + + @Override + public String getName() { + return "Default Truffle Runtime"; + } + + @Override + public CallTarget createCallTarget(RootNode rootNode, FrameDescriptor frameDescriptor) { + return new DefaultCallTarget(rootNode, frameDescriptor); + } + + @Override + public CallTarget createCallTarget(RootNode rootNode) { + return createCallTarget(rootNode, new FrameDescriptor()); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.impl; + +import java.util.*; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; + +final class DefaultVirtualFrame implements VirtualFrame { + + private static final Object UNDEFINED_OBJECT = null; + private static final Boolean UNDEFINED_BOOLEAN = false; + private static final Integer UNDEFINED_INTEGER = 0; + private static final Float UNDEFINED_FLOAT = 0.0f; + private static final Long UNDEFINED_LONG = 0L; + private static final Double UNDEFINED_DOUBLE = 0.0d; + + private final FrameDescriptor descriptor; + private final PackedFrame caller; + private final Arguments arguments; + private FrameVersion currentVersion; + protected Object[] locals; + protected Class[] tags; + + DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) { + this.descriptor = descriptor; + this.caller = caller; + this.arguments = arguments; + this.currentVersion = descriptor.getCurrentVersion(); + this.locals = new Object[descriptor.getSize()]; + // The tags are only needed for assertion checking, so initialize the field only when assertions are enabled + assert (this.tags = new Class[descriptor.getSize()]) != null; + } + + @Override + public Arguments getArguments() { + return arguments; + } + + @Override + public PackedFrame getCaller() { + return caller; + } + + @Override + public PackedFrame pack() { + return new DefaultPackedFrame(this); + } + + @Override + public MaterializedFrame materialize() { + return new DefaultMaterializedFrame(this); + } + + @Override + public Object getObject(FrameSlot slot) { + return get(slot, Object.class, UNDEFINED_OBJECT); + } + + @Override + public void setObject(FrameSlot slot, Object value) { + set(slot, Object.class, value); + } + + @Override + public boolean getBoolean(FrameSlot slot) { + return (Boolean) get(slot, Float.class, UNDEFINED_BOOLEAN); + } + + @Override + public void setBoolean(FrameSlot slot, boolean value) { + set(slot, Float.class, value); + } + + @Override + public int getInt(FrameSlot slot) { + return (Integer) get(slot, Integer.class, UNDEFINED_INTEGER); + } + + @Override + public void setInt(FrameSlot slot, int value) { + set(slot, Integer.class, value); + } + + @Override + public long getLong(FrameSlot slot) { + return (Long) get(slot, Long.class, UNDEFINED_LONG); + } + + @Override + public void setLong(FrameSlot slot, long value) { + set(slot, Long.class, value); + } + + @Override + public float getFloat(FrameSlot slot) { + return (Float) get(slot, Float.class, UNDEFINED_FLOAT); + } + + @Override + public void setFloat(FrameSlot slot, float value) { + set(slot, Float.class, value); + } + + @Override + public double getDouble(FrameSlot slot) { + return (Double) get(slot, Double.class, UNDEFINED_DOUBLE); + } + + @Override + public void setDouble(FrameSlot slot, double value) { + set(slot, Double.class, value); + } + + private Object get(FrameSlot slot, Class< ? > accessType, Object defaultValue) { + Object value = locals[slot.getIndex()]; + assert verifyGet(slot, accessType, value); + if (value == null) { + return defaultValue; + } else { + return value; + } + } + + private boolean verifyGet(FrameSlot slot, Class< ? > accessType, Object value) { + assert descriptor.getSlots().get(slot.getIndex()) == slot; + Class< ? > tag = tags[slot.getIndex()]; + if (value == null) { + assert tag == null || tag == Object.class; + } else { + assert tag == accessType : "Local variable " + slot + " was written with set" + tag.getSimpleName() + ", but is read with get" + accessType.getSimpleName(); + } + return true; + } + + private void set(FrameSlot slot, Class< ? > accessType, Object value) { + assert verifySet(slot, accessType, value); + locals[slot.getIndex()] = value; + } + + private boolean verifySet(FrameSlot slot, Class< ? > accessType, Object value) { + assert descriptor.getSlots().get(slot.getIndex()) == slot; + tags[slot.getIndex()] = accessType; + assert accessType.isAssignableFrom(slot.getType()) : "Local variable " + slot + ": " + accessType + " is not assignable from " + slot.getType(); + if (value == null) { + assert accessType == Object.class; + } else { + assert slot.getType().isAssignableFrom(value.getClass()) : "Local variable " + slot + ": " + slot.getType() + " is not assignable from " + value.getClass(); + } + return true; + } + + @Override + public void updateToLatestVersion() { + if (currentVersion.getNext() != null) { + doUpdateToLatestVersion(); + } + } + + private void doUpdateToLatestVersion() { + FrameVersion version = currentVersion; + while (version.getNext() != null) { + version = version.getNext(); + if (version instanceof FrameVersion.TypeChange) { + ((FrameVersion.TypeChange) version).applyTransformation(this); + } else if (version instanceof FrameVersion.Resize) { + int newSize = ((FrameVersion.Resize) version).getNewSize(); + locals = Arrays.copyOf(locals, newSize); + } + } + currentVersion = version; + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/ExactMath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/ExactMath.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.intrinsics; + +/** + * This class contains methods that will be part of java.lang.Math starting with JDK 8. Until JDK 8 is release, we + * duplicate them here because they are generally useful for dynamic language implementations. + */ +public class ExactMath { + + public static int addExact(int x, int y) { + int r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + public static long addExact(long x, long y) { + long r = x + y; + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("long overflow"); + } + return r; + } + + public static int subtractExact(int x, int y) { + int r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("integer overflow"); + } + return r; + } + + public static long subtractExact(long x, long y) { + long r = x - y; + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("long overflow"); + } + return r; + } + + public static int multiplyExact(int x, int y) { + long r = (long) x * (long) y; + if ((int) r != r) { + throw new ArithmeticException("long overflow"); + } + return (int) r; + } + + public static long multiplyExact(long x, long y) { + long r = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) || (x == Long.MIN_VALUE && y == -1)) { + throw new ArithmeticException("long overflow"); + } + } + return r; + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/TruffleIntrinsics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/intrinsics/TruffleIntrinsics.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.intrinsics; + +/** + * Predefined Truffle intrinsics that allow direct influence of the generated machine code. + */ +public final class TruffleIntrinsics { + + /** + * Specifies that the compiler should put a deoptimization point at this position that will continue execution in the interpreter. + * Should be used to cut off cold paths that should not be part of the compiled machine code. + */ + public static void deoptimize() { + } + + /** + * Checks whether the Thread has been interrupted in the interpreter in order to avoid endless loops. The compiled code may choose a more efficient implementation. + */ + public static void checkThreadInterrupted() { + if (Thread.currentThread().isInterrupted()) { + throw new RuntimeException("Timeout"); + } + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ExplodeLoop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ExplodeLoop.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import java.lang.annotation.*; + +/** + * Specifies for a method that the loops with constant number of invocations should be fully unrolled. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ExplodeLoop { +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/GraphPrintVisitor.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.net.*; +import java.util.*; + +import javax.xml.parsers.*; +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +import org.w3c.dom.*; + +/** + * Utility class for creating output for the ideal graph visualizer. + */ +public class GraphPrintVisitor { + + public static final String GraphVisualizerAddress = "127.0.0.1"; + public static final int GraphVisualizerPort = 4444; + + private Document dom; + private Map nodeMap; + private List edgeList; + private Map prevNodeMap; + private int id; + private Element graphDocument; + private Element groupElement; + private Element graphElement; + private Element nodesElement; + private Element edgesElement; + + public GraphPrintVisitor() { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + + dom = db.newDocument(); + } catch (ParserConfigurationException ex) { + System.out.println("Error while trying to instantiate DocumentBuilder " + ex); + } + + graphDocument = dom.createElement("graphDocument"); + dom.appendChild(graphDocument); + } + + public GraphPrintVisitor beginGroup(String groupName) { + groupElement = dom.createElement("group"); + graphDocument.appendChild(groupElement); + Element properties = dom.createElement("properties"); + groupElement.appendChild(properties); + + if (!groupName.isEmpty()) { + // set group name + Element propName = dom.createElement("p"); + propName.setAttribute("name", "name"); + propName.setTextContent(groupName); + properties.appendChild(propName); + } + + // forget old nodes + nodeMap = prevNodeMap = null; + edgeList = null; + + return this; + } + + public GraphPrintVisitor beginGraph(String graphName) { + if (null == groupElement) { + beginGroup(""); + } else if (null != prevNodeMap) { + // TODO: difference (create removeNode,removeEdge elements) + } + + graphElement = dom.createElement("graph"); + groupElement.appendChild(graphElement); + Element properties = dom.createElement("properties"); + graphElement.appendChild(properties); + nodesElement = dom.createElement("nodes"); + graphElement.appendChild(nodesElement); + edgesElement = dom.createElement("edges"); + graphElement.appendChild(edgesElement); + + // set graph name + Element propName = dom.createElement("p"); + propName.setAttribute("name", "name"); + propName.setTextContent(graphName); + properties.appendChild(propName); + + // save old nodes + prevNodeMap = nodeMap; + nodeMap = new HashMap<>(); + edgeList = new ArrayList<>(); + + return this; + } + + @Override + public String toString() { + if (null != dom) { + try { + Transformer tr = TransformerFactory.newInstance().newTransformer(); + tr.setOutputProperty(OutputKeys.INDENT, "yes"); + tr.setOutputProperty(OutputKeys.METHOD, "xml"); + tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + StringWriter strWriter = new StringWriter(); + tr.transform(new DOMSource(dom), new StreamResult(strWriter)); + return strWriter.toString(); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + return ""; + } + + public void printToFile(File f) { + try { + Transformer tr = TransformerFactory.newInstance().newTransformer(); + tr.setOutputProperty(OutputKeys.INDENT, "yes"); + tr.setOutputProperty(OutputKeys.METHOD, "xml"); + tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + tr.transform(new DOMSource(dom), new StreamResult(new FileOutputStream(f))); + } catch (TransformerException | FileNotFoundException e) { + e.printStackTrace(); + } + } + + public void printToSysout() { + try { + Transformer tr = TransformerFactory.newInstance().newTransformer(); + tr.setOutputProperty(OutputKeys.INDENT, "yes"); + tr.setOutputProperty(OutputKeys.METHOD, "xml"); + tr.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + tr.transform(new DOMSource(dom), new StreamResult(System.out)); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + + public void printToNetwork() { + try { + Transformer tr = TransformerFactory.newInstance().newTransformer(); + tr.setOutputProperty(OutputKeys.METHOD, "xml"); + + Socket socket = new Socket(GraphVisualizerAddress, GraphVisualizerPort); + BufferedOutputStream stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000); + tr.transform(new DOMSource(dom), new StreamResult(stream)); + } catch (TransformerException | IOException e) { + e.printStackTrace(); + } + } + + private String nextId() { + return String.valueOf(id++); + } + + private String oldOrNextId(Object node) { + if (null != prevNodeMap && prevNodeMap.containsKey(node)) { + Element nodeElem = prevNodeMap.get(node); + return nodeElem.getAttribute("id"); + } else { + return nextId(); + } + } + + protected Element getElementByObject(Object op) { + return nodeMap.get(op); + } + + protected void createElementForNode(Object node) { + boolean exists = nodeMap.containsKey(node); + if (!exists || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) { + Element nodeElem = dom.createElement("node"); + nodeElem.setAttribute("id", !exists ? oldOrNextId(node) : nextId()); + nodeMap.put(node, nodeElem); + Element properties = dom.createElement("properties"); + nodeElem.appendChild(properties); + nodesElement.appendChild(nodeElem); + + setNodeProperty(node, "name", node.getClass().getSimpleName().replaceFirst("Node$", "")); + NodeInfo nodeInfo = node.getClass().getAnnotation(NodeInfo.class); + if (nodeInfo != null && !nodeInfo.shortName().isEmpty()) { + setNodeProperty(node, "shortName", nodeInfo.shortName()); + } + setNodeProperty(node, "nodeType", (Node.class.isAssignableFrom(node.getClass()) ? Node.class.getSimpleName() : "other")); + setNodeProperty(node, "nodeClass", node.getClass().getSimpleName()); + copyDebugProperties(node); // TODO: may overwrite property "name"? (currently allowed) + readNodeProperties(node); + } + } + + private Element getPropertyElement(Object node, String propertyName) { + Element nodeElem = getElementByObject(node); + Element propertiesElem = (Element) nodeElem.getElementsByTagName("properties").item(0); + if (propertiesElem == null) { + return null; + } + + NodeList propList = propertiesElem.getElementsByTagName("p"); + for (int i = 0; i < propList.getLength(); i++) { + Element p = (Element) propList.item(i); + if (propertyName.equals(p.getAttribute("name"))) { + return p; + } + } + return null; + } + + protected void setNodeProperty(Object node, String propertyName, Object value) { + Element nodeElem = getElementByObject(node); + Element propElem = getPropertyElement(node, propertyName); // if property exists, replace its value + if (null == propElem) { // if property doesn't exist, create one + propElem = dom.createElement("p"); + propElem.setAttribute("name", propertyName); + nodeElem.getElementsByTagName("properties").item(0).appendChild(propElem); + } + propElem.setTextContent(String.valueOf(value)); + } + + private void copyDebugProperties(Object node) { + if (node instanceof Node) { + Map debugProperties = ((Node) node).getDebugProperties(); + for (Map.Entry property : debugProperties.entrySet()) { + setNodeProperty(node, property.getKey(), property.getValue()); + } + } + } + + private void readNodeProperties(Object node) { + Field[] fields = NodeUtil.getAllFields(node.getClass()); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + if (Node.class.isAssignableFrom(field.getType()) || (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType()))) { + continue; + } + String key = field.getName(); + if (field.getAnnotation(HiddenField.class) == null && getPropertyElement(node, key) == null) { + try { + field.setAccessible(true); + Object value = field.get(node); + setNodeProperty(node, key, value); + } catch (IllegalArgumentException | IllegalAccessException e) { + assert false : e; + } + } + } + } + + protected void connectNodes(Object a, Object b) { + if (nodeMap.get(a) == null || nodeMap.get(b) == null) { + return; + } + + String fromId = nodeMap.get(a).getAttribute("id"); + String toId = nodeMap.get(b).getAttribute("id"); + + // count existing to-edges + int count = 0; + for (Element e : edgeList) { + if (e.getAttribute("to").equals(toId)) { + ++count; + } + } + + Element edgeElem = dom.createElement("edge"); + edgeElem.setAttribute("from", fromId); + edgeElem.setAttribute("to", toId); + edgeElem.setAttribute("index", String.valueOf(count)); + edgesElement.appendChild(edgeElem); + edgeList.add(edgeElem); + } + + public GraphPrintVisitor visit(Object node) { + if (null == graphElement) { + beginGraph("truffle tree"); + } + + // if node is visited once again, skip + if (getElementByObject(node) == null || NodeUtil.findAnnotation(node.getClass(), GraphDuplicate.class) != null) { + visitAny(node); + } + + return this; + } + + private void visitAny(Object node) { + // respect node's custom handler + if (NodeUtil.findAnnotation(node.getClass(), NullGraphPrintHandler.class) != null) { + return; + } + if (NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class) != null) { + Class gpHandlerClass = NodeUtil.findAnnotation(node.getClass(), CustomGraphPrintHandler.class).handler(); + try { + GraphPrintHandler gpHandler = gpHandlerClass.newInstance(); + gpHandler.visit(node, new GraphPrintAdapter()); + } catch (InstantiationException e) { + assert false; + } catch (IllegalAccessException e) { + assert false; + } + return; + } + + // default handler + createElementForNode(node); + + List children = NodeUtil.findNodeChildren(node); + for (Object child : children) { + if (child == null) { + continue; + } else if (child instanceof Node) { + visit(child); + } else { + continue; + } + connectNodes(node, child); + } + } + + public class GraphPrintAdapter { + public void createElementForNode(Object node) { + GraphPrintVisitor.this.createElementForNode(node); + } + public void visit(Object node) { + GraphPrintVisitor.this.visit(node); + } + public void connectNodes(Object node, Object child) { + GraphPrintVisitor.this.connectNodes(node, child); + } + public void setNodeProperty(Object node, String propertyName, Object value) { + GraphPrintVisitor.this.setNodeProperty(node, propertyName, value); + } + } + + public interface GraphPrintHandler { + void visit(Object node, GraphPrintAdapter gPrinter); + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface CustomGraphPrintHandler { + Class handler(); + } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface NullGraphPrintHandler { + } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface GraphDuplicate { + } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.FIELD) + public @interface HiddenField { + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import java.lang.annotation.*; +import java.util.*; + +/** + * Abstract base class for all Truffle nodes. + */ +public abstract class Node implements Cloneable { + + /** + * Utility constant representing an empty node array. + */ + public static final Node[] EMPTY_ARRAY = new Node[0]; + + private Node parent; + + /** + * Marks array fields that are children of this node. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface Children { + } + + /** + * Marks fields that represent child nodes of this node. + */ + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.FIELD}) + public @interface Child { + } + + /** + * Method that updates the link to the parent in the array of specified new child nodes to this node. + * + * @param newChildren the array of new children whose parent should be updated + * @return the array of new children + */ + protected final T[] adoptChildren(T[] newChildren) { + if (newChildren != null) { + for (T n : newChildren) { + adoptChild(n); + } + } + return newChildren; + } + + /** + * Method that updates the link to the parent in the specified new child node to this node. + * + * @param newChild the new child whose parent should be updated + * @return the new child + */ + protected final T adoptChild(T newChild) { + if (newChild != null) { + ((Node) newChild).parent = this; + } + return newChild; + } + + /** + * Returns properties of this node interesting for debugging and can be overwritten by subclasses to add their own + * custom properties. + * + * @return the properties as a key/value hash map + */ + public Map getDebugProperties() { + Map properties = new HashMap<>(); + return properties; + } + + /** + * The current parent node of this node. + * + * @return the parent node + */ + public final Node getParent() { + return parent; + } + + /** + * Replaces one child of this node with another node. + * + * @param oldChild the old child + * @param newChild the new child that should replace the old child + * @return the new child + */ + public final T replaceChild(T oldChild, T newChild) { + NodeUtil.replaceChild(this, oldChild, newChild); + adoptChild(newChild); + return newChild; + } + + /** + * Replaces this node with another node. + * + * @param newNode the new node that is the replacement + * @param reason a description of the reason for the replacement + * @return the new node + */ + @SuppressWarnings({"unchecked"}) + public T replace(T newNode, String reason) { + assert this.getParent() != null; + return (T) this.getParent().replaceChild(this, newNode); + } + + /** + * Replaces this node with another node. + * + * @param newNode the new node that is the replacement + * @return the new node + */ + public T replace(T newNode) { + return replace(newNode, ""); + } + + /** + * Invokes the {@link NodeVisitor#visit(Node)} method for this node and recursively also for all child nodes. + * + * @param nodeVisitor the visitor + */ + public final void accept(NodeVisitor nodeVisitor) { + if (nodeVisitor.visit(this)) { + for (Node child : this.getChildren()) { + if (child != null) { + child.accept(nodeVisitor); + } + } + } + } + + /** + * Iterator over the children of this node. + * + * @return the iterator + */ + public final Iterable getChildren() { + final Node node = this; + return new Iterable() { + + public Iterator iterator() { + return new NodeUtil.NodeIterator(node); + } + }; + } + + /** + * Creates a shallow copy of this node. + * + * @return the new copy + */ + public Node copy() { + try { + return (Node) super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * This method must never be called. It enforces that {@link Object#clone} is not directly called by subclasses. + * Use the {@link #copy()} method instead. + */ + @Override + @Deprecated + protected final Object clone() throws CloneNotSupportedException { + throw new IllegalStateException("This method should never be called, use the copy method instead!"); + } + + /** + * Converts this node to a textual representation useful for debugging. + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(getClass().getSimpleName()); + Map properties = getDebugProperties(); + boolean hasProperties = false; + for (Map.Entry entry : properties.entrySet()) { + sb.append(hasProperties ? "," : "<"); + hasProperties = true; + sb.append(entry.getKey()).append("=").append(entry.getValue()); + } + if (hasProperties) { + sb.append(">"); + } + sb.append("@").append(Integer.toHexString(hashCode())); + return sb.toString(); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeInfo.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import java.lang.annotation.*; + +/** + * Annotation for providing additional information on nodes. + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface NodeInfo { + + /** + * Short name representing the node that can be used for debugging. + * @return the short name + */ + String shortName() default ""; +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,702 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import sun.misc.*; + +/** + * Utility class that manages the special access methods for node instances. + */ +public class NodeUtil { + + public static final class NodeClass { + + private final Class parentClass; + private final long[] nodeFieldOffsets; + private final Class[] nodeFieldClasses; + private final long[] nodeArrayFieldOffsets; + private final Class[] nodeArrayFieldClasses; + private final long parentOffset; + private final long[] nodeDataFieldOffsets; + private final Class< ? >[] nodeDataFieldClasses; + + private static final Map, NodeClass> nodeClasses = new IdentityHashMap<>(); + + public static NodeClass get(Class< ? > clazz) { + NodeClass nodeClass = nodeClasses.get(clazz); + if (nodeClass == null) { + nodeClass = new NodeClass(clazz); + nodeClasses.put(clazz, nodeClass); + } + return nodeClass; + } + + private NodeClass(Class< ? > clazz) { + // scan object fields + Class< ? > parentClassTmp = null; + List nodeFieldOffsetsList = new ArrayList<>(); + List> nodeFieldClassesList = new ArrayList<>(); + List nodeArrayFieldOffsetsList = new ArrayList<>(); + List> nodeArrayFieldClassesList = new ArrayList<>(); + List nodeDataFieldOffsetList = new ArrayList<>(); + List> nodeDataFieldClassList = new ArrayList<>(); + Field[] fields = getAllFields(clazz); + long parentOffsetTemp = -1; + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) { + continue; + } + + // Node fields + if (Node.class.isAssignableFrom(field.getType())) { + if (!field.getName().equals("parent")) { + nodeFieldOffsetsList.add(unsafe.objectFieldOffset(field)); + nodeFieldClassesList.add(field.getType()); + } else { + parentOffsetTemp = unsafe.objectFieldOffset(field); + parentClassTmp = field.getType(); + } + } else if (field.getType().getComponentType() != null && Node.class.isAssignableFrom(field.getType().getComponentType())) { + nodeArrayFieldOffsetsList.add(unsafe.objectFieldOffset(field)); + nodeArrayFieldClassesList.add(field.getType()); + } else { + nodeDataFieldOffsetList.add(unsafe.objectFieldOffset(field)); + nodeDataFieldClassList.add(field.getType()); + } + } + this.parentClass = parentClassTmp; + this.nodeFieldOffsets = toLongArray(nodeFieldOffsetsList); + this.nodeFieldClasses = nodeFieldClassesList.toArray(new Class[nodeFieldClassesList.size()]); + this.nodeArrayFieldOffsets = toLongArray(nodeArrayFieldOffsetsList); + this.nodeArrayFieldClasses = nodeArrayFieldClassesList.toArray(new Class[nodeArrayFieldClassesList.size()]); + this.nodeDataFieldOffsets = toLongArray(nodeDataFieldOffsetList); + this.nodeDataFieldClasses = nodeDataFieldClassList.toArray(new Class< ? >[nodeDataFieldClassList.size()]); + + this.parentOffset = parentOffsetTemp; + } + } + + public static class NodeIterator implements Iterator { + + private final Node node; + private final NodeClass nodeClass; + private final int childrenCount; + private int index; + + public NodeIterator(Node node) { + this(node, 0); + } + + public NodeIterator(Node node, int index) { + this.node = node; + this.index = index; + this.nodeClass = NodeClass.get(node.getClass()); + this.childrenCount = childrenCount(); + } + + private int childrenCount() { + int nodeCount = nodeClass.nodeFieldOffsets.length; + for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); + if (children != null) { + nodeCount += children.length; + } + } + return nodeCount; + } + + private Node nodeAt(int idx) { + int nodeCount = nodeClass.nodeFieldOffsets.length; + if (idx < nodeCount) { + return (Node) unsafe.getObject(node, nodeClass.nodeFieldOffsets[idx]); + } else { + for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); + if (idx < nodeCount + nodeArray.length) { + return nodeArray[idx - nodeCount]; + } + nodeCount += nodeArray.length; + } + } + return null; + } + + private void forward() { + if (index < childrenCount) { + index++; + } + } + + @Override + public boolean hasNext() { + return index < childrenCount; + } + + @Override + public Node next() { + try { + return nodeAt(index); + } finally { + forward(); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private static long[] toLongArray(List list) { + long[] array = new long[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + return array; + } + + private static final Unsafe unsafe = getUnsafe(); + + private static Unsafe getUnsafe() { + try { + return Unsafe.getUnsafe(); + } catch (SecurityException e) { + } + try { + Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeInstance.setAccessible(true); + return (Unsafe) theUnsafeInstance.get(Unsafe.class); + } catch (Exception e) { + throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); + } + } + + @SuppressWarnings("unchecked") + public static T cloneNode(T orig) { + Class< ? extends Node> clazz = orig.getClass(); + NodeClass nodeClass = NodeClass.get(clazz); + Node clone = orig.copy(); + if (clone == null) { + return null; + } + + unsafe.putObject(clone, nodeClass.parentOffset, null); + + for (long fieldOffset : nodeClass.nodeFieldOffsets) { + Node child = (Node) unsafe.getObject(orig, fieldOffset); + if (child != null) { + Node clonedChild = cloneNode(child); + if (clonedChild == null) { + return null; + } + + unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); + unsafe.putObject(clone, fieldOffset, clonedChild); + } + } + for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + Node[] children = (Node[]) unsafe.getObject(orig, fieldOffset); + if (children != null) { + Node[] clonedChildren = new Node[children.length]; + for (int i = 0; i < children.length; i++) { + Node clonedChild = cloneNode(children[i]); + if (clonedChild == null) { + return null; + } + + clonedChildren[i] = clonedChild; + unsafe.putObject(clonedChild, nodeClass.parentOffset, clone); + } + unsafe.putObject(clone, fieldOffset, clonedChildren); + } + } + return (T) clone; + } + + public static List findNodeChildren(Object node) { + List nodes = new ArrayList<>(); + NodeClass nodeClass = NodeClass.get(node.getClass()); + + for (long fieldOffset : nodeClass.nodeFieldOffsets) { + Object child = unsafe.getObject(node, fieldOffset); + if (child != null) { + nodes.add(child); + } + } + for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + Object[] children = (Object[]) unsafe.getObject(node, fieldOffset); + if (children != null) { + nodes.addAll(Arrays.asList(children)); + } + } + + return nodes; + } + + public static void replaceChild(Node parent, Node oldChild, Node newChild) { + NodeClass nodeClass = NodeClass.get(parent.getClass()); + + for (long fieldOffset : nodeClass.nodeFieldOffsets) { + if (unsafe.getObject(parent, fieldOffset) == oldChild) { + unsafe.putObject(parent, fieldOffset, newChild); + } + } + for (long fieldOffset : nodeClass.nodeArrayFieldOffsets) { + Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset); + if (array != null) { + for (int i = 0; i < array.length; i++) { + if (array[i] == oldChild) { + array[i] = newChild; + return; + } + } + } + } + } + + public static long[] getNodeDataFieldOffsets(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeDataFieldOffsets, clazz.nodeDataFieldClasses.length); + } + + public static Class[] getNodeDataFieldClasses(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeDataFieldClasses, clazz.nodeDataFieldClasses.length); + } + + public static long getNodeParentOffset(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return clazz.parentOffset; + } + + /** Returns the number of Node field declarations in the class hierarchy. */ + public static long[] getNodeFieldOffsets(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeFieldOffsets, clazz.nodeFieldOffsets.length); + } + + /** Returns the number of Node[] declaration in the class hierarchy. */ + public static long[] getNodeFieldArrayOffsets(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeArrayFieldOffsets, clazz.nodeArrayFieldOffsets.length); + } + + public static Class[] getNodeFieldArrayClasses(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeArrayFieldClasses, clazz.nodeArrayFieldClasses.length); + } + + public static Class getNodeParentClass(Class< ? > nodeClass) { + return NodeClass.get(nodeClass).parentClass; + } + + public static Class[] getNodeFieldClasses(Class< ? > nodeClass) { + NodeClass clazz = NodeClass.get(nodeClass); + return Arrays.copyOf(clazz.nodeFieldClasses, clazz.nodeFieldClasses.length); + } + + /** Returns all declared fields in the class hierarchy. */ + public static Field[] getAllFields(Class< ? extends Object> clazz) { + Field[] declaredFields = clazz.getDeclaredFields(); + if (clazz.getSuperclass() != null) { + return concat(getAllFields(clazz.getSuperclass()), declaredFields); + } + return declaredFields; + } + + public static T[] concat(T[] first, T[] second) { + T[] result = Arrays.copyOf(first, first.length + second.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + /** find annotation in class/interface hierarchy. */ + public static T findAnnotation(Class< ? > clazz, Class annotationClass) { + if (clazz.getAnnotation(annotationClass) != null) { + return clazz.getAnnotation(annotationClass); + } else { + for (Class< ? > intf : clazz.getInterfaces()) { + if (intf.getAnnotation(annotationClass) != null) { + return intf.getAnnotation(annotationClass); + } + } + if (clazz.getSuperclass() != null) { + return findAnnotation(clazz.getSuperclass(), annotationClass); + } + } + return null; + } + + @SuppressWarnings("unchecked") + public static T findParent(final Node start, final Class clazz) { + assert start != null; + if (clazz.isInstance(start.getParent())) { + return (T) start.getParent(); + } else { + return start.getParent() != null ? findParent(start.getParent(), clazz) : null; + } + } + + @SuppressWarnings("unchecked") + public static I findParentInterface(final Node start, final Class clazz) { + assert start != null; + if (clazz.isInstance(start.getParent())) { + return (I) start.getParent(); + } else { + return (start.getParent() != null ? findParentInterface(start.getParent(), clazz) : null); + } + } + + @SuppressWarnings("unchecked") + public static T findFirstNodeInstance(Object root, Class clazz) { + List childNodes = findNodeChildren(root); + + for (Object childNode : childNodes) { + if (clazz.isInstance(childNode)) { + return (T) childNode; + } else { + return findFirstNodeInstance(childNode, clazz); + } + } + return null; + } + + public static List findAllNodeInstances(final Node root, final Class clazz) { + final List nodeList = new ArrayList<>(); + root.accept(new NodeVisitor() { + + @SuppressWarnings("unchecked") + @Override + public boolean visit(Node node) { + if (clazz.isInstance(node)) { + nodeList.add((T) node); + } + return true; + } + }); + return nodeList; + } + + // Don't visit found node instances. + public static List findNodeInstancesShallow(final Node root, final Class clazz) { + final List nodeList = new ArrayList<>(); + root.accept(new NodeVisitor() { + + @SuppressWarnings("unchecked") + @Override + public boolean visit(Node node) { + if (clazz.isInstance(node)) { + nodeList.add((T) node); + return false; + } + return true; + } + }); + return nodeList; + } + + /** Find node instances within current function only (not in nested functions). */ + public static List findNodeInstancesInFunction(final Node root, final Class clazz) { + final List nodeList = new ArrayList<>(); + root.accept(new NodeVisitor() { + + @SuppressWarnings("unchecked") + @Override + public boolean visit(Node node) { + if (clazz.isInstance(node)) { + nodeList.add((T) node); + } else if (node instanceof RootNode && node != root) { + return false; + } + return true; + } + }); + return nodeList; + } + + public static List findNodeInstancesInFunctionInterface(final Node root, final Class clazz) { + final List nodeList = new ArrayList<>(); + root.accept(new NodeVisitor() { + + @SuppressWarnings("unchecked") + @Override + public boolean visit(Node node) { + if (clazz.isInstance(node)) { + nodeList.add((I) node); + } else if (node instanceof RootNode && node != root) { + return false; + } + return true; + } + }); + return nodeList; + } + + public static String printTreeToString(Node node) { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + printTree(new PrintStream(byteOut), node); + try { + byteOut.flush(); + } catch (IOException e) { + } + return new String(byteOut.toByteArray()); + } + + /** + * Prints a human readable form of a {@link Node} AST to the given {@link PrintStream}. This print method does not + * check for cycles in the node structure. + * + * @param p the {@link PrintStream} to print to. + * @param node the root node to write + */ + public static void printTree(PrintStream p, Node node) { + printTree(p, node, new NodeTreeResolver()); + } + + /** + * Prints a human readable form of a tree to the given {@link PrintStream}. The {@link TreeResolver} interface needs + * to be implemented to specify how the method can read the tree from plain a object. + * + * @param p the {@link PrintStream} to print to. + * @param o the root object to be printed. + * @param resolver an implementation of a tree resolver + */ + public static void printTree(PrintStream p, Object o, TreeResolver resolver) { + printTree(p, o, resolver, 1); + p.println(); + } + + private static void printTree(PrintStream p, Object node, TreeResolver resolver, int level) { + if (node == null) { + p.print("null"); + return; + } + + p.print(node.getClass().getSimpleName()); + + Field[] fields = NodeUtil.getAllFields(node.getClass()); + p.print("("); + + ArrayList childFields = new ArrayList<>(); + + boolean first = true; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (Modifier.isStatic(field.getModifiers()) || resolver.isFiltered(field)) { + continue; + } + if (resolver.isChildObject(field) || resolver.isChildArrayObject(field)) { + childFields.add(field); + } + if (!resolver.isDataField(field)) { + continue; + } + if (!first) { + p.print(", "); + } else { + first = false; + } + + Object value = getObjectValue(node, field.getType(), unsafe.objectFieldOffset(field)); + + p.print(field.getName()); + p.print(" = "); + p.print(resolver.toString(value)); + } + p.print(")"); + + if (childFields.size() != 0) { + p.print(" {"); + } + + // I refetch the fields to get declaration order. + for (int i = 0; i < childFields.size(); i++) { + Field field = childFields.get(i); + Class< ? > fieldClass = field.getType(); + String name = field.getName(); + + long offset = unsafe.objectFieldOffset(field); + + Object value = getObjectValue(node, fieldClass, offset); + + printNewLine(p, level); + p.print(name); + if (value == null) { + p.print(" = null "); + } else if (resolver.isChildObject(field)) { + p.print(" = "); + printTree(p, value, resolver, level + 1); + } else if (resolver.isChildArrayObject(field)) { + Object[] objectArray = resolver.convertToArray(field, value); + if (objectArray.length == 0) { + p.print(" = []"); + } else { + p.print(" = ["); + for (int j = 0; j < objectArray.length; j++) { + printTree(p, objectArray[j], resolver, level + 1); + if (j < objectArray.length - 1) { + p.print(", "); + } + } + p.print("]"); + } + } else { + assert false; + } + } + + if (childFields.size() != 0) { + printNewLine(p, level - 1); + p.print("}"); + } + } + + private static Object getObjectValue(Object base, Class< ? > fieldClass, long offset) { + if (fieldClass == boolean.class) { + return unsafe.getBoolean(base, offset); + } else if (fieldClass == byte.class) { + return unsafe.getByte(base, offset); + } else if (fieldClass == short.class) { + return unsafe.getShort(base, offset); + } else if (fieldClass == char.class) { + return unsafe.getChar(base, offset); + } else if (fieldClass == int.class) { + return unsafe.getInt(base, offset); + } else if (fieldClass == long.class) { + return unsafe.getLong(base, offset); + } else if (fieldClass == float.class) { + return unsafe.getFloat(base, offset); + } else if (fieldClass == double.class) { + return unsafe.getDouble(base, offset); + } else { + return unsafe.getObject(base, offset); + } + } + + private static void printNewLine(PrintStream p, int level) { + p.println(); + for (int i = 0; i < level; i++) { + p.print(" "); + } + } + + private static class NodeTreeResolver implements TreeResolver { + + @Override + public boolean isFiltered(Field f) { + if (f.getName().equals("parent")) { + return true; + } + return f.isSynthetic(); + } + + @Override + public boolean isDataField(Field f) { + return !isChildArrayObject(f) && !isChildObject(f); + } + + @Override + public boolean isChildObject(Field f) { + return Node.class.isAssignableFrom(f.getType()); + } + + @Override + public boolean isChildArrayObject(Field f) { + return f.getType().getComponentType() != null && Node.class.isAssignableFrom(f.getType().getComponentType()); + } + + @Override + public Object[] convertToArray(Field f, Object data) { + return (Object[]) data; + } + + @Override + public String toString(Object o) { + return o == null ? "null" : o.toString(); + } + } + + /** + * Specifies how a tree can be built from plain objects. + */ + public interface TreeResolver { + + /** + * Returns true if a {@link Field} is filtered from the tree. + * + * @param f the field to check + */ + boolean isFiltered(Field f); + + /** + * Returns true if a {@link Field} is a field that contains a data value which should not be traversed + * recursively. + * + * @param f the field to check + * @return true if a the given field is a data field else false. + */ + boolean isDataField(Field f); + + /** + * Returns true if a {@link Field} is a field that contains an {@link Object} which should be recursively + * visited. + * + * @param f the field to check + * @return true if a the given field is a child field else false. + */ + boolean isChildObject(Field f); + + /** + * Returns true if a {@link Field} is a field that contains any kind of list/array structure which itself holds + * values that should be recursively visited. + * + * @param f the field to check + * @return true if a the given field is a child array/list field else false. + */ + boolean isChildArrayObject(Field f); + + /** + * Converts an given child array object to array which can be traversed. This is especially useful to convert + * any kind of list structure to a traversable array. + * + * @param f the field for meta data needed to convert the data {@link Object}. + * @param value the actual value of the child array/list object. + * @return the converted {@link Object} array. + */ + Object[] convertToArray(Field f, Object value); + + /** + * Returns a human readable string for any data field object in the tree. + * + * @param o the object to convert to string. + * @return the converted string + */ + String toString(Object o); + } + +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +/** + * Visitor for trees of nodes. + */ +public interface NodeVisitor { + + /** + * This visitor method is called for every node in the tree. Its return value determines if the children of this + * node should be excluded in the iteration. + * + * @param node the node that is currently visited + * @return {@code true} if the children should be visited too, {@code false} otherwise + */ + boolean visit(Node node); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +import com.oracle.truffle.api.*; +import com.oracle.truffle.api.frame.*; + +/** + * A root node is a node with a method to execute it given only a frame as a parameter. Therefore, a root node can be used to create a call target using {@link TruffleRuntime#createCallTarget(RootNode, FrameDescriptor)}. + */ +public abstract class RootNode extends Node { + + /** + * Executes this function using the specified frame and returns the result value. + * @param frame the frame of the currently executing guest language method + * @return the value of the execution + */ + public abstract Object execute(VirtualFrame frame); +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/SlowPathException.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +/** + * An exception thrown to enter a slow path. The Truffle optimizer has special knowledge of this exception class and + * will never compile a catch block that catches this exception type. + */ +public class SlowPathException extends Exception { + + private static final long serialVersionUID = 3676602078425211386L; + + /** + * Creates an exception thrown to enter a slow path. + */ + public SlowPathException(String message, Throwable cause) { + super(message, cause); + } +} diff -r 707e9cca11de -r 64f4195d0ecf graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java Wed Dec 19 10:01:08 2012 +0100 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.nodes; + +/** + * An exception that should be thrown if the return value cannot be represented as a value of the return type. The + * Truffle optimizer has special knowledge of this exception class and will never compile a catch block that catches this + * exception type. + */ +public final class UnexpectedResultException extends SlowPathException { + + private static final long serialVersionUID = 3676602078425211386L; + private final Object result; + + /** + * Creates the exception with the alternative result that cannot be respresented as a value of the return type. + * @param result the alternative result + */ + public UnexpectedResultException(Object result) { + super(null, null); + assert !(result instanceof Throwable); + this.result = result; + } + + /** + * @return the unexpected result + */ + public Object getResult() { + return result; + } + + /** + * For performance reasons, this exception does not record any stack trace information. + */ + @Override + public synchronized Throwable fillInStackTrace() { + return null; + } +} diff -r 707e9cca11de -r 64f4195d0ecf mx/projects --- a/mx/projects Tue Dec 18 15:05:58 2012 +0100 +++ b/mx/projects Wed Dec 19 10:01:08 2012 +0100 @@ -90,6 +90,13 @@ project@com.oracle.graal.hotspot.server@checkstyle=com.oracle.graal.graph project@com.oracle.graal.hotspot.server@javaCompliance=1.7 +# graal.hotspot.test +project@com.oracle.graal.hotspot.test@subDir=graal +project@com.oracle.graal.hotspot.test@sourceDirs=src +project@com.oracle.graal.hotspot.test@dependencies=com.oracle.graal.hotspot,com.oracle.graal.compiler.test +project@com.oracle.graal.hotspot.test@checkstyle=com.oracle.graal.graph +project@com.oracle.graal.hotspot.test@javaCompliance=1.7 + # graal.graph project@com.oracle.graal.graph@subDir=graal project@com.oracle.graal.graph@sourceDirs=src @@ -247,3 +254,18 @@ project@com.oracle.graal.asm.amd64@dependencies=com.oracle.graal.asm,com.oracle.graal.amd64 project@com.oracle.graal.asm.amd64@checkstyle=com.oracle.graal.graph project@com.oracle.graal.asm.amd64@javaCompliance=1.7 + +# truffle.api +project@com.oracle.truffle.api@subDir=graal +project@com.oracle.truffle.api@sourceDirs=src +project@com.oracle.truffle.api@dependencies= +project@com.oracle.truffle.api@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.api@javaCompliance=1.7 + +# truffle.api.test +project@com.oracle.truffle.api.test@subDir=graal +project@com.oracle.truffle.api.test@sourceDirs=src +project@com.oracle.truffle.api.test@dependencies=com.oracle.truffle.api,JUNIT +project@com.oracle.truffle.api.test@checkstyle=com.oracle.graal.graph +project@com.oracle.truffle.api.test@javaCompliance=1.7 +