changeset 13360:cf7b5b507541

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 17 Dec 2013 15:44:23 +0100
parents 136df94b5aa8 e1a50eac0eac
children 5a6c617a66ac
files
diffstat 31 files changed, 1240 insertions(+), 363 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Tue Dec 17 15:44:23 2013 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.code.Register.*;
 
 import java.nio.*;
+import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.Register.RegisterCategory;
@@ -111,22 +112,23 @@
 
     // @formatter:on
 
-    private final int supportedSSEVersion;
-    private final int supportedAVXVersion;
-
-    public AMD64(int supportedSSEVersion, int supportedAVXVersion) {
-        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, r15.encoding + 1, 8);
-        assert supportedSSEVersion >= 2;
-        this.supportedSSEVersion = supportedSSEVersion;
-        this.supportedAVXVersion = supportedAVXVersion;
+    /**
+     * Basic set of CPU features mirroring what is returned from the cpuid instruction.
+     */
+    public static enum CPUFeature {
+        SSE, SSE2, SSE3, SSE4, SSE4a, SSE4_1, SSE4_2, SSSE3, POPCNT, LZCNT, AVX, AVX2, ERMS, AMD_3DNOW_PREFETCH, AES,
     }
 
-    public int getSupportedSSEVersion() {
-        return supportedSSEVersion;
+    private final EnumSet<CPUFeature> features;
+
+    public AMD64(EnumSet<CPUFeature> features) {
+        super("AMD64", 8, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, r15.encoding + 1, 8);
+        this.features = features;
+        assert features.contains(CPUFeature.SSE2) : "minimum config for x64";
     }
 
-    public int getSupportedAVXVersion() {
-        return supportedAVXVersion;
+    public EnumSet<CPUFeature> getFeatures() {
+        return features;
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Tue Dec 17 15:44:23 2013 +0100
@@ -174,6 +174,10 @@
         this.frameRegister = registerConfig == null ? null : registerConfig.getFrameRegister();
     }
 
+    private boolean supports(CPUFeature feature) {
+        return ((AMD64) target.arch).getFeatures().contains(feature);
+    }
+
     private static int encode(Register r) {
         assert r.encoding < 16 && r.encoding >= 0 : "encoding out of range: " + r.encoding;
         return r.encoding & 0x7;
@@ -450,6 +454,7 @@
     }
 
     public final void bsrq(Register dst, Register src) {
+        assert !supports(CPUFeature.LZCNT);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0xBD);
@@ -457,6 +462,7 @@
     }
 
     public final void bsrq(Register dst, AMD64Address src) {
+        assert !supports(CPUFeature.LZCNT);
         prefixq(src, dst);
         emitByte(0x0F);
         emitByte(0xBD);
@@ -464,6 +470,7 @@
     }
 
     public final void bsrl(Register dst, Register src) {
+        assert !supports(CPUFeature.LZCNT);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
         emitByte(0xBD);
@@ -471,6 +478,7 @@
     }
 
     public final void bsrl(Register dst, AMD64Address src) {
+        assert !supports(CPUFeature.LZCNT);
         prefix(src, dst);
         emitByte(0x0F);
         emitByte(0xBD);
@@ -1405,6 +1413,7 @@
     }
 
     public final void popcntl(Register dst, AMD64Address src) {
+        assert supports(CPUFeature.POPCNT);
         emitByte(0xF3);
         prefix(src, dst);
         emitByte(0x0F);
@@ -1413,6 +1422,7 @@
     }
 
     public final void popcntl(Register dst, Register src) {
+        assert supports(CPUFeature.POPCNT);
         emitByte(0xF3);
         int encode = prefixAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -1421,6 +1431,7 @@
     }
 
     public final void popcntq(Register dst, AMD64Address src) {
+        assert supports(CPUFeature.POPCNT);
         emitByte(0xF3);
         prefixq(src, dst);
         emitByte(0x0F);
@@ -1429,6 +1440,7 @@
     }
 
     public final void popcntq(Register dst, Register src) {
+        assert supports(CPUFeature.POPCNT);
         emitByte(0xF3);
         int encode = prefixqAndEncode(dst.encoding, src.encoding);
         emitByte(0x0F);
@@ -2549,28 +2561,28 @@
     }
 
     void prefetchr(AMD64Address src) {
-        // assert(VM_Version::supports_3dnow_prefetch(), "must support");
+        assert supports(CPUFeature.AMD_3DNOW_PREFETCH);
         prefetchPrefix(src);
         emitByte(0x0D);
         emitOperandHelper(0, src);
     }
 
     public void prefetcht0(AMD64Address src) {
-        // NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
+        assert supports(CPUFeature.SSE);
         prefetchPrefix(src);
         emitByte(0x18);
         emitOperandHelper(1, src);
     }
 
     public void prefetcht1(AMD64Address src) {
-        // NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
+        assert supports(CPUFeature.SSE);
         prefetchPrefix(src);
         emitByte(0x18);
         emitOperandHelper(2, src);
     }
 
     public void prefetcht2(AMD64Address src) {
-        // NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
+        assert supports(CPUFeature.SSE);
         prefix(src);
         emitByte(0x0f);
         emitByte(0x18);
@@ -2578,7 +2590,7 @@
     }
 
     public void prefetchw(AMD64Address src) {
-        // assert(VM_Version::supports_3dnow_prefetch(), "must support");
+        assert supports(CPUFeature.AMD_3DNOW_PREFETCH);
         prefix(src);
         emitByte(0x0f);
         emitByte(0x0D);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java	Tue Dec 17 15:44:23 2013 +0100
@@ -27,6 +27,7 @@
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.phases.common.*;
 
 /**
  * Tests any optimization that commons loads of non-inlineable constants.
@@ -37,7 +38,7 @@
 
     // A method where a constant is used on the normal and exception edge of a non-inlined call.
     // The dominating block of both usages is the block containing the call.
-    public static Object testSnippet(String[] arr, int i) {
+    public static Object test0Snippet(String[] arr, int i) {
         Object result = null;
         try {
             result = Array.get(arr, i);
@@ -53,13 +54,70 @@
     @Test
     public void test0() {
         // Ensure the exception path is profiled
-        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(getMethod("testSnippet"));
+        ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(getMethod("test0Snippet"));
         javaMethod.reprofile();
-        testSnippet(array, array.length);
+        test0Snippet(array, array.length);
 
-        test("testSnippet", array, 0);
-        test("testSnippet", array, 2);
-        test("testSnippet", array, 3);
-        test("testSnippet", array, 1);
+        test("test0Snippet", array, 0);
+        test("test0Snippet", array, 2);
+        test("test0Snippet", array, 3);
+        test("test0Snippet", array, 1);
+    }
+
+    public static final char[] alphabet = "abcdefghijklmnopqrstuvwxyz".toCharArray();
+
+    static int noninlineLength(char[] s) {
+        return s.length;
+    }
+
+    /**
+     * A constant with usages before and after a non-inlined call.
+     */
+    public static int test1Snippet(String s) {
+        if (s == null) {
+            return noninlineLength(alphabet) + 1;
+        }
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Test
+    public void test1() {
+        getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
+        test1Snippet(new String(alphabet));
+
+        test("test1Snippet", (Object) null);
+        test("test1Snippet", "test1Snippet");
+        test("test1Snippet", "");
+    }
+
+    /**
+     * A constant with only usage in a loop.
+     */
+    public static int test2Snippet(String s) {
+        char[] sChars = s.toCharArray();
+        int count = 0;
+        for (int i = 0; i < alphabet.length && i < sChars.length; i++) {
+            if (alphabet[i] == sChars[i]) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @Test
+    public void test2() {
+        assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
+        test2Snippet(new String(alphabet));
+
+        test("test2Snippet", (Object) null);
+        test("test2Snippet", "test1Snippet");
+        test("test2Snippet", "");
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Tue Dec 17 15:44:23 2013 +0100
@@ -418,7 +418,8 @@
 
     /**
      * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
-     * interval.
+     * interval. In case of a spilled interval which is re-materialized this is
+     * {@link Value#ILLEGAL}.
      */
     private AllocatableValue location;
 
@@ -498,6 +499,17 @@
      */
     private Interval locationHint;
 
+    /**
+     * The value with which a spilled child interval can be re-materialized. Currently this must be
+     * a Constant.
+     */
+    private Constant materializedValue;
+
+    /**
+     * The number of times {@link #addMaterializationValue(Constant)} is called.
+     */
+    private int numMaterializationValuesAdded;
+
     void assignLocation(AllocatableValue newLocation) {
         if (isRegister(newLocation)) {
             assert this.location == null : "cannot re-assign location for " + this;
@@ -505,6 +517,8 @@
                 this.location = asRegister(newLocation).asValue(kind);
                 return;
             }
+        } else if (isIllegal(newLocation)) {
+            assert canMaterialize();
         } else {
             assert this.location == null || isRegister(this.location) : "cannot re-assign location for " + this;
             assert isStackSlot(newLocation);
@@ -621,7 +635,7 @@
 
     // returns true if this interval has a shadow copy on the stack that is always correct
     boolean alwaysInMemory() {
-        return splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory;
+        return (splitParent().spillState == SpillState.StoreAtDefinition || splitParent().spillState == SpillState.StartInMemory) && !canMaterialize();
     }
 
     void removeFirstUsePos() {
@@ -693,6 +707,34 @@
         currentSplitChild = this;
     }
 
+    /**
+     * Sets the value which is used for re-materialization.
+     */
+    void addMaterializationValue(Constant value) {
+        if (numMaterializationValuesAdded == 0) {
+            materializedValue = value;
+        } else {
+            // Interval is defined on multiple places -> no materialization is possible.
+            materializedValue = null;
+        }
+        numMaterializationValuesAdded++;
+    }
+
+    /**
+     * Returns true if this interval can be re-materialized when spilled. This means that no
+     * spill-moves are needed. Instead of restore-moves the materializeValue is restored.
+     */
+    public boolean canMaterialize() {
+        return getMaterializedValue() != null;
+    }
+
+    /**
+     * Returns the value which is moved to a register instead of a restore-move from stack.
+     */
+    public Constant getMaterializedValue() {
+        return splitParent().materializedValue;
+    }
+
     int calcTo() {
         assert first != Range.EndMarker : "interval has no range";
 
@@ -864,12 +906,24 @@
         }
     }
 
+    private RegisterPriority adaptPriority(RegisterPriority priority) {
+        /*
+         * In case of re-materialized values we require that use-operands are registers, because we
+         * don't have the value at a stack location. (Note that ShouldHaveRegister means that the
+         * operand can also be a StackSlot).
+         */
+        if (priority == RegisterPriority.ShouldHaveRegister && canMaterialize()) {
+            return RegisterPriority.MustHaveRegister;
+        }
+        return priority;
+    }
+
     // Note: use positions are sorted descending . first use has highest index
     int firstUsage(RegisterPriority minRegisterPriority) {
         assert isVariable(operand) : "cannot access use positions for fixed intervals";
 
         for (int i = usePosList.size() - 1; i >= 0; --i) {
-            RegisterPriority registerPriority = usePosList.registerPriority(i);
+            RegisterPriority registerPriority = adaptPriority(usePosList.registerPriority(i));
             if (registerPriority.greaterEqual(minRegisterPriority)) {
                 return usePosList.usePos(i);
             }
@@ -882,7 +936,7 @@
 
         for (int i = usePosList.size() - 1; i >= 0; --i) {
             int usePos = usePosList.usePos(i);
-            if (usePos >= from && usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) {
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
                 return usePos;
             }
         }
@@ -894,7 +948,7 @@
 
         for (int i = usePosList.size() - 1; i >= 0; --i) {
             int usePos = usePosList.usePos(i);
-            if (usePos >= from && usePosList.registerPriority(i) == exactRegisterPriority) {
+            if (usePos >= from && adaptPriority(usePosList.registerPriority(i)) == exactRegisterPriority) {
                 return usePos;
             }
         }
@@ -910,7 +964,7 @@
             if (usePos > from) {
                 return prev;
             }
-            if (usePosList.registerPriority(i).greaterEqual(minRegisterPriority)) {
+            if (adaptPriority(usePosList.registerPriority(i)).greaterEqual(minRegisterPriority)) {
                 prev = usePos;
             }
         }
@@ -1181,6 +1235,10 @@
             buf.append(usePosList.usePos(i)).append(':').append(usePosList.registerPriority(i));
             prev = usePosList.usePos(i);
         }
-        return buf.append("} spill-state{").append(spillState()).append("}").toString();
+        buf.append("} spill-state{").append(spillState()).append("}");
+        if (canMaterialize()) {
+            buf.append(" (remat:").append(getMaterializedValue().toString()).append(")");
+        }
+        return buf.toString();
     }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Tue Dec 17 15:44:23 2013 +0100
@@ -263,11 +263,11 @@
         }
     };
 
-    static final IntervalPredicate IS_OOP_INTERVAL = new IntervalPredicate() {
+    static final IntervalPredicate IS_STACK_INTERVAL = new IntervalPredicate() {
 
         @Override
         public boolean apply(Interval i) {
-            return !isRegister(i.operand) && i.kind() == Kind.Object;
+            return !isRegister(i.operand);
         }
     };
 
@@ -282,7 +282,9 @@
     void assignSpillSlot(Interval interval) {
         // assign the canonical spill slot of the parent (if a part of the interval
         // is already spilled) or allocate a new spill slot
-        if (interval.spillSlot() != null) {
+        if (interval.canMaterialize()) {
+            interval.assignLocation(Value.ILLEGAL);
+        } else if (interval.spillSlot() != null) {
             interval.assignLocation(interval.spillSlot());
         } else {
             StackSlot slot = frameMap.allocateSpillSlot(interval.kind());
@@ -519,9 +521,7 @@
 
     // called once before assignment of register numbers
     void eliminateSpillMoves() {
-        if (getTraceLevel() >= 3) {
-            TTY.println(" Eliminating unnecessary spill moves");
-        }
+        Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves");
 
         // collect all intervals that must be stored after their definition.
         // the list is sorted by Interval.spillDefinitionPos
@@ -553,9 +553,7 @@
                     if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
                         // move target is a stack slot that is always correct, so eliminate
                         // instruction
-                        if (getTraceLevel() >= 4) {
-                            TTY.println("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
-                        }
+                        indent.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
                         instructions.set(j, null); // null-instructions are deleted by assignRegNum
                     }
 
@@ -565,25 +563,23 @@
                     assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval";
 
                     while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) {
-                        if (!insertionBuffer.initialized()) {
-                            // prepare insertion buffer (appended when all instructions of the block
-                            // are processed)
-                            insertionBuffer.init(instructions);
+                        if (!interval.canMaterialize()) {
+                            if (!insertionBuffer.initialized()) {
+                                // prepare insertion buffer (appended when all instructions of the
+                                // block are processed)
+                                insertionBuffer.init(instructions);
+                            }
+
+                            AllocatableValue fromLocation = interval.location();
+                            AllocatableValue toLocation = canonicalSpillOpr(interval);
+
+                            assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
+                            assert isStackSlot(toLocation) : "to operand must be a stack slot";
+
+                            insertionBuffer.append(j + 1, ir.spillMoveFactory.createMove(toLocation, fromLocation));
+
+                            indent.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
                         }
-
-                        AllocatableValue fromLocation = interval.location();
-                        AllocatableValue toLocation = canonicalSpillOpr(interval);
-
-                        assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
-                        assert isStackSlot(toLocation) : "to operand must be a stack slot";
-
-                        insertionBuffer.append(j + 1, ir.spillMoveFactory.createMove(toLocation, fromLocation));
-
-                        if (getTraceLevel() >= 4) {
-                            StackSlot slot = interval.spillSlot();
-                            TTY.println("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, slot, opId);
-                        }
-
                         interval = interval.next;
                     }
                 }
@@ -595,9 +591,10 @@
         } // end of block iteration
 
         assert interval == Interval.EndMarker : "missed an interval";
+        indent.outdent();
     }
 
-    private void checkIntervals(Interval interval) {
+    private static void checkIntervals(Interval interval) {
         Interval prev = null;
         Interval temp = interval;
         while (temp != Interval.EndMarker) {
@@ -607,13 +604,11 @@
                 assert temp.spillDefinitionPos() >= prev.spillDefinitionPos() : "when intervals are sorted by from :  then they must also be sorted by spillDefinitionPos";
             }
 
-            assert temp.spillSlot() != null : "interval has no spill slot assigned";
+            assert temp.spillSlot() != null || temp.canMaterialize() : "interval has no spill slot assigned";
             assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
             assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
 
-            if (traceLevel >= 4) {
-                TTY.println("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
-            }
+            Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
 
             prev = temp;
             temp = temp.next;
@@ -695,6 +690,8 @@
 
         // iterate all blocks
         for (final Block block : sortedBlocks) {
+            Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId());
+
             final BitSet liveGen = new BitSet(liveSize);
             final BitSet liveKill = new BitSet(liveSize);
 
@@ -713,9 +710,7 @@
                             int operandNum = operandNumber(operand);
                             if (!liveKill.get(operandNum)) {
                                 liveGen.set(operandNum);
-                                if (getTraceLevel() >= 4) {
-                                    TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id());
-                                }
+                                Debug.log("liveGen for operand %d", operandNum);
                             }
                             if (block.getLoop() != null) {
                                 intervalInLoop.setBit(operandNum, block.getLoop().index);
@@ -735,9 +730,7 @@
                         int operandNum = operandNumber(operand);
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
-                            if (getTraceLevel() >= 4) {
-                                TTY.println("  Setting liveGen for LIR opId %d, operand %d because of state for %s", op.id(), operandNum, op);
-                            }
+                            Debug.log("liveGen in state for operand %d", operandNum);
                         }
                         return operand;
                     }
@@ -749,6 +742,7 @@
                         if (isVariable(operand)) {
                             int varNum = operandNumber(operand);
                             liveKill.set(varNum);
+                            Debug.log("liveKill for operand %d", varNum);
                             if (block.getLoop() != null) {
                                 intervalInLoop.setBit(varNum, block.getLoop().index);
                             }
@@ -764,6 +758,7 @@
                     }
                 };
 
+                Indent indent2 = indent.logAndIndent("handle op %d", op.id());
                 op.forEachInput(useProc);
                 op.forEachAlive(useProc);
                 // Add uses of live locals from interpreter's point of view for proper debug
@@ -771,17 +766,19 @@
                 op.forEachState(stateProc);
                 op.forEachTemp(defProc);
                 op.forEachOutput(defProc);
+                indent2.outdent();
             } // end of instruction iteration
 
-            blockData.get(block).liveGen = liveGen;
-            blockData.get(block).liveKill = liveKill;
-            blockData.get(block).liveIn = new BitSet(liveSize);
-            blockData.get(block).liveOut = new BitSet(liveSize);
+            BlockData blockSets = blockData.get(block);
+            blockSets.liveGen = liveGen;
+            blockSets.liveKill = liveKill;
+            blockSets.liveIn = new BitSet(liveSize);
+            blockSets.liveOut = new BitSet(liveSize);
 
-            if (getTraceLevel() >= 4) {
-                TTY.println("liveGen  B%d %s", block.getId(), blockData.get(block).liveGen);
-                TTY.println("liveKill B%d %s", block.getId(), blockData.get(block).liveKill);
-            }
+            indent.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
+            indent.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+
+            indent.outdent();
         } // end of block iteration
     }
 
@@ -814,6 +811,7 @@
      * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block.
      */
     void computeGlobalLiveSets() {
+        Indent indent = Debug.logAndIndent("compute global live sets");
         int numBlocks = blockCount();
         boolean changeOccurred;
         boolean changeOccurredInBlock;
@@ -825,9 +823,12 @@
         do {
             changeOccurred = false;
 
+            Indent indent2 = indent.logAndIndent("new iteration %d", iterationCount);
+
             // iterate all blocks in reverse order
             for (int i = numBlocks - 1; i >= 0; i--) {
                 Block block = blockAt(i);
+                BlockData blockSets = blockData.get(block);
 
                 changeOccurredInBlock = false;
 
@@ -844,10 +845,10 @@
                         liveOut.clear();
                     }
 
-                    if (!blockData.get(block).liveOut.equals(liveOut)) {
+                    if (!blockSets.liveOut.equals(liveOut)) {
                         // A change occurred. Swap the old and new live out sets to avoid copying.
-                        BitSet temp = blockData.get(block).liveOut;
-                        blockData.get(block).liveOut = liveOut;
+                        BitSet temp = blockSets.liveOut;
+                        blockSets.liveOut = liveOut;
                         liveOut = temp;
 
                         changeOccurred = true;
@@ -860,15 +861,13 @@
                     // !liveKill(block))
                     // note: liveIn has to be computed only in first iteration or if liveOut has
                     // changed!
-                    BitSet liveIn = blockData.get(block).liveIn;
+                    BitSet liveIn = blockSets.liveIn;
                     liveIn.clear();
-                    liveIn.or(blockData.get(block).liveOut);
-                    liveIn.andNot(blockData.get(block).liveKill);
-                    liveIn.or(blockData.get(block).liveGen);
-                }
+                    liveIn.or(blockSets.liveOut);
+                    liveIn.andNot(blockSets.liveKill);
+                    liveIn.or(blockSets.liveGen);
 
-                if (getTraceLevel() >= 4) {
-                    traceLiveness(changeOccurredInBlock, iterationCount, block);
+                    indent2.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
                 }
             }
             iterationCount++;
@@ -876,6 +875,7 @@
             if (changeOccurred && iterationCount > 50) {
                 throw new BailoutException("too many iterations in computeGlobalLiveSets");
             }
+            indent2.outdent();
         } while (changeOccurred);
 
         if (DetailedAsserts.getValue()) {
@@ -888,55 +888,53 @@
             if (DetailedAsserts.getValue()) {
                 reportFailure(numBlocks);
             }
-
-            TTY.println("preds=" + startBlock.getPredecessorCount() + ", succs=" + startBlock.getSuccessorCount());
-            TTY.println("startBlock-ID: " + startBlock.getId());
-
             // bailout if this occurs in product mode.
             throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn);
         }
+        indent.outdent();
     }
 
     private void reportFailure(int numBlocks) {
-        TTY.println(gen.getGraph().toString());
-        TTY.println("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):");
+        Indent indent = Debug.logAndIndent("report failure");
+        indent.log("graph: %s", gen.getGraph());
+        indent.log("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):");
         BitSet startBlockLiveIn = blockData.get(ir.cfg.getStartBlock()).liveIn;
         for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
             Value operand = operandFor(operandNum);
-            TTY.println("  var %d; operand=%s; node=%s", operandNum, operand.toString(), gen.valueForOperand(operand));
+            indent.log("  var %d; operand=%s; node=%s", operandNum, operand, gen.valueForOperand(operand));
         }
 
         // print some additional information to simplify debugging
         for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) {
             Value operand = operandFor(operandNum);
-            TTY.println("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand.toString(), gen.valueForOperand(operand));
+            final Indent indent2 = indent.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, gen.valueForOperand(operand));
 
             Deque<Block> definedIn = new ArrayDeque<>();
             HashSet<Block> usedIn = new HashSet<>();
             for (Block block : sortedBlocks) {
                 if (blockData.get(block).liveGen.get(operandNum)) {
                     usedIn.add(block);
-                    TTY.println("used in block B%d {", block.getId());
+                    indent2.log("used in block B%d {", block.getId());
                     for (LIRInstruction ins : ir.lir(block)) {
-                        TTY.println("  " + ins.id() + ": " + ins.toString());
+                        indent2.log("  %d: %s", ins.id(), ins);
                         ins.forEachState(new ValueProcedure() {
 
                             @Override
                             public Value doValue(Value liveStateOperand) {
-                                TTY.println("    operand=" + liveStateOperand);
+                                indent2.log("    operand=" + liveStateOperand);
                                 return liveStateOperand;
                             }
                         });
                     }
-                    TTY.println("}");
+                    indent2.log("}");
                 }
                 if (blockData.get(block).liveKill.get(operandNum)) {
                     definedIn.add(block);
-                    TTY.println("defined in block B%d {", block.getId());
+                    indent2.log("defined in block B%d {", block.getId());
                     for (LIRInstruction ins : ir.lir(block)) {
-                        TTY.println("  " + ins.id() + ": " + ins.toString());
+                        indent2.log("  %d: %s", ins.id(), ins);
                     }
-                    TTY.println("}");
+                    indent2.log("}");
                 }
             }
 
@@ -957,12 +955,13 @@
                     }
                 }
             }
-            TTY.print("**** offending usages are in: ");
+            indent.log("**** offending usages are in: ");
             for (Block block : usedIn) {
-                TTY.print("B%d ", block.getId());
+                indent2.log("B%d ", block.getId());
             }
-            TTY.println();
+            indent2.outdent();
         }
