changeset 5055:90c150a0a22b

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 08 Mar 2012 12:46:19 +0100
parents b4f548d49f96 c53115427ff9
children 26f8371c229c
files
diffstat 19 files changed, 601 insertions(+), 367 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Thu Mar 08 12:46:19 2012 +0100
@@ -129,6 +129,7 @@
     // Other printing settings
     public static boolean PrintQueue                         = ____;
     public static boolean PrintCompilation                   = ____;
+    public static boolean PrintProfilingInformation          = ____;
     public static boolean PrintXirTemplates                  = ____;
     public static boolean PrintIRWithLIR                     = ____;
     public static boolean PrintAssembly                      = ____;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Thu Mar 08 12:46:19 2012 +0100
@@ -33,6 +33,7 @@
 import com.oracle.max.graal.compiler.util.InliningUtil.InliningCallback;
 import com.oracle.max.graal.cri.*;
 import com.oracle.max.graal.debug.*;
+import com.oracle.max.graal.debug.internal.*;
 import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.nodes.*;
 
@@ -245,14 +246,13 @@
     private static class WeightBasedInliningPolicy implements InliningPolicy {
         @Override
         public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
-            if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
-                Debug.log("not inlining (CompiledCodeSize too large %d): %s", info.compiledCodeSize(), info);
+            if (!checkCompiledCodeSize(info)) {
                 return false;
             }
 
             double penalty = Math.pow(GraalOptions.InliningSizePenaltyExp, callerGraph.getNodeCount() / (double) GraalOptions.MaximumDesiredSize) / GraalOptions.InliningSizePenaltyExp;
             if (info.weight > GraalOptions.MaximumInlineWeight / (1 + penalty * GraalOptions.InliningSizePenalty)) {
-                Debug.log("not inlining (cut off by weight %e): ", info.weight);
+                Debug.log("not inlining (cut off by weight %e): %s", info.weight, info);
                 return false;
             }
 
@@ -265,13 +265,7 @@
         @Override
         public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
             double maxSize = Math.max(GraalOptions.MaximumTrivialSize, Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize);
-            if (info.weight <= maxSize) {
-                Debug.log("inlining (size %f): %s", info.weight, info);
-                return true;
-            } else {
-                Debug.log("not inlining (too large %f): %s", info.weight, info);
-                return false;
-            }
+            return decideSizeBasedInlining(info, maxSize);
         }
     }
 
@@ -279,8 +273,7 @@
         @Override
         public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
             assert GraalOptions.ProbabilityAnalysis;
-            if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
-                Debug.log("not inlining (CompiledCodeSize too large %d): %s", info.compiledCodeSize(), info);
+            if (!checkCompiledCodeSize(info)) {
                 return false;
             }
 
@@ -288,13 +281,7 @@
             double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize * inlineWeight;
             maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize);
 
-            if (info.weight <= maxSize) {
-                Debug.log("inlining (size %f <= %f): %s", info.weight, maxSize, info);
-                return true;
-            } else {
-                Debug.log("not inlining (too large %f > %f): %s", info.weight, maxSize, info);
-                return false;
-            }
+            return decideSizeBasedInlining(info, maxSize);
         }
     }
 
@@ -302,8 +289,7 @@
         @Override
         public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
             assert GraalOptions.ProbabilityAnalysis;
-            if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
-                Debug.log("not inlining (CompiledCodeSize too large %d): %s", info.compiledCodeSize(), info);
+            if (!checkCompiledCodeSize(info)) {
                 return false;
             }
 
@@ -312,13 +298,7 @@
             maxSize = maxSize + maxSize * inlineBoost;
             maxSize = Math.min(GraalOptions.MaximumGreedyInlineSize, Math.max(GraalOptions.MaximumTrivialSize, maxSize));
 
-            if (info.weight <= maxSize) {
-                Debug.log("inlining (size %f <= %f): %s", info.weight, maxSize, info);
-                return true;
-            } else {
-                Debug.log("not inlining (too large %f > %f): %s", info.weight, maxSize, info);
-                return false;
-            }
+            return decideSizeBasedInlining(info, maxSize);
         }
     }
 
@@ -326,8 +306,7 @@
         @Override
         public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) {
             assert GraalOptions.ProbabilityAnalysis;
-            if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
-                Debug.log("not inlining (CompiledCodeSize too large %d): %s", info.compiledCodeSize(), info);
+            if (!checkCompiledCodeSize(info)) {
                 return false;
             }
 
@@ -345,16 +324,28 @@
             maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * maxSize * inlineRatio;
             maxSize = Math.max(maxSize, GraalOptions.MaximumTrivialSize);
 
-            if (info.weight <= maxSize) {
-                Debug.log("inlining (size %f <= %f): %s", info.weight, maxSize, info);
-                return true;
-            } else {
-                Debug.log("not inlining (too large %f > %f): %s", info.weight, maxSize, info);
-                return false;
-            }
+            return decideSizeBasedInlining(info, maxSize);
         }
     }
 
+    private static boolean decideSizeBasedInlining(InlineInfo info, double maxSize) {
+        boolean success = info.weight <= maxSize;
+        if (DebugScope.getInstance().isLogEnabled()) {
+            String formatterString = success ? "inlining invoke at %s@%d (size %f <= %f): %s" : "not inlining invoke at %s@%d (too large %f > %f): %s";
+            Debug.log(formatterString, CiUtil.format("%H.%n(%p):%r", info.invoke.stateAfter().method()), info.invoke.bci(), info.weight, maxSize, info);
+        }
+        return success;
+    }
+
+    private static boolean checkCompiledCodeSize(InlineInfo info) {
+        if (GraalOptions.SmallCompiledCodeSize >= 0 && info.compiledCodeSize() > GraalOptions.SmallCompiledCodeSize) {
+            Debug.log("not inlining invoke at %s@%d (CompiledCodeSize %d > %d): %s", CiUtil.format("%H.%n(%p):%r", info.invoke.stateAfter().method()), info.invoke.bci(), info.compiledCodeSize(), GraalOptions.SmallCompiledCodeSize, info);
+            return false;
+        }
+        return true;
+    }
+
+
     private interface WeightComputationPolicy {
         double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.examples/src/examples/HelloWorld.java	Thu Mar 08 12:46:19 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 examples;
+
+
+public class HelloWorld {
+    public static void main(String[] args) {
+        System.out.println("hello world!");
+    }
+}
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java	Thu Mar 08 12:46:19 2012 +0100
@@ -48,7 +48,11 @@
         this.timerFilter = timerFilter;
         this.dumpFilter = dumpFilter;
         this.methodFilter = methodFilter == null ? null : methodFilter.split(",");
-        dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort));
+        if (GraalOptions.PrintIdealGraphFile) {
+            dumpHandlers.add(new IdealGraphPrinterDumpHandler());
+        } else {
+            dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort));
+        }
         dumpHandlers.add(new CFGPrinterObserver());
     }
 
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java	Thu Mar 08 12:46:19 2012 +0100
@@ -302,7 +302,7 @@
 
         @Override
         public double getBranchTakenProbability(HotSpotMethodData data, int position) {
-            return 1;
+            return getExecutionCount(data, position) != 0 ? 1 : 0;
         }
 
         @Override
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Thu Mar 08 12:46:19 2012 +0100
@@ -238,6 +238,7 @@
         return ((HotSpotTypeResolvedImpl) holder()).constantPool();
     }
 
+    @Override
     public void dumpProfile() {
         TTY.println("profile info for %s", this);
         TTY.println("canBeStaticallyBound: " + canBeStaticallyBound());
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java	Thu Mar 08 12:46:19 2012 +0100
@@ -457,6 +457,7 @@
             block.successors.add(block.retSuccessor);
             assert block.retSuccessor != block.jsrSuccessor;
         }
+        Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.successors, block.jsrSuccessor, block.retSuccessor, block.jsrScope);
 
         if (block.jsrSuccessor != null || !scope.isEmpty()) {
             for (int i = 0; i < block.successors.size(); i++) {
@@ -468,7 +469,7 @@
                 if (successor == block.retSuccessor) {
                     nextScope = scope.pop();
                 }
-                if (!successor.jsrScope.isEmpty()) {
+                if (!successor.jsrScope.isPrefixOf(nextScope)) {
                     throw new JsrNotSupportedBailout("unstructured control flow  (" + successor.jsrScope + " " + nextScope + ")");
                 }
                 if (!nextScope.isEmpty()) {
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Thu Mar 08 12:46:19 2012 +0100
@@ -152,6 +152,10 @@
             log.println("Compiling " + method);
         }
 
+        if (GraalOptions.PrintProfilingInformation) {
+            method.dumpProfile();
+        }
+
         // compute the block map, setup exception handlers and get the entrypoint(s)
         BciBlockMapping blockMap = createBlockMap();
         this.canTrapBitSet = blockMap.canTrap;
@@ -531,7 +535,11 @@
     }
 
     private void genGoto() {
-        appendGoto(createTarget(currentBlock.successors.get(0), frameState));
+        double probability = profilingInfo.getBranchTakenProbability(bci());
+        if (probability < 0) {
+            probability = 1;
+        }
+        appendGoto(createTarget(probability, currentBlock.successors.get(0), frameState));
         assert currentBlock.normalSuccessors == 1;
     }
 
@@ -1188,6 +1196,15 @@
         return x;
     }
 
+    private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) {
+        assert probability >= 0 && probability <= 1;
+        if (probability == 0 && config.useBranchPrediction()) {
+            return currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
+        } else {
+            return createTarget(block, stateAfter);
+        }
+    }
+
     private FixedNode createTarget(Block block, FrameStateBuilder stateAfter) {
         assert block != null && stateAfter != null;
         assert !block.isExceptionEntry || stateAfter.stackSize() == 1;
@@ -1255,22 +1272,13 @@
      * deoptimizes immediately.
      */
     private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
-        assert probability >= 0 && probability <= 1;
-        if (probability == 0) {
-            FrameStateBuilder state = stateAfter.copy();
-            state.clearNonLiveLocals(block.localsLiveIn);
-
-            BeginNode begin = currentGraph.add(new BeginNode());
-            DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateReprofile));
-            begin.setNext(deopt);
-            begin.setStateAfter(state.create(block.startBci));
-            return begin;
-        }
-
-        FixedNode target = createTarget(block, stateAfter);
+        FixedNode target = createTarget(probability, block, stateAfter);
         assert !(target instanceof BeginNode);
         BeginNode begin = currentGraph.add(new BeginNode());
         begin.setNext(target);
