changeset 5482:9f4783c0269e

folded -G:+CheckcastCounters functionality into checkcast snippets fixed bug in translation of @Parameter(multiple = true) parameters modified commands.py to appease jacoco
author Doug Simon <doug.simon@oracle.com>
date Wed, 06 Jun 2012 18:04:07 +0200
parents e26e6dca0bcf
children d554a6709d5e 82f44f47e1aa
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadMultipleParameterNode.java graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetParameterNode.java mx/commands.py
diffstat 6 files changed, 178 insertions(+), 190 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Tue Jun 05 21:43:42 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed Jun 06 18:04:07 2012 +0200
@@ -67,12 +67,15 @@
     @Snippet
     public static Object checkcastExact(@Parameter("object") Object object, @Parameter("exactHub") Object exactHub, @Constant("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            isNull.inc();
             return object;
         }
         Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
         if (objectHub != exactHub) {
+            exactMiss.inc();
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
         }
+        exactHit.inc();
         return object;
     }
 
@@ -86,12 +89,15 @@
     @Snippet
     public static Object checkcastPrimary(@Parameter("hub") Object hub, @Parameter("object") Object object, @Constant("checkNull") boolean checkNull, @Constant("superCheckOffset") int superCheckOffset) {
         if (checkNull && object == null) {
+            isNull.inc();
             return object;
         }
         Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
         if (UnsafeLoadNode.loadObject(objectHub, 0, superCheckOffset, true) != hub) {
+            displayMiss.inc();
             DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
         }
+        displayHit.inc();
         return object;
     }
 