+        indent.outdent();
     }
 
     private void verifyLiveness() {
@@ -977,21 +976,10 @@
         }
     }
 
-    private void traceLiveness(boolean changeOccurredInBlock, int iterationCount, Block block) {
-        char c = iterationCount == 0 || changeOccurredInBlock ? '*' : ' ';
-        TTY.print("(%d) liveIn%c  B%d ", iterationCount, c, block.getId());
-        TTY.println(blockData.get(block).liveIn.toString());
-        TTY.print("(%d) liveOut%c B%d ", iterationCount, c, block.getId());
-        TTY.println(blockData.get(block).liveOut.toString());
-    }
-
     void addUse(AllocatableValue operand, int from, int to, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
-        if (getTraceLevel() >= 2 && kind == null) {
-            TTY.println(" use %s from %d to %d (%s)", operand, from, to, registerPriority.name());
-        }
 
         Interval interval = getOrCreateInterval(operand);
         if (kind != Kind.Illegal) {
@@ -1002,15 +990,14 @@
 
         // Register use position at even instruction id.
         interval.addUsePos(to & ~1, registerPriority);
+
+        Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
     }
 
     void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
-        if (getTraceLevel() >= 2) {
-            TTY.println(" temp %s tempPos %d (%s)", operand, tempPos, RegisterPriority.MustHaveRegister.name());
-        }
 
         Interval interval = getOrCreateInterval(operand);
         if (kind != Kind.Illegal) {
@@ -1019,19 +1006,20 @@
 
         interval.addRange(tempPos, tempPos + 1);
         interval.addUsePos(tempPos, registerPriority);
+        interval.addMaterializationValue(null);
+
+        Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
     }
 
     boolean isProcessed(Value operand) {
         return !isRegister(operand) || attributes(asRegister(operand)).isAllocatable();
     }
 
-    void addDef(AllocatableValue operand, int defPos, RegisterPriority registerPriority, PlatformKind kind) {
+    void addDef(AllocatableValue operand, LIRInstruction op, RegisterPriority registerPriority, PlatformKind kind) {
         if (!isProcessed(operand)) {
             return;
         }
-        if (getTraceLevel() >= 2) {
-            TTY.println(" def %s defPos %d (%s)", operand, defPos, registerPriority.name());
-        }
+        int defPos = op.id();
 
         Interval interval = getOrCreateInterval(operand);
         if (kind != Kind.Illegal) {
@@ -1050,9 +1038,7 @@
             // also add register priority for dead intervals
             interval.addRange(defPos, defPos + 1);
             interval.addUsePos(defPos, registerPriority);
-            if (getTraceLevel() >= 2) {
-                TTY.println("Warning: def of operand %s at %d occurs without use", operand, defPos);
-            }
+            Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
         }
 
         changeSpillDefinitionPos(interval, defPos);
@@ -1060,6 +1046,9 @@
             // detection of method-parameters and roundfp-results
             interval.setSpillState(SpillState.StartInMemory);
         }
+        interval.addMaterializationValue(gen.getMaterializedValue(op, operand));
+
+        Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
     }
 
     /**
@@ -1153,6 +1142,9 @@
     }
 
     void buildIntervals() {
+
+        Indent indent = Debug.logAndIndent("build intervals");
+
         intervalsSize = operandSize();
         intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY];
 
@@ -1161,7 +1153,10 @@
 
         // iterate all blocks in reverse order
         for (int i = blockCount() - 1; i >= 0; i--) {
+
             Block block = blockAt(i);
+            Indent indent2 = indent.logAndIndent("handle block %d", block.getId());
+
             List<LIRInstruction> instructions = ir.lir(block);
             final int blockFrom = getFirstLirInstructionId(block);
             int blockTo = getLastLirInstructionId(block);
@@ -1174,9 +1169,7 @@
             for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
                 assert live.get(operandNum) : "should not stop here otherwise";
                 AllocatableValue operand = operandFor(operandNum);
-                if (getTraceLevel() >= 2) {
-                    TTY.println("live in %s to %d", operand, blockTo + 2);
-                }
+                indent.log("live in %d: %s", operandNum, operand);
 
                 addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal);
 
@@ -1195,6 +1188,8 @@
                 final LIRInstruction op = instructions.get(j);
                 final int opId = op.id();
 
+                Indent indent3 = indent2.logAndIndent("handle inst %d: %s", opId, op);
+
                 // add a temp range for each register if operation destroys caller-save registers
                 if (op.destroysCallerSavedRegisters()) {
                     for (Register r : callerSaveRegs) {
@@ -1202,9 +1197,7 @@
                             addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal);
                         }
                     }
-                    if (getTraceLevel() >= 4) {
-                        TTY.println("operation destroys all caller-save registers");
-                    }
+                    indent.log("operation destroys all caller-save registers");
                 }
 
                 op.forEachOutput(new ValueProcedure() {
@@ -1212,7 +1205,7 @@
                     @Override
                     public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                         if (isVariableOrRegister(operand)) {
-                            addDef((AllocatableValue) operand, opId, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
+                            addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind());
                             addRegisterHint(op, operand, mode, flags, true);
                         }
                         return operand;
@@ -1270,7 +1263,10 @@
                 // special steps for some instructions (especially moves)
                 handleMethodArguments(op);
 
+                indent3.outdent();
+
             } // end of instruction iteration
+            indent2.outdent();
         } // end of block iteration
 
         // add the range [0, 1] to all fixed intervals.
@@ -1280,6 +1276,7 @@
                 interval.addRange(0, 1);
             }
         }
+        indent.outdent();
     }
 
     // * Phase 5: actual register allocation
@@ -1431,6 +1428,7 @@
     };
 
     public void allocateRegisters() {
+        Indent indent = Debug.logAndIndent("allocate registers");
         Interval precoloredIntervals;
         Interval notPrecoloredIntervals;
 
@@ -1442,6 +1440,7 @@
         LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals);
         lsw.walk();
         lsw.finishAllocation();
+        indent.outdent();
     }
 
     // * Phase 6: resolve data flow
@@ -1546,6 +1545,8 @@
      * have been split.
      */
     void resolveDataFlow() {
+        Indent indent = Debug.logAndIndent("resolve data flow");
+
         int numBlocks = blockCount();
         MoveResolver moveResolver = new MoveResolver(this);
         BitSet blockCompleted = new BitSet(numBlocks);
@@ -1608,6 +1609,7 @@
                 }
             }
         }
