changeset 5651:d05664608cb7

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 19 Jun 2012 11:38:30 +0200
parents 8d420cfd2a6f (diff) 419df70cc6a2 (current diff)
children 1f263f152cda
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AnchorNode.java
diffstat 12 files changed, 314 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/NewInstanceSnippets.java	Tue Jun 19 11:38:30 2012 +0200
@@ -61,21 +61,9 @@
     public static Object newInstance(
                     @Parameter("hub") Object hub,
                     @ConstantParameter("size") int size,
-                    @ConstantParameter("checkInit") boolean checkInit,
                     @ConstantParameter("useTLAB") boolean useTLAB,
                     @ConstantParameter("logType") String logType) {
 
-        if (checkInit) {
-            int klassState = load(hub, 0, klassStateOffset(), Kind.Int);
-            if (klassState != klassStateFullyInitialized()) {
-                if (logType != null) {
-                    Log.print(logType);
-                    Log.println(" - uninit alloc");
-                }
-                return verifyOop(NewInstanceStubCall.call(hub));
-            }
-        }
-
         if (useTLAB) {
             Word thread = asWord(register(r15, wordKind()));
             Word top = loadWord(thread, threadTlabTopOffset());
@@ -135,16 +123,6 @@
     }
 
     @Fold
-    private static int klassStateOffset() {
-        return HotSpotGraalRuntime.getInstance().getConfig().klassStateOffset;
-    }
-
-    @Fold
-    private static int klassStateFullyInitialized() {
-        return HotSpotGraalRuntime.getInstance().getConfig().klassStateFullyInitialized;
-    }
-
-    @Fold
     private static int threadTlabTopOffset() {
         return HotSpotGraalRuntime.getInstance().getConfig().threadTlabTopOffset;
     }
@@ -186,7 +164,7 @@
             this.cache = new Cache(runtime);
             this.useTLAB = useTLAB;
             try {
-                newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class, boolean.class, String.class));
+                newInstance = runtime.getResolvedJavaMethod(NewInstanceSnippets.class.getDeclaredMethod("newInstance", Object.class, int.class, boolean.class, String.class));
             } catch (NoSuchMethodException e) {
                 throw new GraalInternalError(e);
             }
@@ -203,7 +181,7 @@
             int instanceSize = type.instanceSize();
             assert (instanceSize % wordSize()) == 0;
             assert instanceSize >= 0;