+
+        assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) :
+            "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information.";
         return begin;
     }
 
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/JsrScope.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/JsrScope.java	Thu Mar 08 12:46:19 2012 +0100
@@ -51,6 +51,10 @@
         return scope == 0;
     }
 
+    public boolean isPrefixOf(JsrScope other) {
+        return (scope & other.scope) == scope;
+    }
+
     public JsrScope pop() {
         return new JsrScope(scope >>> 16);
     }
--- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/IfBoxingEliminationTest.java	Thu Mar 08 12:45:49 2012 +0100
+++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/IfBoxingEliminationTest.java	Thu Mar 08 12:46:19 2012 +0100
@@ -69,31 +69,37 @@
         return result;
     }
 
-    private void test(String snippet) {
-        StructuredGraph graph = parse(snippet);
-        BoxingMethodPool pool = new BoxingMethodPool(runtime());
-        IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool);
-        PhasePlan phasePlan = getDefaultPhasePlan();
-        phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
-        phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase());
-        identifyBoxingPhase.apply(graph);
-        Collection<Invoke> hints = new ArrayList<>();
-        for (Invoke invoke : graph.getInvokes()) {
-            hints.add(invoke);
-        }
-        new InliningPhase(null, runtime(), hints, null, phasePlan).apply(graph);
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new PhiStampPhase().apply(graph);
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        Debug.dump(graph, "Graph");
-        new BoxingEliminationPhase().apply(graph);
-        Debug.dump(graph, "Graph");
-        new ExpandBoxingNodesPhase(pool).apply(graph);
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new DeadCodeEliminationPhase().apply(graph);
-        StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
-        new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
-        new DeadCodeEliminationPhase().apply(referenceGraph);
-        assertEquals(referenceGraph, graph);
+    private void test(final String snippet) {
+        Debug.scope("IfBoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() {
+            @Override
+            public void run() {
+                StructuredGraph graph = parse(snippet);
+                BoxingMethodPool pool = new BoxingMethodPool(runtime());
+                IdentifyBoxingPhase identifyBoxingPhase = new IdentifyBoxingPhase(pool);
+                PhasePlan phasePlan = getDefaultPhasePlan();
+                phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
+                phasePlan.addPhase(PhasePosition.AFTER_PARSING, new PhiStampPhase());
+                identifyBoxingPhase.apply(graph);
+                Collection<Invoke> hints = new ArrayList<>();
+                for (Invoke invoke : graph.getInvokes()) {
+                    hints.add(invoke);
+                }
+                new InliningPhase(null, runtime(), hints, null, phasePlan).apply(graph);
+                new CanonicalizerPhase(null, runtime(), null).apply(graph);
+                new PhiStampPhase().apply(graph);
+                new CanonicalizerPhase(null, runtime(), null).apply(graph);
+                Debug.dump(graph, "Graph");
+                new BoxingEliminationPhase().apply(graph);
+                Debug.dump(graph, "Graph");
+                new ExpandBoxingNodesPhase(pool).apply(graph);
+                new CanonicalizerPhase(null, runtime(), null).apply(graph);
+                new DeadCodeEliminationPhase().apply(graph);
+                StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
+                new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
+                new DeadCodeEliminationPhase().apply(referenceGraph);
+
+                assertEquals(referenceGraph, graph);
+            }
+        });
     }
 }
--- a/mx/commands.py	Thu Mar 08 12:45:49 2012 +0100
+++ b/mx/commands.py	Thu Mar 08 12:46:19 2012 +0100
@@ -29,6 +29,7 @@
 import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing
 from os.path import join, exists, dirname, basename
 from argparse import ArgumentParser, REMAINDER
+from threading import Thread
 import mx
 import sanitycheck
 import json
@@ -230,6 +231,17 @@
     if len(failed) != 0:
         mx.abort('DaCapo failures: ' + str(failed))
     
+def intro(args):
+    """"run a simple program and visualize its compilation in the Graal Visualizer"""
+    # Start the visualizer in a separate thread
+    t = Thread(target=gv, args=([[]]))
+    t.start()
+    
+    # Give visualizer time to start
+    mx.log('Waiting 5 seconds for visualizer to start')
+    time.sleep(5)
+    
+    vm(['-G:Dump=HelloWorld', '-G:MethodFilter=main', '-Xcomp', '-XX:CompileOnly=HelloWorld::main', '-cp', mx.classpath('com.oracle.max.graal.examples')] + args + ['examples.HelloWorld'])
 
 def scaladacapo(args):
     """run one or all Scala DaCapo benchmarks
@@ -484,8 +496,8 @@
         
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'
     mx.expand_project_in_args(args)  
-    if mx.java().debug:
-        args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000'] + args
+    if mx.java().debug_port is not None:
+        args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args
     if _jacoco == 'on' or _jacoco == 'append':
         jacocoagent = mx.library("JACOCOAGENT", True)
         agentOptions = {
@@ -646,6 +658,7 @@
     parser = ArgumentParser(prog='mx gate');
     parser.add_argument('-n', '--omit-native-build', action='store_false', dest='buildNative', help='omit cleaning and building native code')
     parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM')
+    parser.add_argument('--jacocout', help='specify the output directory for jacoco report')
 
     args = parser.parse_args(args)
 
@@ -660,7 +673,7 @@
         t = Task('BuildJava')
         build(['--no-native'])
         tasks.append(t.stop())
-    
+        global _jacoco
         for vmbuild in ['fastdebug', 'product']:
             global _vmbuild
             _vmbuild = vmbuild
@@ -674,19 +687,35 @@
             vm(['-esa', '-version'])
             tasks.append(t.stop())
             
+            if vmbuild == 'product' and args.jacocout is not None:
+                _jacoco = 'on'
+            
             t = Task('UnitTests:' + vmbuild)
             unittest([])
             tasks.append(t.stop())
             
+            if vmbuild == 'product' and args.jacocout is not None:
+                _jacoco = 'append'
+            
             t = Task('JavaTesterTests:' + vmbuild)
             jtt([])
             tasks.append(t.stop())
             
+            if vmbuild == 'product' and args.jacocout is not None:
+                _jacoco = 'off'
+            
             for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
                 t = Task(str(test) + ':' + vmbuild)
                 if not test.test('graal'):
                     t.abort(test.group + ' ' + test.name + ' Failed')
                 tasks.append(t.stop())
+        
+        if args.jacocout is not None:
+            jacocoreport([args.jacocout])
+        
+        t = Task('BootstrapWithDeoptALot')
+        vm(['-XX:+DeoptimizeALot', '-XX:+VerifyOops', '-version'], vmbuild='fastdebug')
+        tasks.append(t.stop())
 
         t = Task('Checkstyle')
         if mx.checkstyle([]) != 0:
@@ -727,7 +756,9 @@
 
 def gv(args):
     """run the Graal Visualizer"""
-    mx.run(['ant', '-f', join(_graal_home, 'visualizer', 'build.xml'), '-q', 'run'])
+    with open(join(_graal_home, '.graal_visualizer.log'), 'w') as fp:
+        mx.log('[Graal Visualizer output is in ' + fp.name + ']')
+        mx.run(['ant', '-f', join(_graal_home, 'visualizer', 'build.xml'), '-l', fp.name, 'run'])
     
 def bench(args):
     """run benchmarks and parse their output for results
@@ -852,6 +883,7 @@
         'clean': [clean, ''],
         'copyrightcheck': [copyrightcheck, ''],
         'hsdis': [hsdis, '[att]'],
+        'intro': [intro, ''],
         'dacapo': [dacapo, '[[n] benchmark] [VM options|@DaCapo options]'],
         'scaladacapo': [scaladacapo, '[[n] benchmark] [VM options|@Scala DaCapo options]'],
         'specjvm2008': [specjvm2008, '[VM options|@specjvm2008 options]'],