+        indent.outdent();
     }
 
     // * Phase 7: assign register numbers back to LIR
@@ -1652,15 +1654,18 @@
             interval = splitChildAtOpId(interval, opId, mode);
         }
 
+        if (isIllegal(interval.location()) && interval.canMaterialize()) {
+            return interval.getMaterializedValue();
+        }
         return interval.location();
     }
 
-    IntervalWalker initComputeOopMaps() {
+    protected IntervalWalker initIntervalWalker(IntervalPredicate predicate) {
         // setup lists of potential oops for walking
         Interval oopIntervals;
         Interval nonOopIntervals;
 
-        oopIntervals = createUnhandledLists(IS_OOP_INTERVAL, null).first;
+        oopIntervals = createUnhandledLists(predicate, null).first;
 
         // intervals that have no oops inside need not to be processed.
         // to ensure a walking until the last instruction id, add a dummy interval
@@ -1671,7 +1676,11 @@
         return new IntervalWalker(this, oopIntervals, nonOopIntervals);
     }
 
-    void computeOopMap(IntervalWalker iw, LIRInstruction op, BitSet registerRefMap, BitSet frameRefMap) {
+    /**
+     * Visits all intervals for a frame state. The frame state use this information to build the OOP
+     * maps.
+     */
+    void markFrameLocations(IntervalWalker iw, LIRInstruction op, LIRFrameState info) {
         if (getTraceLevel() >= 3) {
             TTY.println("creating oop map at opId %d", op.id());
         }
@@ -1694,11 +1703,11 @@
             // moves, any intervals which end at this instruction are included
             // in the oop map since we may safepoint while doing the patch
             // before we've consumed the inputs.
-            if (op.id() < interval.currentTo()) {
+            if (op.id() < interval.currentTo() && !isIllegal(interval.location())) {
                 // caller-save registers must not be included into oop-maps at calls
                 assert !op.destroysCallerSavedRegisters() || !isRegister(operand) || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
 
-                frameMap.setReference(interval.location(), registerRefMap, frameRefMap);
+                info.markLocation(interval.location(), frameMap);
 
                 // Spill optimization: when the stack value is guaranteed to be always correct,
                 // then it must be added to the oop map even if the interval is currently in a
@@ -1707,7 +1716,7 @@
                     assert interval.spillDefinitionPos() > 0 : "position not set correctly";
                     assert interval.spillSlot() != null : "no spill slot assigned";
                     assert !isRegister(interval.operand) : "interval is on stack :  so stack slot is registered twice";
-                    frameMap.setReference(interval.spillSlot(), registerRefMap, frameRefMap);
+                    info.markLocation(interval.spillSlot(), frameMap);
                 }
             }
         }
@@ -1718,9 +1727,8 @@
     }
 
     private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) {
-        BitSet registerRefMap = op.destroysCallerSavedRegisters() && callKillsRegisters ? null : frameMap.initRegisterRefMap();
-        BitSet frameRefMap = frameMap.initFrameRefMap();
-        computeOopMap(iw, op, registerRefMap, frameRefMap);
+        info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters);
+        markFrameLocations(iw, op, info);
 
         info.forEachState(new ValueProcedure() {
 
@@ -1750,12 +1758,11 @@
                 // the intervals
                 // if the interval is not live, colorLirOperand will cause an assert on failure
                 Value result = colorLirOperand((Variable) operand, tempOpId, mode);
-                assert !hasCall(tempOpId) || isStackSlot(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
+                assert !hasCall(tempOpId) || isStackSlot(result) || isConstant(result) || !isCallerSave(result) : "cannot have caller-save register operands at calls";
                 return result;
             }
         });