@@ -101,6 +107,7 @@
     @Snippet
     public static Object checkcastSecondary(@Parameter("hub") Object hub, @Parameter("object") Object object, @Parameter(value = "hints", multiple = true) Object[] hints, @Constant("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            isNull.inc();
             return object;
         }
         Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
@@ -109,6 +116,7 @@
         for (int i = 0; i < hints.length; i++) {
             Object hintHub = hints[i];
             if (hintHub == objectHub) {
+                hintsHit.inc();
                 return object;
             }
         }
@@ -125,6 +133,7 @@
     @Snippet
     public static Object checkcastUnknown(@Parameter("hub") Object hub, @Parameter("object") Object object, @Parameter(value = "hints", multiple = true) Object[] hints, @Constant("checkNull") boolean checkNull) {
         if (checkNull && object == null) {
+            isNull.inc();
             return object;
         }
         Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
@@ -133,6 +142,7 @@
         for (int i = 0; i < hints.length; i++) {
             Object hintHub = hints[i];
             if (hintHub == objectHub) {
+                hintsHit.inc();
                 return object;
             }
         }
@@ -150,11 +160,13 @@
     static boolean checkSecondarySubType(Object t, Object s) {
         // if (S.cache == T) return true
         if (UnsafeLoadNode.loadObject(s, 0, secondarySuperCacheOffset(), true) == t) {
+            cacheHit.inc();
             return true;
         }
 
         // if (T == S) return true
         if (s == t) {
+            T_equals_S.inc();
             return true;
         }
 
@@ -164,29 +176,38 @@
         for (int i = 0; i < secondarySupers.length; i++) {
             if (t == loadNonNullObjectElement(secondarySupers, i)) {
                 DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t);
+                secondariesHit.inc();
                 return true;
             }
         }
-
+        secondariesMiss.inc();
         return false;
     }
 
     static boolean checkUnknownSubType(Object t, Object s) {
         // int off = T.offset
         int superCheckOffset = UnsafeLoadNode.load(t, 0, superCheckOffsetOffset(), CiKind.Int);
+        boolean primary = superCheckOffset != secondarySuperCacheOffset();
 
         // if (T = S[off]) return true
         if (UnsafeLoadNode.loadObject(s, 0, superCheckOffset, true) == t) {
+            if (primary) {
+                cacheHit.inc();
+            } else {
+                displayHit.inc();
+            }
             return true;
         }
 
         // if (off != &cache) return false
-        if (superCheckOffset != secondarySuperCacheOffset()) {
+        if (primary) {
+            displayMiss.inc();
             return false;
         }
 
         // if (T == S) return true
         if (s == t) {
+            T_equals_S.inc();
             return true;
         }
 
@@ -195,23 +216,29 @@
         for (int i = 0; i < secondarySupers.length; i++) {
             if (t == loadNonNullObjectElement(secondarySupers, i)) {
                 DirectObjectStoreNode.store(s, secondarySuperCacheOffset(), 0, t);
+                secondariesHit.inc();
                 return true;
             }
         }
 
+        secondariesMiss.inc();
         return false;
     }
 
     /**
-     * Counters for the various code paths through a type check.
+     * Counters for the various code paths through a checkcast.
      */
     public enum Counter {
         hintsHit("hit a hint type"),
-        hintsMissed("missed the hint types"),
-        exactType("tested type is (statically) final"),
-        noHints("profile information is not used"),
-        isNull("object tested is null"),
-        exception("type test failed with a ClassCastException");
+        exactHit("exact type test succeeded"),
+        exactMiss("exact type test failed"),
+        isNull("object tested was null"),
+        cacheHit("secondary type cache hit"),
+        secondariesHit("secondaries scan succeeded"),
+        secondariesMiss("secondaries scan failed"),
+        displayHit("primary type test succeeded"),
+        displayMiss("primary type test failed"),
+        T_equals_S("object type was equal to secondary type");
 
         final String description;
         final int index;
@@ -246,51 +273,6 @@
         static final boolean ENABLED = GraalOptions.CheckcastCounters;
     }
 
-    /**
-     * Type test used when {@link GraalOptions#CheckcastCounters} is enabled.
-     */
-    @Snippet
-    public static Object checkcastCounters(@Parameter("hub") Object hub, @Parameter("object") Object object, @Parameter(value = "hints", multiple = true) Object[] hints, @Constant("hintsAreExact") boolean hintsAreExact) {
-        if (object == null) {
-            isNull.inc();
-            return object;
-        }
-        Object objectHub = UnsafeLoadNode.loadObject(object, 0, hubOffset(), true);
-        if (hints.length == 0) {
-            noHints.inc();
-            if (!checkUnknownSubType(hub, objectHub)) {
-                exception.inc();
-                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-            }
-        } else {
-            // if we get an exact match: succeed immediately
-            ExplodeLoopNode.explodeLoop();
-            for (int i = 0; i < hints.length; i++) {
-                Object hintHub = hints[i];
-                if (hintHub == objectHub) {
-                    if (hintsAreExact) {
-                        exactType.inc();
-                    } else {
-                        hintsHit.inc();
-                    }
-                    return object;
-                }
-            }
-            if (!hintsAreExact) {
-                if (!checkUnknownSubType(hub, objectHub)) {
-                    exception.inc();
-                    DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-                } else {
-                    hintsMissed.inc();
-                }
-            } else {
-                exception.inc();
-                DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
-            }
-        }
-        return object;
-    }
-
     @Fold
     private static int superCheckOffsetOffset() {
         return CompilerImpl.getInstance().getConfig().superCheckOffsetOffset;
@@ -353,7 +335,6 @@
         private final RiResolvedMethod primary;
         private final RiResolvedMethod secondary;
         private final RiResolvedMethod unknown;
-        private final RiResolvedMethod counters;
         private final RiRuntime runtime;
 
         public Templates(RiRuntime runtime) {
@@ -364,7 +345,6 @@
                 primary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastPrimary", Object.class, Object.class, boolean.class, int.class));
                 secondary = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastSecondary", Object.class, Object.class, Object[].class, boolean.class));
                 unknown = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastUnknown", Object.class, Object.class, Object[].class, boolean.class));
-                counters = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastCounters", Object.class, Object.class, Object[].class, boolean.class));
             } catch (NoSuchMethodException e) {
                 throw new GraalInternalError(e);
             }
@@ -383,11 +363,7 @@
             Arguments arguments;
             SnippetTemplate.Key key;
 
-            if (GraalOptions.CheckcastCounters) {
-                HotSpotKlassOop[] hints = createHints(hintInfo);
-                key = new SnippetTemplate.Key(counters).add("hints", multiple(Object.class, hints.length)).add("hintsAreExact", hintInfo.exact);
-                arguments = arguments("hub", hub).add("object", object).add("hints", hints);
-            } else if (target == null) {
+            if (target == null) {
                 HotSpotKlassOop[] hints = createHints(hintInfo);
                 key = new SnippetTemplate.Key(unknown).add("hints", multiple(Object.class, hints.length)).add("checkNull", checkNull);
                 arguments = arguments("hub", hub).add("object", object).add("hints", hints);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Tue Jun 05 21:43:42 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed Jun 06 18:04:07 2012 +0200
@@ -24,8 +24,6 @@
 
 import java.lang.reflect.*;
 
-import sun.misc.*;
-
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Tue Jun 05 21:43:42 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Wed Jun 06 18:04:07 2012 +0200
@@ -35,6 +35,7 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.snippets.Snippet.Arguments;
 import com.oracle.graal.snippets.Snippet.Constant;
@@ -158,6 +159,7 @@
 
         int parameterCount = signature.argumentCount(false);
         Parameter[] parameterAnnotations = new Parameter[parameterCount];
+        ConstantNode[] placeholders = new ConstantNode[parameterCount];
         for (int i = 0; i < parameterCount; i++) {
             Constant c = CiUtil.getParameterAnnotation(Constant.class, i, method);
             if (c != null) {
@@ -176,7 +178,9 @@
                     assert multiple != null : method + ": requires a Multiple named " + name;
                     assert checkMultipleArgument(method, signature, i, name, multiple);
                     Object array = ((Multiple) multiple).array;
-                    replacements.put(snippetGraph.getLocal(i), ConstantNode.forObject(array, runtime, snippetCopy));
+                    ConstantNode placeholder = ConstantNode.forObject(array, runtime, snippetCopy);
+                    replacements.put(snippetGraph.getLocal(i), placeholder);
+                    placeholders[i] = placeholder;
                 }
                 parameterAnnotations[i] = p;
             }
@@ -193,28 +197,36 @@
         for (int i = 0; i < parameterCount; i++) {
             Parameter p = parameterAnnotations[i];
             if (p != null) {
-                ValueNode parameter;
                 if (p.multiple()) {
-                    parameter = null;
                     assert snippetCopy.getLocal(i) == null;
-                    ConstantNode array = (ConstantNode) replacements.get(snippetGraph.getLocal(i));
-                    for (LoadIndexedNode loadIndexed : snippetCopy.getNodes(LoadIndexedNode.class)) {
-                        if (loadIndexed.array() == array) {
+                    Object array = ((Multiple) key.get(p.value())).array;
+                    int length = Array.getLength(array);
+                    LocalNode[] locals = new LocalNode[length];
+                    Stamp stamp = StampFactory.forKind(runtime.getType(array.getClass().getComponentType()).kind(false));
+                    for (int j = 0; j < length; j++) {
+                        assert (parameterCount & 0xFFFF) == parameterCount;
+                        int idx = i << 16 | j;
+                        LocalNode local = snippetCopy.unique(new LocalNode(idx, stamp));
+                        locals[j] = local;
+                    }
+                    parameters.put(p.value(), locals);
+
+                    ConstantNode placeholder = placeholders[i];
+                    assert placeholder != null;
+                    for (Node usage : placeholder.usages().snapshot()) {
+                        if (usage instanceof LoadIndexedNode) {
+                            LoadIndexedNode loadIndexed = (LoadIndexedNode) usage;
                             Debug.dump(snippetCopy, "Before replacing %s", loadIndexed);
-                            LoadMultipleParameterNode lmp = new LoadMultipleParameterNode(array, i, loadIndexed.index(), loadIndexed.stamp());
-                            StructuredGraph g = (StructuredGraph) loadIndexed.graph();
-                            g.add(lmp);
-                            g.replaceFixedWithFixed(loadIndexed, lmp);
-                            parameter = lmp;
+                            LoadSnippetParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetParameterNode(locals, loadIndexed.index(), loadIndexed.stamp()));
+                            snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter);
                             Debug.dump(snippetCopy, "After replacing %s", loadIndexed);
-                            break;
                         }
                     }
                 } else {
-                    parameter = snippetCopy.getLocal(i);
+                    LocalNode local = snippetCopy.getLocal(i);
+                    assert local != null;
+                    parameters.put(p.value(), local);
                 }
-                assert parameter != null;
-                parameters.put(p.value(), parameter);
             }
         }
 
@@ -274,6 +286,8 @@
 
         new DeadCodeEliminationPhase().apply(snippetCopy);
 
+        assert checkAllMultipleParameterPlaceholdersAreDeleted(parameterCount, placeholders);
+
         this.graph = snippetCopy;
         nodes = new ArrayList<>(graph.getNodeCount());
         ReturnNode retNode = null;
@@ -291,6 +305,15 @@
         this.returnNode = retNode;
     }
 
+    private static boolean checkAllMultipleParameterPlaceholdersAreDeleted(int parameterCount, ConstantNode[] placeholders) {
+        for (int i = 0; i < parameterCount; i++) {
+            if (placeholders[i] != null) {
+                assert placeholders[i].isDeleted() : placeholders[i];
+            }
+        }
+        return true;
+    }
+
     private static boolean checkConstantArgument(final RiResolvedMethod method, RiSignature signature, int i, String name, Object arg, CiKind kind) {
         if (kind.isObject()) {
             Class<?> type = signature.argumentTypeAt(i, method.holder()).resolve(method.holder()).toJava();
@@ -320,9 +343,9 @@
 
     /**
      * The named parameters of this template that must be bound to values during instantiation.
-     * Each parameter is either a {@link LocalNode} or a {@link LoadMultipleParameterNode} instance.
+     * Each value in this map is either a {@link LocalNode} instance or a {@link LocalNode} array.
      */
-    private final Map<String, ValueNode> parameters;
+    private final Map<String, Object> parameters;
 
     /**
      * The return node (if any) of the snippet.
@@ -344,28 +367,28 @@
 
         for (Map.Entry<String, Object> e : args) {
             String name = e.getKey();
-            ValueNode parameter = parameters.get(name);
+            Object parameter = parameters.get(name);
             assert parameter != null : this + " has no parameter named " + name;
             Object argument = e.getValue();
             if (parameter instanceof LocalNode) {
                 if (argument instanceof ValueNode) {
-                    replacements.put(parameter, (ValueNode) argument);
+                    replacements.put((LocalNode) parameter, (ValueNode) argument);
                 } else {
                     CiKind kind = ((LocalNode) parameter).kind();
                     CiConstant constant = CiConstant.forBoxed(kind, argument);
-                    replacements.put(parameter, ConstantNode.forCiConstant(constant, runtime, replaceeGraph));
+                    replacements.put((LocalNode) parameter, ConstantNode.forCiConstant(constant, runtime, replaceeGraph));
                 }
             } else {
-                assert parameter instanceof LoadMultipleParameterNode;
+                assert parameter instanceof LocalNode[];
+                LocalNode[] locals = (LocalNode[]) parameter;
                 Object array = argument;
                 assert array != null && array.getClass().isArray();
-                int length = Array.getLength(array);
-                LoadMultipleParameterNode lmp = (LoadMultipleParameterNode) parameter;
-                assert length == lmp.getLocalCount() : length + " != " + lmp.getLocalCount();
+                int length = locals.length;
+                assert Array.getLength(array) == length : length + " != " + Array.getLength(array);
                 for (int j = 0; j < length; j++) {
-                    LocalNode local = lmp.getLocal(j);
+                    LocalNode local = locals[j];
                     assert local != null;
-                    CiConstant constant = CiConstant.forBoxed(lmp.kind(), Array.get(array, j));
+                    CiConstant constant = CiConstant.forBoxed(local.kind(), Array.get(array, j));
                     ConstantNode element = ConstantNode.forCiConstant(constant, runtime, replaceeGraph);
                     replacements.put(local, element);
                 }
@@ -434,16 +457,18 @@
     public String toString() {
         StringBuilder buf = new StringBuilder(graph.toString()).append('(');
         String sep = "";
-        for (Map.Entry<String, ValueNode> e : parameters.entrySet()) {
+        for (Map.Entry<String, Object> e : parameters.entrySet()) {
             String name = e.getKey();
-            ValueNode value = e.getValue();
+            Object value = e.getValue();
             buf.append(sep);
             sep = ", ";
             if (value instanceof LocalNode) {
-                buf.append(value.kind().name()).append(' ').append(name);
+                LocalNode local = (LocalNode) value;
+                buf.append(local.kind().name()).append(' ').append(name);
             } else {
-                LoadMultipleParameterNode lmp = (LoadMultipleParameterNode) value;
-                buf.append(value.kind().name()).append('[').append(lmp.getLocalCount()).append("] ").append(name);
+                LocalNode[] locals = (LocalNode[]) value;
+                String kind = locals.length == 0 ? "?" : locals[0].kind().name();
+                buf.append(kind).append('[').append(locals.length).append("] ").append(name);
             }
         }
         return buf.append(')').toString();
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadMultipleParameterNode.java	Tue Jun 05 21:43:42 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-/*
- * 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.snippets.nodes;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.snippets.Snippet.Parameter;
-
-/**
- * Implements the semantics of a snippet {@link Parameter} whose {@link Parameter#multiple()} element is {@code true}.
- */
-public final class LoadMultipleParameterNode extends FixedWithNextNode implements Canonicalizable {
-
-    @Input private ValueNode index;
-
-    private final LocalNode[] locals;
-
-    public ValueNode index() {
-        return index;
-    }
-
-    public LoadMultipleParameterNode(ConstantNode array, int localIndex, ValueNode index, Stamp stamp) {
-        super(stamp);
-        int length = Array.getLength(array.asConstant().asObject());
-        this.index = index;
-        locals = new LocalNode[length];
-        for (int i = 0; i < length; i++) {
-            int idx = localIndex << 16 | i;
-            LocalNode local = array.graph().unique(new LocalNode(idx, stamp()));
-            locals[i] = local;
-        }
-    }
-
-    public LocalNode getLocal(int idx) {
-        assert idx < locals.length;
-        return locals[idx];
-    }
-
-    public int getLocalCount() {
-        return locals.length;
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        assert index.isConstant();
-        return getLocal(index().asConstant().asInt());
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/LoadSnippetParameterNode.java	Wed Jun 06 18:04:07 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * 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.snippets.nodes;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.snippets.Snippet.Parameter;
+
+/**
+ * Implements the semantics of a snippet {@link Parameter} whose {@link Parameter#multiple()} element is {@code true}.
+ */
+public final class LoadSnippetParameterNode extends FixedWithNextNode implements Canonicalizable {
+
+    @Input private ValueNode index;
+
+    private final LocalNode[] locals;
+
+    public LoadSnippetParameterNode(LocalNode[] locals, ValueNode index, Stamp stamp) {
+        super(stamp);
+        this.index = index;
+        this.locals = locals;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (index.isConstant()) {
+            return locals[index.asConstant().asInt()];
+        }
+        return this;
+    }
+}
--- a/mx/commands.py	Tue Jun 05 21:43:42 2012 +0200
+++ b/mx/commands.py	Wed Jun 06 18:04:07 2012 +0200
@@ -565,9 +565,8 @@
         # Exclude all compiler tests and snippets
         excludes = ['com.oracle.graal.compiler.tests.*']
         for p in mx.projects():
-            for s in p.source_dirs():
-                _add_classes_with_annotation(excludes, s, None, '@Snippet')
-                _add_classes_with_annotation(excludes, s, None, '@ClassSubstitution')
+            _add_classes_with_annotation(excludes, p, None, '@Snippet', includeInnerClasses=True)
+            _add_classes_with_annotation(excludes, p, None, '@ClassSubstitution', includeInnerClasses=True)
         agentOptions = {
                         'append' : 'true' if _jacoco == 'append' else 'false',
                         'bootclasspath' : 'true',
@@ -578,32 +577,41 @@
     exe = join(_jdk(build), 'bin', mx.exe_suffix('java'))
     return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
 
-def _add_classes_with_annotation(classes, srcDir, pkgRoot, annotation):
+def _add_classes_with_annotation(classes, p, pkgRoot, annotation, includeInnerClasses=False):
     """
-    Scan 'srcDir' for Java source files containing a line starting with 'annotation'
+    Scan the sources of project 'p' for Java source files containing a line starting with 'annotation'
     (ignoring preceding whitespace) and add the fully qualified class name
     to 'classes' for each Java source file matched.
     """
     pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$")
-    for root, _, files in os.walk(srcDir):
-        for name in files:
-            if name.endswith('.java') and name != 'package-info.java':
-                hasTest = False
-                with open(join(root, name)) as f:
-                    pkg = None
-                    for line in f:
-                        if line.startswith("package "):
-                            match = pkgDecl.match(line)
-                            if match:
-                                pkg = match.group(1)
-                        else:
-                            if line.strip().startswith(annotation):
-                                hasTest = True
-                                break
-                if hasTest:
-                    assert pkg is not None
-                    if pkgRoot is None or pkg.startswith(pkgRoot):
-                        classes.append(pkg + '.' + name[:-len('.java')])
+    for srcDir in p.source_dirs():
+        outputDir = p.output_dir()
+        for root, _, files in os.walk(srcDir):
+            for name in files:
+                if name.endswith('.java') and name != 'package-info.java':
+                    hasTest = False
+                    with open(join(root, name)) as f:
+                        pkg = None
+                        for line in f:
+                            if line.startswith("package "):
+                                match = pkgDecl.match(line)
+                                if match:
+                                    pkg = match.group(1)
+                            else:
+                                if line.strip().startswith(annotation):
+                                    hasTest = True
+                                    break
+                    if hasTest:
+                        basename = name[:-len('.java')]
+                        assert pkg is not None
+                        if pkgRoot is None or pkg.startswith(pkgRoot):
+                            pkgOutputDir = join(outputDir, pkg.replace('.', os.path.sep))
+                            for e in os.listdir(pkgOutputDir):
+                                if includeInnerClasses:
+                                    if e.endswith('.class') and (e.startswith(basename) or e.startswith(basename + '$')):
+                                        classes.append(pkg + '.' + e[:-len('.class')])
+                                elif e == basename + '.class':
+                                    classes.append(pkg + '.' + basename)
 
 
 # Table of unit tests.
@@ -639,7 +647,7 @@
         p = mx.project(proj)
         classes = []
         for pkg in _unittests[proj]:
-            _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test')
+            _add_classes_with_annotation(classes, p, pkg, '@Test')
     
         if len(pos) != 0:
             classes = [c for c in classes if containsAny(c, pos)]
@@ -669,7 +677,7 @@
         p = mx.project(proj)
         classes = []
         for pkg in _jtttests[proj]:
-            _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test')
+            _add_classes_with_annotation(classes, p, pkg, '@Test')
     
         if len(pos) != 0:
             classes = [c for c in classes if containsAny(c, pos)]