-            Key key = new Key(newInstance).add("size", instanceSize).add("checkInit", !type.isInitialized()).add("useTLAB", useTLAB).add("logType", LOG_ALLOCATION ? type.name() : null);
+            Key key = new Key(newInstance).add("size", instanceSize).add("useTLAB", useTLAB).add("logType", LOG_ALLOCATION ? type.name() : null);
             Arguments arguments = arguments("hub", hub);
             SnippetTemplate template = cache.get(key);
             Debug.log("Lowering newInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, arguments);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Jun 19 11:38:30 2012 +0200
@@ -662,7 +662,7 @@
 
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
-        if (type instanceof ResolvedJavaType) {
+        if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
             NewInstanceNode n = currentGraph.add(new NewInstanceNode((ResolvedJavaType) type));
             frameState.apush(append(n));
         } else {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets.test/src/com/oracle/graal/snippets/WordTest.java	Tue Jun 19 11:38:30 2012 +0200
@@ -0,0 +1,124 @@
+/*
+ * 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 static com.oracle.graal.nodes.calc.Condition.*;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.*;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.tests.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
+/**
+ * Tests for the {@link Word} type.
+ */
+public class WordTest extends GraalCompilerTest implements SnippetsInterface {
+
+    private final SnippetInstaller installer;
+
+    public WordTest() {
+        TargetDescription target = Graal.getRequiredCapability(GraalCompiler.class).target;
+        installer = new SnippetInstaller(runtime, target);
+    }
+
+    @Override
+    protected StructuredGraph parse(Method m) {
+        ResolvedJavaMethod resolvedMethod = runtime.getResolvedJavaMethod(m);
+        return installer.makeGraph(resolvedMethod, null);
+    }
+
+    @Test
+    public void test_arithmetic() {
+        long[] words = new long[] {Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
+        for (long word : words) {
+            for (int addend = -1000; addend < 1000; addend++) {
+                test("plus_int", word, addend);
+                test("plus_int", word, -addend);
+                test("minus_int", word, addend);
+                test("minus_int", word, -addend);
+            }
+            for (long addend : words) {
+                test("plus_int", word, (int) addend);
+                test("minus_int", word, (int) addend);
+                test("plus_int", word, -((int) addend));
+                test("minus_int", word, -((int) addend));
+            }
+        }
+    }
+
+    @Test
+    public void test_compare() {
+        long[] words = new long[] {Long.MIN_VALUE, Long.MIN_VALUE + 1, -1L, 0L, 1L, Long.MAX_VALUE - 1, Long.MAX_VALUE};
+        for (long word1 : words) {
+            for (long word2 : words) {
+                for (Condition cond : new Condition[] {AE, AT, EQ, NE, BE, BT}) {
+                    test("compare" + cond.name(), word1, word2);
+                    test("compare" + cond.name(), word2, word1);
+                }
+            }
+        }
+    }
+
+    @Snippet
+    public static long plus_int(long word, int addend) {
+        return Word.fromLong(word).plus(addend).toLong();
+    }
+
+    @Snippet
+    public static long minus_int(long word, int addend) {
+        return Word.fromLong(word).plus(addend).toLong();
+    }
+
+    @Snippet
+    public static boolean compareAE(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.AE, Word.fromLong(word2));
+    }
+    @Snippet
+    public static boolean compareAT(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.AT, Word.fromLong(word2));
+    }
+    @Snippet
+    public static boolean compareEQ(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.EQ, Word.fromLong(word2));
+    }
+    @Snippet
+    public static boolean compareNE(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.NE, Word.fromLong(word2));
+    }
+    @Snippet
+    public static boolean compareBE(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.BE, Word.fromLong(word2));
+    }
+    @Snippet
+    public static boolean compareBT(long word1, long word2) {
+        return Word.fromLong(word1).cmp(Condition.BT, Word.fromLong(word2));
+    }
+
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java	Tue Jun 19 11:38:30 2012 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.snippets.Word.Operation;
 import com.oracle.graal.snippets.nodes.*;
 
 /**
@@ -67,6 +68,9 @@
                         return false;
                     }
                 }
+                if (method.getAnnotation(Operation.class) != null) {
+                    return false;
+                }
                 return true;
             }
         };
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Tue Jun 19 11:38:30 2012 +0200
@@ -134,10 +134,10 @@
         }
     }
 
-    private StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) {
+    public StructuredGraph makeGraph(final ResolvedJavaMethod method, final InliningPolicy policy) {
         StructuredGraph graph = graphCache.get(method);
         if (graph == null) {
-            graph = buildGraph(method, policy);
+            graph = buildGraph(method, policy == null ? inliningPolicy(method) : policy);
             //System.out.println("built " + graph);
             graphCache.put(method, graph);
         }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Word.java	Tue Jun 19 11:38:30 2012 +0200
@@ -26,6 +26,7 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
 
 /**
@@ -46,32 +47,83 @@
      * The canonical {@link Operation} represented by a method in the {@link Word} class.
      */
     public enum Opcode {
+        L2W,
+        I2W,
+        W2L,
+        W2I,
         PLUS,
         MINUS,
         COMPARE;
     }
 