--- a/mx/projects	Thu Mar 08 12:45:49 2012 +0100
+++ b/mx/projects	Thu Mar 08 12:46:19 2012 +0100
@@ -1,32 +1,4 @@
-# Library specification format:
-#
-#     library@<name>@<prop>=<value>
-#
-# Library properties (* = required):
-#
-#    *path: the file system path for the library to appear on a class path
-#     urls: a comma seperated list of URLs from which the library can be downloaded
-#     optional: if "true" then this library will be omitted from a class path if it doesn't exist on the file system and no URLs are specified
-#     eclipse.container: the name of the Eclipse library container corresponding to the library
-#
-# Project specification format:
-#
-#     project@<name>@<prop>=<value>
-#
-# The name of a project also denotes the directory it is in.
-#
-# Project properties:
-#
-#    *sourceDirs: a comma separated list of source directoriy names (relative to the project directory)
-#     dependencies: a comma separated list of the libraries and project the project depends upon (transitive dependencies may be omitted)
-#     eclipse.output: the output directory name (relative to the project directory)
-#     checkstyle: the project whose Checkstyle configuration (i.e. <project>/.checkstyle_checks.xml) is used
-#
-# The eclipse.* properties are only used when generating Eclipse project configuration files.
-#
-# Values can use environment variables with the syntax used in a Bash shell script.
-#
-
+# The format of this file is described in the documentation for my.py.
 
 library@JDK_TOOLS@path=${JAVA_HOME}/lib/tools.jar
 library@JDK_TOOLS@optional=true
@@ -55,91 +27,113 @@
 project@com.oracle.max.graal.hotspot@sourceDirs=src
 project@com.oracle.max.graal.hotspot@dependencies=com.oracle.max.graal.snippets
 project@com.oracle.max.graal.hotspot@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.hotspot@javaCompliance=1.7
 
 # graal.graph
 project@com.oracle.max.graal.graph@subDir=graal
 project@com.oracle.max.graal.graph@sourceDirs=src
 project@com.oracle.max.graal.graph@dependencies=com.oracle.max.graal.debug,JUNIT
+project@com.oracle.max.graal.graph@javaCompliance=1.7
 
 # graal.debug
 project@com.oracle.max.graal.debug@subDir=graal
 project@com.oracle.max.graal.debug@sourceDirs=src
 project@com.oracle.max.graal.debug@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.debug@javaCompliance=1.7
 
 # graal.lir
 project@com.oracle.max.graal.lir@subDir=graal
 project@com.oracle.max.graal.lir@sourceDirs=src
 project@com.oracle.max.graal.lir@dependencies=com.oracle.max.asm,com.oracle.max.graal.nodes
 project@com.oracle.max.graal.lir@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.lir@javaCompliance=1.7
 
 # graal.lir.amd64
 project@com.oracle.max.graal.lir.amd64@subDir=graal
 project@com.oracle.max.graal.lir.amd64@sourceDirs=src
 project@com.oracle.max.graal.lir.amd64@dependencies=com.oracle.max.graal.lir
 project@com.oracle.max.graal.lir.amd64@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.lir.amd64@javaCompliance=1.7
 
 # graal.alloc
 project@com.oracle.max.graal.alloc@subDir=graal
 project@com.oracle.max.graal.alloc@sourceDirs=src
 project@com.oracle.max.graal.alloc@dependencies=com.oracle.max.graal.lir
 project@com.oracle.max.graal.alloc@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.alloc@javaCompliance=1.7
 
 # graal.snippets
 project@com.oracle.max.graal.snippets@subDir=graal
 project@com.oracle.max.graal.snippets@sourceDirs=src,test
 project@com.oracle.max.graal.snippets@dependencies=com.oracle.max.graal.printer
 project@com.oracle.max.graal.snippets@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.snippets@javaCompliance=1.7
 
 # graal.nodes
 project@com.oracle.max.graal.nodes@subDir=graal
 project@com.oracle.max.graal.nodes@sourceDirs=src,test
 project@com.oracle.max.graal.nodes@dependencies=com.oracle.max.cri,com.oracle.max.graal.graph
 project@com.oracle.max.graal.nodes@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.nodes@javaCompliance=1.7
 
 # graal.compiler
 project@com.oracle.max.graal.compiler@subDir=graal
 project@com.oracle.max.graal.compiler@sourceDirs=src
 project@com.oracle.max.graal.compiler@dependencies=com.oracle.max.graal.lir.amd64,com.oracle.max.graal.alloc
 project@com.oracle.max.graal.compiler@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.compiler@javaCompliance=1.7
 
 # graal.java
 project@com.oracle.max.graal.java@subDir=graal
 project@com.oracle.max.graal.java@sourceDirs=src
 project@com.oracle.max.graal.java@dependencies=com.oracle.max.graal.compiler
 project@com.oracle.max.graal.java@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.java@javaCompliance=1.7
 
 # graal.printer
 project@com.oracle.max.graal.printer@subDir=graal
 project@com.oracle.max.graal.printer@sourceDirs=src
 project@com.oracle.max.graal.printer@dependencies=com.oracle.max.graal.java
 project@com.oracle.max.graal.printer@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.printer@javaCompliance=1.7
 
 # graal.test
 project@com.oracle.max.graal.tests@subDir=graal
 project@com.oracle.max.graal.tests@sourceDirs=src
 project@com.oracle.max.graal.tests@dependencies=com.oracle.max.graal.printer
 project@com.oracle.max.graal.tests@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.tests@javaCompliance=1.7
 
 # graal.jtt
 project@com.oracle.max.graal.jtt@subDir=graal
 project@com.oracle.max.graal.jtt@sourceDirs=src
 project@com.oracle.max.graal.jtt@dependencies=JUNIT
 project@com.oracle.max.graal.jtt@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.jtt@javaCompliance=1.7
+
+# graal.examples
+project@com.oracle.max.graal.examples@subDir=graal
+project@com.oracle.max.graal.examples@sourceDirs=src
+project@com.oracle.max.graal.examples@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.graal.examples@javaCompliance=1.7
 
 # max.asm
 project@com.oracle.max.asm@subDir=graal
 project@com.oracle.max.asm@sourceDirs=src
 project@com.oracle.max.asm@dependencies=com.oracle.max.criutils
 project@com.oracle.max.asm@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.asm@javaCompliance=1.7
 
 # max.cri
 project@com.oracle.max.cri@subDir=graal
 project@com.oracle.max.cri@sourceDirs=src
 project@com.oracle.max.cri@dependencies=
 project@com.oracle.max.cri@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.cri@javaCompliance=1.7
 
 # max.criutils
 project@com.oracle.max.criutils@subDir=graal
 project@com.oracle.max.criutils@sourceDirs=src
 project@com.oracle.max.criutils@dependencies=com.oracle.max.cri
 project@com.oracle.max.criutils@checkstyle=com.oracle.max.graal.graph
+project@com.oracle.max.criutils@javaCompliance=1.7
--- a/mxtool/mx.py	Thu Mar 08 12:45:49 2012 +0100
+++ b/mxtool/mx.py	Thu Mar 08 12:46:19 2012 +0100
@@ -25,64 +25,104 @@
 #
 # ----------------------------------------------------------------------------------------------------
 #
-# mx is a command line tool inspired by mvn (http://maven.apache.org/)
-# and hg (http://mercurial.selenic.com/). It includes a mechanism for
-# managing the dependencies between a set of projects (like Maven)
-# as well as making it simple to run commands
-# (like hg is the interface to the Mercurial commands).
-#
-# The organizing principle of mx is a project suite. A suite is a directory
-# containing one or more projects. It's not coincidental that this closely
-# matches the layout of one or more projects in a Mercurial repository.
-# The configuration information for a suite lives in an 'mx' sub-directory
-# at the top level of the suite. 
-#
-# When launched, mx treats the current working directory as a suite.
-# This is the primary suite. All other suites are called included suites.
-#
-# The configuration files (i.e. in the 'mx' sub-directory) of a suite are:
-#
-#   projects    - Defines the projects and libraries in the suite and the dependencies between them
-#   commands.py - Suite specific extensions to the commands available to mx. This is only processed
-#                 for the primary suite.
-#   includes    - Other suites to be loaded. This is recursive. 
-#   env         - A set of environment variable definitions.
-#
-# The includes and env files are typically not put under version control
-# as they usually contain local file-system paths.
-#
-# The projects file is like the pom.xml file from Maven except that
-# it is a properties file (not XML). Each non-comment line
-# in the file specifies an attribute of a project or library. The main 
-# difference between a project and a library is that the former contains
-# source code built by the mx tool where as the latter is an external
-# dependency. The format of the projects file is 
-#
-# Library specification format:
-#
-#     library@<name>@<prop>=<value>
-#
-# Built-in library properties (* = required):
-#
-#    *path: the file system path for the library to appear on a class path
-#     urls: a comma seperated list of URLs from which the library can be downloaded
-#     optional: if "true" then this library will be omitted from a class path if it doesn't exist on the file system and no URLs are specified
-#
-# Project specification format:
-#
-#     project@<name>@<prop>=<value>
-#
-# The name of a project also denotes the directory it is in.
-#
-# Built-in project properties:
-#
-#    *sourceDirs: a comma separated list of source directoriy names (relative to the project directory)
-#     dependencies: a comma separated list of the libraries and project the project depends upon (transitive dependencies may be omitted)
-#     checkstyle: the project whose Checkstyle configuration (i.e. <project>/.checkstyle_checks.xml) is used
-#
-# Other properties can be specified for projects and libraries for use by extension commands.
-#
-# Values can use environment variables with Bash syntax (e.g. ${HOME}).
+
+r"""
+mx is a command line tool inspired by mvn (http://maven.apache.org/)
+and hg (http://mercurial.selenic.com/). It includes a mechanism for
+managing the dependencies between a set of projects (like Maven)
+as well as making it simple to run commands
+(like hg is the interface to the Mercurial commands).
+
+The organizing principle of mx is a project suite. A suite is a directory
+containing one or more projects. It's not coincidental that this closely
+matches the layout of one or more projects in a Mercurial repository.
+The configuration information for a suite lives in an 'mx' sub-directory
+at the top level of the suite.
+
+When launched, mx treats the current working directory as a suite.
+This is the primary suite. All other suites are called included suites.
+
+The configuration files (i.e. in the 'mx' sub-directory) of a suite are:
+
+  projects
+      Defines the projects and libraries in the suite and the
+      dependencies between them.
+
+  commands.py
+      Suite specific extensions to the commands available to mx.
+      This is only processed for the primary suite.
+
+  includes
+      Other suites to be loaded. This is recursive.
+
+  env
+      A set of environment variable definitions. These override any
+      existing environment variables.
+
+The includes and env files are typically not put under version control
+as they usually contain local file-system paths.
+
+The projects file is like the pom.xml file from Maven except that
+it is a properties file (not XML). Each non-comment line
+in the file specifies an attribute of a project or library. The main
+difference between a project and a library is that the former contains
+source code built by the mx tool where as the latter is an external
+dependency. The format of the projects file is
+
+Library specification format:
+
+    library@<name>@<prop>=<value>
+
+Built-in library properties (* = required):
+
+   *path
+        The file system path for the library to appear on a class path.
+
+    urls
+        A comma separated list of URLs from which the library (jar) can
+        be downloaded and saved in the location specified by 'path'.
+
+    optional
+        If "true" then this library will be omitted from a class path
+        if it doesn't exist on the file system and no URLs are specified.
+
+Project specification format:
+
+    project@<name>@<prop>=<value>
+
+The name of a project also denotes the directory it is in.
+
+Built-in project properties (* = required):
+
+    subDir
+        The sub-directory of the suite in which the project directory is
+        contained. If not specified, the project directory is directly
+        under the suite directory.
+
+   *sourceDirs
+        A comma separated list of source directory names (relative to
+        the project directory).
+
+    dependencies
+        A comma separated list of the libraries and project the project
+        depends upon (transitive dependencies should be omitted).
+
+    checkstyle
+        The project whose Checkstyle configuration
+        (i.e. <project>/.checkstyle_checks.xml) is used.
+
+    native
+        "true" if the project is native.
+
+    javaCompliance
+        The minimum JDK version (format: x.y) to which the project's
+        sources comply (required for non-native projects).
+
+Other properties can be specified for projects and libraries for use
+by extension commands.
+
+Property values can use environment variables with Bash syntax (e.g. ${HOME}).
+"""
 
 import sys, os, errno, time, subprocess, shlex, types, urllib2, contextlib, StringIO, zipfile, signal
 import shutil, fnmatch, re, xml.dom.minidom