-
-        info.finish(registerRefMap, frameRefMap);
+        info.finish(op, frameMap);
     }
 
     private void assignLocations(List<LIRInstruction> instructions, final IntervalWalker iw) {
@@ -1811,7 +1818,7 @@
     }
 
     private void assignLocations() {
-        IntervalWalker iw = initComputeOopMaps();
+        IntervalWalker iw = initIntervalWalker(IS_STACK_INTERVAL);
         for (Block block : sortedBlocks) {
             assignLocations(ir.lir(block), iw);
         }
@@ -1819,6 +1826,8 @@
 
     public void allocate() {
 
+        Indent indent = Debug.logAndIndent(false, "allocate %s", gen.getGraph().method());
+
         try (Scope s = Debug.scope("LifetimeAnalysis")) {
             numberInstructions();
             printLir("Before register allocation", true);
@@ -1869,11 +1878,21 @@
             printLir("After register number assignment", true);
             EdgeMoveOptimizer.optimize(ir);
             ControlFlowOptimizer.optimize(ir);
+
+            /*
+             * Temporarily disabled because of problem in specjvm2008. TODO: fix the problem and
+             * re-enable it.
+             * 
+             * RedundantMoveElimination.optimize(ir, frameMap, gen.getGraph().method());
+             */
+
             NullCheckOptimizer.optimize(ir, target.implicitNullCheckLimit);
             printLir("After control flow optimization", false);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
+
+        indent.outdent();
     }
 
     void printIntervals(String label) {
@@ -1998,7 +2017,7 @@
                 }
                 Value l1 = i1.location();
                 Value l2 = i2.location();
-                if (i1.intersects(i2) && (l1.equals(l2))) {
+                if (i1.intersects(i2) && !isIllegal(l1) && (l1.equals(l2))) {
                     if (DetailedAsserts.getValue()) {
                         TTY.println("Intervals %d and %d overlap and have the same register assigned", i1.operandNumber, i2.operandNumber);
                         TTY.println(i1.logString(this));
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java	Tue Dec 17 15:44:23 2013 +0100
@@ -399,66 +399,52 @@
     // 1) the left part has already a location assigned
     // 2) the right part is sorted into to the unhandled-list
     void splitBeforeUsage(Interval interval, int minSplitPos, int maxSplitPos) {
-        if (getTraceLevel() >= 2) {
-            TTY.println("----- splitting interval: ");
-        }
-        if (getTraceLevel() >= 4) {
-            TTY.println(interval.logString(allocator));
-        }
-        if (getTraceLevel() >= 2) {
-            TTY.println("      between %d and %d", minSplitPos, maxSplitPos);
-        }
 
-        assert interval.from() < minSplitPos : "cannot split at start of interval";
-        assert currentPosition < minSplitPos : "cannot split before current position";
-        assert minSplitPos <= maxSplitPos : "invalid order";
-        assert maxSplitPos <= interval.to() : "cannot split after end of interval";
+        try (Indent indent = Debug.logAndIndent("splitting interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) {
 
-        int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
+            assert interval.from() < minSplitPos : "cannot split at start of interval";
+            assert currentPosition < minSplitPos : "cannot split before current position";
+            assert minSplitPos <= maxSplitPos : "invalid order";
+            assert maxSplitPos <= interval.to() : "cannot split after end of interval";
 
-        assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
-        assert optimalSplitPos <= interval.to() : "cannot split after end of interval";
-        assert optimalSplitPos > interval.from() : "cannot split at start of interval";
+            int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, true);
 
-        if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
-            // the split position would be just before the end of the interval
-            // . no split at all necessary
-            if (getTraceLevel() >= 4) {
-                TTY.println("      no split necessary because optimal split position is at end of interval");
+            assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range";
+            assert optimalSplitPos <= interval.to() : "cannot split after end of interval";
+            assert optimalSplitPos > interval.from() : "cannot split at start of interval";
+
+            if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
+                // the split position would be just before the end of the interval
+                // . no split at all necessary
+                indent.log("no split necessary because optimal split position is at end of interval");
+                return;
             }
-            return;
-        }
 
-        // must calculate this before the actual split is performed and before split position is
-        // moved to odd opId
-        boolean moveNecessary = !allocator.isBlockBegin(optimalSplitPos) && !interval.hasHoleBetween(optimalSplitPos - 1, optimalSplitPos);
+            // must calculate this before the actual split is performed and before split position is
+            // moved to odd opId
+            boolean moveNecessary = !allocator.isBlockBegin(optimalSplitPos) && !interval.hasHoleBetween(optimalSplitPos - 1, optimalSplitPos);
 
-        if (!allocator.isBlockBegin(optimalSplitPos)) {
-            // move position before actual instruction (odd opId)
-            optimalSplitPos = (optimalSplitPos - 1) | 1;
-        }
+            if (!allocator.isBlockBegin(optimalSplitPos)) {
+                // move position before actual instruction (odd opId)
+                optimalSplitPos = (optimalSplitPos - 1) | 1;
+            }
 
-        if (getTraceLevel() >= 4) {
-            TTY.println("      splitting at position %d", optimalSplitPos);
-        }
-        assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary";
-        assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary";
+            indent.log("splitting at position %d", optimalSplitPos);
 
-        Interval splitPart = interval.split(optimalSplitPos, allocator);
+            assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary";
+            assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary";
 
-        splitPart.setInsertMoveWhenActivated(moveNecessary);
+            Interval splitPart = interval.split(optimalSplitPos, allocator);
 
-        assert splitPart.from() >= currentInterval.currentFrom() : "cannot append new interval before current walk position";
-        unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+            splitPart.setInsertMoveWhenActivated(moveNecessary);
 
-        if (getTraceLevel() >= 2) {
-            TTY.println("      split interval in two parts (insertMoveWhenActivated: %b)", moveNecessary);
-        }
-        if (getTraceLevel() >= 2) {
-            TTY.print("      ");
-            TTY.println(interval.logString(allocator));
-            TTY.print("      ");
-            TTY.println(splitPart.logString(allocator));
+            assert splitPart.from() >= currentInterval.currentFrom() : "cannot append new interval before current walk position";
+            unhandledLists.addToListSortedByStartAndUsePositions(RegisterBinding.Any, splitPart);
+
+            if (Debug.isLogEnabled()) {
+                indent.log("left interval  %s: %s", moveNecessary ? "      " : "", interval.logString(allocator));
+                indent.log("right interval %s: %s", moveNecessary ? "(move)" : "", splitPart.logString(allocator));
+            }
         }
     }
 
@@ -472,11 +458,7 @@
         int maxSplitPos = currentPosition;
         int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from());
 
-        if (getTraceLevel() >= 2) {
-            TTY.print("----- splitting and spilling interval: ");
-            TTY.println(interval.logString(allocator));
-            TTY.println("      between %d and %d", minSplitPos, maxSplitPos);
-        }
+        Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos);
 
         assert interval.state == State.Active : "why spill interval that is not active?";
         assert interval.from() <= minSplitPos : "cannot split before start of interval";
@@ -486,33 +468,31 @@
 
         if (minSplitPos == interval.from()) {
             // the whole interval is never used, so spill it entirely to memory
-            if (getTraceLevel() >= 2) {
-                TTY.println("      spilling entire interval because split pos is at beginning of interval");
-                TTY.println("      use positions: " + interval.usePosList().size());
-            }
-            assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
 
-            allocator.assignSpillSlot(interval);
-            allocator.changeSpillState(interval, minSplitPos);
+            try (Indent indent2 = indent.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) {
 
-            // Also kick parent intervals out of register to memory when they have no use
-            // position. This avoids short interval in register surrounded by intervals in
-            // memory . avoid useless moves from memory to register and back
-            Interval parent = interval;
-            while (parent != null && parent.isSplitChild()) {
-                parent = parent.getSplitChildBeforeOpId(parent.from());
+                assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition";
 
-                if (isRegister(parent.location())) {
-                    if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
-                        // parent is never used, so kick it out of its assigned register
-                        if (getTraceLevel() >= 4) {
-                            TTY.println("      kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                allocator.assignSpillSlot(interval);
+                allocator.changeSpillState(interval, minSplitPos);
+
+                // Also kick parent intervals out of register to memory when they have no use
+                // position. This avoids short interval in register surrounded by intervals in
+                // memory . avoid useless moves from memory to register and back
+                Interval parent = interval;
+                while (parent != null && parent.isSplitChild()) {
+                    parent = parent.getSplitChildBeforeOpId(parent.from());
+
+                    if (isRegister(parent.location())) {
+                        if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
+                            // parent is never used, so kick it out of its assigned register
+                            indent2.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                            allocator.assignSpillSlot(parent);
+                        } else {
+                            // do not go further back because the register is actually used by
+                            // the interval
+                            parent = null;
                         }
-                        allocator.assignSpillSlot(parent);
-                    } else {
-                        // do not go further back because the register is actually used by the
-                        // interval
-                        parent = null;
                     }
                 }
             }
@@ -530,35 +510,30 @@
                 optimalSplitPos = (optimalSplitPos - 1) | 1;
             }
 
-            if (getTraceLevel() >= 4) {
-                TTY.println("      splitting at position %d", optimalSplitPos);
-            }
-            assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary";
-            assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary";
+            try (Indent indent2 = indent.logAndIndent("splitting at position %d", optimalSplitPos)) {
+                assert allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 1) : "split pos must be odd when not on block boundary";
+                assert !allocator.isBlockBegin(optimalSplitPos) || (optimalSplitPos % 2 == 0) : "split pos must be even on block boundary";
 
-            Interval spilledPart = interval.split(optimalSplitPos, allocator);
-            allocator.assignSpillSlot(spilledPart);
-            allocator.changeSpillState(spilledPart, optimalSplitPos);
+                Interval spilledPart = interval.split(optimalSplitPos, allocator);
+                allocator.assignSpillSlot(spilledPart);
+                allocator.changeSpillState(spilledPart, optimalSplitPos);
 
-            if (!allocator.isBlockBegin(optimalSplitPos)) {
-                if (getTraceLevel() >= 4) {
-                    TTY.println("      inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                if (!allocator.isBlockBegin(optimalSplitPos)) {
+                    indent2.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                    insertMove(optimalSplitPos, interval, spilledPart);
                 }
-                insertMove(optimalSplitPos, interval, spilledPart);
-            }
 
-            // the currentSplitChild is needed later when moves are inserted for reloading
-            assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
-            spilledPart.makeCurrentSplitChild();
+                // the currentSplitChild is needed later when moves are inserted for reloading
+                assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild";
+                spilledPart.makeCurrentSplitChild();
 
-            if (getTraceLevel() >= 2) {
-                TTY.println("      split interval in two parts");
-                TTY.print("      ");
-                TTY.println(interval.logString(allocator));
-                TTY.print("      ");
-                TTY.println(spilledPart.logString(allocator));
+                if (Debug.isLogEnabled()) {
+                    indent2.log("left interval: %s", interval.logString(allocator));
+                    indent2.log("spilled interval   : %s", spilledPart.logString(allocator));
+                }
             }
         }
+        indent.outdent();
     }
 
     void splitStackInterval(Interval interval) {
@@ -883,13 +858,8 @@
         Interval interval = currentInterval;
         boolean result = true;
 
-        if (getTraceLevel() >= 2) {
-            TTY.println("+++++ activating interval " + interval.logString(allocator));
-        }
-
-        if (getTraceLevel() >= 4) {
-            TTY.println("      splitParent: %s, insertMoveWhenActivated: %b", interval.splitParent().operandNumber, interval.insertMoveWhenActivated());
-        }
+        Indent indent = Debug.logAndIndent("activating interval %s,  splitParent: %s, insertMoveWhenActivated: %b", interval.logString(allocator), interval.splitParent().operandNumber,
+                        interval.insertMoveWhenActivated());
 
         final Value operand = interval.operand;
         if (interval.location() != null && isStackSlot(interval.location())) {
@@ -940,6 +910,8 @@
         }
         interval.makeCurrentSplitChild();
 
+        indent.outdent();
+
         return result; // true = interval is moved to active list
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/MoveResolver.java	Tue Dec 17 15:44:23 2013 +0100
@@ -199,9 +199,7 @@
 
         insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr));
 
-        if (allocator.getTraceLevel() >= 4) {
-            TTY.println("MoveResolver: inserted move from %d (%s) to %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location());
-        }
+        Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
     }
 
     private void insertMove(Value fromOpr, Interval toInterval) {
@@ -211,9 +209,7 @@
         AllocatableValue toOpr = toInterval.operand;
         insertionBuffer.append(insertIdx, allocator.ir.spillMoveFactory.createMove(toOpr, fromOpr));
 
-        if (allocator.getTraceLevel() >= 4) {
-            TTY.print("MoveResolver: inserted move from constant %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location());
-        }
+        Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
     }
 
     private void resolveMappings() {
@@ -283,9 +279,7 @@
                 }
                 spillInterval.assignLocation(spillSlot);
 
-                if (allocator.getTraceLevel() >= 4) {
-                    TTY.println("created new Interval %s for spilling", spillInterval.operand);
-                }
+                Debug.log("created new Interval for spilling: %s", spillInterval);
 
                 // insert a move from register to stack and update the mapping
                 insertMove(fromInterval, spillInterval);
@@ -325,9 +319,18 @@
     }
 
     void addMapping(Interval fromInterval, Interval toInterval) {
-        if (allocator.getTraceLevel() >= 4) {
-            TTY.println("MoveResolver: adding mapping from interval %d (%s) to interval %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location());
+
+        if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
+            Debug.log("no store to rematerializable interval %s needed", toInterval);
+            return;
         }
+        if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
+            // Instead of a reload, re-materialize the value
+            Value rematValue = fromInterval.getMaterializedValue();
+            addMapping(rematValue, toInterval);
+            return;
+        }
+        Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
         assert fromInterval.kind() == toInterval.kind();
@@ -337,9 +340,8 @@
     }
 
     void addMapping(Value fromOpr, Interval toInterval) {
-        if (allocator.getTraceLevel() >= 4) {
-            TTY.println("MoveResolver: adding mapping from %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location());
-        }
+        Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+
         assert isConstant(fromOpr) : "only for constants";
 
         mappingFrom.add(null);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Dec 17 15:44:23 2013 +0100
@@ -28,6 +28,7 @@
 import static com.oracle.graal.lir.LIR.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
 import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -39,10 +40,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.StandardOp.JumpOp;
-import com.oracle.graal.lir.StandardOp.LabelOp;
-import com.oracle.graal.lir.StandardOp.NoOp;
+import com.oracle.graal.lir.StandardOp.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
@@ -136,6 +134,19 @@
         public String toString() {
             return block + "#" + op;
         }
+
+        /**
+         * Removes the {@link #op} from its original location if it is still at that location.
+         */
+        public void unpin(LIR lir) {
+            if (index >= 0) {
+                // Replace the move with a filler op so that the operation
+                // list does not need to be adjusted.
+                List<LIRInstruction> instructions = lir.lir(block);
+                instructions.set(index, new NoOp(null, -1));
+                index = -1;
+            }
+        }
     }
 
     private Map<Constant, LoadConstant> constantLoads;
@@ -176,6 +187,19 @@
         this.printIRWithLIR = Options.PrintIRWithLIR.getValue();
     }
 
+    /**
+     * Returns a value for a interval definition, which can be used for re-materialization.
+     * 
+     * @param op An instruction which defines a value
+     * @param operand The destination operand of the instruction
+     * @return Returns the value which is moved to the instruction and which can be reused at all
+     *         reload-locations in case the interval of this instruction is spilled. Currently this
+     *         can only be a {@link Constant}.
+     */
+    public Constant getMaterializedValue(LIRInstruction op, Value operand) {
+        return null;
+    }
+
     @SuppressWarnings("hiding")
     protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
         return new DebugInfoBuilder(nodeOperands);
@@ -248,7 +272,6 @@
                     LoadConstant load = constantLoads.get(value);
                     if (load == null) {
                         int index = lir.lir(currentBlock).size();
-                        // loadedValue = newVariable(value.getPlatformKind());
                         loadedValue = emitMove(value);
                         LIRInstruction op = lir.lir(currentBlock).get(index);
                         constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op));
@@ -256,13 +279,7 @@
                         Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock);
                         loadedValue = load.variable;
                         if (dominator != load.block) {
-                            if (load.index >= 0) {
-                                // Replace the move with a filler op so that the operation
-                                // list does not need to be adjusted.
-                                List<LIRInstruction> instructions = lir.lir(load.block);
-                                instructions.set(load.index, new NoOp(null, -1));
-                                load.index = -1;
-                            }
+                            load.unpin(lir);
                         } else {
                             assert load.block != currentBlock || load.index < lir.lir(currentBlock).size();
                         }
@@ -870,6 +887,19 @@
             // Remove loads where all usages are in the same block.
             for (Iterator<Map.Entry<Constant, LoadConstant>> iter = constantLoads.entrySet().iterator(); iter.hasNext();) {
                 LoadConstant lc = iter.next().getValue();
+
+                // Move loads of constant outside of loops
+                if (OptScheduleOutOfLoops.getValue()) {
+                    Block outOfLoopDominator = lc.block;
+                    while (outOfLoopDominator.getLoop() != null) {
+                        outOfLoopDominator = outOfLoopDominator.getDominator();
+                    }
+                    if (outOfLoopDominator != lc.block) {
+                        lc.unpin(lir);
+                        lc.block = outOfLoopDominator;
+                    }
+                }
+
                 if (lc.index != -1) {
                     assert lir.lir(lc.block).get(lc.index) == lc.op;
                     iter.remove();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Tue Dec 17 15:44:23 2013 +0100
@@ -37,7 +37,40 @@
 public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory {
 
     protected Architecture createArchitecture(HotSpotVMConfig config) {
-        return new AMD64(config.useSSE, config.useAVX);
+        return new AMD64(computeFeatures(config));
+    }
+
+    protected EnumSet<AMD64.CPUFeature> computeFeatures(HotSpotVMConfig config) {
+        // Configure the feature set using the HotSpot flag settings.
+        EnumSet<AMD64.CPUFeature> features = EnumSet.noneOf(AMD64.CPUFeature.class);
+        assert config.useSSE >= 2 : "minimum config for x64";
+        features.add(AMD64.CPUFeature.SSE);
+        features.add(AMD64.CPUFeature.SSE2);
+        if (config.useSSE > 2) {
+            features.add(AMD64.CPUFeature.SSE3);
+        }
+        if (config.useSSE > 3) {
+            features.add(AMD64.CPUFeature.SSE4);
+        }
+        if (config.useAVX > 0) {
+            features.add(AMD64.CPUFeature.AVX);
+        }
+        if (config.useAVX > 1) {
+            features.add(AMD64.CPUFeature.AVX2);
+        }
+        if (config.useCountLeadingZerosInstruction) {
+            features.add(AMD64.CPUFeature.LZCNT);
+        }
+        if (config.usePopCountInstruction) {
+            features.add(AMD64.CPUFeature.POPCNT);
+        }
+        if (config.useAESIntrinsics) {
+            features.add(AMD64.CPUFeature.AES);
+        }
+        if (config.allocatePrefetchInstr == 3) {
+            features.add(AMD64.CPUFeature.AMD_3DNOW_PREFETCH);
+        }
+        return features;
     }
 
     protected TargetDescription createTarget(HotSpotVMConfig config) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Tue Dec 17 15:44:23 2013 +0100
@@ -40,6 +40,13 @@
 
     private final Register[] allocatable;
 
+    /**
+     * The same as {@link #allocatable}, except if parameter registers are removed with the
+     * {@link #RegisterPressure} option. The caller saved registers always include all parameter
+     * registers.
+     */
+    private final Register[] callerSaved;
+
     private final HashMap<PlatformKind, Register[]> categorized = new HashMap<>();
 
     private final RegisterAttributes[] attributesMap;
@@ -129,12 +136,20 @@
 
         csl = null;
         allocatable = initAllocatable(config.useCompressedOops);
+        Set<Register> callerSaveSet = new HashSet<>();
+        Collections.addAll(callerSaveSet, allocatable);
+        Collections.addAll(callerSaveSet, xmmParameterRegisters);
+        Collections.addAll(callerSaveSet, javaGeneralParameterRegisters);
+        Collections.addAll(callerSaveSet, nativeGeneralParameterRegisters);
+        callerSaved = callerSaveSet.toArray(new Register[callerSaveSet.size()]);
+        assert callerSaved.length == allocatable.length || RegisterPressure.getValue() != null;
+
         attributesMap = RegisterAttributes.createMap(this, AMD64.allRegisters);
     }
 
     @Override
     public Register[] getCallerSaveRegisters() {
-        return getAllocatableRegisters();
+        return callerSaved;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Tue Dec 17 15:44:23 2013 +0100
@@ -42,20 +42,24 @@
 public class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
 
     @State protected LIRFrameState state;
-    @Temp({OperandFlag.REG}) private AllocatableValue temp;
+    @Temp({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue temp;
 
     private final HotSpotVMConfig config;
 
     public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
         this.state = state;
         this.config = config;
-        temp = tool.newVariable(tool.target().wordKind);
+        if (isPollingPageFar(config)) {
+            temp = tool.newVariable(tool.target().wordKind);
+        } else {
+            // Don't waste a register if it's unneeded
+            temp = Value.ILLEGAL;
+        }
     }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
-        RegisterValue scratch = (RegisterValue) temp;
-        emitCode(crb, asm, config, false, state, scratch.getRegister());
+        emitCode(crb, asm, config, false, state, temp instanceof RegisterValue ? ((RegisterValue) temp).getRegister() : null);
     }
 
     /**
@@ -76,7 +80,7 @@
             if (state != null) {
                 crb.recordInfopoint(pos, state, InfopointReason.SAFEPOINT);
             }
-            asm.movq(scratch, new AMD64Address(scratch));
+            asm.testl(rax, new AMD64Address(scratch));
         } else {
             crb.recordMark(atReturn ? MARK_POLL_RETURN_NEAR : MARK_POLL_NEAR);
             if (state != null) {
@@ -84,7 +88,7 @@
             }
             // The C++ code transforms the polling page offset into an RIP displacement
             // to the real address at that offset in the polling page.
-            asm.movq(scratch, new AMD64Address(rip, 0));
+            asm.testl(rax, new AMD64Address(rip, 0));
         }
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Tue Dec 17 15:44:23 2013 +0100
@@ -39,7 +39,7 @@
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
         String file = System.getProperty("java.home") + "/lib/rt.jar";
-        new CompileTheWorld(file, 1, 5, false).compile();
+        new CompileTheWorld(file, null, 1, 5, false).compile();
         ExitVMOnException.setValue(originalSetting);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Tue Dec 17 15:44:23 2013 +0100
@@ -47,7 +47,7 @@
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
-public final class CompilationTask implements Runnable {
+public class CompilationTask implements Runnable {
 
     public static final ThreadLocal<Boolean> withinEnqueue = new ThreadLocal<Boolean>() {
 
@@ -77,7 +77,7 @@
         return new CompilationTask(backend, plan, optimisticOpts, profilingInfo, method, entryBCI, id);
     }
 
-    private CompilationTask(HotSpotBackend backend, PhasePlan plan, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, HotSpotResolvedJavaMethod method, int entryBCI, int id) {
+    protected CompilationTask(HotSpotBackend backend, PhasePlan plan, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, HotSpotResolvedJavaMethod method, int entryBCI, int id) {
         assert id >= 0;
         this.backend = backend;
         this.plan = plan;
@@ -120,6 +120,10 @@
 
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
+    protected Suites getSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultSuites();
+    }
+
     public void runCompilation() {
         /*
          * no code must be outside this try/finally because it could happen otherwise that
@@ -164,7 +168,7 @@
                 }
                 InlinedBytecodes.add(method.getCodeSize());
                 CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
-                Suites suites = providers.getSuites().getDefaultSuites();
+                Suites suites = getSuites(providers);
                 result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, plan, optimisticOpts, profilingInfo, method.getSpeculationLog(), suites, true,
                                 new CompilationResult(), CompilationResultBuilderFactory.Default);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Tue Dec 17 15:44:23 2013 +0100
@@ -22,7 +22,9 @@
  */
 package com.oracle.graal.hotspot;
 
+import static com.oracle.graal.hotspot.CompileTheWorld.Options.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.io.*;
@@ -34,10 +36,14 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.HotSpotOptions.OptionConsumer;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.options.OptionValue.OverrideScope;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 
 /**
@@ -45,6 +51,83 @@
  */
 public final class CompileTheWorld {
 
+    static class Options {
+        // @formatter:off
+        @Option(help = "Compile all methods in all classes on given class path")
+        public static final OptionValue<String> CompileTheWorldClasspath = new OptionValue<>(null);
+        @Option(help = "First class to consider when using -XX:+CompileTheWorld")
+        public static final OptionValue<Integer> CompileTheWorldStartAt = new OptionValue<>(1);
+        @Option(help = "Last class to consider when using -XX:+CompileTheWorld")
+        public static final OptionValue<Integer> CompileTheWorldStopAt = new OptionValue<>(Integer.MAX_VALUE);
+        @Option(help = "Option value overrides to use during compile the world. For example, " +
+                       "to disable inlining and partial escape analysis specify '-PartialEscapeAnalysis -Inline'. " +
+                       "The format for each option is the same as on the command line just without the '-G:' prefix.")
+        public static final OptionValue<String> CompileTheWorldConfig = new OptionValue<>(null);
+        // @formatter:on
+    }
+
+    /**
+     * A mechanism for overriding Graal options that effect compilation. A {@link Config} object
+     * should be used in a try-with-resources statement to ensure overriding of options is scoped
+     * properly. For example:
+     * 
+     * <pre>
+     *     Config config = ...;
+     *     try (AutoCloseable s = config == null ? null : config.apply()) {
+     *         // perform a Graal compilation
+     *     }
+     * </pre>
+     */
+    @SuppressWarnings("serial")
+    static class Config extends HashMap<OptionValue<?>, Object> implements AutoCloseable, OptionConsumer {
+        OverrideScope scope;
+
+        /**
+         * Creates a {@link Config} object by parsing a set of space separated override options.
+         * 
+         * @param options a space separated set of option value settings with each option setting in
+         *            a format compatible with
+         *            {@link HotSpotOptions#parseOption(String, OptionConsumer)}
+         */
+        Config(String options) {
+            for (String option : options.split("\\s+")) {
+                if (!HotSpotOptions.parseOption(option, this)) {
+                    throw new GraalInternalError("Invalid option specified: %s", option);
+                }
+            }
+        }
+
+        /**
+         * Applies the overrides represented by this object. The overrides are in effect until
+         * {@link #close()} is called on this object.
+         */
+        Config apply() {
+            assert scope == null;
+            scope = OptionValue.override(this);
+            return this;
+        }
+
+        public void close() {
+            assert scope != null;
+            scope.close();
+
+            scope = null;
+
+        }
+
+        public void set(OptionDescriptor desc, Object value) {
+            put(desc.getOptionValue(), value);
+        }
+    }
+
+    static Config parseConfig(String input) {
+        if (input == null) {
+            return null;
+        } else {
+            return new Config(input);
+        }
+    }
+
     /**
      * This is our magic token to trigger reading files from the boot class path.
      */
@@ -54,13 +137,13 @@
     private final HotSpotGraalRuntime runtime = runtime();
     private final VMToCompilerImpl vmToCompiler = (VMToCompilerImpl) runtime.getVMToCompiler();
 
-    /** List of Zip/Jar files to compile (see {@link GraalOptions#CompileTheWorld}. */
+    /** List of Zip/Jar files to compile (see {@link #CompileTheWorldClasspath}. */
     private final String files;
 
-    /** Class index to start compilation at (see {@link GraalOptions#CompileTheWorldStartAt}. */
+    /** Class index to start compilation at (see {@link #CompileTheWorldStartAt}. */
     private final int startAt;
 
-    /** Class index to stop compilation at (see {@link GraalOptions#CompileTheWorldStopAt}. */
+    /** Class index to stop compilation at (see {@link #CompileTheWorldStopAt}. */
     private final int stopAt;
 
     // Counters
@@ -69,28 +152,30 @@
     private long compileTime = 0;
 
     private boolean verbose;
+    private final Config config;
 
     /**
-     * Create a compile-the-world instance with default values from
-     * {@link GraalOptions#CompileTheWorld}, {@link GraalOptions#CompileTheWorldStartAt} and
-     * {@link GraalOptions#CompileTheWorldStopAt}.
+     * Creates a compile-the-world instance with default values from
+     * {@link Options#CompileTheWorldClasspath}, {@link Options#CompileTheWorldStartAt} and
+     * {@link Options#CompileTheWorldStopAt}.
      */
     public CompileTheWorld() {
-        this(CompileTheWorld.getValue(), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue(), true);
+        this(CompileTheWorldClasspath.getValue(), parseConfig(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(), CompileTheWorldStopAt.getValue(), true);
     }
 
     /**
-     * Create a compile-the-world instance.
+     * Creates a compile-the-world instance.
      * 
      * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile
      * @param startAt index of the class file to start compilation at
      * @param stopAt index of the class file to stop compilation at
      */
-    public CompileTheWorld(String files, int startAt, int stopAt, boolean verbose) {
+    public CompileTheWorld(String files, Config config, int startAt, int stopAt, boolean verbose) {
         this.files = files;
         this.startAt = startAt;
         this.stopAt = stopAt;
         this.verbose = verbose;
+        this.config = config;
 
         // We don't want the VM to exit when a method fails to compile...
         ExitVMOnException.setValue(false);
@@ -101,12 +186,10 @@
     }
 
     /**
-     * Compile all methods in all classes in the Zip/Jar files in
-     * {@link GraalOptions#CompileTheWorld}. If the GraalOptions.CompileTheWorld contains the magic
-     * token {@link CompileTheWorld#SUN_BOOT_CLASS_PATH} passed up from HotSpot we take the files
-     * from the boot class path.
-     * 
-     * @throws Throwable
+     * Compiles all methods in all classes in the Zip/Jar archive files in
+     * {@link #CompileTheWorldClasspath}. If {@link #CompileTheWorldClasspath} contains the magic
+     * token {@link #SUN_BOOT_CLASS_PATH} passed up from HotSpot we take the files from the boot
+     * class path.
      */
     public void compile() throws Throwable {
         if (SUN_BOOT_CLASS_PATH.equals(files)) {
@@ -145,7 +228,7 @@
     }
 
     /**
-     * Compile all methods in all classes in the Zip/Jar files passed.
+     * Compiles all methods in all classes in the Zip/Jar files passed.
      * 
      * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile
      * @throws Throwable
@@ -186,7 +269,7 @@
                 String className = je.getName().substring(0, je.getName().length() - ".class".length());
                 classFileCounter++;
 
-                try {
+                try (AutoCloseable s = config == null ? null : config.apply()) {
                     // Load and initialize class
                     Class<?> javaClass = Class.forName(className.replace('/', '.'), true, loader);
 
@@ -233,25 +316,49 @@
     }
 
     /**
-     * Helper method to schedule a method for compilation and gather some statistics.
+     * A compilation task that creates a fresh compilation suite for its compilation. This is
+     * required so that a CTW compilation can be {@linkplain Config configured} differently from a
+     * VM triggered compilation.
+     */
+    static class CTWCompilationTask extends CompilationTask {
+
+        CTWCompilationTask(HotSpotBackend backend, PhasePlan plan, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, HotSpotResolvedJavaMethod method, int entryBCI, int id) {
+            super(backend, plan, optimisticOpts, profilingInfo, method, entryBCI, id);
+        }
+
+        @Override
+        protected Suites getSuites(HotSpotProviders providers) {
+            return providers.getSuites().createSuites();
+        }
+    }
+
+    /**
+     * Compiles a method and gathers some statistics.
      */
     private void compileMethod(HotSpotResolvedJavaMethod method) {
         try {
             long start = System.currentTimeMillis();
-            vmToCompiler.compileMethod(method, StructuredGraph.INVOCATION_ENTRY_BCI, true);
+
+            final ProfilingInfo profilingInfo = method.getCompilationProfilingInfo(false);
+            final OptimisticOptimizations optimisticOpts = new OptimisticOptimizations(profilingInfo);
+            int id = vmToCompiler.allocateCompileTaskId();
+            HotSpotBackend backend = runtime.getHostBackend();
+            PhasePlan phasePlan = vmToCompiler.createPhasePlan(backend.getProviders(), optimisticOpts, false);
+            CompilationTask task = new CTWCompilationTask(backend, phasePlan, optimisticOpts, profilingInfo, method, INVOCATION_ENTRY_BCI, id);
+            task.runCompilation();
+
             compileTime += (System.currentTimeMillis() - start);
             compiledMethodsCounter++;
             method.reprofile();  // makes the method also not-entrant
         } catch (Throwable t) {
             // Catch everything and print a message
-            println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method));
+            println("CompileTheWorldClasspath (%d) : Error compiling method: %s", classFileCounter, MetaUtil.format("%H.%n(%p):%r", method));
             t.printStackTrace(TTY.cachedOut);
         }
     }
 
     /**
-     * Helper method for CompileTheWorld to determine if a method should be compiled (Cf.
-     * CompilationPolicy::can_be_compiled).
+     * Determines if a method should be compiled (Cf. CompilationPolicy::can_be_compiled).
      * 
      * @return true if it can be compiled, false otherwise
      */
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Dec 17 15:44:23 2013 +0100
@@ -23,7 +23,9 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.graph.UnsafeAccess.*;
+import static com.oracle.graal.hotspot.CompileTheWorld.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.Options.*;
+import static com.oracle.graal.phases.GraalOptions.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -232,23 +234,23 @@
         initMirror(typeVoid);
 
         // Set some global options:
-        if (config.compileTheWorld) {
-            GraalOptions.CompileTheWorld.setValue(CompileTheWorld.SUN_BOOT_CLASS_PATH);
+        if (config.compileTheWorld && CompileTheWorld.Options.CompileTheWorldClasspath.getValue() == null) {
+            CompileTheWorld.Options.CompileTheWorldClasspath.setValue(SUN_BOOT_CLASS_PATH);
         }
         if (config.compileTheWorldStartAt != 1) {
-            GraalOptions.CompileTheWorldStartAt.setValue(config.compileTheWorldStartAt);
+            CompileTheWorld.Options.CompileTheWorldStartAt.setValue(config.compileTheWorldStartAt);
         }
         if (config.compileTheWorldStopAt != Integer.MAX_VALUE) {
-            GraalOptions.CompileTheWorldStopAt.setValue(config.compileTheWorldStopAt);
+            CompileTheWorld.Options.CompileTheWorldStopAt.setValue(config.compileTheWorldStopAt);
         }
 
         // Only set HotSpotPrintCompilation and HotSpotPrintInlining if they still have their
         // default value (false).
-        if (GraalOptions.HotSpotPrintCompilation.getValue() == false) {
-            GraalOptions.HotSpotPrintCompilation.setValue(config.printCompilation);
+        if (HotSpotPrintCompilation.getValue() == false) {
+            HotSpotPrintCompilation.setValue(config.printCompilation);
         }
-        if (GraalOptions.HotSpotPrintInlining.getValue() == false) {
-            GraalOptions.HotSpotPrintInlining.setValue(config.printInlining);
+        if (HotSpotPrintInlining.getValue() == false) {
+            HotSpotPrintInlining.setValue(config.printInlining);
         }
 
         if (Boolean.valueOf(System.getProperty("graal.printconfig"))) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Tue Dec 17 15:44:23 2013 +0100
@@ -103,6 +103,22 @@
 
     // Called from VM code
     public static boolean setOption(String option) {
+        return parseOption(option, null);
+    }
+
+    interface OptionConsumer {
+        void set(OptionDescriptor desc, Object value);
+    }
+
+    /**
+     * Parses a given option value specification.
+     * 
+     * @param option the specification of an option and its value
+     * @param setter the object to notify of the parsed option and value. If null, the
+     *            {@link OptionValue#setValue(Object)} method of the specified option is called
+     *            instead.
+     */
+    public static boolean parseOption(String option, OptionConsumer setter) {
         if (option.length() == 0) {
             return false;
         }
@@ -175,9 +191,13 @@
         }
 
         if (value != null) {
-            OptionValue<?> optionValue = desc.getOptionValue();
-            optionValue.setValue(value);
-            // Logger.info("Set option " + desc.getName() + " to " + value);
+            if (setter != null) {
+                setter.set(desc, value);
+            } else {
+                OptionValue<?> optionValue = desc.getOptionValue();
+                optionValue.setValue(value);
+                // Logger.info("Set option " + desc.getName() + " to " + value);
+            }
         } else {
             Logger.info("Wrong value \"" + valueString + "\" for option " + optionName);
             return false;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Dec 17 15:44:23 2013 +0100
@@ -669,6 +669,7 @@
     @HotSpotVMFlag(name = "UseTLAB") @Stable public boolean useTLAB;
     @HotSpotVMFlag(name = "UseBiasedLocking") @Stable public boolean useBiasedLocking;
     @HotSpotVMFlag(name = "UsePopCountInstruction") @Stable public boolean usePopCountInstruction;
+    @HotSpotVMFlag(name = "UseCountLeadingZerosInstruction") @Stable public boolean useCountLeadingZerosInstruction;
     @HotSpotVMFlag(name = "UseAESIntrinsics") @Stable public boolean useAESIntrinsics;
     @HotSpotVMFlag(name = "UseCRC32Intrinsics") @Stable public boolean useCRC32Intrinsics;
     @HotSpotVMFlag(name = "UseG1GC") @Stable public boolean useG1GC;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Dec 17 15:44:23 2013 +0100
@@ -97,6 +97,10 @@
         this.runtime = runtime;
     }
 
+    public int allocateCompileTaskId() {
+        return compileTaskIds.incrementAndGet();
+    }
+
     public void startCompiler(boolean bootstrapEnabled) throws Throwable {
 
         FastNodeClassRegistry.initialize();
@@ -556,7 +560,7 @@
 
                 final ProfilingInfo profilingInfo = method.getCompilationProfilingInfo(osrCompilation);
                 final OptimisticOptimizations optimisticOpts = new OptimisticOptimizations(profilingInfo);
-                int id = compileTaskIds.incrementAndGet();
+                int id = allocateCompileTaskId();
                 HotSpotBackend backend = runtime.getHostBackend();
                 CompilationTask task = CompilationTask.create(backend, createPhasePlan(backend.getProviders(), optimisticOpts, osrCompilation), optimisticOpts, profilingInfo, method, entryBCI, id);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Tue Dec 17 15:44:23 2013 +0100
@@ -41,7 +41,7 @@
 /**
  * Represents a field in a HotSpot type.
  */
-public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField, LocationIdentity {
+public class HotSpotResolvedJavaField extends CompilerObject implements ResolvedJavaField {
 
     // Must not conflict with any fields flags used by the VM - the assertion in the constructor
     // checks this assumption
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Dec 17 15:44:23 2013 +0100
@@ -217,7 +217,7 @@
             TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), "  "));
         }
 
-        Indent indent = Debug.logAndIndent(false, "build graph for %s", method.toString());
+        Indent indent = Debug.logAndIndent(false, "build graph for %s", method);
 
         // compute the block map, setup exception handlers and get the entrypoint(s)
         BciBlockMapping blockMap = createBlockMap();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Tue Dec 17 15:44:23 2013 +0100
@@ -166,15 +166,15 @@
 
     /**
      * The maximum distance an operation with an {@linkplain #getExceptionEdge(LIRInstruction)
-     * exception edge} can be from the last instruction of a LIR block. The value of 2 is based on a
-     * non-void call operation that has an exception edge. Such a call op will have a move op after
-     * it to put the return value into the result variable.
+     * exception edge} can be from the last instruction of a LIR block. The value of 3 is based on a
+     * non-void call operation that has an exception edge. Such a call may move the result to
+     * another register and then spill it.
      * <p>
      * The rationale for such a constant is to limit the search for an insertion point when adding
      * move operations at the end of a block. Such moves must be inserted before all control flow
      * instructions.
      */
-    public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 2;
+    public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3;
 
     public static boolean verifyBlock(LIR lir, Block block) {
         List<LIRInstruction> ops = lir.lir(block);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Tue Dec 17 15:44:23 2013 +0100
@@ -41,7 +41,7 @@
     public final BytecodeFrame topFrame;
     private final VirtualObject[] virtualObjects;
     public final LabelRef exceptionEdge;
-    private DebugInfo debugInfo;
+    protected DebugInfo debugInfo;
 
     public LIRFrameState(BytecodeFrame topFrame, VirtualObject[] virtualObjects, LabelRef exceptionEdge) {
         this.topFrame = topFrame;
@@ -109,8 +109,45 @@
         }
     }
 
-    public void finish(BitSet registerRefMap, BitSet frameRefMap) {
-        debugInfo = new DebugInfo(topFrame, registerRefMap, frameRefMap);
+    /**
+     * Called by the register allocator before {@link #markLocation} to initialize the frame state.
+     * 
+     * @param frameMap The frame map.
+     * @param canHaveRegisters True if there can be any register map entries.
+     */
+    public void initDebugInfo(FrameMap frameMap, boolean canHaveRegisters) {
+        BitSet registerRefMap = (canHaveRegisters ? frameMap.initRegisterRefMap() : null);
+        debugInfo = new DebugInfo(topFrame, registerRefMap, frameMap.initFrameRefMap());
+    }
+
+    /**
+     * Called by the register allocator to mark the specified location as a reference in the
+     * reference map of the debug information. The tracked location can be a {@link RegisterValue}
+     * or a {@link StackSlot}. Note that a {@link Constant} is automatically tracked.
+     * 
+     * @param location The location to be added to the reference map.
+     * @param frameMap The frame map.
+     */
+    public void markLocation(Value location, FrameMap frameMap) {
+        if (location.getKind() == Kind.Object) {
+            if (isRegister(location)) {
+                debugInfo.getRegisterRefMap().set(asRegister(location).number);
+            } else if (isStackSlot(location)) {
+                int index = frameMap.indexForStackSlot(asStackSlot(location));
+                debugInfo.getFrameRefMap().set(index);
+            } else {
+                assert isConstant(location);
+            }
+        }
+    }
+
+    /**
+     * Called by the register allocator after all locations are marked.
+     * 
+     * @param op The instruction to which this frame state belongs.
+     * @param frameMap The frame map.
+     */
+    public void finish(LIRInstruction op, FrameMap frameMap) {
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Tue Dec 17 15:44:23 2013 +0100
@@ -0,0 +1,462 @@
+/*
+ * Copyright (c) 2013, 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.lir;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.nodes.cfg.*;
+
+/**
+ * Removes move instructions, where the destination value is already in place.
+ */
+public final class RedundantMoveElimination {
+
+    public static void optimize(LIR lir, FrameMap frameMap, ResolvedJavaMethod method) {
+        RedundantMoveElimination redundantMoveElimination = new RedundantMoveElimination();
+        redundantMoveElimination.doOptimize(lir, frameMap, method);
+    }
+
+    /**
+     * Holds the entry and exit states for each block for dataflow analysis. The state is an array
+     * with an element for each relevant location (register or stack slot). Each element holds the
+     * global number of the location's definition. A location definition is simply an output of an
+     * instruction. Note that because instructions can have multiple outputs it is not possible to
+     * use the instruction id for value numbering. In addition, the result of merging at block
+     * entries (= phi values) get unique value numbers.
+     * 
+     * The value numbers also contain information if it is an object kind value or not: if the
+     * number is negative it is an object kind value.
+     */
+    private static class BlockData {
+
+        BlockData(int stateSize) {
+            entryState = new int[stateSize];
+            exitState = new int[stateSize];
+        }
+
+        /*
+         * The state at block entry for global dataflow analysis. It contains a global value number
+         * for each location to optimize.
+         */
+        int[] entryState;
+
+        /*
+         * The state at block exit for global dataflow analysis. It contains a global value number
+         * for each location to optimize.
+         */
+        int[] exitState;
+
+        /*
+         * The starting number for global value numbering in this block.
+         */
+        int entryValueNum;
+    }
+
+    Map<Block, BlockData> blockData = new HashMap<>();
+
+    Register[] callerSaveRegs;
+
+    Map<StackSlot, Integer> stackIndices = new HashMap<>();
+
+    int numRegs;
+
+    /*
+     * Pseudo value for a not yet assigned location.
+     */
+    static final int INIT_VALUE = 0;
+
+    /**
+     * The main method doing the elimination of redundant moves.
+     */
+    private void doOptimize(LIR lir, FrameMap frameMap, ResolvedJavaMethod method) {
+
+        try (Indent indent = Debug.logAndIndent(false, "eliminate redundant moves in %s", method)) {
+
+            callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters();
+
+            initBlockData(lir);
+
+            solveDataFlow(lir);
+
+            eliminateMoves(lir);
+        }
+    }
+
+    private void initBlockData(LIR lir) {
+
+        List<Block> blocks = lir.linearScanOrder();
+        numRegs = 0;
+
+        /*
+         * Search for relevant locations which can be optimized. These are register or stack slots
+         * which occur as destinations of move instructions.
+         */
+        for (Block block : blocks) {
+            List<LIRInstruction> instructions = lir.lir(block);
+            for (LIRInstruction op : instructions) {
+                if (isEligibleMove(op)) {
+                    Value dest = ((MoveOp) op).getResult();
+                    if (isRegister(dest)) {
+                        int regNum = ((RegisterValue) dest).getRegister().number;
+                        if (regNum >= numRegs) {
+                            numRegs = regNum + 1;
+                        }
+                    } else if (isStackSlot(dest)) {
+                        StackSlot stackSlot = (StackSlot) dest;
+                        if (!stackIndices.containsKey(stackSlot)) {
+                            stackIndices.put(stackSlot, stackIndices.size());
+                        }
+                    }
+                }
+            }
+        }
+
+        /*
+         * Now we know the number of locations to optimize, so we can allocate the block states.
+         */
+        int numLocations = numRegs + stackIndices.size();
+        Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
+        for (Block block : blocks) {
+            BlockData data = new BlockData(numLocations);
+            blockData.put(block, data);
+        }
+    }
+
+    /**
+     * Calculates the entry and exit states for all basic blocks.
+     */
+    private void solveDataFlow(LIR lir) {
+
+        Indent indent = Debug.logAndIndent("solve data flow");
+
+        List<Block> blocks = lir.linearScanOrder();
+
+        /*
+         * Iterate until there are no more changes.
+         */
+        int currentValueNum = 1;
+        boolean firstRound = true;
+        boolean changed;
+        do {
+            changed = false;
+            Indent indent2 = indent.logAndIndent("new iteration");
+
+            for (Block block : blocks) {
+
+                BlockData data = blockData.get(block);
+                /*
+                 * Initialize the number for global value numbering for this block. It is essential
+                 * that the starting number for a block is consistent at all iterations and also in
+                 * eliminateMoves().
+                 */
+                if (firstRound) {
+                    data.entryValueNum = currentValueNum;
+                }
+                int valueNum = data.entryValueNum;
+                assert valueNum > 0;
+                boolean newState = false;
+
+                if (block == blocks.get(0) || block.isExceptionEntry()) {
+                    /*
+                     * The entry block has undefined values. And also exception handler blocks: the
+                     * LinearScan can insert moves at the end of an exception handler predecessor
+                     * block (after the invoke, which throws the exception), and in reality such
+                     * moves are not in the control flow in case of an exception. So we assume a
+                     * save default for exception handler blocks.
+                     */
+                    indent2.log("kill all values at entry of block %d", block.getId());
+                    clearValues(data.entryState, valueNum);
+                } else {
+                    /*
+                     * Merge the states of predecessor blocks
+                     */
+                    for (Block predecessor : block.getPredecessors()) {
+                        BlockData predData = blockData.get(predecessor);
+                        newState |= mergeState(data.entryState, predData.exitState, valueNum);
+                    }
+                }
+                // Advance by the value numbers which are "consumed" by clearValues and mergeState
+                valueNum += data.entryState.length;
+
+                if (newState || firstRound) {
+
+                    Indent indent3 = indent2.logAndIndent("update block %d", block.getId());
+
+                    /*
+                     * Derive the exit state from the entry state by iterating through all
+                     * instructions of the block.
+                     */
+                    int[] iterState = data.exitState;
+                    copyState(iterState, data.entryState);
+                    List<LIRInstruction> instructions = lir.lir(block);
+
+                    for (LIRInstruction op : instructions) {
+                        valueNum = updateState(iterState, op, valueNum);
+                    }
+                    changed = true;
+                    indent3.outdent();
+                }
+                if (firstRound) {
+                    currentValueNum = valueNum;
+                }
+            }
+            firstRound = false;
+            indent2.outdent();
+
+        } while (changed);
+
+        indent.outdent();
+    }
+
+    /**
+     * Deletes all move instructions where the target location already contains the source value.
+     */
+    private void eliminateMoves(LIR lir) {
+
+        Indent indent = Debug.logAndIndent("eliminate moves");
+
+        List<Block> blocks = lir.linearScanOrder();
+
+        for (Block block : blocks) {
+
+            Indent indent2 = indent.logAndIndent("eliminate moves in block %d", block.getId());
+
+            List<LIRInstruction> instructions = lir.lir(block);
+            BlockData data = blockData.get(block);
+            boolean hasDead = false;
+
+            // Reuse the entry state for iteration, we don't need it later.
+            int[] iterState = data.entryState;
+
+            // Add the values which are "consumed" by clearValues and mergeState in solveDataFlow
+            int valueNum = data.entryValueNum + data.entryState.length;
+
+            int numInsts = instructions.size();
+            for (int idx = 0; idx < numInsts; idx++) {
+                LIRInstruction op = instructions.get(idx);
+                if (isEligibleMove(op)) {
+                    MoveOp moveOp = (MoveOp) op;
+                    int sourceIdx = getStateIdx(moveOp.getInput());
+                    int destIdx = getStateIdx(moveOp.getResult());
+                    if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
+                        assert iterState[sourceIdx] != INIT_VALUE;
+                        indent2.log("delete move %s", op);
+                        instructions.set(idx, null);
+                        hasDead = true;
+                    }
+                }
+                // It doesn't harm if updateState is also called for a deleted move
+                valueNum = updateState(iterState, op, valueNum);
+            }
+            if (hasDead) {
+                instructions.removeAll(Collections.singleton(null));
+            }
+            indent2.outdent();
+        }
+        indent.outdent();
+    }
+
+    /**
+     * Updates the state for one instruction.
+     */
+    private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
+
+        try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
+            if (isEligibleMove(op)) {
+                /*
+                 * Handle the special case of a move instruction
+                 */
+                MoveOp moveOp = (MoveOp) op;
+                int sourceIdx = getStateIdx(moveOp.getInput());
+                int destIdx = getStateIdx(moveOp.getResult());
+                if (sourceIdx >= 0 && destIdx >= 0) {
+                    state[destIdx] = state[sourceIdx];
+                    indent.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
+                    return initValueNum;
+                }
+            }
+
+            int valueNum = initValueNum;
+
+            if (op.destroysCallerSavedRegisters()) {
+                indent.log("kill all caller save regs");
+
+                for (Register reg : callerSaveRegs) {
+                    if (reg.number < numRegs) {
+                        // Kind.Object is the save default
+                        state[reg.number] = encodeValueNum(valueNum++, true);
+                    }
+                }
+            }
+
+            /*
+             * Value procedure for the instruction's output and temp values
+             */
+            class OutputValueProc extends ValueProcedure {
+
+                int opValueNum;
+
+                OutputValueProc(int opValueNum) {
+                    this.opValueNum = opValueNum;
+                }
+
+                @Override
+                public Value doValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    int stateIdx = getStateIdx(operand);
+                    if (stateIdx >= 0) {
+                        /*
+                         * Assign a unique number to the output or temp location.
+                         */
+                        state[stateIdx] = encodeValueNum(opValueNum++, operand.getKind() == Kind.Object);
+                        indent.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
+                    }
+                    return operand;
+                }
+            }
+
+            OutputValueProc outputValueProc = new OutputValueProc(valueNum);
+            op.forEachOutput(outputValueProc);
+            op.forEachTemp(outputValueProc);
+            valueNum = outputValueProc.opValueNum;
+
+            if (op.hasState()) {
+                /*
+                 * All instructions with framestates (mostly method calls), may do garbage
+                 * collection. GC will rewrite all object references which are live at this point.
+                 * So we can't rely on their values.
+                 */
+                indent.log("kill all object values");
+                clearValuesOfKindObject(state, valueNum);
+                valueNum += state.length;
+            }
+
+            return valueNum;
+        }
+    }
+
+    /**
+     * The state merge function for dataflow joins.
+     */
+    private static boolean mergeState(int[] dest, int[] source, int defNum) {
+        assert dest.length == source.length;
+        boolean changed = false;
+        for (int idx = 0; idx < source.length; idx++) {
+            int phiNum = defNum + idx;
+            if (dest[idx] != source[idx] && source[idx] != INIT_VALUE && dest[idx] != encodeValueNum(phiNum, isObjectValue(dest[idx]))) {
+                if (dest[idx] != INIT_VALUE) {
+                    dest[idx] = encodeValueNum(phiNum, isObjectValue(dest[idx]) || isObjectValue(source[idx]));
+                } else {
+                    dest[idx] = source[idx];
+                }
+                changed = true;
+            }
+        }
+        return changed;
+    }
+
+    private static void copyState(int[] dest, int[] source) {
+        assert dest.length == source.length;
+        for (int idx = 0; idx < source.length; idx++) {
+            dest[idx] = source[idx];
+        }
+    }
+
+    private static void clearValues(int[] state, int defNum) {
+        for (int idx = 0; idx < state.length; idx++) {
+            int phiNum = defNum + idx;
+            // Let the killed values assume to be object references: it's the save default.
+            state[idx] = encodeValueNum(phiNum, true);
+        }
+    }
+
+    private static void clearValuesOfKindObject(int[] state, int defNum) {
+        for (int idx = 0; idx < state.length; idx++) {
+            int phiNum = defNum + idx;
+            if (isObjectValue(state[idx])) {
+                state[idx] = encodeValueNum(phiNum, true);
+            }
+        }
+    }
+
+    /**
+     * Returns the index to the state arrays in BlockData for a specific location.
+     */
+    private int getStateIdx(Value location) {
+        if (isRegister(location)) {
+            int regNum = ((RegisterValue) location).getRegister().number;
+            if (regNum < numRegs) {
+                return regNum;
+            }
+        }
+        if (isStackSlot(location)) {
+            StackSlot slot = (StackSlot) location;
+            Integer index = stackIndices.get(slot);
+            if (index != null) {
+                return index.intValue() + numRegs;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Encodes a value number + the is-object information to a number to be stored in a state.
+     */
+    private static int encodeValueNum(int valueNum, boolean isObjectKind) {
+        assert valueNum > 0;
+        if (isObjectKind) {
+            return -valueNum;
+        }
+        return valueNum;
+    }
+
+    /**
+     * Returns true if an encoded value number (which is stored in a state) refers to an object
+     * reference.
+     */
+    private static boolean isObjectValue(int encodedValueNum) {
+        return encodedValueNum < 0;
+    }
+
+    /**
+     * Returns true for a move instruction which is a candidate for elimination.
+     */
+    private static boolean isEligibleMove(LIRInstruction op) {
+        if (op instanceof MoveOp) {
+            MoveOp moveOp = (MoveOp) op;
+            Value source = moveOp.getInput();
+            Value dest = moveOp.getResult();
+            /*
+             * Moves with mismatching kinds are not moves, but memory loads/stores!
+             */
+            return source.getKind() == dest.getKind() && source.getPlatformKind() == dest.getPlatformKind() && source.getKind() != Kind.Illegal;
+        }
+        return false;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Tue Dec 17 15:44:23 2013 +0100
@@ -42,9 +42,9 @@
     void setStateAfter(FrameState x);
 
     /**
-     * Determines if this node has a side-effect. Such nodes can not be safely re-executed because
-     * they modified state which is visible to other thread or modified state beyond what is
-     * captured in {@link FrameState} nodes.
+     * Determines if this node has a side-effect. Such nodes cannot be safely re-executed because
+     * they modify state which is visible to other threads or modify state beyond what is captured
+     * in {@link FrameState} nodes.
      */
     boolean hasSideEffect();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Dec 17 15:44:23 2013 +0100
@@ -25,6 +25,8 @@
 import static com.oracle.graal.graph.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,13 +36,14 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-public class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+public class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, Canonicalizable {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
     @Input private ValueNode expected;
     @Input private ValueNode newValue;
     private final int displacement;
+    private final LocationIdentity locationIdentity;
 
     public ValueNode object() {
         return object;
@@ -63,6 +66,10 @@
     }
 
     public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) {
+        this(object, displacement, offset, expected, newValue, LocationIdentity.ANY_LOCATION);
+    }
+
+    public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) {
         super(StampFactory.forKind(Kind.Boolean.getStackKind()));
         assert expected.kind() == newValue.kind();
         this.object = object;
@@ -70,11 +77,12 @@
         this.expected = expected;
         this.newValue = newValue;
         this.displacement = displacement;
+        this.locationIdentity = locationIdentity;
     }
 
     @Override
     public LocationIdentity getLocationIdentity() {
-        return LocationIdentity.ANY_LOCATION;
+        return locationIdentity;
     }
 
     @Override
@@ -82,6 +90,24 @@
         tool.getLowerer().lower(this, tool);
     }
 
+    @Override
+    public Node canonical(CanonicalizerTool tool) {
+        if (getLocationIdentity() == LocationIdentity.ANY_LOCATION) {
+            Constant offsetConstant = offset().asConstant();
+            if (offsetConstant != null) {
+                ResolvedJavaType receiverType = ObjectStamp.typeOrNull(object());
+                if (receiverType != null) {
+                    long constantOffset = offsetConstant.asLong();
+                    ResolvedJavaField field = receiverType.findInstanceFieldWithOffset(constantOffset);
+                    if (field != null && expected().kind() == field.getKind() && newValue().kind() == field.getKind()) {
+                        return graph().add(new CompareAndSwapNode(object, displacement, offset, expected, newValue, field));
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
     @NodeIntrinsic
     public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, Object expected, Object newValue) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/NodeWithState.java	Tue Dec 17 15:44:23 2013 +0100
@@ -29,13 +29,11 @@
 /**
  * Interface for nodes which have {@link FrameState} nodes as input.
  * <p>
- * Some node can declare more than one interface which requires a {@link FrameState} input (e.g.
+ * Some node can implement more than one interface which requires a {@link FrameState} input (e.g.
  * {@link DeoptimizingNode} and {@link StateSplit}). Since this interface can only report one
- * {@link FrameState}, such nodes must ensure they only maintain a link to at most one
- * {@link FrameState} at all times. Usually this is not a problem because {@link FrameState} are
- * associated only with {@link StateSplit} nodes before the {@link #AFTER_FSA} stage and only with
- * {@link DeoptimizingNode} after.
- * 
+ * FrameState, such nodes must ensure they only maintain a link to at most one FrameState at all
+ * times. Usually this is not a problem because FrameStates are associated only with StateSplit
+ * nodes before the {@link #AFTER_FSA} stage and only with DeoptimizingNodes after.
  * 
  */
 public interface NodeWithState {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Dec 17 15:44:02 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Dec 17 15:44:23 2013 +0100
@@ -87,14 +87,6 @@
     @Option(help = "")
     public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
 
-    // compilation queue
-    @Option(help = "Compile all methods in all classes on given class path")
-    public static final OptionValue<String> CompileTheWorld = new OptionValue<>(null);
-    @Option(help = "First class to consider when using CompileTheWorld")
-    public static final OptionValue<Integer> CompileTheWorldStartAt = new OptionValue<>(1);
-    @Option(help = "Last class to consider when using CompileTheWorld")
-    public static final OptionValue<Integer> CompileTheWorldStopAt = new OptionValue<>(Integer.MAX_VALUE);
-
     // graph caching
     @Option(help = "")
     public static final OptionValue<Boolean> CacheGraphs = new OptionValue<>(true);
--- a/mx/mx_graal.py	Tue Dec 17 15:44:02 2013 +0100
+++ b/mx/mx_graal.py	Tue Dec 17 15:44:23 2013 +0100
@@ -1348,14 +1348,14 @@
 
 def trufflejar(args=None):
     """make truffle.jar"""
-    
+
     # Test with the built classes
     _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'])
-    
+
     # We use the DSL processor as the starting point for the classpath - this
     # therefore includes the DSL processor, the DSL and the API.
     packagejar(mx.classpath("com.oracle.truffle.dsl.processor").split(os.pathsep), "truffle.jar", None, "com.oracle.truffle.dsl.processor.TruffleProcessor")
-    
+
     # Test with the JAR
     _unittest(["com.oracle.truffle.api.test", "com.oracle.truffle.api.dsl.test"], ['@Test', '@LongTest', '@Parameters'], "truffle.jar:")
 
@@ -1453,7 +1453,7 @@
     mx.distribution('GRAAL').add_update_listener(_installGraalJarInJdks)
 
 def packagejar(classpath, outputFile, mainClass=None, annotationProcessor=None, stripDebug=False):
-    prefix = '' if mx.get_os() != 'windows' else '\\??\\' # long file name hack
+    prefix = '' if mx.get_os() != 'windows' else '\\??\\'  # long file name hack
     print "creating", outputFile
     filecount, totalsize = 0, 0
     with zipfile.ZipFile(outputFile, 'w', zipfile.ZIP_DEFLATED) as zf:
@@ -1475,7 +1475,7 @@
                 for root, _, files in os.walk(cp):
                     for f in files:
                         fullname = os.path.join(root, f)
-                        arcname = fullname[len(cp)+1:].replace('\\', '/')
+                        arcname = fullname[len(cp) + 1:].replace('\\', '/')
                         if f.endswith(".class"):
                             zf.write(prefix + fullname, arcname)
 
--- a/mx/projects	Tue Dec 17 15:44:02 2013 +0100
+++ b/mx/projects	Tue Dec 17 15:44:23 2013 +0100
@@ -1,5 +1,5 @@
 # The format of this file is described in the documentation for my.py.
-
+mxversion=1.0
 suite=graal
 
 library@JDK_TOOLS@path=${JAVA_HOME}/lib/tools.jar
--- a/mxtool/mx.py	Tue Dec 17 15:44:02 2013 +0100
+++ b/mxtool/mx.py	Tue Dec 17 15:44:23 2013 +0100
@@ -675,6 +675,7 @@
         self.imports = []
         self.commands = None
         self.primary = primary
+        self.requiredMxVersion = None
         self.name = _suitename(mxDir)  # validated in _load_projects
         if load:
             # load suites bottom up to make sure command overriding works properly
@@ -714,10 +715,17 @@
                     parts = key.split('@')
 
                     if len(parts) == 1:
-                        if parts[0] != 'suite':
+                        if parts[0] == 'suite':
+                            if self.name != value:
+                                abort('suite name in project file does not match ' + _suitename(self.mxDir))
+                        elif parts[0] == 'mxversion':
+                            try:
+                                self.requiredMxVersion = JavaVersion(value)
+                            except AssertionError as ae:
+                                abort('Exception while parsing "mxversion" in project file: ' + str(ae))
+                        else:
                             abort('Single part property must be "suite": ' + key)
-                        if self.name != value:
-                            abort('suite name in project file does not match ' + _suitename(self.mxDir))
+
                         continue
                     if len(parts) != 3:
                         abort('Property name does not have 3 parts separated by "@": ' + key)
@@ -889,6 +897,10 @@
 
     def _post_init(self, opts):
         self._load_projects()
+        if self.requiredMxVersion is None:
+            warn("This suite does not express any required mx version. Consider adding 'mxversion=<version>' to your projects file.")
+        elif self.requiredMxVersion > version:
+            abort("This suite requires mx version " + str(self.requiredMxVersion) + " while your current mx verion is " + str(version) + ". Please update mx.")
         # set the global data structures, checking for conflicts unless _check_global_structures is False
         for p in self.projects:
             existing = _projects.get(p.name)
@@ -1552,7 +1564,7 @@
     def __init__(self, versionString):
         validChar = r'[\x21-\x25\x27-\x29\x2c\x2f-\x5e\x60-\x7f]'
         separator = r'[.\-_]'
-        m = re.match(validChar + '+(' + separator + validChar + '+)*', versionString)
+        m = re.match("^" + validChar + '+(' + separator + validChar + '+)*$', versionString)
         assert m is not None, 'not a recognized version string: ' + versionString
         self.versionString = versionString
         self.parts = [int(f) if f.isdigit() else f for f in re.split(separator, versionString)]
@@ -4516,6 +4528,8 @@
         # no need to show the stack trace when the user presses CTRL-C
         abort(1)
 
+version = JavaVersion("1.0")
+
 if __name__ == '__main__':
     # rename this module as 'mx' so it is not imported twice by the commands.py modules
     sys.modules['mx'] = sys.modules.pop('__main__')
--- a/src/share/vm/graal/graalCompiler.cpp	Tue Dec 17 15:44:02 2013 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Tue Dec 17 15:44:23 2013 +0100
@@ -115,6 +115,11 @@
         // Avoid -Xcomp and -Xbatch problems by turning on interpreter and background compilation for bootstrapping.
         FlagSetting a(UseInterpreter, true);
         FlagSetting b(BackgroundCompilation, true);
+#ifndef PRODUCT
+        // Turn off CompileTheWorld during bootstrap
+        // so that a complete bootstrap occurs
+        FlagSetting c(CompileTheWorld, false);
+#endif
         VMToCompiler::bootstrap();
       }