-    private Word() {
+    private Word(long value) {
+        this.value = value;
+    }
+
+    private final long value;
+
+    @Operation(L2W)
+    public static Word fromLong(long value) {
+        return new Word(value);
+    }
+
+    @Operation(I2W)
+    public static Word fromInt(int value) {
+        return new Word(value);
+    }
+
+    @Operation(W2I)
+    public int toInt() {
+        return (int) value;
+    }
+
+    @Operation(W2L)
+    public long toLong() {
+        return value;
     }
 
     @Operation(COMPARE)
-    public native boolean cmp(Condition condition, Word other);
+    public boolean cmp(Condition condition, Word other) {
+        long a = value;
+        long b = other.value;
+        switch (condition) {
+            case AE: return (a >= b) ^ ((a < 0) != (b < 0));
+            case AT: return (a > b) ^ ((a < 0) != (b < 0));
+            case BE: return (a <= b) ^ ((a < 0) != (b < 0));
+            case BT: return (a < b) ^ ((a < 0) != (b < 0));
+            case EQ: return a == b;
+            case NE: return a != b;
+            default: throw new GraalInternalError("Unexpected operation on word: " + condition);
+        }
+    }
 
     @Operation(PLUS)
-    public native Word plus(int addend);
-
-    @Operation(PLUS)
-    public native Word plus(long addend);
+    public Word plus(int addend) {
+        return new Word(value + addend);
+    }
 
     @Operation(PLUS)
-    public native Word plus(Word addend);
+    public Word plus(long addend) {
+        return new Word(value + addend);
+    }
 
-    @Operation(MINUS)
-    public native Word minus(int addend);
+    @Operation(PLUS)
+    public Word plus(Word addend) {
+        return new Word(value + addend.value);
+    }
 
     @Operation(MINUS)
-    public native Word minus(long addend);
+    public Word minus(int addend) {
+        return new Word(value - addend);
+    }
 
     @Operation(MINUS)
-    public native Word minus(Word addend);
+    public Word minus(long addend) {
+        return new Word(value - addend);
+    }
+
+    @Operation(MINUS)
+    public Word minus(Word addend) {
+        return new Word(value - addend.value);
+    }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/WordTypeRewriterPhase.java	Tue Jun 19 11:38:30 2012 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.extended.*;
@@ -81,7 +81,7 @@
             if (operation != null) {
                 NodeInputList<ValueNode> arguments = callTargetNode.arguments();
                 Invoke invoke = (Invoke) callTargetNode.usages().first();
-                assert invoke != null;
+                assert invoke != null : callTargetNode.targetMethod();
 
                 Opcode opcode = operation.value();
                 switch (opcode) {
@@ -99,6 +99,40 @@
                         invoke.intrinsify(op);
                         break;
                     }
+
+                    case W2I: {
+                        assert arguments.size() == 1;
+                        ValueNode value = arguments.last();
+                        ValueNode intValue = fromWordKindTo(graph, value, Kind.Int);
+                        invoke.intrinsify(intValue);
+                        break;
+                    }
+
+                    case W2L: {
+                        assert arguments.size() == 1;
+                        ValueNode value = arguments.last();
+                        ValueNode longValue = fromWordKindTo(graph, value, Kind.Long);
+                        invoke.intrinsify(longValue);
+                        break;
+                    }
+
+                    case L2W: {
+                        assert arguments.size() == 1;
+                        ValueNode value = arguments.last();
+                        assert value.kind() == Kind.Long;
+                        ValueNode wordValue = asWordKind(graph, value);
+                        invoke.intrinsify(wordValue);
+                        break;
+                    }
+
+                    case I2W: {
+                        assert arguments.size() == 1;
+                        ValueNode value = arguments.last();
+                        assert value.kind() == Kind.Int;
+                        invoke.intrinsify(asWordKind(graph, value));
+                        break;
+                    }
+
                     default: {
                         throw new GraalInternalError("Unknown opcode: %s", opcode);
                     }
@@ -111,7 +145,7 @@
      * Creates comparison node for a given condition and two input values.
      */
     private ValueNode compare(Condition condition, StructuredGraph graph, ValueNode left, ValueNode right) {
-        assert condition.isUnsigned();
+        assert condition.isUnsigned() || condition == Condition.EQ || condition == Condition.NE : condition;
         assert left.kind() == wordKind;
         assert right.kind() == wordKind;
 
@@ -158,6 +192,21 @@
         return value;
     }
 
+    private static ValueNode fromWordKindTo(StructuredGraph graph, ValueNode value, Kind to) {
+        Kind from = value.kind();
+        if (from != to) {
+            Op op;
+            if (from.isLong()) {
+                op = Op.L2I;
+            } else {
+                assert from.isInt();
+                op = Op.I2L;
+            }
+            return graph.unique(new ConvertNode(op, value));
+        }
+        return value;
+    }
+
     public boolean isWord(ValueNode node) {
         return isWord(node.stamp().declaredType());
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Tue Jun 19 11:38:30 2012 +0200
@@ -67,7 +67,7 @@
         }
 
         final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method);
-        InstalledCode compiledMethod = compile(riMethod, graph);
+        InstalledCode compiledMethod = getCode(riMethod, graph);
         try {
             Object result = compiledMethod.execute("1", "2", "3");
             Assert.assertEquals("1-2-3", result);
@@ -81,7 +81,7 @@
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
         final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method);
-        InstalledCode compiledMethod = compile(riMethod, graph);
+        InstalledCode compiledMethod = getCode(riMethod, graph);
         try {
             Object result = compiledMethod.executeVarargs("1", "2", "3");
             Assert.assertEquals("1 2 3", result);
@@ -95,7 +95,7 @@
         Method method = getMethod("testMethodVirtual");
         final StructuredGraph graph = parse(method);
         final ResolvedJavaMethod riMethod = runtime.getResolvedJavaMethod(method);
-        InstalledCode compiledMethod = compile(riMethod, graph);
+        InstalledCode compiledMethod = getCode(riMethod, graph);
         try {
             f1 = "0";
             Object result = compiledMethod.executeVarargs(this, "1", "2", "3");
@@ -123,7 +123,7 @@
             }
         }
 
-        InstalledCode compiledMethod = compile(riMethod, graph);
+        InstalledCode compiledMethod = getCode(riMethod, graph);
         final CompilableObject compilableObject = new CompilableObjectImpl(0);
 
         Object result;
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalCompilerTest.java	Tue Jun 19 11:38:30 2012 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.tests;
 
 import java.lang.reflect.*;
+import java.util.*;
 import java.util.concurrent.*;
 
 import junit.framework.*;
@@ -163,8 +164,7 @@
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
-        InstalledCode compiledMethod = compile(runtime.getResolvedJavaMethod(method), parse(method));
-        compiledMethod.method();
+        InstalledCode compiledMethod = getCode(runtime.getResolvedJavaMethod(method), parse(method));
 
         if (exception != null) {
             try {
@@ -179,13 +179,35 @@
         }
     }
 
-    protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) {
-        return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable<InstalledCode>() {
+    private Map<ResolvedJavaMethod, InstalledCode> cache = new HashMap<>();
+
+    /**
+     * Gets installed code for a given method and graph, compiling it first if necessary.
+     */
+    protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) {
+        return getCode(method, graph, false);
+    }
+
+    /**
+     * Gets installed code for a given method and graph, compiling it first if necessary.
+     *
+     * @param forceCompile specifies whether to ignore any previous code cached for the (method, key) pair
+     */
+    protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph, boolean forceCompile) {
+        if (!forceCompile) {
+            InstalledCode cached = cache.get(method);
+            if (cached != null && cached.isValid()) {
+                return cached;
+            }
+        }
+        InstalledCode installedCode = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable<InstalledCode>() {
             public InstalledCode call() throws Exception {
                 CompilationResult targetMethod = runtime.compile(method, graph);
                 return addMethod(method, targetMethod);
             }
         });