@@ -107,31 +147,32 @@
     def __init__(self, suite, name):
         self.name = name
         self.suite = suite
-        
+
     def __str__(self):
         return self.name
-    
+
     def __eq__(self, other):
         return self.name == other.name
-    
+
     def __ne__(self, other):
         return self.name != other.name
 
     def __hash__(self):
         return hash(self.name)
-    
+
     def isLibrary(self):
         return isinstance(self, Library)
-    
+
 class Project(Dependency):
-    def __init__(self, suite, name, srcDirs, deps, dir):
+    def __init__(self, suite, name, srcDirs, deps, javaCompliance, dir):
         Dependency.__init__(self, suite, name)
         self.srcDirs = srcDirs
         self.deps = deps
         self.checkstyleProj = name
+        self.javaCompliance = JavaCompliance(javaCompliance) if javaCompliance is not None else None
         self.native = False
         self.dir = dir
-        
+
     def all_deps(self, deps, includeLibs, includeSelf=True):
         """
         Add the transitive set of dependencies for this project, including
@@ -152,7 +193,7 @@
         if not self in deps and includeSelf:
             deps.append(self)
         return deps
-    
+
     def _compute_max_dep_distances(self, name, distances, dist):
         currentDist = distances.get(name);
         if currentDist is None or currentDist < dist:
@@ -161,7 +202,7 @@
             if p is not None:
                 for dep in p.deps:
                     self._compute_max_dep_distances(dep, distances, dist + 1)
-                
+
     def canonical_deps(self):
         """
         Get the dependencies of this project that are not recursive (i.e. cannot be reached
@@ -174,19 +215,19 @@
             assert d > 0 or n == self.name
             if d == 1:
                 result.add(n)
-                
-            
+
+
         if len(result) == len(self.deps) and frozenset(self.deps) == result:
             return self.deps
         return result;
-    
+
 
     def source_dirs(self):
         """
         Get the directories in which the sources of this project are found.
         """
         return [join(self.dir, s) for s in self.srcDirs]
-        
+
     def output_dir(self):
         """
         Get the directory in which the class files of this project are found/placed.
@@ -195,6 +236,14 @@
             return None
         return join(self.dir, 'bin')
 
+    def jasmin_output_dir(self):
+        """
+        Get the directory in which the Jasmin assembled class files of this project are found/placed.
+        """
+        if self.native:
+            return None
+        return join(self.dir, 'jasmin_classes')
+
     def append_to_classpath(self, cp, resolve):
         if not self.native:
             cp.append(self.output_dir())
@@ -205,7 +254,7 @@
         self.path = path.replace('/', os.sep)
         self.urls = urls
         self.mustExist = mustExist
-    
+
     def get_path(self, resolve):
         path = self.path
         if not isabs(path):
@@ -214,14 +263,14 @@
             assert not len(self.urls) == 0, 'cannot find required library  ' + self.name + " " + path;
             print('Downloading ' + self.name + ' from ' + str(self.urls))
             download(path, self.urls)
-            
+
         return path
-        
+
     def append_to_classpath(self, cp, resolve):
         path = self.get_path(resolve)
         if exists(path) or not resolve:
             cp.append(path)
-    
+
 class Suite:
     def __init__(self, dir, primary):
         self.dir = dir
@@ -237,7 +286,7 @@
 
     def _load_projects(self, mxDir):
         libsMap = dict()
-        projsMap = dict() 
+        projsMap = dict()
         projectsFile = join(mxDir, 'projects')
         if not exists(projectsFile):
             return
@@ -246,9 +295,9 @@
                 line = line.strip()
                 if len(line) != 0 and line[0] != '#':
                     key, value = line.split('=', 1)
-                    
+
                     parts = key.split('@')
-                    
+
                     if len(parts) == 2:
                         pass
                     if len(parts) != 3:
@@ -260,31 +309,34 @@
                         m = libsMap
                     else:
                         abort('Property name does not start with "project@" or "library@": ' + key)
-                        
+
                     attrs = m.get(name)
                     if attrs is None:
                         attrs = dict()
                         m[name] = attrs
                     value = expandvars_in_property(value)
                     attrs[attr] = value
-                        
+
         def pop_list(attrs, name):
             v = attrs.pop(name, None)
             if v is None or len(v.strip()) == 0:
                 return []
             return [n.strip() for n in v.split(',')]
-        
+
         for name, attrs in projsMap.iteritems():
             srcDirs = pop_list(attrs, 'sourceDirs')
             deps = pop_list(attrs, 'dependencies')
+            javaCompliance = attrs.pop('javaCompliance', None)
             subDir = attrs.pop('subDir', None);
             if subDir is None:
                 dir = join(self.dir, name)
             else:
                 dir = join(self.dir, subDir, name)
-            p = Project(self, name, srcDirs, deps, dir)
+            p = Project(self, name, srcDirs, deps, javaCompliance, dir)
             p.checkstyleProj = attrs.pop('checkstyle', name)
             p.native = attrs.pop('native', '') == 'true'
+            if not p.native and p.javaCompliance is None:
+                abort('javaCompliance property required for non-native project ' + name)
             p.__dict__.update(attrs)
             self.projects.append(p)
 
@@ -295,15 +347,15 @@
             l = Library(self, name, path, mustExist, urls)
             l.__dict__.update(attrs)
             self.libs.append(l)
-        
+
     def _load_commands(self, mxDir):
         commands = join(mxDir, 'commands.py')
         if exists(commands):
             # temporarily extend the Python path
             sys.path.insert(0, mxDir)
-    
+
             mod = __import__('commands')
-    
+
             # revert the Python path
             del sys.path[0]
 
@@ -311,17 +363,17 @@
                 abort(commands + ' must define an mx_init(env) function')
             if hasattr(mod, 'mx_post_parse_cmd_line'):
                 self.mx_post_parse_cmd_line = mod.mx_post_parse_cmd_line
-                
+
             mod.mx_init()
             self.commands = mod
-                
+
     def _load_includes(self, mxDir):
         includes = join(mxDir, 'includes')
         if exists(includes):
             with open(includes) as f:
                 for line in f:
                     self.includes.append(expandvars_in_property(line.strip()))
-        
+
     def _load_env(self, mxDir):
         e = join(mxDir, 'env')
         if exists(e):
@@ -331,7 +383,7 @@
                     if len(line) != 0 and line[0] != '#':
                         key, value = line.split('=', 1)
                         os.environ[key.strip()] = expandvars_in_property(value.strip())
-    
+
     def _post_init(self, opts):
         mxDir = join(self.dir, 'mx')
         self._load_includes(mxDir)
@@ -348,7 +400,7 @@
             if existing is not None:
                 abort('cannot redefine library  ' + l.name)
             _libs[l.name] = l
-        
+
 def get_os():
     """
     Get a canonical form of sys.platform.
@@ -371,7 +423,7 @@
     if not _suites.has_key(dir):
         suite = Suite(dir, primary)
         _suites[dir] = suite
-        return suite 
+        return suite
 
 def suites():
     """
@@ -384,7 +436,7 @@
     Get the list of all loaded projects.
     """
     return _projects.values()
-    
+
 def project(name, fatalIfMissing=True):
     """
     Get the project for a given name. This will abort if the named project does
@@ -421,7 +473,7 @@
     path (e.g. downloading a missing library) if 'resolve' is true.
     """
     if names is None:
-        return _as_classpath(sorted_deps(True), resolve)
+        return _as_classpath(sorted_deps(includeLibs=True), resolve)
     deps = []
     if isinstance(names, types.StringTypes):
         project(names).all_deps(deps, True, includeSelf)
@@ -429,15 +481,20 @@
         for n in names:
             project(n).all_deps(deps, True, includeSelf)
     return _as_classpath(deps, resolve)
-    
-def sorted_deps(includeLibs=False):
+
+def sorted_deps(projectNames=None, includeLibs=False):
     """
-    Gets the loaded projects and libraries sorted such that dependencies
+    Gets projects and libraries sorted such that dependencies
     are before the projects that depend on them. Unless 'includeLibs' is
     true, libraries are omitted from the result.
     """
     deps = []
-    for p in _projects.itervalues():
+    if projectNames is None:
+        projects = _projects.values()
+    else:
+        projects = [project(name) for name in projectNames]
+
+    for p in projects:
         p.all_deps(deps, includeLibs)
     return deps
 
@@ -446,14 +503,15 @@
     # Override parent to append the list of available commands
     def format_help(self):
         return ArgumentParser.format_help(self) + _format_commands()
-    
-    
+
+
     def __init__(self):
         self.java_initialized = False
         ArgumentParser.__init__(self, prog='mx')
-    
+
         self.add_argument('-v', action='store_true', dest='verbose', help='enable verbose output')
-        self.add_argument('-d', action='store_true', dest='java_dbg', help='make Java processes wait on port 8000 for a debugger')
+        self.add_argument('--dbg', type=int, dest='java_dbg_port', help='make Java processes wait on <port> for a debugger', metavar='<port>')
+        self.add_argument('-d', action='store_const', const=8000, dest='java_dbg_port', help='alias for "-dbg 8000"')
         self.add_argument('--cp-pfx', dest='cp_prefix', help='class path prefix', metavar='<arg>')
         self.add_argument('--cp-sfx', dest='cp_suffix', help='class path suffix', metavar='<arg>')
         self.add_argument('--J', dest='java_args', help='Java VM arguments (e.g. --J @-dsa)', metavar='@<args>', default=DEFAULT_JAVA_ARGS)
@@ -465,15 +523,15 @@
             # Time outs are (currently) implemented with Unix specific functionality
             self.add_argument('--timeout', help='Timeout (in seconds) for command', type=int, default=0, metavar='<secs>')
             self.add_argument('--ptimeout', help='Timeout (in seconds) for subprocesses', type=int, default=0, metavar='<secs>')
-        
+
     def _parse_cmd_line(self, args=None):
         if args is None:
             args = sys.argv[1:]
 
         self.add_argument('commandAndArgs', nargs=REMAINDER, metavar='command args...')
-        
+
         opts = self.parse_args()
-        
+
         # Give the timeout options a default value to avoid the need for hasattr() tests
         opts.__dict__.setdefault('timeout', 0)
         opts.__dict__.setdefault('ptimeout', 0)
@@ -486,13 +544,13 @@
 
         if opts.user_home is None or opts.user_home == '':
             abort('Could not find user home. Use --user-home option or ensure HOME environment variable is set.')
-    
+
         os.environ['JAVA_HOME'] = opts.java_home
         os.environ['HOME'] = opts.user_home
-        
+
         commandAndArgs = opts.__dict__.pop('commandAndArgs')
         return opts, commandAndArgs
-    
+
 def _format_commands():
     msg = '\navailable commands:\n\n'
     for cmd in sorted(commands.iterkeys()):
@@ -531,7 +589,7 @@
                 if e.errno == errno.EINTR:
                     continue
                 raise
-    
+
     def _returncode(status):
         if os.WIFSIGNALED(status):
             return -os.WTERMSIG(status)
@@ -540,7 +598,7 @@
         else:
             # Should never happen
             raise RuntimeError("Unknown child exit status!")
-        
+
     end = time.time() + timeout
     delay = 0.0005
     while True:
@@ -576,19 +634,19 @@
     Each line of the standard output and error streams of the subprocess are redirected to
     out and err if they are callable objects.
     """
-    
+
     assert isinstance(args, types.ListType), "'args' must be a list: " + str(args)
     for arg in args:
         assert isinstance(arg, types.StringTypes), 'argument is not a string: ' + str(arg)
-    
+
     if _opts.verbose:
         log(' '.join(args))
-        
+
     if timeout is None and _opts.ptimeout != 0:
         timeout = _opts.ptimeout
 
     global _currentSubprocess
-        
+
     try:
         # On Unix, the new subprocess should be in a separate group so that a timeout alarm
         # can use os.killpg() to kill the whole subprocess group
@@ -597,13 +655,13 @@
         if get_os() == 'windows':
             creationflags = subprocess.CREATE_NEW_PROCESS_GROUP
         else:
-            preexec_fn = os.setsid  
-        
+            preexec_fn = os.setsid
+
         if not callable(out) and not callable(err) and timeout is None:
             # The preexec_fn=os.setsid
             p = subprocess.Popen(args, cwd=cwd, preexec_fn=preexec_fn, creationflags=creationflags)
             _currentSubprocess = (p, args)
-	    retcode = waitOn(p)
+            retcode = waitOn(p)
         else:
             def redirect(stream, f):
                 for line in iter(stream.readline, ''):
@@ -641,12 +699,12 @@
         if _opts.verbose:
             raise subprocess.CalledProcessError(retcode, ' '.join(args))
         abort(retcode)
-        
+
     return retcode
 
 def exe_suffix(name):
     """
-    Gets the platform specific suffix for an executable 
+    Gets the platform specific suffix for an executable
     """
     if get_os() == 'windows':
         return name + '.exe'
@@ -664,12 +722,30 @@
     return name
 
 """
+A JavaCompliance simplifies comparing Java compliance values extracted from a JDK version string.
+"""
+class JavaCompliance:
+    def __init__(self, ver):
+        m = re.match('1\.(\d+).*', ver)
+        assert m is not None, 'not a recognized version string: ' + vstring
+        self.value = int(m.group(1))
+
+    def __str__ (self):
+        return '1.' + str(self.value)
+
+    def __cmp__ (self, other):
+        if isinstance(other, types.StringType):
+            other = JavaCompliance(other)
+
+        return cmp(self.value, other.value)
+
+"""
 A JavaConfig object encapsulates info on how Java commands are run.
 """
 class JavaConfig:
     def __init__(self, opts):
         self.jdk = opts.java_home
-        self.debug = opts.java_dbg
+        self.debug_port = opts.java_dbg_port
         self.java =  exe_suffix(join(self.jdk, 'bin', 'java'))
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
         self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
@@ -679,11 +755,11 @@
 
         def delAtAndSplit(s):
             return shlex.split(s.lstrip('@'))
-        
+
         self.java_args = delAtAndSplit(_opts.java_args)
         self.java_args_pfx = sum(map(delAtAndSplit, _opts.java_args_pfx), [])
         self.java_args_sfx = sum(map(delAtAndSplit, _opts.java_args_sfx), [])
-        
+
         # Prepend the -d64 VM option only if the java command supports it
         try:
             output = subprocess.check_output([self.java, '-d64', '-version'], stderr=subprocess.STDOUT)
@@ -694,17 +770,18 @@
             except subprocess.CalledProcessError as e:
                 print e.output
                 abort(e.returncode)
-        
+
         output = output.split()
         assert output[1] == 'version'
         self.version = output[2].strip('"')
-        
-        if self.debug:
-            self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000']
+        self.javaCompliance = JavaCompliance(self.version)
+
+        if self.debug_port is not None:
+            self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)]
 
     def format_cmd(self, args):
         return [self.java] + self.java_args_pfx + self.java_args + self.java_args_sfx + args
-    
+
 def check_get_env(key):
     """
     Gets an environment variable, aborting with a useful message if it is not set.
@@ -725,7 +802,7 @@
     """
     Write a message to the console.
     All script output goes through this method thus allowing a subclass
-    to redirect it. 
+    to redirect it.
     """
     if msg is None:
         print
@@ -740,7 +817,7 @@
         else:
             cp.append(part)
     return os.pathsep.join(cp)
-    
+
 def expand_project_in_args(args):
     for i in range(len(args)):
         if args[i] == '-cp' or args[i] == '-classpath':
@@ -765,7 +842,7 @@
             abort('Property contains an undefined environment variable: ' + value)
         return result
 
-           
+
 def abort(codeOrMessage):
     """
     Aborts the program with a SystemExit exception.
@@ -773,7 +850,7 @@
     if it is None, the exit status is zero; if it has another type (such as a string),
     the object's value is printed and the exit status is one.
     """
-    
+
     #import traceback
     #traceback.print_stack()
     currentSubprocess = _currentSubprocess
@@ -783,7 +860,7 @@
             p.kill()
         else:
             _kill_process_group(p.pid)
-    
+
     raise SystemExit(codeOrMessage)
 
 def download(path, urls, verbose=False):
@@ -795,23 +872,23 @@
     d = dirname(path)
     if d != '' and not exists(d):
         os.makedirs(d)
-        
+
     # Try it with the Java tool first since it can show a progress counter
     myDir = dirname(__file__)
-    
+
     javaSource = join(myDir, 'URLConnectionDownload.java')
     javaClass = join(myDir, 'URLConnectionDownload.class')
     if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
         subprocess.check_call([java().javac, '-d', myDir, javaSource])
     if run([java().java, '-cp', myDir, 'URLConnectionDownload', path] + urls) == 0:
         return
-        
+
     def url_open(url):
         userAgent = 'Mozilla/5.0 (compatible)'
         headers = { 'User-Agent' : userAgent }
         req = urllib2.Request(url, headers=headers)
         return urllib2.urlopen(req);
-        
+
     for url in urls:
         try:
             if (verbose):
@@ -824,7 +901,7 @@
                 with contextlib.closing(url_open(url)) as f:
                     data = f.read()
                     zipdata = StringIO.StringIO(f.read())
-            
+
                 zf = zipfile.ZipFile(zipdata, 'r')
                 data = zf.read(entry)
                 with open(path, 'wb') as f:
@@ -839,10 +916,10 @@
             log('Error reading from ' + url + ': ' + str(e))
         except zipfile.BadZipfile as e:
             log('Error in zip file downloaded from ' + url + ': ' + str(e))
-            
+
     abort('Could not download to ' + path + ' from any of the following URLs:\n\n    ' +
               '\n    '.join(urls) + '\n\nPlease use a web browser to do the download manually')
-            
+
 def update_file(path, content):
     """
     Updates a file with some given content if the content differs from what's in
@@ -854,44 +931,47 @@
         if existed:
             with open(path, 'rb') as f:
                 old = f.read()
-        
+
         if old == content:
             return False
-            
+
         with open(path, 'wb') as f:
             f.write(content)
-            
+
         log(('modified ' if existed else 'created ') + path)
         return True;
     except IOError as e:
         abort('Error while writing to ' + path + ': ' + str(e));
 
 # Builtin commands
-            
+
 def build(args, parser=None):
     """compile the Java and C sources, linking the latter
 
     Compile all the Java source code using the appropriate compilers
     and linkers for the various source code types."""
-    
+
     suppliedParser = parser is not None
     if not suppliedParser:
         parser = ArgumentParser(prog='mx build')
-    
+
+    javaCompliance = java().javaCompliance
+
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
     parser.add_argument('-f', action='store_true', dest='force', help='force compilation even if class files are up to date')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
-    parser.add_argument('--source', dest='compliance', help='Java compliance level', default='1.6')
+    parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance))
     parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
+    parser.add_argument('--projects', action='store', help='comma separated projects to build (omit to build all projects)')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not build Java projects')
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not build native projects')
     parser.add_argument('--jdt', help='Eclipse installation or path to ecj.jar for using the Eclipse batch compiler instead of javac', metavar='<path>')
-    
+
     if suppliedParser:
         parser.add_argument('remainder', nargs=REMAINDER, metavar='...')
 
     args = parser.parse_args(args)
-    
+
     jdtJar = None
     if args.jdt is not None:
         if args.jdt.endswith('.jar'):
@@ -903,15 +983,19 @@
                 jdtJar = join(plugins, sorted(choices, reverse=True)[0])
 
     built = set()
-    for p in sorted_deps():
-        
+
+    projects = None
+    if args.projects is not None:
+        projects = args.projects.split(',')
+
+    for p in sorted_deps(projects):
         if p.native:
             if args.native:
                 log('Calling GNU make {0}...'.format(p.dir))
-    
+
                 if args.clean:
                     run([gmake_cmd(), 'clean'], cwd=p.dir)
-                    
+
                 run([gmake_cmd()], cwd=p.dir)
                 built.add(p.name)
             continue
@@ -919,7 +1003,12 @@
             if not args.java:
                 continue
 
-        
+        # skip building this Java project if its Java compliance level is "higher" than the configured JDK
+        if javaCompliance < p.javaCompliance:
+            log('Excluding {0} from build (Java compliance level {1} required)'.format(p.name, p.javaCompliance))
+            continue
+
+
         outputDir = p.output_dir()
         if exists(outputDir):
             if args.clean:
@@ -936,31 +1025,63 @@
             for dep in p.all_deps([], False):
                 if dep.name in built:
                     mustBuild = True
-            
+
+        jasminAvailable = None
         javafilelist = []
         for sourceDir in sourceDirs:
             for root, _, files in os.walk(sourceDir):
                 javafiles = [join(root, name) for name in files if name.endswith('.java') and name != 'package-info.java']
                 javafilelist += javafiles
-                
-                # Copy all non Java resources
+
+                # Copy all non Java resources or assemble Jasmin files
                 nonjavafilelist = [join(root, name) for name in files if not name.endswith('.java')]
                 for src in nonjavafilelist:
-                    dst = join(outputDir, src[len(sourceDir) + 1:])
-                    if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) != os.path.getmtime(src)):
-                        shutil.copyfile(src, dst)
-                
+                    if src.endswith('.jasm'):
+                        className = None
+                        with open(src) as f:
+                            for line in f:
+                                if line.startswith('.class '):
+                                    className = line.split()[-1]
+                                    break
+
+                        if className is not None:
+                            jasminOutputDir = p.jasmin_output_dir()
+                            classFile = join(jasminOutputDir, className.replace('/', os.sep) + '.class')
+                            if exists(dirname(classFile)) and (not exists(classFile) or os.path.getmtime(classFile) < os.path.getmtime(src)):
+                                if jasminAvailable is None:
+                                    try:
+                                        with open(os.devnull) as devnull:
+                                            subprocess.call('jasmin', stdout=devnull, stderr=subprocess.STDOUT)
+                                        jasminAvailable = True
+                                    except OSError as e:
+                                        jasminAvailable = False
+
+                                if jasminAvailable:
+                                    log('Assembling Jasmin file ' + src)
+                                    run(['jasmin', '-d', jasminOutputDir, src])
+                                else:
+                                    log('The jasmin executable could not be found - skipping ' + src)
+                                    with file(classFile, 'a'):
+                                        os.utime(classFile, None)
+
+                        else:
+                            log('could not file .class directive in Jasmin source: ' + src)
+                    else:
+                        dst = join(outputDir, src[len(sourceDir) + 1:])
+                        if exists(dirname(dst)) and (not exists(dst) or os.path.getmtime(dst) != os.path.getmtime(src)):
+                            shutil.copyfile(src, dst)
+
                 if not mustBuild:
                     for javafile in javafiles:
                         classfile = outputDir + javafile[len(sourceDir):-len('java')] + 'class'
                         if not exists(classfile) or os.path.getmtime(javafile) > os.path.getmtime(classfile):
                             mustBuild = True
                             break
-                
+
         if not mustBuild:
             log('[all class files for {0} are up to date - skipping]'.format(p.name))
             continue
-            
+
         if len(javafilelist) == 0:
             log('[no Java sources for {0} - skipping]'.format(p.name))
             continue
@@ -971,7 +1092,7 @@
         argfile = open(argfileName, 'wb')
         argfile.write('\n'.join(javafilelist))
         argfile.close()
-        
+
         try:
             if jdtJar is None:
                 log('Compiling Java sources for {0} with javac...'.format(p.name))
@@ -981,11 +1102,11 @@
                         """
                         Class to errFilt the 'is Sun proprietary API and may be removed in a future release'
                         warning when compiling the VM classes.
-                        
+
                         """
                         def __init__(self):
                             self.c = 0
-                        
+
                         def eat(self, line):
                             if 'proprietary API' in line:
                                 self.c = 2
@@ -994,7 +1115,7 @@
                             else:
                                 log(line.rstrip())
                     errFilt=Filter().eat
-                    
+
                 run([java().javac, '-g', '-J-Xmx1g', '-source', args.compliance, '-classpath', cp, '-d', outputDir, '@' + argfile.name], err=errFilt)
             else:
                 log('Compiling Java sources for {0} with JDT...'.format(p.name))
@@ -1009,7 +1130,7 @@
                          '-d', outputDir, '@' + argfile.name])
         finally:
             os.remove(argfileName)
-                    
+
     if suppliedParser:
         return args
     return None
@@ -1018,7 +1139,7 @@
     """process all project files to canonicalize the dependencies
 
     The exit code of this command reflects how many files were updated."""
-    
+
     changedFiles = 0
     for s in suites():
         projectsFile = join(s.dir, 'mx', 'projects')
@@ -1039,7 +1160,7 @@
         if update_file(projectsFile, content):
             changedFiles += 1
     return changedFiles;
-    
+
 def checkstyle(args):
     """run Checkstyle on the Java sources
 
@@ -1047,16 +1168,16 @@
    produced by Checkstyle result in a non-zero exit code.
 
 If no projects are given, then all Java projects are checked."""
-    
+
     for p in sorted_deps():
         if p.native:
             continue
         sourceDirs = p.source_dirs()
         dotCheckstyle = join(p.dir, '.checkstyle')
-        
+
         if not exists(dotCheckstyle):
             continue
-        
+
         for sourceDir in sourceDirs:
             javafilelist = []
             for root, _, files in os.walk(sourceDir):
@@ -1075,16 +1196,16 @@
                         break
             else:
                 mustCheck = True
-            
+
             if not mustCheck:
                 log('[all Java sources in {0} already checked - skipping]'.format(sourceDir))
                 continue
 
-            if exists(timestampFile):                
+            if exists(timestampFile):
                 os.utime(timestampFile, None)
             else:
                 file(timestampFile, 'a')
-            
+
             dotCheckstyleXML = xml.dom.minidom.parse(dotCheckstyle)
             localCheckConfig = dotCheckstyleXML.getElementsByTagName('local-check-config')[0]
             configLocation = localCheckConfig.getAttribute('location')
@@ -1102,9 +1223,9 @@
             else:
                 log('[unknown Checkstyle configuration type "' + configType + '" in {0} - skipping]'.format(sourceDir))
                 continue
-                
+
             exclude = join(p.dir, '.checkstyle.exclude')
-            
+
             if exists(exclude):
                 with open(exclude) as f:
                     # Convert patterns to OS separators
@@ -1112,15 +1233,16 @@
                 def match(name):
                     for p in patterns:
                         if p in name:
-                            log('excluding: ' + name)
+                            if _opts.verbose:
+                                log('excluding: ' + name)
                             return True
                     return False
-                    
+
                 javafilelist = [name for name in javafilelist if not match(name)]
-            
+
             auditfileName = join(p.dir, 'checkstyleOutput.txt')
             log('Running Checkstyle on {0} using {1}...'.format(sourceDir, config))
-            
+
             try:
 
                 # Checkstyle is unable to read the filenames to process from a file, and the
@@ -1137,7 +1259,7 @@
                             i += 1
                         else:
                             break
-                    
+
                     batch = javafilelist[:i]
                     javafilelist = javafilelist[i:]
                     try:
@@ -1162,13 +1284,13 @@
     """
 
     suppliedParser = parser is not None
-    
+
     parser = parser if suppliedParser else ArgumentParser(prog='mx build');
     parser.add_argument('--no-native', action='store_false', dest='native', help='do not clean native projects')
     parser.add_argument('--no-java', action='store_false', dest='java', help='do not clean Java projects')
 
     args = parser.parse_args(args)
-    
+
     for p in projects():
         if p.native:
             if args.native:
@@ -1179,10 +1301,14 @@
                 if outputDir != '' and exists(outputDir):
                     log('Removing {0}...'.format(outputDir))
                     shutil.rmtree(outputDir)
-                    
+
     if suppliedParser:
         return args
-    
+
+def about(args):
+    """show the 'man page' for mx"""
+    print __doc__
+
 def help_(args):
     """show help for a given command
 
@@ -1192,11 +1318,11 @@
     if len(args) == 0:
         _argParser.print_help()
         return
-    
+
     name = args[0]
     if not commands.has_key(name):
         _argParser.error('unknown command: ' + name)
-    
+
     value = commands[name]
     (func, usage) = value[:2]
     doc = func.__doc__
@@ -1213,7 +1339,7 @@
 
 def projectgraph(args, suite=None):
     """create dot graph for project structure ("mx projectgraph | dot -Tpdf -oprojects.pdf")"""
-    
+
     print 'digraph projects {'
     print 'rankdir=BT;'
     print 'node [shape=rect];'
@@ -1227,19 +1353,28 @@
 
     if suite is None:
         suite = _mainSuite
-        
+
     def println(out, obj):
         out.write(str(obj) + '\n')
-        
+
     for p in projects():
-        if p.native:
-            continue
-        
         if not exists(p.dir):
             os.makedirs(p.dir)
 
+        if p.native:
+            eclipseNativeSettingsDir = join(suite.dir, 'mx', 'eclipse-native-settings')
+            if exists(eclipseNativeSettingsDir):
+                for name in os.listdir(eclipseNativeSettingsDir):
+                    path = join(eclipseNativeSettingsDir, name)
+                    if isfile(path):
+                        with open(join(eclipseNativeSettingsDir, name)) as f:
+                            content = f.read()
+                        content = content.replace('${javaHome}', java().jdk)
+                        update_file(join(p.dir, name), content)
+            continue
+
         out = StringIO.StringIO()
-        
+
         println(out, '<?xml version="1.0" encoding="UTF-8"?>')
         println(out, '<classpath>')
         for src in p.srcDirs:
@@ -1247,14 +1382,14 @@
             if not exists(srcDir):
                 os.mkdir(srcDir)
             println(out, '\t<classpathentry kind="src" path="' + src + '"/>')
-    
+
         # Every Java program depends on the JRE
         println(out, '\t<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>')
-        
+
         for dep in p.all_deps([], True):
             if dep == p:
                 continue;
-            
+
             if dep.isLibrary():
                 if hasattr(dep, 'eclipse.container'):
                     println(out, '\t<classpathentry exported="true" kind="con" path="' + getattr(dep, 'eclipse.container') + '"/>')
@@ -1267,10 +1402,11 @@
                         if isabs(path):
                             println(out, '\t<classpathentry exported="true" kind="lib" path="' + path + '"/>')
                         else:
-                            println(out, '\t<classpathentry exported="true" kind="lib" path="' + join(suite.dir, path) + '"/>')
+                            projRelPath = os.path.relpath(join(suite.dir, path), p.dir)
+                            println(out, '\t<classpathentry exported="true" kind="lib" path="' + projRelPath + '"/>')
             else:
                 println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + dep.name + '"/>')
-                        
+
         println(out, '\t<classpathentry kind="output" path="' + getattr(p, 'eclipse.output', 'bin') + '"/>')
         println(out, '</classpath>')
         update_file(join(p.dir, '.classpath'), out.getvalue())
@@ -1279,7 +1415,7 @@
         csConfig = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
         if exists(csConfig):
             out = StringIO.StringIO()
-            
+
             dotCheckstyle = join(p.dir, ".checkstyle")
             checkstyleConfigPath = '/' + p.checkstyleProj + '/.checkstyle_checks.xml'
             println(out, '<?xml version="1.0" encoding="UTF-8"?>')
@@ -1305,14 +1441,14 @@
                             assert isdir(exclDir), 'excluded source directory listed in ' + exclude + ' does not exist or is not a directory: ' + exclDir
                         println(out, '\t\t<filter-data value="' + line + '"/>')
                 println(out, '\t</filter>')
-                        
+
             println(out, '</fileset-config>')
             update_file(dotCheckstyle, out.getvalue())
             out.close()
-        
+
 
         out = StringIO.StringIO()
-        
+
         println(out, '<?xml version="1.0" encoding="UTF-8"?>')
         println(out, '<projectDescription>')
         println(out, '\t<name>' + p.name + '</name>')
@@ -1353,6 +1489,7 @@
                 if isfile(path):
                     with open(join(eclipseSettingsDir, name)) as f:
                         content = f.read()
+                    content = content.replace('${javaCompliance}', str(p.javaCompliance))
                     update_file(join(settingsDir, name), content)
 
 def netbeansinit(args, suite=None):
@@ -1363,17 +1500,17 @@
 
     def println(out, obj):
         out.write(str(obj) + '\n')
-        
+
     updated = False
     for p in projects():
         if p.native:
             continue
-        
+
         if not exists(join(p.dir, 'nbproject')):
             os.makedirs(join(p.dir, 'nbproject'))
 
         out = StringIO.StringIO()
-        
+
         println(out, '<?xml version="1.0" encoding="UTF-8"?>')
         println(out, '<project name="' + p.name + '" default="default" basedir=".">')
         println(out, '\t<description>Builds, tests, and runs the project ' + p.name + '.</description>')
@@ -1381,7 +1518,7 @@
         println(out, '</project>')
         updated = update_file(join(p.dir, 'build.xml'), out.getvalue()) or updated
         out.close()
-        
+
         out = StringIO.StringIO()
         println(out, '<?xml version="1.0" encoding="UTF-8"?>')
         println(out, '<project xmlns="http://www.netbeans.org/ns/project/1">')
@@ -1397,18 +1534,18 @@
         println(out, '                <root id="test.src.dir"/>')
         println(out, '            </test-roots>')
         println(out, '        </data>')
-        
+
         firstDep = True
         for dep in p.all_deps([], True):
             if dep == p:
                 continue;
-            
+
             if not dep.isLibrary():
                 n = dep.name.replace('.', '_')
                 if firstDep:
                     println(out, '        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">')
                     firstDep = False
-                    
+
                 println(out, '            <reference>')
                 println(out, '                <foreign-project>' + n + '</foreign-project>')
                 println(out, '                <artifact-type>jar</artifact-type>')
@@ -1417,19 +1554,19 @@
                 println(out, '                <clean-target>clean</clean-target>')
                 println(out, '                <id>jar</id>')
                 println(out, '            </reference>')
-            
+
         if not firstDep:
             println(out, '        </references>')
-            
+
         println(out, '    </configuration>')
         println(out, '</project>')
         updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.getvalue()) or updated
         out.close()
-        
+
         out = StringIO.StringIO()
-        
+
         jdkPlatform = 'JDK_' + java().version
-        
+
         content = """
 annotation.processing.enabled=false
 annotation.processing.enabled.in.editor=false
@@ -1517,12 +1654,12 @@
                 mainSrc = False
             else:
                 println(out, 'src.' + src + '.dir=${' + ref + '}')
-            
-        javacClasspath = []    
+
+        javacClasspath = []
         for dep in p.all_deps([], True):
             if dep == p:
                 continue;
-            
+
             if dep.isLibrary():
                 if not dep.mustExist:
                     continue
@@ -1531,22 +1668,22 @@
                     path = path.replace('\\', '\\\\')
                 ref = 'file.reference.' + dep.name + '-bin'
                 println(out, ref + '=' + path)
-                    
+
             else:
                 n = dep.name.replace('.', '_')
                 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/')
                 ref = 'reference.' + n + '.jar'
                 println(out, 'project.' + n + '=' + relDepPath)
                 println(out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar')
-                
+
             javacClasspath.append('${' + ref + '}')
-            
+
         println(out, 'javac.classpath=\\\n    ' + (os.pathsep + '\\\n    ').join(javacClasspath))
-        
+
 
         updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated
         out.close()
-    
+
     if updated:
         log('If using NetBeans:')
         log('  1. Ensure that a platform named "JDK ' + java().version + '" is defined (Tools -> Java Platforms)')
@@ -1554,21 +1691,21 @@
 
 def ideclean(args, suite=None):
     """remove all Eclipse and NetBeans project configurations"""
-    
+
     def rm(path):
         if exists(path):
             os.remove(path)
-    
+
     for p in projects():
         if p.native:
             continue
-        
+
         shutil.rmtree(join(p.dir, '.settings'), ignore_errors=True)
         shutil.rmtree(join(p.dir, 'nbproject'), ignore_errors=True)
         rm(join(p.dir, '.classpath'))
         rm(join(p.dir, '.project'))
         rm(join(p.dir, 'build.xml'))
-        
+
 def ideinit(args, suite=None):
     """(re)generate Eclipse and NetBeans project configurations"""
     eclipseinit(args, suite)
@@ -1580,7 +1717,7 @@
     Run the JDK javap class file disassembler with the following prepended options:
 
         -private -verbose -classpath <path to project classes>"""
-        
+
     javap = java().javap
     if not exists(javap):
         abort('The javap executable does not exists: ' + javap)
@@ -1602,13 +1739,14 @@
     """
     assert _argParser is not None
     _argParser.add_argument(*args, **kwargs)
-    
+
 # Table of commands in alphabetical order.
 # Keys are command names, value are lists: [<function>, <usage msg>, <format args to doc string of function>...]
 # If any of the format args are instances of Callable, then they are called with an 'env' are before being
-# used in the call to str.format().  
+# used in the call to str.format().
 # Extensions should update this table directly
 commands = {
+    'about': [about, ''],
     'build': [build, '[options]'],
     'checkstyle': [checkstyle, ''],
     'canonicalizeprojects': [canonicalizeprojects, ''],
@@ -1630,26 +1768,26 @@
     if exists(cwdMxDir) and isdir(cwdMxDir):
         global _mainSuite
         _mainSuite = _loadSuite(os.getcwd(), True)
-            
+
     opts, commandAndArgs = _argParser._parse_cmd_line()
-    
+
     global _opts, _java
     _opts = opts
     _java = JavaConfig(opts)
-    
+
     for s in suites():
         s._post_init(opts)
-    
+
     if len(commandAndArgs) == 0:
         _argParser.print_help()
         return
-    
+
     command = commandAndArgs[0]
     command_args = commandAndArgs[1:]
-    
+
     if not commands.has_key(command):
         abort('mx: unknown command \'{0}\'\n{1}use "mx help" for more options'.format(command, _format_commands()))
-        
+
     c, _ = commands[command][:2]
     def term_handler(signum, frame):
         abort(1)
--- a/src/cpu/x86/vm/c1_globals_x86.hpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/cpu/x86/vm/c1_globals_x86.hpp	Thu Mar 08 12:46:19 2012 +0100
@@ -37,27 +37,41 @@
 define_pd_global(bool, ResizeTLAB,                   true );
 define_pd_global(bool, InlineIntrinsics,             true );
 define_pd_global(bool, PreferInterpreterNativeStubs, false);
-define_pd_global(bool, ProfileTraps,                 true );   // changed for GRAAL
-define_pd_global(bool, UseOnStackReplacement,        true );
 define_pd_global(bool, TieredCompilation,            false);
-define_pd_global(intx, CompileThreshold,             4500 );   // changed for GRAAL
 define_pd_global(intx, BackEdgeThreshold,            100000);
 
 define_pd_global(intx, OnStackReplacePercentage,     933  );
 define_pd_global(intx, FreqInlineSize,               325  );
 define_pd_global(intx, NewSizeThreadIncrease,        4*K  );
-define_pd_global(intx, InitialCodeCacheSize,         4*M);      // changed for GRAAL
-define_pd_global(intx, ReservedCodeCacheSize,        48*M );    // changed for GRAAL
-define_pd_global(bool, ProfileInterpreter,           true );    // changed for GRAAL
-define_pd_global(intx, CodeCacheExpansionSize,       64*K );    // changed for GRAAL
-define_pd_global(uintx,CodeCacheMinBlockLength,      4);        // changed for GRAAL
 define_pd_global(uintx,PermSize,                     12*M );
 define_pd_global(uintx,MaxPermSize,                  64*M );
 define_pd_global(bool, NeverActAsServerClassMachine, true );
 define_pd_global(uint64_t,MaxRAM,                    1ULL*G);
 define_pd_global(bool, CICompileOSR,                 true );
-define_pd_global(intx, TypeProfileWidth,             8    );    // changed for GRAAL
+
+#ifdef GRAAL
+define_pd_global(bool, ProfileTraps,                 true );
+define_pd_global(bool, UseOnStackReplacement,        false);
+define_pd_global(intx, CompileThreshold,             4500 );
+define_pd_global(intx, InitialCodeCacheSize,         4*M  );
+define_pd_global(intx, ReservedCodeCacheSize,        48*M );
+define_pd_global(bool, ProfileInterpreter,           true );
+define_pd_global(intx, CodeCacheExpansionSize,       64*K );
+define_pd_global(uintx,CodeCacheMinBlockLength,      4);
+define_pd_global(intx, TypeProfileWidth,             8);
+#else
+define_pd_global(bool, ProfileTraps,                 false);
+define_pd_global(bool, UseOnStackReplacement,        true );
+define_pd_global(intx, CompileThreshold,             1500 );
+define_pd_global(intx, InitialCodeCacheSize,         160*K);
+define_pd_global(intx, ReservedCodeCacheSize,        32*M );
+define_pd_global(bool, ProfileInterpreter,           false);
+define_pd_global(intx, CodeCacheExpansionSize,       32*K );
+define_pd_global(uintx,CodeCacheMinBlockLength,      1);
+define_pd_global(intx, TypeProfileWidth,             0);
+#endif // GRAAL
 #endif // !TIERED
+
 define_pd_global(bool, RoundFPResults,               true );
 
 define_pd_global(bool, LIRFillDelaySlots,            false);
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Thu Mar 08 12:46:19 2012 +0100
@@ -346,7 +346,7 @@
       // Test to see if we should create a method data oop
       __ cmp32(rcx, ExternalAddress((address)&InvocationCounter::InterpreterProfileLimit));
       __ jcc(Assembler::less, *profile_method_continue);
-
+      
       // if no method data exists, go to profile_method
       __ test_method_data_pointer(rax, *profile_method);
     }
--- a/src/share/vm/code/nmethod.cpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/share/vm/code/nmethod.cpp	Thu Mar 08 12:46:19 2012 +0100
@@ -1178,7 +1178,9 @@
 }
 
 void nmethod::inc_decompile_count() {
+#ifndef GRAAL
   if (!is_compiled_by_c2()) return;
+#endif
   // Could be gated by ProfileTraps, but do not bother...
   methodOop m = method();
   if (m == NULL)  return;
--- a/src/share/vm/oops/methodDataOop.cpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/share/vm/oops/methodDataOop.cpp	Thu Mar 08 12:46:19 2012 +0100
@@ -861,6 +861,19 @@
   return CompilationPolicy::policy()->is_mature(_method);
 }
 
+void methodDataOopDesc::inc_decompile_count() {
+  _nof_decompiles += 1;
+  if (decompile_count() > (uint)PerMethodRecompilationCutoff) {
+#ifdef GRAAL
+    // TODO (ch) enable this in the fastdebug build only once we are more stable
+    ResourceMark m;
+    tty->print_cr("WARN: endless recompilation of %s. Method was set to not compilable.", method()->name_and_sig_as_C_string());
+    //ShouldNotReachHere();
+#endif
+    method()->set_not_compilable(CompLevel_full_optimization);
+  }
+}
+
 // Translate a bci to its corresponding data index (di).
 address methodDataOopDesc::bci_to_dp(int bci) {
   ResourceMark rm;
--- a/src/share/vm/oops/methodDataOop.hpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/share/vm/oops/methodDataOop.hpp	Thu Mar 08 12:46:19 2012 +0100
@@ -1507,12 +1507,7 @@
   uint decompile_count() const {
     return _nof_decompiles;
   }
-  void inc_decompile_count() {
-    _nof_decompiles += 1;
-    if (decompile_count() > (uint)PerMethodRecompilationCutoff) {
-      method()->set_not_compilable(CompLevel_full_optimization);
-    }
-  }
+  void inc_decompile_count();
 
   // Support for code generation
   static ByteSize data_offset() {
--- a/src/share/vm/runtime/deoptimization.cpp	Thu Mar 08 12:45:49 2012 +0100
+++ b/src/share/vm/runtime/deoptimization.cpp	Thu Mar 08 12:46:19 2012 +0100
@@ -164,7 +164,7 @@
   // that can confuse an asynchronous stack walker. This counter is
   // decremented at the end of unpack_frames().
   if (TraceDeoptimization) {
-    tty->print("Deoptimization "); 
+    tty->print_cr("Deoptimizing thread " INTPTR_FORMAT, thread);
   }
   thread->inc_in_deopt_handler();