+        cache.put(method, installedCode);
+        return installedCode;
     }
 
     protected InstalledCode addMethod(final ResolvedJavaMethod method, final CompilationResult tm) {
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java	Mon Jun 18 18:01:53 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java	Tue Jun 19 11:38:30 2012 +0200
@@ -36,11 +36,13 @@
     protected JavaTypeProfile currentProfile;
 
     @Override
-    protected InstalledCode compile(final ResolvedJavaMethod method, final StructuredGraph graph) {
+    protected InstalledCode getCode(final ResolvedJavaMethod method, final StructuredGraph graph) {
+        boolean forceCompile = false;
         if (currentProfile != null) {
             replaceProfile(graph, currentProfile);
+            forceCompile = true;
         }
-        return super.compile(method, graph);
+        return super.getCode(method, graph, forceCompile);
     }
 
     protected JavaTypeProfile profile(Class... types) {
--- a/mx/commands.py	Mon Jun 18 18:01:53 2012 +0200
+++ b/mx/commands.py	Tue Jun 19 11:38:30 2012 +0200
@@ -175,7 +175,7 @@
     """run one or all DaCapo benchmarks
     
     DaCapo options are distinguished from VM options by a '@' prefix.
-    For example, '@--iterations @5' will pass '--iterations 5' to the
+    For example, '@-n @5' will pass '-n 5' to the
     DaCapo harness."""
 
     numTests = {}
@@ -624,26 +624,7 @@
                                 elif e == basename + '.class':
                                     classes.append(pkg + '.' + basename)
 
-
-# Table of unit tests.
-# Keys are project names, values are package name lists.
-# All source files in the given (project,package) pairs are scanned for lines
-# containing '@Test'. These are then determined to be the classes defining
-# unit tests.
-_unittests = {
-    'com.oracle.graal.tests': ['com.oracle.graal.compiler.tests'],
-}
-_jtttests = {
-    'com.oracle.graal.jtt': ['com.oracle.graal.jtt'],
-}
-
-def unittest(args):
-    """run the Graal Compiler Unit Tests in the GraalVM
-    
-    If filters are supplied, only tests whose fully qualified name
-    include a filter as a substring are run. Negative filters are
-    those with a '-' prefix. VM args should have a @ prefix."""
-    
+def _run_tests(args, harnessName, harness):
     pos = [a for a in args if a[0] != '-' and a[0] != '@' ]
     neg = [a[1:] for a in args if a[0] == '-']
     vmArgs = [a[1:] for a in args if a[0] == '@']
@@ -654,18 +635,30 @@
                 return True
         return False
     
-    for proj in _unittests.iterkeys():
-        p = mx.project(proj)
-        classes = []
-        for pkg in _unittests[proj]:
-            _find_classes_with_annotations(classes, p, pkg, ['@Test'])
+    for p in mx.projects():
+        if getattr(p, 'testHarness', None) == harnessName:
+            classes = []
+            _find_classes_with_annotations(classes, p, None, ['@Test'])
+        
+            if len(pos) != 0:
+                classes = [c for c in classes if containsAny(c, pos)]
+            if len(neg) != 0:
+                classes = [c for c in classes if not containsAny(c, neg)]
+            
+            if len(classes) != 0:
+                mx.log('running tests in ' + p.name)
+                harness(p, vmArgs, classes)                
+
+def unittest(args):
+    """run the Graal Compiler Unit Tests in the GraalVM
     
-        if len(pos) != 0:
-            classes = [c for c in classes if containsAny(c, pos)]
-        if len(neg) != 0:
-            classes = [c for c in classes if not containsAny(c, neg)]
-        
-        vm(['-XX:-BootstrapGraal', '-esa'] + vmArgs + ['-cp', mx.classpath(proj), 'org.junit.runner.JUnitCore'] + classes)
+    If filters are supplied, only tests whose fully qualified name
+    include a filter as a substring are run. Negative filters are
+    those with a '-' prefix. VM args should have a @ prefix."""
+    
+    def harness(p, vmArgs, classes):
+        vm(['-XX:-BootstrapGraal', '-esa'] + vmArgs + ['-cp', mx.classpath(p.name), 'org.junit.runner.JUnitCore'] + classes)
+    _run_tests(args, 'unittest', harness)
     
 def jtt(args):
     """run the Java Tester Tests in the GraalVM
@@ -674,28 +667,9 @@
     include a filter as a substring are run. Negative filters are
     those with a '-' prefix. VM args should have a @ prefix."""
     
-    pos = [a for a in args if a[0] != '-' and a[0] != '@' ]
-    neg = [a[1:] for a in args if a[0] == '-']
-    vmArgs = [a[1:] for a in args if a[0] == '@']
-
-    def containsAny(c, substrings):
-        for s in substrings:
-            if s in c:
-                return True
-        return False
-    
-    for proj in _jtttests.iterkeys():
-        p = mx.project(proj)
-        classes = []
-        for pkg in _jtttests[proj]:
-            _find_classes_with_annotations(classes, p, pkg, ['@Test'])
-    
-        if len(pos) != 0:
-            classes = [c for c in classes if containsAny(c, pos)]
-        if len(neg) != 0:
-            classes = [c for c in classes if not containsAny(c, neg)]
-            
-        vm(['-XX:-BootstrapGraal', '-XX:CompileOnly=com/oracle/graal/jtt', '-XX:CompileCommand=compileonly,java/lang/Object::<init>', '-XX:CompileCommand=quiet', '-Xcomp', '-esa'] + vmArgs + ['-cp', mx.classpath(proj), 'org.junit.runner.JUnitCore'] + classes)
+    def harness(p, vmArgs, classes):
+        vm(['-XX:-BootstrapGraal', '-XX:CompileOnly=com/oracle/graal/jtt', '-XX:CompileCommand=compileonly,java/lang/Object::<init>', '-XX:CompileCommand=quiet', '-Xcomp', '-esa'] + vmArgs + ['-cp', mx.classpath(p.name), 'org.junit.runner.JUnitCore'] + classes)
+    _run_tests(args, 'jtt', harness)
     
 def buildvms(args):
     """build one or more VMs in various configurations"""
--- a/mx/projects	Mon Jun 18 18:01:53 2012 +0200
+++ b/mx/projects	Tue Jun 19 11:38:30 2012 +0200
@@ -119,9 +119,10 @@
 # graal.snippets.test
 project@com.oracle.graal.snippets.test@subDir=graal
 project@com.oracle.graal.snippets.test@sourceDirs=src
-project@com.oracle.graal.snippets.test@dependencies=com.oracle.graal.snippets
+project@com.oracle.graal.snippets.test@dependencies=com.oracle.graal.snippets,com.oracle.graal.tests
 project@com.oracle.graal.snippets.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.snippets.test@javaCompliance=1.7
+project@com.oracle.graal.snippets.test@testHarness=unittest
 
 # graal.nodes
 project@com.oracle.graal.nodes@subDir=graal
@@ -184,6 +185,7 @@
 project@com.oracle.graal.tests@dependencies=JUNIT,com.oracle.graal.printer,com.oracle.graal.api
 project@com.oracle.graal.tests@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.tests@javaCompliance=1.7
+project@com.oracle.graal.tests@testHarness=unittest
 
 # graal.jtt
 project@com.oracle.graal.jtt@subDir=graal
@@ -191,6 +193,7 @@
 project@com.oracle.graal.jtt@dependencies=JUNIT
 project@com.oracle.graal.jtt@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.jtt@javaCompliance=1.7
+project@com.oracle.graal.jtt@testHarness=jtt
 
 # graal.examples
 project@com.oracle.graal.examples@subDir=graal