changeset 5266:c9dd4054c23b

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 20 Apr 2012 13:44:06 +0200
parents b8661be84cfd (diff) d87155082c4d (current diff)
children 8191f71d7f51
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java
diffstat 108 files changed, 3439 insertions(+), 1153 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Fri Apr 13 15:52:25 2012 +0200
+++ b/.hgignore	Fri Apr 20 13:44:06 2012 +0200
@@ -1,4 +1,6 @@
 ^mx/env
+^mx/checkstyle-timestamps
+^mx/eclipse-launches
 ^mx/ecj.jar
 ^mx/includes
 ^build/
@@ -9,7 +11,6 @@
 ^java64/
 ^work/
 \.checkstyle$
-\.checkstyle.*.timestamp
 \.classpath
 \.project
 \.settings/
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -41,7 +41,6 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.max.asm.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.cri.xir.*;
@@ -128,46 +127,38 @@
 
         new PhiStampPhase().apply(graph);
 
+        if (GraalOptions.ProbabilityAnalysis && graph.start().probability() == 0) {
+            new ComputeProbabilityPhase().apply(graph);
+        }
+
+        if (GraalOptions.PropagateTypes) {
+            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
+        }
+
         if (GraalOptions.OptCanonicalizer) {
             new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
         }
 
-        if (GraalOptions.ProbabilityAnalysis && graph.start().probability() == 0) {
-            new ComputeProbabilityPhase().apply(graph);
-        }
-
         if (GraalOptions.Intrinsify) {
             new IntrinsificationPhase(runtime).apply(graph);
         }
 
-        if (GraalOptions.PropagateTypes) {
-            if (GraalOptions.OptCanonicalizer) {
-                new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
-            }
-
-            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
-        }
-
         if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) {
             new InliningPhase(target, runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph);
             new DeadCodeEliminationPhase().apply(graph);
             new PhiStampPhase().apply(graph);
-        }
+            if (GraalOptions.PropagateTypes) {
+                new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
+            }
 
-        if (GraalOptions.OptCanonicalizer) {
-            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+            if (GraalOptions.OptCanonicalizer) {
+                new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+            }
         }
 
-        if (GraalOptions.PropagateTypes) {
-            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
-        }
 
         plan.runPhases(PhasePosition.HIGH_LEVEL, graph);
 
-        if (GraalOptions.OptLoops) {
-            new SafepointPollingEliminationPhase().apply(graph);
-        }
-
         if (GraalOptions.EscapeAnalysis && !plan.isPhaseDisabled(EscapeAnalysisPhase.class)) {
             new EscapeAnalysisPhase(target, runtime, assumptions, cache, plan, optimisticOpts).apply(graph);
             new PhiStampPhase().apply(graph);
@@ -175,7 +166,18 @@
                 new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
             }
         }
-
+        if (GraalOptions.OptLoops) {
+            if (GraalOptions.OptLoopTransform) {
+                new LoopTransformPhase().apply(graph);
+            }
+            if (GraalOptions.OptSafepointElimination) {
+                new SafepointPollingEliminationPhase().apply(graph);
+            }
+        }
+        new RemoveValueProxyPhase().apply(graph);
+        if (GraalOptions.OptCanonicalizer) {
+            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+        }
         if (GraalOptions.OptGVN) {
             new GlobalValueNumberingPhase().apply(graph);
         }
@@ -197,6 +199,9 @@
         if (GraalOptions.PropagateTypes) {
             new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
         }
+        if (GraalOptions.OptCanonicalizer) {
+            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+        }
         if (GraalOptions.OptGVN) {
             new GlobalValueNumberingPhase().apply(graph);
         }
@@ -228,7 +233,7 @@
                     b.linearScanNumber = z++;
                 }
 
-                LIR lir = new LIR(schedule.getCFG(), schedule.getNodesFor(), linearScanOrder, codeEmittingOrder);
+                LIR lir = new LIR(schedule.getCFG(), schedule.getBlockToNodesMap(), linearScanOrder, codeEmittingOrder);
                 Debug.dump(lir, "After linear scan order");
                 return lir;
 
@@ -263,24 +268,14 @@
         return frameMap;
     }
 
-    private TargetMethodAssembler createAssembler(FrameMap frameMap, LIR lir) {
-        AbstractAssembler masm = backend.newAssembler(frameMap.registerConfig);
-        TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime, frameMap, lir.slowPaths, masm);
-        tasm.setFrameSize(frameMap.frameSize());
-        tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea());
-        return tasm;
-    }
-
     public CiTargetMethod emitCode(CiAssumptions assumptions, RiResolvedMethod method, LIR lir, FrameMap frameMap) {
-        TargetMethodAssembler tasm = createAssembler(frameMap, lir);
-        lir.emitCode(tasm);
-
+        TargetMethodAssembler tasm = backend.newAssembler(frameMap, lir);
+        backend.emitCode(tasm, method, lir);
         CiTargetMethod targetMethod = tasm.finishTargetMethod(method, false);
         if (assumptions != null && !assumptions.isEmpty()) {
             targetMethod.setAssumptions(assumptions);
         }
 
-        Debug.dump(lir, "After code generation");
         Debug.dump(targetMethod, "After code generation");
         return targetMethod;
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri Apr 20 13:44:06 2012 +0200
@@ -98,6 +98,9 @@
     //rematerialize settings
     public static float   MinimumUsageProbability            = 0.95f;
 
+    //loop transform settings
+    public static float   MinimumPeelProbability             = 0.25f;
+
     // debugging settings
     public static int     MethodEndBreakpointGuards          = 0;
     public static boolean ZapStackOnMethodEntry              = ____;
@@ -143,6 +146,7 @@
     public static boolean PrintAssembly                      = ____;
     public static boolean PrintCodeBytes                     = ____;
     public static int     PrintAssemblyBytesPerLine          = 16;
+    public static boolean PrintBailout                       = ____;
     public static int     TraceLinearScanLevel               = 0;
     public static boolean TraceRegisterAllocation            = false;
     public static int     TraceLIRGeneratorLevel             = 0;
@@ -192,12 +196,14 @@
     public static boolean OptReadElimination                 = true;
     public static boolean OptGVN                             = true;
     public static boolean OptCanonicalizer                   = true;
-    public static boolean OptLoops                           = ____;
+    public static boolean OptLoops                           = true;
     public static boolean ScheduleOutOfLoops                 = true;
     public static boolean OptReorderLoops                    = true;
     public static boolean OptEliminateGuards                 = true;
     public static boolean OptImplicitNullChecks              = true;
     public static boolean OptLivenessAnalysis                = true;
+    public static boolean OptLoopTransform                   = true;
+    public static boolean OptSafepointElimination            = true;
 
     /**
      * Flag to turn on SSA-based register allocation, which is currently under development.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Fri Apr 20 13:44:06 2012 +0200
@@ -846,7 +846,7 @@
             TTY.println("startBlock-ID: " + startBlock.getId());
 
             // bailout of if this occurs in product mode.
-            throw new CiBailout("liveIn set of first block must be empty");
+            throw new GraalInternalError("liveIn set of first block must be empty");
         }
     }
 
@@ -860,7 +860,7 @@
         for (int operandNum = 0; operandNum < blockData.get(ir.cfg.getStartBlock()).liveIn.size(); operandNum++) {
             if (blockData.get(ir.cfg.getStartBlock()).liveIn.get(operandNum)) {
                 CiValue operand = operandFor(operandNum);
-                TTY.println(" var %d; operand=%s", operandNum, operand.toString());
+                TTY.println(" var %d; operand=%s; node=%s", operandNum, operand.toString(), gen.valueForOperand(operand));
 
                 for (int j = 0; j < numBlocks; j++) {
                     Block block = blockAt(j);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Fri Apr 20 13:44:06 2012 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.virtual.*;
 
 public class DebugInfoBuilder {
@@ -54,7 +55,13 @@
             FrameState current = topState;
             do {
                 for (Node n : current.virtualObjectMappings()) {
-                    VirtualObjectFieldNode field = (VirtualObjectFieldNode) n;
+                    Node p = n;
+                    while (p instanceof PhiNode) {
+                        PhiNode phi = (PhiNode) p;
+                        assert phi.type() == PhiType.Virtual;
+                        p = phi.valueAt(0);
+                    }
+                    VirtualObjectFieldNode field = (VirtualObjectFieldNode) p;
                     // null states occur for objects with 0 fields
                     if (field != null && !objectStates.containsKey(field.object())) {
                         objectStates.put(field.object(), field);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri Apr 20 13:44:06 2012 +0200
@@ -27,6 +27,7 @@
 import static com.oracle.max.cri.ci.CiValue.*;
 
 import java.util.*;
+import java.util.Map.Entry;
 
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.util.*;
@@ -173,6 +174,15 @@
         return nodeOperands.get(node);
     }
 
+    public ValueNode valueForOperand(CiValue value) {
+        for (Entry<Node, CiValue> entry : nodeOperands.entries()) {
+            if (entry.getValue() == value) {
+                return (ValueNode) entry.getKey();
+            }
+        }
+        return null;
+    }
+
     /**
      * Creates a new {@linkplain Variable variable}.
      * @param kind The kind of the new variable.
@@ -480,13 +490,15 @@
         CiValue[] params = new CiValue[incomingArguments.locations.length];
         for (int i = 0; i < params.length; i++) {
             params[i] = toStackKind(incomingArguments.locations[i]);
+            if (CiValueUtil.isStackSlot(params[i])) {
+                CiStackSlot slot = CiValueUtil.asStackSlot(params[i]);
+                if (slot.inCallerFrame() && !lir.hasArgInCallerFrame()) {
+                    lir.setHasArgInCallerFrame();
+                }
+            }
         }
-        append(new ParametersOp(params));
 
-        XirSnippet prologue = xir.genPrologue(null, method);
-        if (prologue != null) {
-            emitXir(prologue, null, null, false);
-        }
+        append(new ParametersOp(params));
 
         for (LocalNode local : graph.getNodes(LocalNode.class)) {
             CiValue param = params[local.index()];
@@ -580,24 +592,13 @@
     }
 
     @Override
-    public void visitExceptionObject(ExceptionObjectNode x) {
-        XirSnippet snippet = xir.genExceptionObject(site(x));
-        LIRDebugInfo info = state();
-        emitXir(snippet, x, info, true);
-    }
-
-    @Override
     public void visitReturn(ReturnNode x) {
         CiValue operand = CiValue.IllegalValue;
         if (!x.kind().isVoid()) {
             operand = resultOperandFor(x.kind());
             emitMove(operand(x.result()), operand);
         }
-        XirSnippet epilogue = xir.genEpilogue(site(x), method);
-        if (epilogue != null) {
-            emitXir(epilogue, x, null, false);
-            emitReturn(operand);
-        }
+        emitReturn(operand);
     }
 
     protected abstract void emitReturn(CiValue input);
@@ -611,11 +612,11 @@
         moveToPhi(end.merge(), end);
     }
 
+    /**
+     * Runtime specific classes can override this to insert a safepoint at the end of a loop.
+     */
     @Override
     public void visitLoopEnd(LoopEndNode x) {
-        if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) {
-            emitSafepointPoll(x);
-        }
     }
 
     private ArrayList<CiValue> phiValues = new ArrayList<>();
@@ -661,14 +662,6 @@
         }
     }
 
-
-    public void emitSafepointPoll(FixedNode x) {
-        if (!lastState.method().noSafepointPolls()) {
-            XirSnippet snippet = xir.genSafepointPoll(site(x));
-            emitXir(snippet, x, state(), false);
-        }
-    }
-
     @Override
     public void emitIf(IfNode x) {
         assert x.defaultSuccessor() == x.falseSuccessor() : "wrong destination";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformDataResolver.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.loop;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.graal.graph.NodeClass.Position;
+import com.oracle.graal.nodes.*;
+
+
+
+public class LoopTransformDataResolver {
+    private List<ResolvableSuperBlock> resolvables = new LinkedList<>();
+
+    private abstract static class ResolvableSuperBlock {
+        final SuperBlock block;
+        public ResolvableSuperBlock(SuperBlock block) {
+            this.block = block;
+        }
+        public abstract void resolve();
+    }
+
+    private static class PeeledResolvableSuperBlock extends ResolvableSuperBlock{
+        final SuperBlock peel;
+        final boolean nextIteration;
+        public PeeledResolvableSuperBlock(SuperBlock peeled, SuperBlock peel, boolean nextIteration) {
+            super(peeled);
+            this.peel = peel;
+            this.nextIteration = nextIteration;
+        }
+        @Override
+        public void resolve() {
+            if (nextIteration) {
+                SuperBlock peeled = block;
+                LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
+                Map<Node, Node> dup = peel.getDuplicationMapping();
+                List<PhiNode> newPhis = new LinkedList<>();
+                for (PhiNode phi : loopBegin.phis().snapshot()) {
+                    ValueNode first = null;
+                    if (loopBegin.loopEnds().count() == 1) {
+                        ValueNode b = phi.valueAt(loopBegin.loopEnds().first()); // back edge value
+                        first = prim(b); // corresponding value in the peel
+                    } else {
+                        Map<EndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the corresponding loop exits
+                        MergeNode merge = null; // look for the merge if the peel's exits
+                        for (LoopEndNode end : loopBegin.loopEnds()) {
+                            EndNode newEnd = (EndNode) dup.get(end);
+                            if (newEnd != null) {
+                                reverseEnds.put(newEnd, end);
+                                if (prim(phi.valueAt(end)) != null) {
+                                    merge = newEnd.merge();
+                                }
+                            }
+                        }
+                        if (merge != null) { // found values of interest (backedge values that exist in the peel)
+                            PhiNode firstPhi = loopBegin.graph().add(new PhiNode(phi.kind(), merge, phi.type()));
+                            for (EndNode end : merge.forwardEnds()) {
+                                LoopEndNode loopEnd = reverseEnds.get(end);
+                                ValueNode prim = prim(phi.valueAt(loopEnd));
+                                assert prim != null;
+                                firstPhi.addInput(prim);
+                            }
+                            first = firstPhi;
+                            merge.stateAfter().replaceFirstInput(phi, firstPhi); // fix the merge's state after (see SuperBlock.mergeExits)
+                        }
+                    }
+                    if (first != null) { // create a new phi (we don't patch the old one since some usages of the old one may still be valid)
+                        PhiNode newPhi = loopBegin.graph().add(new PhiNode(phi.kind(), loopBegin, phi.type()));
+                        newPhi.addInput(first);
+                        for (LoopEndNode end : loopBegin.orderedLoopEnds()) {
+                            newPhi.addInput(phi.valueAt(end));
+                        }
+                        dup.put(phi, newPhi);
+                        newPhis.add(newPhi);
+                        for (Node usage : phi.usages().snapshot()) {
+                            if (dup.get(usage) != null) { // patch only usages that should use the new phi ie usages that were peeled
+                                usage.replaceFirstInput(phi, newPhi);
+                            }
+                        }
+                    }
+                }
+                // check new phis to see if they have as input some old phis, replace those inputs with the new corresponding phis
+                for (PhiNode phi : newPhis) {
+                    for (int i = 0; i < phi.valueCount(); i++) {
+                        ValueNode v = phi.valueAt(i);
+                        if (loopBegin.isPhiAtMerge(v)) {
+                            PhiNode newV = (PhiNode) dup.get(v);
+                            if (newV != null) {
+                                phi.setValueAt(i, newV);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Gets the corresponding value in the peel.
+         * @param b original value
+         * @return corresponding value in the peel
+         */
+        public ValueNode prim(ValueNode b) {
+            SuperBlock peeled = block;
+            LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
+            Map<Node, Node> dup = peel.getDuplicationMapping();
+            if (loopBegin.isPhiAtMerge(b)) {
+                PhiNode phi = (PhiNode) b;
+                return phi.valueAt(loopBegin.forwardEnd());
+            } else {
+                ValueNode v = (ValueNode) dup.get(b);
+                if (v == null && nextIteration) {
+                    // may not be right in inversion case
+                    return b;
+                }
+                return v;
+            }
+        }
+    }
+
+    private static class PeelResolvableSuperBlock extends ResolvableSuperBlock{
+        final SuperBlock peeled;
+        public PeelResolvableSuperBlock(SuperBlock peel, SuperBlock peeled) {
+            super(peel);
+            this.peeled = peeled;
+        }
+        @Override
+        public void resolve() {
+            SuperBlock peel = block;
+            LoopBeginNode loopBegin = (LoopBeginNode) peeled.getEntry();
+            for (Entry<Node, Node> entry : peel.getDuplicationMapping().entrySet()) {
+                Node oriNode = entry.getKey();
+                Node newNode = entry.getValue();
+                for (NodeClassIterator iter = oriNode.inputs().iterator(); iter.hasNext();) {
+                    Position pos = iter.nextPosition();
+                    if (pos.isValidFor(newNode, oriNode) && pos.get(newNode) == null) {
+                        Node oriInput = pos.get(oriNode);
+                        // oriInput is not checked against null because oriNode.inputs().iterator() only iterates over non-null pos/input
+                        Node v;
+                        if (loopBegin.isPhiAtMerge(oriInput)) {
+                            PhiNode phi = (PhiNode) oriInput;
+                            v = phi.valueAt(loopBegin.forwardEnd());
+                        } else {
+                            v = oriInput;
+                        }
+                        pos.set(newNode, v);
+                    }
+                }
+            }
+        }
+    }
+
+    public class WholeLoop {
+        private final SuperBlock from;
+        public WholeLoop(SuperBlock from) {
+            this.from = from;
+        }
+        public void peeled(SuperBlock peel) {
+            resolvables.add(new PeelResolvableSuperBlock(peel, from));
+            resolvables.add(new PeeledResolvableSuperBlock(from, peel, true));
+        }
+
+    }
+
+    public void resolve() {
+        for (ResolvableSuperBlock resolvable : this.resolvables) {
+            resolvable.resolve();
+        }
+    }
+
+    public WholeLoop wholeLoop(SuperBlock block) {
+        return new WholeLoop(block);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/LoopTransformUtil.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.loop;
+
+import java.util.*;
+
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+
+
+public class LoopTransformUtil {
+
+    public static void peel(Loop loop) {
+        peel(loop, wholeLoop(loop));
+    }
+
+    public static void peel(Loop loop, SuperBlock wholeLoop) {
+        SuperBlock peel = wholeLoop.duplicate(); // duplicates the nodes, merges early exits
+
+        peel.insertBefore(loop.loopBegin().forwardEnd()); // connects peeled part's CFG
+
+        LoopTransformDataResolver resolver = new LoopTransformDataResolver();
+        resolver.wholeLoop(wholeLoop).peeled(peel); // block (comming from the loop) was peeled into peel
+        resolver.resolve();
+
+        peel.finish();
+    }
+
+    public static SuperBlock wholeLoop(Loop loop) {
+        List<BeginNode> blocks = new LinkedList<>();
+        List<BeginNode> earlyExits = new LinkedList<>();
+        for (Block b : loop.blocks) {
+            blocks.add(b.getBeginNode());
+        }
+        for (Block b : loop.exits) {
+            earlyExits.add(b.getBeginNode());
+        }
+        return new SuperBlock(loop.loopBegin(), loop.loopBegin(), blocks, earlyExits, loop.loopBegin());
+    }
+
+    public static int estimateSize(Loop loop) {
+        int fixed = 0;
+        for (Block b : loop.blocks) {
+            fixed += b.getBeginNode().getBlockNodes().count();
+        }
+        return fixed * 3;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/loop/SuperBlock.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.loop;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
+
+public class SuperBlock {
+    protected BeginNode entry;
+    protected BeginNode exit;
+    protected List<BeginNode> blocks;
+    protected List<BeginNode> earlyExits;
+    protected LoopBeginNode loop;
+    protected Map<Node, Node> duplicationMapping;
+    protected SuperBlock original;
+    protected NodeBitMap loopNodes;
+
+    public SuperBlock(BeginNode entry, BeginNode exit, List<BeginNode> blocks, List<BeginNode> earlyExits, LoopBeginNode loop) {
+        this.entry = entry;
+        this.exit = exit;
+        this.blocks = blocks;
+        this.earlyExits = earlyExits;
+        this.loop = loop;
+        assert blocks.contains(entry);
+        assert !blocks.contains(exit) || exit == entry;
+    }
+
+    public Map<Node, Node> getDuplicationMapping() {
+        return duplicationMapping;
+    }
+
+    public BeginNode getEntry() {
+        return entry;
+    }
+
+    public NodeBitMap loopNodes() {
+        if (loopNodes == null) {
+            loopNodes = computeNodes();
+        }
+        return loopNodes;
+    }
+
+    public SuperBlock duplicate() {
+        NodeBitMap nodes = loopNodes();
+        Map<Node, Node> replacements = new HashMap<>();
+        StructuredGraph graph = (StructuredGraph) entry.graph();
+        BeginNode newEntry = graph.add(new BeginNode());
+        BeginNode newExit = null;
+        List<BeginNode> newEarlyExits = new ArrayList<>(earlyExits.size());
+        if (!(exit instanceof MergeNode)) {
+            newExit = graph.add(new BeginNode());
+            replacements.put(exit, newExit);
+        }
+        replacements.put(entry, newEntry); // no merge/loop begin
+        for (BeginNode earlyExit : earlyExits) {
+            BeginNode newEarlyExit = graph.add(new BeginNode());
+            newEarlyExits.add(newEarlyExit);
+            replacements.put(earlyExit, newEarlyExit);
+        }
+        if (loop != null) {
+            for (LoopEndNode end : loop.loopEnds()) {
+                if (nodes.isMarked(end)) {
+                    replacements.put(end, graph.add(new EndNode()));
+                }
+            }
+        }
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
+        if (exit instanceof MergeNode) {
+            newExit = mergeExits(replacements, graph, duplicates, (MergeNode) exit);
+        }
+
+        List<BeginNode> newBlocks = new ArrayList<>(blocks.size());
+        for (BeginNode block : blocks) {
+            BeginNode newBlock = (BeginNode) duplicates.get(block);
+            if (newBlock == null) {
+                newBlock = (BeginNode) replacements.get(block);
+            }
+            assert newBlock != null : block;
+            newBlocks.add(newBlock);
+        }
+        for (Entry<Node, Node> e : replacements.entrySet()) {
+            duplicates.put(e.getKey(), e.getValue());
+        }
+        SuperBlock superBlock = new SuperBlock(newEntry, newExit, newBlocks, newEarlyExits, loop);
+        superBlock.duplicationMapping = duplicates;
+        superBlock.original = this;
+        return superBlock;
+    }
+
+    private BeginNode mergeExits(Map<Node, Node> replacements, StructuredGraph graph, Map<Node, Node> duplicates, MergeNode mergeExit) {
+        BeginNode newExit;
+        List<EndNode> endsToMerge = new LinkedList<>();
+        if (mergeExit == loop) {
+            LoopBeginNode loopBegin = (LoopBeginNode) mergeExit;
+            for (LoopEndNode le : loopBegin.loopEnds()) {
+                Node duplicate = replacements.get(le);
+                if (duplicate != null) {
+                    endsToMerge.add((EndNode) duplicate);
+                }
+            }
+        } else {
+            for (EndNode end : mergeExit.forwardEnds()) {
+                Node duplicate = duplicates.get(end);
+                if (duplicate != null) {
+                    endsToMerge.add((EndNode) duplicate);
+                }
+            }
+        }
+
+        if (endsToMerge.size() == 1) {
+            EndNode end = endsToMerge.get(0);
+            assert end.usages().count() == 0;
+            newExit = graph.add(new BeginNode());
+            end.replaceAtPredecessors(newExit);
+            end.safeDelete();
+        } else {
+            assert endsToMerge.size() > 1;
+            MergeNode newExitMerge = graph.add(new MergeNode());
+            newExit = newExitMerge;
+            FrameState state = mergeExit.stateAfter().duplicate();
+            newExitMerge.setStateAfter(state); // this state is wrong (incudes phis from the loop begin) needs to be fixed while resolving data
+            for (EndNode end : endsToMerge) {
+                newExitMerge.addForwardEnd(end);
+            }
+        }
+        return newExit;
+    }
+
+    public void finish() {
+        if (original != null) {
+            mergeEarlyExits((StructuredGraph) entry.graph(), original.earlyExits, duplicationMapping);
+        }
+    }
+
+    private static void mergeEarlyExits(StructuredGraph graph, List<BeginNode> earlyExits, Map<Node, Node> duplicates) {
+        for (BeginNode earlyExit : earlyExits) {
+            BeginNode newEarlyExit = (BeginNode) duplicates.get(earlyExit);
+            assert newEarlyExit != null;
+            MergeNode merge = graph.add(new MergeNode());
+            EndNode originalEnd = graph.add(new EndNode());
+            EndNode newEnd = graph.add(new EndNode());
+            merge.addForwardEnd(originalEnd);
+            merge.addForwardEnd(newEnd);
+            FixedNode next = earlyExit.next();
+            earlyExit.setNext(originalEnd);
+            newEarlyExit.setNext(newEnd);
+            merge.setNext(next);
+            FrameState exitState = earlyExit.stateAfter();
+            FrameState state = exitState.duplicate();
+            merge.setStateAfter(state);
+            for (ValueProxyNode vpn : earlyExit.proxies().snapshot()) {
+                ValueNode replaceWith;
+                ValueProxyNode newVpn = (ValueProxyNode) duplicates.get(vpn);
+                if (newVpn != null) {
+                    PhiNode phi = graph.add(new PhiNode(vpn.kind(), merge, vpn.type()));
+                    phi.addInput(vpn);
+                    phi.addInput(newVpn);
+                    if (vpn.type() == PhiType.Value) {
+                        replaceWith = phi;
+                    } else {
+                        assert vpn.type() == PhiType.Virtual;
+                        VirtualObjectFieldNode vof = (VirtualObjectFieldNode) GraphUtil.unProxify(vpn);
+                        VirtualObjectFieldNode newVof = (VirtualObjectFieldNode) GraphUtil.unProxify(newVpn);
+                        replaceWith = mergeVirtualChain(graph, vof, newVof, phi, earlyExit, newEarlyExit, merge);
+                    }
+                } else {
+                    replaceWith = vpn.value();
+                }
+                state.replaceFirstInput(vpn, replaceWith);
+                for (Node usage : vpn.usages().snapshot()) {
+                    if (usage != exitState && !merge.isPhiAtMerge(usage)) {
+                        usage.replaceFirstInput(vpn, replaceWith);
+                    }
+                }
+            }
+        }
+    }
+
+    private static ValueProxyNode findProxy(ValueNode value, BeginNode proxyPoint) {
+        for (ValueProxyNode vpn : proxyPoint.proxies()) {
+            ValueNode v = vpn;
+            while (v instanceof ValueProxyNode) {
+                v = ((ValueProxyNode) v).value();
+                if (v == value) {
+                    return vpn;
+                }
+            }
+        }
+        return null;
+    }
+
+    private static ValueNode mergeVirtualChain(
+                    StructuredGraph graph,
+                    VirtualObjectFieldNode vof,
+                    VirtualObjectFieldNode newVof,
+                    PhiNode vPhi,
+                    BeginNode earlyExit,
+                    BeginNode newEarlyExit,
+                    MergeNode merge) {
+        VirtualObjectNode vObject = vof.object();
+        assert newVof.object() == vObject;
+        ValueNode[] virtualState = virtualState(vof);
+        ValueNode[] newVirtualState = virtualState(newVof);
+        ValueNode chain = vPhi;
+        for (int i = 0; i < virtualState.length; i++) {
+            ValueNode value = virtualState[i];
+            ValueNode newValue = newVirtualState[i];
+            assert value.kind() == newValue.kind();
+            if (value != newValue) {
+                PhiNode valuePhi = graph.add(new PhiNode(value.kind(), merge, PhiType.Value));
+                ValueProxyNode inputProxy = findProxy(value, earlyExit);
+                if (inputProxy != null) {
+                    ValueProxyNode newInputProxy = findProxy(newValue, newEarlyExit);
+                    assert newInputProxy != null : "no proxy for " + newValue + " at " + newEarlyExit;
+                    valuePhi.addInput(inputProxy);
+                    valuePhi.addInput(newInputProxy);
+                } else {
+                    valuePhi.addInput(graph.unique(new ValueProxyNode(value, earlyExit, PhiType.Value)));
+                    valuePhi.addInput(newValue);
+                }
+                chain = graph.add(new VirtualObjectFieldNode(vObject, chain, valuePhi, i));
+            }
+        }
+        return chain;
+    }
+
+    private static ValueNode[] virtualState(VirtualObjectFieldNode vof) {
+        VirtualObjectNode vObj = vof.object();
+        int fieldsCount = vObj.fieldsCount();
+        int dicovered = 0;
+        ValueNode[] state = new ValueNode[fieldsCount];
+        ValueNode currentField = vof;
+        do {
+            if (currentField instanceof VirtualObjectFieldNode) {
+                int index = ((VirtualObjectFieldNode) currentField).index();
+                if (state[index] == null) {
+                    dicovered++;
+                    state[index] = ((VirtualObjectFieldNode) currentField).input();
+                    if (dicovered >= fieldsCount) {
+                        break;
+                    }
+                }
+                currentField = ((VirtualObjectFieldNode) currentField).lastState();
+            } else {
+                assert currentField instanceof PhiNode && ((PhiNode) currentField).type() == PhiType.Virtual : currentField;
+                currentField = ((PhiNode) currentField).valueAt(0);
+            }
+        } while (currentField != null);
+        return state;
+    }
+
+    private NodeBitMap computeNodes() {
+        NodeBitMap nodes = entry.graph().createNodeBitMap();
+        for (BeginNode b : blocks) {
+            for (Node n : b.getBlockNodes()) {
+                if (n instanceof Invoke) {
+                    nodes.mark(((Invoke) n).callTarget());
+                }
+                if (n instanceof StateSplit) {
+                    FrameState stateAfter = ((StateSplit) n).stateAfter();
+                    if (stateAfter != null) {
+                        nodes.mark(stateAfter);
+                    }
+                }
+                nodes.mark(n);
+            }
+        }
+        for (BeginNode earlyExit : earlyExits) {
+            FrameState stateAfter = earlyExit.stateAfter();
+            assert stateAfter != null;
+            nodes.mark(stateAfter);
+            nodes.mark(earlyExit);
+            for (ValueProxyNode proxy : earlyExit.proxies()) {
+                nodes.mark(proxy);
+            }
+        }
+
+        for (BeginNode b : blocks) {
+            for (Node n : b.getBlockNodes()) {
+                for (Node usage : n.usages()) {
+                    markFloating(usage, nodes, "");
+                }
+            }
+        }
+
+        if (entry instanceof LoopBeginNode) {
+            for (PhiNode phi : ((LoopBeginNode) entry).phis()) {
+                nodes.clear(phi);
+            }
+        }
+
+        return nodes;
+    }
+
+    private static boolean markFloating(Node n, NodeBitMap loopNodes, String ind) {
+        //System.out.println(ind + "markFloating(" + n + ")");
+        if (loopNodes.isMarked(n)) {
+            return true;
+        }
+        if (n instanceof FixedNode) {
+            return false;
+        }
+        boolean mark = false;
+        if (n instanceof PhiNode) {
+            mark = loopNodes.isMarked(((PhiNode) n).merge());
+            if (mark) {
+                loopNodes.mark(n);
+            } else {
+                return false;
+            }
+        }
+        for (Node usage : n.usages()) {
+            if (markFloating(usage, loopNodes, " " + ind)) {
+                mark = true;
+            }
+        }
+        if (mark) {
+            loopNodes.mark(n);
+            return true;
+        }
+        return false;
+    }
+
+    public void insertBefore(FixedNode fixed) {
+        assert entry.predecessor() == null;
+        assert exit.next() == null;
+        fixed.replaceAtPredecessors(entry);
+        exit.setNext(fixed);
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -130,8 +130,12 @@
 
         @Override
         public void loopEnds(LoopBeginNode loopBegin, List<BlockExitState> loopEndStates) {
-            while (!(virtualObjectField instanceof PhiNode)) {
-                virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState();
+            while (!loopBegin.isPhiAtMerge(virtualObjectField)) {
+                if (virtualObjectField instanceof PhiNode) {
+                    virtualObjectField = ((PhiNode) virtualObjectField).valueAt(0);
+                } else {
+                    virtualObjectField = ((VirtualObjectFieldNode) virtualObjectField).lastState();
+                }
             }
             for (BlockExitState loopEndState : loopEndStates) {
                 ((PhiNode) virtualObjectField).addInput(loopEndState.virtualObjectField);
@@ -184,6 +188,11 @@
             FixedNode next = node.next();
             graph.removeFixed(node);
 
+            for (ValueProxyNode vpn : virtual.usages().filter(ValueProxyNode.class).snapshot()) {
+                assert vpn.value() == virtual;
+                graph.replaceFloating(vpn, virtual);
+            }
+
             if (virtual.fieldsCount() > 0) {
                 final BlockExitState startState = new BlockExitState(escapeFields, virtual);
                 final PostOrderNodeIterator<?> iterator = new PostOrderNodeIterator<BlockExitState>(next, startState) {
@@ -193,9 +202,25 @@
                         if (changedField != -1) {
                             state.updateField(changedField);
                         }
+                        if (curNode instanceof LoopExitNode) {
+                            state.virtualObjectField = graph.unique(new ValueProxyNode(state.virtualObjectField, (LoopExitNode) curNode, PhiType.Virtual));
+                            for (int i = 0; i < state.fieldState.length; i++) {
+                                state.fieldState[i] = graph.unique(new ValueProxyNode(state.fieldState[i], (LoopExitNode) curNode, PhiType.Value));
+                            }
+                        }
                         if (!curNode.isDeleted() && curNode instanceof StateSplit && ((StateSplit) curNode).stateAfter() != null) {
                             if (state.virtualObjectField != null) {
-                                ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(state.virtualObjectField);
+                                ValueNode v = state.virtualObjectField;
+                                if (curNode instanceof LoopBeginNode) {
+                                    while (!((LoopBeginNode) curNode).isPhiAtMerge(v)) {
+                                        if (v instanceof PhiNode) {
+                                            v = ((PhiNode) v).valueAt(0);
+                                        } else {
+                                            v = ((VirtualObjectFieldNode) v).lastState();
+                                        }
+                                    }
+                                }
+                                ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v);
                             }
                         }
                     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoopTransformPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.phases;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.loop.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+
+public class LoopTransformPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+            Loop[] loops = cfg.getLoops();
+            // outermost first
+            Arrays.sort(loops, new Comparator<Loop>() {
+                @Override
+                public int compare(Loop o1, Loop o2) {
+                    return o1.depth - o2.depth;
+                }
+            });
+            for (Loop loop : loops) {
+                double entryProbability = loop.loopBegin().forwardEnd().probability();
+                if (entryProbability > GraalOptions.MinimumPeelProbability
+                                && LoopTransformUtil.estimateSize(loop) + graph.getNodeCount() < GraalOptions.MaximumDesiredSize) {
+                    Debug.log("Peeling %s", loop);
+                    LoopTransformUtil.peel(loop);
+                    Debug.dump(graph, "After peeling %s", loop);
+                }
+            }
+        }
+    }
+
+
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -30,6 +30,9 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.max.cri.ri.*;
 
+/**
+ * Processes all {@link Lowerable} nodes to do their lowering.
+ */
 public class LoweringPhase extends Phase {
 
     private final GraalRuntime runtime;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/RemoveValueProxyPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.phases;
+
+import com.oracle.graal.nodes.*;
+
+public class RemoveValueProxyPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (ValueProxyNode vpn : graph.getNodes(ValueProxyNode.class)) {
+            graph.replaceFloating(vpn, vpn.value());
+        }
+        for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) {
+            FrameState stateAfter = exit.stateAfter();
+            if (stateAfter != null) {
+                exit.setStateAfter(null);
+                if (stateAfter.usages().count() == 0) {
+                    stateAfter.safeDelete();
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -227,6 +227,9 @@
         if (newInstance instanceof ValueNode && ((ValueNode) newInstance).kind() != CiKind.Object) {
             StructuredGraph graph = (StructuredGraph) newInstance.graph();
             for (CheckCastNode checkCastNode : newInstance.usages().filter(CheckCastNode.class).snapshot()) {
+                for (ValueProxyNode vpn : checkCastNode.usages().filter(ValueProxyNode.class).snapshot()) {
+                    graph.replaceFloating(vpn, checkCastNode);
+                }
                 for (Node checkCastUsage : checkCastNode.usages().snapshot()) {
                     if (checkCastUsage instanceof ValueAnchorNode) {
                         ValueAnchorNode valueAnchorNode = (ValueAnchorNode) checkCastUsage;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/schedule/SchedulePhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -38,7 +38,10 @@
     private ControlFlowGraph cfg;
     private NodeMap<Block> earliestCache;
 
-    private BlockMap<List<Node>> nodesFor;
+    /**
+     * Map from blocks to the nodes in each block.
+     */
+    private BlockMap<List<Node>> blockToNodesMap;
 
     public SchedulePhase() {
         super("Schedule");
@@ -48,7 +51,7 @@
     protected void run(StructuredGraph graph) {
         cfg = ControlFlowGraph.compute(graph, true, true, true, false);
         earliestCache = graph.createNodeMap();
-        nodesFor = new BlockMap<>(cfg);
+        blockToNodesMap = new BlockMap<>(cfg);
 
         assignBlockToNodes(graph);
         sortNodesWithinBlocks(graph);
@@ -56,7 +59,7 @@
 
     public void scheduleGraph() {
         for (Block block : cfg.getBlocks()) {
-            List<Node> nodeList = nodesFor.get(block);
+            List<Node> nodeList = blockToNodesMap.get(block);
             ScheduledNode last = null;
             for (Node node : nodeList) {
                 if (!(node instanceof FrameState)) {
@@ -73,19 +76,25 @@
         return cfg;
     }
 
-    public BlockMap<List<Node>> getNodesFor() {
-        return nodesFor;
+    /**
+     * Gets the map from each block to the nodes in the block.
+     */
+    public BlockMap<List<Node>> getBlockToNodesMap() {
+        return blockToNodesMap;
     }
 
+    /**
+     * Gets the nodes in a given block.
+     */
     public List<Node> nodesFor(Block block) {
-        return nodesFor.get(block);
+        return blockToNodesMap.get(block);
     }
 
     private void assignBlockToNodes(StructuredGraph graph) {
         for (Block block : cfg.getBlocks()) {
             List<Node> nodes = new ArrayList<>();
-            assert nodesFor.get(block) == null;
-            nodesFor.put(block, nodes);
+            assert blockToNodesMap.get(block) == null;
+            blockToNodesMap.put(block, nodes);
             for (Node node : block.getNodes()) {
                 nodes.add(node);
             }
@@ -108,6 +117,7 @@
             return;
         }
         assert !(n instanceof PhiNode) : n;
+        assert !(n instanceof MergeNode);
         // if in CFG, schedule at the latest position possible in the outermost loop possible
         Block latestBlock = latestBlock(n);
         Block block;
@@ -120,9 +130,8 @@
         } else {
             block = latestBlock;
         }
-        assert !(n instanceof MergeNode);
         cfg.getNodeToBlock().set(n, block);
-        nodesFor.get(block).add(n);
+        blockToNodesMap.get(block).add(n);
     }
 
     private Block latestBlock(Node n) {
@@ -264,7 +273,7 @@
     }
 
     private void sortNodesWithinBlocks(Block b, NodeBitMap map) {
-        List<Node> instructions = nodesFor.get(b);
+        List<Node> instructions = blockToNodesMap.get(b);
         List<Node> sortedInstructions = new ArrayList<>(instructions.size() + 2);
 
         assert !map.isMarked(b.getBeginNode()) && cfg.blockFor(b.getBeginNode()) == b;
@@ -298,7 +307,7 @@
                 sortedInstructions.add(b.getEndNode());
             }
         }
-        nodesFor.put(b, sortedInstructions);
+        blockToNodesMap.put(b, sortedInstructions);
     }
 
     private void addToSorting(Block b, Node i, List<Node> sortedInstructions, NodeBitMap map) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Apr 20 13:44:06 2012 +0200
@@ -24,18 +24,26 @@
 
 import java.lang.reflect.*;
 
-import com.oracle.max.asm.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.cri.xir.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
 
 /**
  * The {@code Backend} class represents a compiler backend for Graal.
  */
 public abstract class Backend {
+
+    /**
+     * The name of the system property whose value (if non-null) specifies the fully qualified
+     * name of the class to be instantiated by {@link #create(RiRuntime, CiTarget)}.
+     */
+    public static final String BACKEND_CLASS_PROPERTY = "graal.compiler.backend.class";
+
     public final RiRuntime runtime;
     public final CiTarget target;
 
@@ -44,8 +52,13 @@
         this.target = target;
     }
 
-    public static Backend create(CiArchitecture arch, RiRuntime runtime, CiTarget target) {
-        String className = arch.getClass().getName().replace("com.oracle.max.asm", "com.oracle.graal.compiler") + "Backend";
+    /**
+     * Creates the architecture and runtime specific back-end object.
+     * The class of the object instantiated must be in the {@link #BACKEND_CLASS_PROPERTY} system property.
+     */
+    public static Backend create(RiRuntime runtime, CiTarget target) {
+        String className = System.getProperty(BACKEND_CLASS_PROPERTY);
+        assert className != null : "System property must be defined: " + BACKEND_CLASS_PROPERTY;
         try {
             Class<?> c = Class.forName(className);
             Constructor<?> cons = c.getDeclaredConstructor(RiRuntime.class, CiTarget.class);
@@ -55,9 +68,46 @@
         }
     }
 
-    public abstract FrameMap newFrameMap(RiRegisterConfig registerConfig);
+    public FrameMap newFrameMap(RiRegisterConfig registerConfig) {
+        return new FrameMap(runtime, target, registerConfig);
+    }
+
     public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir);
-    public abstract AbstractAssembler newAssembler(RiRegisterConfig registerConfig);
+
+    public abstract TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir);
+
     public abstract CiXirAssembler newXirAssembler();
 
+    /**
+     * Emits code to do stack overflow checking.
+     * 
+     * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate the current frame
+     */
+    protected static void emitStackOverflowCheck(TargetMethodAssembler tasm, boolean afterFrameInit) {
+        if (GraalOptions.StackShadowPages > 0) {
+            int frameSize = tasm.frameMap.frameSize();
+            if (frameSize > 0) {
+                int lastFramePage = frameSize / tasm.target.pageSize;
+                // emit multiple stack bangs for methods with frames larger than a page
+                for (int i = 0; i <= lastFramePage; i++) {
+                    int disp = (i + GraalOptions.StackShadowPages) * tasm.target.pageSize;
+                    if (afterFrameInit) {
+                        disp -= frameSize;
+                    }
+                    tasm.asm.bangStack(disp);
+                }
+            }
+        }
+    }
+
+    /**
+     * Emits the code for a given method. This includes any architecture/runtime specific
+     * prefix/suffix. A prefix typically contains the code for setting up the frame,
+     * spilling callee-save registers, stack overflow checking, handling multiple entry
+     * points etc. A suffix may contain out-of-line stubs and method end guard instructions.
+     *
+     * @param the method associated with {@code lir}
+     * @param lir the LIR of {@code method}
+     */
+    public abstract void emitCode(TargetMethodAssembler tasm, RiResolvedMethod method, LIR lir);
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64Backend.java	Fri Apr 13 15:52:25 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target.amd64;
-
-import com.oracle.max.asm.*;
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.cri.xir.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-
-/**
- * The {@code X86Backend} class represents the backend for the AMD64 architecture.
- */
-public class AMD64Backend extends Backend {
-
-    public AMD64Backend(RiRuntime runtime, CiTarget target) {
-        super(runtime, target);
-    }
-    /**
-     * Creates a new LIRGenerator for x86.
-     * @param compilation the compilation for which to create the LIR generator
-     * @return an appropriate LIR generator instance
-     */
-    @Override
-    public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
-        return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir);
-    }
-
-    @Override
-    public FrameMap newFrameMap(RiRegisterConfig registerConfig) {
-        return new FrameMap(runtime, target, registerConfig);
-    }
-
-    @Override
-    public AbstractAssembler newAssembler(RiRegisterConfig registerConfig) {
-        return new AMD64MacroAssembler(target, registerConfig);
-    }
-
-    @Override
-    public CiXirAssembler newXirAssembler() {
-        return new AMD64XirAssembler(target);
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64DeoptimizationStub.java	Fri Apr 20 13:44:06 2012 +0200
@@ -33,7 +33,7 @@
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
-public class AMD64DeoptimizationStub extends AMD64SlowPath {
+public class AMD64DeoptimizationStub extends AMD64Code {
     public final Label label = new Label();
     public final LIRDebugInfo info;
     public final RiDeoptAction action;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Fri Apr 20 13:44:06 2012 +0200
@@ -74,7 +74,7 @@
 /**
  * This class implements the X86-specific portion of the LIR generator.
  */
-public class AMD64LIRGenerator extends LIRGenerator {
+public abstract class AMD64LIRGenerator extends LIRGenerator {
 
     private static final CiRegisterValue RAX_I = AMD64.rax.asValue(CiKind.Int);
     private static final CiRegisterValue RAX_L = AMD64.rax.asValue(CiKind.Long);
@@ -97,7 +97,6 @@
 
     public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
         super(graph, runtime, target, frameMap, method, lir, xir);
-        lir.methodEndMarker = new AMD64MethodEndStub();
         lir.spillMoveFactory = new AMD64SpillMoveFactory();
     }
 
@@ -575,11 +574,13 @@
         Variable newValue = load(operand(node.newValue()));
 
         CiAddress address;
+        int displacement = node.displacement();
         CiValue index = operand(node.offset());
         if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong())) {
-            address = new CiAddress(kind, load(operand(node.object())), (int) asConstant(index).asLong());
+            displacement += (int) asConstant(index).asLong();
+            address = new CiAddress(kind, load(operand(node.object())), displacement);
         } else {
-            address = new CiAddress(kind, load(operand(node.object())), load(index), CiAddress.Scale.Times1, 0);
+            address = new CiAddress(kind, load(operand(node.object())), load(index), CiAddress.Scale.Times1, displacement);
         }
 
         CiRegisterValue rax = AMD64.rax.asValue(kind);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64MethodEndStub.java	Fri Apr 13 15:52:25 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.target.amd64;
-
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64MethodEndStub extends AMD64SlowPath {
-    @Override
-    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-        for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) {
-            masm.int3();
-        }
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirAssembler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirAssembler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -188,15 +188,10 @@
                     boundLabels.add(label);
                     break;
                 case Safepoint:
-                case Align:
-                case StackOverflowCheck:
-                case PushFrame:
-                case PopFrame:
                 case Push:
                 case Pop:
                 case Mark:
                 case Nop:
-                case RawBytes:
                 case ShouldNotReachHere:
                     break;
                 default:
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64XirOp.java	Fri Apr 20 13:44:06 2012 +0200
@@ -28,6 +28,10 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.max.asm.*;
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
@@ -38,11 +42,6 @@
 import com.oracle.max.cri.xir.CiXirAssembler.XirInstruction;
 import com.oracle.max.cri.xir.CiXirAssembler.XirLabel;
 import com.oracle.max.cri.xir.CiXirAssembler.XirMark;
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
 
 public class AMD64XirOp extends LIRXirInstruction {
     public AMD64XirOp(XirSnippet snippet, CiValue[] operands, CiValue outputOperand, CiValue[] inputs, CiValue[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex,
@@ -86,7 +85,7 @@
         }
     }
 
-    private class SlowPath extends AMD64SlowPath {
+    private class SlowPath extends AMD64Code {
         public final Label[] labels;
 
         public SlowPath(Label[] labels) {
@@ -391,52 +390,6 @@
                     masm.nullCheck(asRegister(pointer));
                     break;
                 }
-                case Align: {
-                    masm.align((Integer) inst.extra);
-                    break;
-                }
-                case StackOverflowCheck: {
-                    int frameSize = tasm.frameMap.frameSize();
-                    int lastFramePage = frameSize / tasm.target.pageSize;
-                    // emit multiple stack bangs for methods with frames larger than a page
-                    for (int i = 0; i <= lastFramePage; i++) {
-                        int offset = (i + GraalOptions.StackShadowPages) * tasm.target.pageSize;
-                        // Deduct 'frameSize' to handle frames larger than the shadow
-                        bangStackWithOffset(tasm, masm, offset - frameSize);
-                    }
-                    break;
-                }
-                case PushFrame: {
-                    int frameSize = tasm.frameMap.frameSize();
-                    masm.decrementq(AMD64.rsp, frameSize); // does not emit code for frameSize == 0
-                    if (GraalOptions.ZapStackOnMethodEntry) {
-                        final int intSize = 4;
-                        for (int i = 0; i < frameSize / intSize; ++i) {
-                            masm.movl(new CiAddress(CiKind.Int, AMD64.rsp.asValue(), i * intSize), 0xC1C1C1C1);
-                        }
-                    }
-                    CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout();
-                    if (csl != null && csl.size != 0) {
-                        int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea();
-                        assert frameToCSA >= 0;
-                        masm.save(csl, frameToCSA);
-                    }
-                    break;
-                }
-                case PopFrame: {
-                    int frameSize = tasm.frameMap.frameSize();
-
-                    CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout();
-                    if (csl != null && csl.size != 0) {
-                        tasm.targetMethod.setRegisterRestoreEpilogueOffset(masm.codeBuffer.position());
-                        // saved all registers, restore all registers
-                        int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea();
-                        masm.restore(csl, frameToCSA);
-                    }
-
-                    masm.incrementq(AMD64.rsp, frameSize);
-                    break;
-                }
                 case Push: {
                     CiRegisterValue value = assureInRegister(tasm, masm, operands[inst.x().index]);
                     masm.push(asRegister(value));
@@ -470,12 +423,6 @@
                     }
                     break;
                 }
-                case RawBytes: {
-                    for (byte b : (byte[]) inst.extra) {
-                        masm.codeBuffer.emitByte(b & 0xff);
-                    }
-                    break;
-                }
                 case ShouldNotReachHere: {
                     AMD64Call.shouldNotReachHere(tasm, masm);
                     break;
@@ -521,16 +468,6 @@
         masm.jcc(cflag, label);
     }
 
-    /**
-     * @param offset the offset RSP at which to bang. Note that this offset is relative to RSP after RSP has been
-     *            adjusted to allocated the frame for the method. It denotes an offset "down" the stack.
-     *            For very large frames, this means that the offset may actually be negative (i.e. denoting
-     *            a slot "up" the stack above RSP).
-     */
-    private static void bangStackWithOffset(TargetMethodAssembler tasm, AMD64MacroAssembler masm, int offset) {
-        masm.movq(new CiAddress(tasm.target.wordKind, AMD64.RSP, -offset), AMD64.rax);
-    }
-
     private static CiValue assureNot64BitConstant(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue value) {
         if (isConstant(value) && (value.kind == CiKind.Long || value.kind == CiKind.Object)) {
             CiRegisterValue register = tasm.frameMap.registerConfig.getScratchRegister().asValue(value.kind);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -141,7 +141,7 @@
                 out.print(succ + " ");
             }
             System.out.println();
-            for (Node node : printSchedule.getNodesFor().get(block)) {
+            for (Node node : printSchedule.getBlockToNodesMap().get(block)) {
                 out.println("  " + node + "    (" + node.usages().size() + ")");
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri Apr 20 13:44:06 2012 +0200
@@ -882,15 +882,7 @@
             returnDuplicate.clearInputs();
             Node n = invoke.next();
             invoke.setNext(null);
-            if (n instanceof BeginNode) {
-                BeginNode begin = (BeginNode) n;
-                FixedNode next = begin.next();
-                begin.setNext(null);
-                returnDuplicate.replaceAndDelete(next);
-                begin.safeDelete();
-            } else {
-                returnDuplicate.replaceAndDelete(n);
-            }
+            returnDuplicate.replaceAndDelete(n);
         }
 
         invoke.node().clearInputs();
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Fri Apr 20 13:44:06 2012 +0200
@@ -158,6 +158,10 @@
         }
     }
 
+    /**
+     * Searches the current debug scope, bottom up, for a context object that is an instance of a given type.
+     * The first such object found is returned.
+     */
     @SuppressWarnings("unchecked")
     public static <T> T contextLookup(Class<T> clazz) {
         if (ENABLED) {
--- a/graal/com.oracle.graal.examples/src/examples/HelloWorld.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.examples/src/examples/HelloWorld.java	Fri Apr 20 13:44:06 2012 +0200
@@ -25,6 +25,20 @@
 
 public class HelloWorld {
     public static void main(String[] args) {
-        System.out.println("hello world!");
+        new HelloWorld(args).greet();
+    }
+
+    public HelloWorld(String[] args) {
+        name = args.length == 0 ? "world" : args[0];
+    }
+
+    public String name;
+
+    public String getName() {
+        return name;
+    }
+
+    public void greet() {
+        System.out.println("hello " + getName() + "!");
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/BitMap.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/BitMap.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,9 +22,8 @@
  */
 package com.oracle.graal.graph;
 
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.BitSet;
+import java.io.*;
+import java.util.*;
 
 /**
  * Implements a bitmap that stores a single bit for a range of integers (0-n).
@@ -114,7 +113,8 @@
         assert length >= 0;
         this.size = length;
         if (length > BITS_PER_WORD) {
-            extra = new long[length >> ADDRESS_BITS_PER_WORD];
+            int n = wordIndex(length - 1) + 1;
+            extra = new long[n];
         }
     }
 
@@ -357,10 +357,27 @@
     }
 
     public void negate() {
-        low = ~low;
-        if (extra != null) {
-            for (int i = 0; i < extra.length; i++) {
-                extra[i] = ~extra[i];
+        if (size == 0) {
+            return;
+        }
+        if (size < BITS_PER_WORD) {
+            long mask = (1L << size) - 1;
+            low = ~low & mask;
+        } else if (size == BITS_PER_WORD) {
+            low = ~low;
+        } else {
+            low = ~low;
+            if (extra != null) {
+                for (int i = 0; i < extra.length; i++) {
+                    extra[i] = ~extra[i];
+                    if (i == extra.length - 1 && wordIndex(size) == i) {
+                        if (bitInWord(size) != 0) {
+                            long mask = (1L << bitInWord(size)) - 1;
+                            extra[i] &= mask;
+                        }
+                    }
+                }
+
             }
         }
     }
@@ -597,17 +614,10 @@
      * Returns a string representation of this bit map with every set bit represented as {@code '1'}
      * and every unset bit represented as {@code '0'}. The first character in the returned string represents
      * bit 0 in this bit map.
-     *
-     * @param length the number of bits represented in the returned string. If {@code length < 0 || length > size()},
-     *            then the value of {@link #length()} is used.
      */
     public String toBinaryString() {
-        int length = length();
-        if (length == 0) {
-            return "";
-        }
-        StringBuilder sb = new StringBuilder(length);
-        for (int i = 0; i < length; ++i) {
+        StringBuilder sb = new StringBuilder(size);
+        for (int i = 0; i < size; ++i) {
             sb.append(get(i) ? '1' : '0');
         }
         return sb.toString();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Apr 20 13:44:06 2012 +0200
@@ -352,6 +352,10 @@
             node.getNodeClass().set(node, this, value);
         }
 
+        public boolean isValidFor(Node node, Node from) {
+            return node.getNodeClass().isValid(this, from.getNodeClass());
+        }
+
         @Override
         public int hashCode() {
             final int prime = 31;
@@ -605,6 +609,18 @@
         return true;
     }
 
+    public boolean isValid(Position pos, NodeClass from) {
+        long[] offsets = pos.input ? inputOffsets : successorOffsets;
+        if (pos.index >= offsets.length) {
+            return false;
+        }
+        long[] fromOffsets = pos.input ? from.inputOffsets : from.successorOffsets;
+        if (pos.index >= fromOffsets.length) {
+            return false;
+        }
+        return offsets[pos.index] == fromOffsets[pos.index];
+    }
+
     public Node get(Node node, Position pos) {
         long offset = pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index];
         if (pos.subIndex == NOT_ITERABLE) {
@@ -678,7 +694,7 @@
         while (index < directInputCount) {
             Node input = getNode(node, inputOffsets[index]);
             if (input == old) {
-                assert other == null || inputTypes[index].isAssignableFrom(other.getClass());
+                assert other == null || inputTypes[index].isAssignableFrom(other.getClass()); // : "Can not assign " + other.getClass() + " to " + inputTypes[index] + " in " + node;
                 putNode(node, inputOffsets[index], other);
                 return true;
             }
@@ -700,7 +716,7 @@
         while (index < directSuccessorCount) {
             Node successor = getNode(node, successorOffsets[index]);
             if (successor == old) {
-                assert other == null || successorTypes[index].isAssignableFrom(other.getClass()) : successorTypes[index] + " is not compatible with " + other.getClass();
+                assert other == null || successorTypes[index].isAssignableFrom(other.getClass()); // : successorTypes[index] + " is not compatible with " + other.getClass();
                 putNode(node, successorOffsets[index], other);
                 return true;
             }
--- a/graal/com.oracle.graal.graph/test/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.graph/test/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Fri Apr 20 13:44:06 2012 +0200
@@ -46,7 +46,7 @@
         TestNode testNode = new TestNode("a");
         Graph graph = new Graph();
         graph.add(testNode);
-        testNode.delete();
+        testNode.safeDelete();
         assertEquals("", toString(graph.getNodes(TestNode.class)));
     }
 
@@ -56,7 +56,7 @@
         Graph graph = new Graph();
         graph.add(new TestNode("a"));
         graph.add(testNode);
-        testNode.delete();
+        testNode.safeDelete();
         assertEquals("a", toString(graph.getNodes(TestNode.class)));
         graph.add(new TestNode("c"));
         assertEquals("ac", toString(graph.getNodes(TestNode.class)));
@@ -77,7 +77,7 @@
         TestNode c = new TestNode("c");
         graph.add(c);
         assertTrue(iterator.hasNext());
-        c.delete();
+        c.safeDelete();
         assertFalse(iterator.hasNext());
     }
 
@@ -90,11 +90,11 @@
             for (int i = 0; i < name.length(); ++i) {
                 char c = name.charAt(i);
                 if (c == 'a') {
-                    tn.delete();
+                    tn.safeDelete();
                     graph.add(new TestNode("b"));
                     graph.add(new TestNode("c"));
                 } else if (c == 'b') {
-                    tn.delete();
+                    tn.safeDelete();
                 } else if (c == 'c') {
                     graph.add(new TestNode("d"));
                     graph.add(new TestNode("e"));
@@ -107,9 +107,9 @@
                 } else if (c == 'd') {
                     for (TestNode tn2 : graph.getNodes(TestNode.class)) {
                         if (tn2.getName().equals("e")) {
-                            tn2.delete();
+                            tn2.safeDelete();
                         } else if (tn2.getName().equals("c")) {
-                            tn2.delete();
+                            tn2.safeDelete();
                         }
                     }
                 } else if (c == 'e') {
@@ -146,7 +146,7 @@
         assertEquals(3, z);
     }
 
-    private String toString(Iterable<TestNode> nodes) {
+    private static String toString(Iterable<TestNode> nodes) {
         StringBuilder sb = new StringBuilder();
         for (TestNode tn : nodes) {
             sb.append(tn.getName());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot;
 
-import java.io.*;
 import java.util.concurrent.*;
 
 import com.oracle.graal.compiler.*;
@@ -133,8 +132,12 @@
         } catch (CiBailout bailout) {
             Debug.metric("Bailouts").increment();
             if (GraalOptions.ExitVMOnBailout) {
+                TTY.cachedOut.println(CiUtil.format("Bailout in %H.%n(%p)", method));
                 bailout.printStackTrace(TTY.cachedOut);
                 System.exit(-1);
+            } else if (GraalOptions.PrintBailout) {
+                TTY.cachedOut.println(CiUtil.format("Bailout in %H.%n(%p)", method));
+                bailout.printStackTrace(TTY.cachedOut);
             }
         } catch (Throwable t) {
             if (GraalOptions.ExitVMOnException) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java	Fri Apr 20 13:44:06 2012 +0200
@@ -23,12 +23,9 @@
 package com.oracle.graal.hotspot;
 
 import java.io.*;
+import java.lang.reflect.*;
 import java.net.*;
 
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.cri.xir.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.graph.*;
 import com.oracle.graal.compiler.target.*;
@@ -37,6 +34,10 @@
 import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.hotspot.server.*;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.xir.*;
 
 /**
  * Singleton class holding the instance of the GraalCompiler.
@@ -128,6 +129,21 @@
         // initialize compiler
         config = vmEntries.getConfiguration();
         config.check();
+
+        if (Boolean.valueOf(System.getProperty("graal.printconfig"))) {
+            printConfig(config);
+        }
+    }
+
+    private static void printConfig(HotSpotVMConfig config) {
+        Field[] fields = config.getClass().getDeclaredFields();
+        for (Field f : fields) {
+            f.setAccessible(true);
+            try {
+                Logger.info(String.format("%9s %-40s = %s", f.getType().getSimpleName(), f.getName(), Logger.pretty(f.get(config))));
+            } catch (Exception e) {
+            }
+        }
     }
 
     @Override
@@ -159,7 +175,7 @@
                 generator = LoggingProxy.getProxy(RiXirGenerator.class, generator);
             }
 
-            Backend backend = Backend.create(target.arch, runtime, target);
+            Backend backend = Backend.create(runtime, target);
             generator.initialize(backend.newXirAssembler());
 
             compiler = new GraalCompiler(getRuntime(), getTarget(), backend, generator);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Apr 20 13:44:06 2012 +0200
@@ -109,8 +109,12 @@
 
     String disassembleJava(HotSpotMethodResolved method);
 
+    StackTraceElement RiMethod_toStackTraceElement(HotSpotMethodResolved method, int bci);
+
     Object executeCompiledMethod(HotSpotCompiledMethod method, Object arg1, Object arg2, Object arg3);
 
+    Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args);
+
     int RiMethod_vtableEntryOffset(HotSpotMethodResolved method);
 
     long[] getDeoptedLeafGraphIds();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Apr 20 13:44:06 2012 +0200
@@ -157,9 +157,15 @@
     public native String disassembleJava(HotSpotMethodResolved method);
 
     @Override
+    public native StackTraceElement RiMethod_toStackTraceElement(HotSpotMethodResolved method, int bci);
+
+    @Override
     public native Object executeCompiledMethod(HotSpotCompiledMethod method, Object arg1, Object arg2, Object arg3);
 
     @Override
+    public native Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args);
+
+    @Override
     public native int RiMethod_vtableEntryOffset(HotSpotMethodResolved method);
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri Apr 20 13:44:06 2012 +0200
@@ -147,7 +147,7 @@
 
     /**
      * This method is the first method compiled during bootstrapping. Put any code in there that warms up compiler paths
-     * that are otherwise no exercised during bootstrapping and lead to later deoptimization when application code is
+     * that are otherwise not exercised during bootstrapping and lead to later deoptimization when application code is
      * compiled.
      */
     @SuppressWarnings("unused")
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/logging/Logger.java	Fri Apr 20 13:44:06 2012 +0200
@@ -33,13 +33,27 @@
 
     public static final boolean ENABLED = Boolean.valueOf(System.getProperty("graal.debug"));
     private static final int SPACING = 4;
-    private static Deque<Boolean> openStack = new LinkedList<>();
-    private static boolean open = false;
-    private static int level = 0;
+    private static final ThreadLocal<Logger> loggerTL;
+
+    private Deque<Boolean> openStack = new LinkedList<>();
+    private boolean open = false;
+    private int level = 0;
 
     private static final PrintStream out;
 
     static {
+        if (ENABLED) {
+            loggerTL = new ThreadLocal<Logger>() {
+                @Override
+                protected Logger initialValue() {
+                    return new Logger();
+                }
+            };
+        } else {
+            loggerTL = null;
+        }
+
+
         PrintStream ps = null;
         String filename = System.getProperty("graal.info_file");
         if (filename != null && !"".equals(filename)) {
@@ -70,12 +84,13 @@
 
     public static void log(String message) {
         if (ENABLED) {
+            Logger logger = loggerTL.get();
             for (String line : message.split("\n")) {
-                if (open) {
+                if (logger.open) {
                     System.out.println("...");
-                    open = false;
+                    logger.open = false;
                 }
-                System.out.print(space(level));
+                System.out.print(space(logger.level));
                 System.out.println(line);
             }
         }
@@ -83,27 +98,29 @@
 
     public static void startScope(String message) {
         if (ENABLED) {
-            if (open) {
+            Logger logger = loggerTL.get();
+            if (logger.open) {
                 System.out.println("...");
-                open = false;
+                logger.open = false;
             }
-            System.out.print(space(level));
+            System.out.print(space(logger.level));
             System.out.print(message);
-            openStack.push(open);
-            open = true;
-            level++;
+            logger.openStack.push(logger.open);
+            logger.open = true;
+            logger.level++;
         }
     }
 
     public static void endScope(String message) {
         if (ENABLED) {
-            level--;
-            if (open) {
+            Logger logger = loggerTL.get();
+            logger.level--;
+            if (logger.open) {
                 System.out.println(message);
             } else {
-                System.out.println(space(level) + "..." + message);
+                System.out.println(space(logger.level) + "..." + message);
             }
-            open = openStack.pop();
+            logger.open = logger.openStack.pop();
         }
     }
 
@@ -147,7 +164,7 @@
             }
             return value + " (0x" + Integer.toHexString((Integer) value) + ")";
         } else if (value instanceof Long) {
-            if ((Long) value < 10) {
+            if ((Long) value < 10 && (Long) value > -10) {
                 return value + "l";
             }
             return value + "l (0x" + Long.toHexString((Long) value) + "l)";
@@ -158,10 +175,19 @@
                 dimensions++;
                 klass = klass.getComponentType();
             }
-            str.append(klass.getSimpleName()).append('[').append(Array.getLength(value)).append(']');
+            int length = Array.getLength(value);
+            str.append(klass.getSimpleName()).append('[').append(length).append(']');
             for (int i = 1; i < dimensions; i++) {
                 str.append("[]");
             }
+            str.append(" {");
+            for (int i = 0; i < length; i++) {
+                str.append(pretty(Array.get(value, i)));
+                if (i < length - 1) {
+                    str.append(", ");
+                }
+            }
+            str.append('}');
             return str.toString();
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotCompiledMethod.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotCompiledMethod.java	Fri Apr 20 13:44:06 2012 +0200
@@ -67,4 +67,24 @@
         assert !Modifier.isStatic(method.accessFlags()) || method.signature().argumentKindAt(2, false) == CiKind.Object;
         return compiler.getVMEntries().executeCompiledMethod(this, arg1, arg2, arg3);
     }
+
+    private boolean checkArgs(Object... args) {
+        CiKind[] sig = CiUtil.signatureToKinds(method);
+        assert args.length == sig.length : CiUtil.format("%H.%n(%p): expected ", method) + sig.length + " args, got " + args.length;
+        for (int i = 0; i < sig.length; i++) {
+            Object arg = args[i];
+            if (arg == null) {
+                assert sig[i].isObject() : CiUtil.format("%H.%n(%p): expected arg ", method) + i + " to be Object, not " + sig[i];
+            } else if (!sig[i].isObject()) {
+                assert sig[i].toUnboxedJavaClass() == arg.getClass() : CiUtil.format("%H.%n(%p): expected arg ", method) + i + " to be " + sig[i] + ", not " + arg.getClass();
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public Object executeVarargs(Object... args) {
+        assert checkArgs(args);
+        return compiler.getVMEntries().executeCompiledMethodVarargs(this, args);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodResolvedImpl.java	Fri Apr 20 13:44:06 2012 +0200
@@ -155,7 +155,12 @@
 
     @Override
     public StackTraceElement toStackTraceElement(int bci) {
-        return CiUtil.toStackTraceElement(this, bci);
+        if (bci < 0 || bci >= codeSize) {
+            // HotSpot code can only construct stack trace elements for valid bcis
+            StackTraceElement ste = compiler.getVMEntries().RiMethod_toStackTraceElement(this, 0);
+            return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1);
+        }
+        return compiler.getVMEntries().RiMethod_toStackTraceElement(this, bci);
     }
 
     @Override
@@ -357,9 +362,6 @@
     public boolean canBeInlined() {
         return canBeInlined;
     }
-    public void neverInline() {
-        this.canBeInlined = false;
-    }
 
     @Override
     public int vtableEntryOffset() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRegisterConfig.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRegisterConfig.java	Fri Apr 20 13:44:06 2012 +0200
@@ -66,14 +66,7 @@
     private final CiRegister[] xmmParameterRegisters = {xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7};
     private final CiRegister[] allParameterRegisters;
 
-    private final CiRegister[] rsaRegs = {
-        rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
-        r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
-        xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
-        xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
-    };
-
-    private final CiCalleeSaveLayout registerSaveArea;
+    private final CiCalleeSaveLayout csl;
 
     public HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) {
         if (config.windowsOs) {
@@ -83,9 +76,20 @@
         }
 
         if (globalStubConfig) {
-            registerSaveArea = new CiCalleeSaveLayout(0, -1, 8, rsaRegs);
+            CiRegister[] regs = {
+                rax,  rcx,  rdx,   rbx,   rsp,   rbp,   rsi,   rdi,
+                r8,   r9,   r10,   r11,   r12,   r13,   r14,   r15,
+                xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
+                xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
+            };
+            csl = new CiCalleeSaveLayout(0, -1, 8, regs);
         } else {
-            registerSaveArea = new CiCalleeSaveLayout(0, 8, 8, new CiRegister[0]);
+            // We reserve space for saving RBP but don't explicitly specify
+            // it as a callee save register since we explicitly do the saving
+            // with push and pop in HotSpotFrameContext
+            final int size = 8;
+            final CiRegister[] regs = {};
+            csl = new CiCalleeSaveLayout(0, size, 8, regs);
         }
 
         attributesMap = RiRegisterAttributes.createMap(this, AMD64.allRegisters);
@@ -191,7 +195,7 @@
     }
 
     public CiCalleeSaveLayout getCalleeSaveLayout() {
-        return registerSaveArea;
+        return csl;
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri Apr 20 13:44:06 2012 +0200
@@ -30,21 +30,23 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.Compiler;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.target.amd64.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.snippets.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ci.CiTargetMethod.Call;
 import com.oracle.max.cri.ci.CiTargetMethod.DataPatch;
+import com.oracle.max.cri.ci.CiTargetMethod.Mark;
 import com.oracle.max.cri.ci.CiTargetMethod.Safepoint;
 import com.oracle.max.cri.ci.CiUtil.RefMapFormatter;
 import com.oracle.max.cri.ri.*;
@@ -55,7 +57,7 @@
  * CRI runtime implementation for the HotSpot VM.
  */
 public class HotSpotRuntime implements GraalRuntime {
-    final HotSpotVMConfig config;
+    public final HotSpotVMConfig config;
     final HotSpotRegisterConfig regConfig;
     private final HotSpotRegisterConfig globalStubRegConfig;
     private final Compiler compiler;
@@ -65,6 +67,8 @@
         this.compiler = compiler;
         regConfig = new HotSpotRegisterConfig(config, false);
         globalStubRegConfig = new HotSpotRegisterConfig(config, true);
+
+        System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName());
     }
 
     @Override
@@ -82,6 +86,44 @@
         return compiler.getVMEntries().disassembleNative(code, address);
     }
 
+    /**
+     * Decodes a call target to a mnemonic if possible.
+     */
+    private String getTargetName(Call call) {
+        Field[] fields = config.getClass().getDeclaredFields();
+        for (Field f : fields) {
+            if (f.getName().endsWith("Stub")) {
+                f.setAccessible(true);
+                try {
+                    if (f.get(config).equals(call.target)) {
+                        return f.getName();
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+        return String.valueOf(call.target);
+    }
+
+    /**
+     * Decodes a mark to a mnemonic if possible.
+     */
+    private static String getMarkName(Mark mark) {
+        Field[] fields = HotSpotXirGenerator.class.getDeclaredFields();
+        for (Field f : fields) {
+            if (Modifier.isStatic(f.getModifiers()) && f.getName().startsWith("MARK_")) {
+                f.setAccessible(true);
+                try {
+                    if (f.get(null).equals(mark.id)) {
+                        return f.getName();
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+        return "MARK:" + mark.id;
+    }
+
     @Override
     public String disassemble(CiTargetMethod tm) {
         byte[] code = Arrays.copyOf(tm.targetCode(), tm.targetCodeSize());
@@ -97,7 +139,7 @@
                 if (call.debugInfo != null) {
                     hcf.addComment(call.pcOffset + call.size, CiUtil.append(new StringBuilder(100), call.debugInfo, slotFormatter).toString());
                 }
-                addOperandComment(hcf, call.pcOffset, "{" + call.target + "}");
+                addOperandComment(hcf, call.pcOffset, "{" + getTargetName(call) + "}");
             } else {
                 if (safepoint.debugInfo != null) {
                     hcf.addComment(safepoint.pcOffset, CiUtil.append(new StringBuilder(100), safepoint.debugInfo, slotFormatter).toString());
@@ -108,6 +150,9 @@
         for (DataPatch site : tm.dataReferences) {
             hcf.addOperandComment(site.pcOffset, "{" + site.constant + "}");
         }
+        for (Mark mark : tm.marks) {
+            hcf.addComment(mark.pcOffset, getMarkName(mark));
+        }
         return hcf.toEmbeddedString();
     }
 
@@ -120,6 +165,8 @@
                     append(e.pcOffset).append(" -> ").
                     append(e.handlerPos).
                     append(nl);
+                hcf.addComment(e.pcOffset, "[exception -> " + e.handlerPos + "]");
+                hcf.addComment(e.handlerPos, "[exception handler for " + e.pcOffset + "]");
             }
             hcf.addComment(0, buf.toString());
         }
@@ -268,7 +315,7 @@
                     graph.addAfterFixed(cas, writeBarrier);
                 } else {
                     // This may be an array store so use an array write barrier
-                    LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), 0, cas.offset(), graph, false);
+                    LocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, false);
                     graph.addAfterFixed(cas, graph.add(new ArrayWriteBarrier(cas.object(), location)));
                 }
             }
@@ -305,10 +352,9 @@
                     AnchorNode anchor = graph.add(new AnchorNode());
                     graph.addBeforeFixed(storeIndexed, anchor);
                     GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID);
-                    ReadNode arrayClass = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull()));
+                    FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull()));
                     arrayClass.setGuard(guard);
-                    graph.addBeforeFixed(storeIndexed, arrayClass);
-                    ReadNode arrayElementKlass = graph.add(new ReadNode(arrayClass, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull()));
+                    FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull()));
                     value = graph.unique(new CheckCastNode(anchor, arrayElementKlass, null, value));
                 }
             }
@@ -334,19 +380,20 @@
             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, store.storeKind(), store.displacement(), store.offset(), graph);
             location.setIndexScalingEnabled(false);
             WriteNode write = graph.add(new WriteNode(store.object(), store.value(), location));
-            FieldWriteBarrier barrier = graph.add(new FieldWriteBarrier(store.object()));
             write.setStateAfter(store.stateAfter());
             graph.replaceFixedWithFixed(store, write);
-            graph.addBeforeFixed(write, barrier);
-        } else if (n instanceof ArrayHeaderSizeNode) {
-            ArrayHeaderSizeNode arrayHeaderSize = (ArrayHeaderSizeNode) n;
-            graph.replaceFloating(arrayHeaderSize, ConstantNode.forLong(config.getArrayOffset(arrayHeaderSize.elementKind()), n.graph()));
+            if (write.value().kind() == CiKind.Object && !write.value().isNullConstant()) {
+                FieldWriteBarrier barrier = graph.add(new FieldWriteBarrier(write.object()));
+                graph.addBeforeFixed(write, barrier);
+            }
         } else if (n instanceof ReadHubNode) {
             ReadHubNode objectClassNode = (ReadHubNode) n;
             LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph);
             ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull()));
             memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
+        } else {
+            assert false : "Node implementing Lowerable not handled: " + n;
         }
     }
 
@@ -389,7 +436,7 @@
                 SafeReadNode klassOop = safeRead(graph, CiKind.Object, receiver, config.klassOopOffset, StampFactory.objectNonNull(), StructuredGraph.INVALID_GRAPH_ID);
                 graph.start().setNext(klassOop);
                 // TODO(thomaswue): Care about primitive classes! Crashes for primitive classes at the moment (klassOop == null)
-                ReadNode result = graph.add(new ReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int)));
+                FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int)));
                 ReturnNode ret = graph.add(new ReturnNode(result));
                 klassOop.setNext(ret);
                 return graph;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Apr 20 13:44:06 2012 +0200
@@ -23,10 +23,8 @@
 package com.oracle.graal.hotspot.ri;
 
 import static com.oracle.graal.hotspot.ri.TemplateFlag.*;
-import static com.oracle.max.cri.ci.CiCallingConvention.Type.*;
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -49,25 +47,25 @@
 
     // this needs to correspond to graal_CodeInstaller.hpp
     // @formatter:off
-    private static final Integer MARK_VERIFIED_ENTRY            = 0x0001;
-    private static final Integer MARK_UNVERIFIED_ENTRY          = 0x0002;
-    private static final Integer MARK_OSR_ENTRY                 = 0x0003;
-    private static final Integer MARK_UNWIND_ENTRY              = 0x0004;
-    private static final Integer MARK_EXCEPTION_HANDLER_ENTRY   = 0x0005;
-    private static final Integer MARK_DEOPT_HANDLER_ENTRY       = 0x0006;
+    public static final Integer MARK_VERIFIED_ENTRY            = 0x0001;
+    public static final Integer MARK_UNVERIFIED_ENTRY          = 0x0002;
+    public static final Integer MARK_OSR_ENTRY                 = 0x0003;
+    public static final Integer MARK_UNWIND_ENTRY              = 0x0004;
+    public static final Integer MARK_EXCEPTION_HANDLER_ENTRY   = 0x0005;
+    public static final Integer MARK_DEOPT_HANDLER_ENTRY       = 0x0006;
 
-    private static final Integer MARK_STATIC_CALL_STUB          = 0x1000;
+    public static final Integer MARK_STATIC_CALL_STUB          = 0x1000;
 
-    private static final Integer MARK_INVOKEINTERFACE           = 0x2001;
-    private static final Integer MARK_INVOKESTATIC              = 0x2002;
-    private static final Integer MARK_INVOKESPECIAL             = 0x2003;
-    private static final Integer MARK_INVOKEVIRTUAL             = 0x2004;
+    public static final Integer MARK_INVOKEINTERFACE           = 0x2001;
+    public static final Integer MARK_INVOKESTATIC              = 0x2002;
+    public static final Integer MARK_INVOKESPECIAL             = 0x2003;
+    public static final Integer MARK_INVOKEVIRTUAL             = 0x2004;
 
-    private static final Integer MARK_IMPLICIT_NULL             = 0x3000;
-    private static final Integer MARK_POLL_NEAR                 = 0x3001;
-    private static final Integer MARK_POLL_RETURN_NEAR          = 0x3002;
-    private static final Integer MARK_POLL_FAR                  = 0x3003;
-    private static final Integer MARK_POLL_RETURN_FAR           = 0x3004;
+    public static final Integer MARK_IMPLICIT_NULL             = 0x3000;
+    public static final Integer MARK_POLL_NEAR                 = 0x3001;
+    public static final Integer MARK_POLL_RETURN_NEAR          = 0x3002;
+    public static final Integer MARK_POLL_FAR                  = 0x3003;
+    public static final Integer MARK_POLL_RETURN_FAR           = 0x3004;
 
     // @formatter:on
 
@@ -104,134 +102,6 @@
         }
     }
 
-    private SimpleTemplates prologueTemplates = new SimpleTemplates(STATIC_METHOD) {
-
-        @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
-            asm.restart(CiKind.Void);
-            XirOperand framePointer = asm.createRegisterTemp("frame pointer", target.wordKind, AMD64.rbp);
-            XirOperand stackPointer = asm.createRegisterTemp("stack pointer", target.wordKind, AMD64.rsp);
-            XirLabel unverifiedStub = null;
-
-            asm.mark(MARK_OSR_ENTRY);
-            asm.mark(MARK_UNVERIFIED_ENTRY);
-            if (!is(STATIC_METHOD, flags)) {
-                unverifiedStub = asm.createOutOfLineLabel("unverified");
-
-                XirOperand temp = asm.createRegisterTemp("temp (r10)", target.wordKind, AMD64.r10);
-                XirOperand cache = asm.createRegisterTemp("cache (rax)", target.wordKind, AMD64.rax);
-
-                CiCallingConvention conventions = registerConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target, false);
-                XirOperand receiver = asm.createRegister("receiver", target.wordKind, asRegister(conventions.locations[0]));
-
-                asm.pload(target.wordKind, temp, receiver, asm.i(config.hubOffset), false);
-                asm.jneq(unverifiedStub, cache, temp);
-            }
-            asm.align(config.codeEntryAlignment);
-            asm.mark(MARK_VERIFIED_ENTRY);
-            asm.stackOverflowCheck();
-            asm.push(framePointer);
-            asm.mov(framePointer, stackPointer);
-            // Compensate for the push of framePointer (the XIR instruction pushFrame is not flexible enough to reduce the frame size, wait until XIR goes away to fix this).
-            asm.add(stackPointer, stackPointer,  asm.i(8));
-            asm.pushFrame();
-
-            // -- out of line -------------------------------------------------------
-            XirOperand thread = asm.createRegisterTemp("thread", target.wordKind, AMD64.r15);
-            XirOperand exceptionOop = asm.createTemp("exception oop", CiKind.Object);
-            XirLabel unwind = asm.createOutOfLineLabel("unwind");
-            asm.bindOutOfLine(unwind);
-
-            asm.mark(MARK_UNWIND_ENTRY);
-
-            asm.pload(CiKind.Object, exceptionOop, thread, asm.i(config.threadExceptionOopOffset), false);
-            asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.createConstant(CiConstant.NULL_OBJECT), false);
-            asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false);
-
-            asm.callRuntime(config.unwindExceptionStub, null, exceptionOop);
-            asm.shouldNotReachHere();
-
-            asm.mark(MARK_EXCEPTION_HANDLER_ENTRY);
-            asm.callRuntime(config.handleExceptionStub, null);
-            asm.shouldNotReachHere();
-
-            asm.mark(MARK_DEOPT_HANDLER_ENTRY);
-            asm.callRuntime(config.handleDeoptStub, null);
-            asm.shouldNotReachHere();
-
-            if (!is(STATIC_METHOD, flags)) {
-                asm.bindOutOfLine(unverifiedStub);
-                asm.jmpRuntime(config.inlineCacheMissStub);
-            }
-
-            return asm.finishTemplate(is(STATIC_METHOD, flags) ? "static prologue" : "prologue");
-        }
-    };
-
-    private SimpleTemplates epilogueTemplates = new SimpleTemplates(STATIC_METHOD, SYNCHRONIZED) {
-
-        @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
-            asm.restart(CiKind.Void);
-            XirOperand framePointer = asm.createRegisterTemp("frame pointer", target.wordKind, AMD64.rbp);
-            XirOperand stackPointer = asm.createRegisterTemp("stack pointer", target.wordKind, AMD64.rsp);
-
-            asm.popFrame();
-            asm.pload(CiKind.Long, framePointer, stackPointer, asm.i(-8), false);
-
-            if (GraalOptions.GenSafepoints) {
-                XirOperand temp = asm.createRegisterTemp("temp", target.wordKind, AMD64.r10);
-                if (config.isPollingPageFar) {
-                    asm.mov(temp, wordConst(asm, config.safepointPollingAddress));
-                    asm.mark(MARK_POLL_RETURN_FAR);
-                    asm.pload(target.wordKind, temp, temp, true);
-                } else {
-                    XirOperand rip = asm.createRegister("rip", target.wordKind, AMD64.rip);
-                    asm.mark(MARK_POLL_RETURN_NEAR);
-                    asm.pload(target.wordKind, temp, rip, asm.i(0xEFBEADDE), true);
-                }
-            }
-
-            return asm.finishTemplate("epilogue");
-        }
-    };
-
-    private SimpleTemplates safepointTemplates = new SimpleTemplates() {
-
-        @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
-            asm.restart(CiKind.Void);
-
-            XirOperand temp = asm.createRegisterTemp("temp", target.wordKind, AMD64.r10);
-            if (config.isPollingPageFar) {
-                asm.mov(temp, wordConst(asm, config.safepointPollingAddress));
-                asm.mark(MARK_POLL_FAR);
-                asm.pload(target.wordKind, temp, temp, true);
-            } else {
-                XirOperand rip = asm.createRegister("rip", target.wordKind, AMD64.rip);
-                asm.mark(MARK_POLL_NEAR);
-                asm.pload(target.wordKind, temp, rip, asm.i(0xEFBEADDE), true);
-            }
-
-            return asm.finishTemplate("safepoint");
-        }
-    };
-
-    private SimpleTemplates exceptionObjectTemplates = new SimpleTemplates() {
-
-        @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
-            XirOperand result = asm.restart(CiKind.Object);
-            XirOperand thread = asm.createRegisterTemp("thread", target.wordKind, AMD64.r15);
-
-            asm.pload(CiKind.Object, result, thread, asm.i(config.threadExceptionOopOffset), false);
-            asm.pstore(CiKind.Object, thread, asm.i(config.threadExceptionOopOffset), asm.o(null), false);
-            asm.pstore(CiKind.Long, thread, asm.i(config.threadExceptionPcOffset), asm.l(0), false);
-
-            return asm.finishTemplate("exception object");
-        }
-    };
-
     private SimpleTemplates invokeInterfaceTemplates = new SimpleTemplates(NULL_CHECK) {
 
         @Override
@@ -958,27 +828,6 @@
     };
 
     @Override
-    public XirSnippet genPrologue(XirSite site, RiResolvedMethod method) {
-        boolean staticMethod = Modifier.isStatic(method.accessFlags());
-        return new XirSnippet(staticMethod ? prologueTemplates.get(site, STATIC_METHOD) : prologueTemplates.get(site));
-    }
-
-    @Override
-    public XirSnippet genEpilogue(XirSite site, RiResolvedMethod method) {
-        return new XirSnippet(epilogueTemplates.get(site));
-    }
-
-    @Override
-    public XirSnippet genSafepointPoll(XirSite site) {
-        return new XirSnippet(safepointTemplates.get(site));
-    }
-
-    @Override
-    public XirSnippet genExceptionObject(XirSite site) {
-        return new XirSnippet(exceptionObjectTemplates.get(site));
-    }
-
-    @Override
     public XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method) {
         return new XirSnippet(invokeInterfaceTemplates.get(site), receiver, wordArg(0));
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/ArrayCopySnippets.java	Fri Apr 20 13:44:06 2012 +0200
@@ -21,16 +21,15 @@
  * questions.
  */
 package com.oracle.graal.hotspot.snippets;
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.cri.*;
-import com.oracle.graal.graph.Node.Fold;
+import com.oracle.graal.graph.Node.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.snippets.*;
-import com.oracle.graal.snippets.nodes.*;
+import com.oracle.max.cri.ci.*;
 
 
 public class ArrayCopySnippets implements SnippetsInterface{
@@ -228,7 +227,7 @@
             copyObjectsUp(src, srcPos * 8L, dest, destPos * 8L, length);
         }
         if (length > 0) {
-            long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object);
+            int header = arrayHeaderSizeFor(CiKind.Object);
             int cardShift = cardTableShift();
             long cardStart = cardTableStart();
             long dstAddr = GetObjectAddressNode.get(dest);
@@ -243,47 +242,47 @@
 
     @Snippet
     public static void copyBytesDown(Object src, int srcPos, Object dest, int destPos, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Byte);
+        int header = arrayHeaderSizeFor(CiKind.Byte);
         for (long i = length - 1; i >= 0; i--) {
-            Byte a = UnsafeLoadNode.load(src, i + (srcPos + header), CiKind.Byte);
-            UnsafeStoreNode.store(dest, i + (destPos + header), a.byteValue(), CiKind.Byte);
+            Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
+            UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
         }
     }
 
     @Snippet
     public static void copyShortsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Short);
+        int header = arrayHeaderSizeFor(CiKind.Short);
         for (long i = (length - 1) * 2; i >= 0; i -= 2) {
-            Character a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Short);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.charValue(), CiKind.Short);
+            Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
         }
     }
 
     @Snippet
     public static void copyIntsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Int);
+        int header = arrayHeaderSizeFor(CiKind.Int);
         for (long i = (length - 1) * 4; i >= 0; i -= 4) {
-            Integer a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Int);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.intValue(), CiKind.Int);
+            Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
         }
     }
 
     @Snippet
     public static void copyLongsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Long);
+        int header = arrayHeaderSizeFor(CiKind.Long);
         for (long i = (length - 1) * 8; i >= 0; i -= 8) {
-            Long a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Long);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.longValue(), CiKind.Long);
+            Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
         }
     }
 
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsDown(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object);
-        for (long i = (length - 1) * 8; i >= 0; i -= 8) {
-            Object a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Object);
-            DirectObjectStoreNode.store(dest, i + (destOffset + header), a);
+        int header = arrayHeaderSizeFor(CiKind.Object);
+        for (long i = (length - 1) * wordSize(); i >= 0; i -= wordSize()) {
+            Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
+            DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
     }
     /**
@@ -296,10 +295,10 @@
      */
     @Snippet
     public static void copyBytesUp(Object src, int srcPos, Object dest, int destPos, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Byte);
+        int header = arrayHeaderSizeFor(CiKind.Byte);
         for (long i = 0; i < length; i++) {
-            Byte a = UnsafeLoadNode.load(src, i + (srcPos + header), CiKind.Byte);
-            UnsafeStoreNode.store(dest, i + (destPos + header), a.byteValue(), CiKind.Byte);
+            Byte a = UnsafeLoadNode.load(src, header, i + srcPos, CiKind.Byte);
+            UnsafeStoreNode.store(dest, header, i + destPos, a.byteValue(), CiKind.Byte);
         }
     }
 
@@ -313,38 +312,38 @@
      */
     @Snippet
     public static void copyShortsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Short);
+        int header = arrayHeaderSizeFor(CiKind.Short);
         for (long i = 0; i < length * 2L; i += 2) {
-            Character a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Short);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.charValue(), CiKind.Short);
+            Character a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Short);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.charValue(), CiKind.Short);
         }
     }
 
     @Snippet
     public static void copyIntsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Int);
+        int header = arrayHeaderSizeFor(CiKind.Int);
         for (long i = 0; i < length * 4L; i += 4) {
-            Integer a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Int);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.intValue(), CiKind.Int);
+            Integer a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Int);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.intValue(), CiKind.Int);
         }
     }
 
     @Snippet
     public static void copyLongsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Long);
+        int header = arrayHeaderSizeFor(CiKind.Long);
         for (long i = 0; i < length * 8L; i += 8) {
-            Long a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Long);
-            UnsafeStoreNode.store(dest, i + (destOffset + header), a.longValue(), CiKind.Long);
+            Long a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Long);
+            UnsafeStoreNode.store(dest, header, i + destOffset, a.longValue(), CiKind.Long);
         }
     }
 
     // Does NOT perform store checks
     @Snippet
     public static void copyObjectsUp(Object src, long srcOffset, Object dest, long destOffset, int length)  {
-        long header = ArrayHeaderSizeNode.sizeFor(CiKind.Object);
-        for (long i = 0; i < length * 8L; i += 8) {
-            Object a = UnsafeLoadNode.load(src, i + (srcOffset + header), CiKind.Object);
-            DirectObjectStoreNode.store(dest, i + (destOffset + header), a);
+        int header = arrayHeaderSizeFor(CiKind.Object);
+        for (long i = 0; i < length * wordSize(); i += wordSize()) {
+            Object a = UnsafeLoadNode.load(src, header, i + srcOffset, CiKind.Object);
+            DirectObjectStoreNode.store(dest, header, i + destOffset, a);
         }
     }
     private static class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
@@ -401,42 +400,42 @@
         @Input private ValueNode object;
         @Input private ValueNode value;
         @Input private ValueNode offset;
+        @Data private final int displacement;
 
-        public DirectObjectStoreNode(ValueNode object, ValueNode offset, ValueNode value) {
+        public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value) {
             super(StampFactory.illegal());
             this.object = object;
             this.value = value;
             this.offset = offset;
+            this.displacement = displacement;
         }
 
         @SuppressWarnings("unused")
         @NodeIntrinsic
-        public static void store(Object obj, long offset, long value) {
-            throw new UnsupportedOperationException();
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static void store(Object obj, long offset, boolean value) {
-            throw new UnsupportedOperationException();
-        }
-
-        @SuppressWarnings("unused")
-        @NodeIntrinsic
-        public static void store(Object obj, long offset, Object value) {
+        public static void store(Object obj, @ConstantNodeParameter int displacement, long offset, Object value) {
             throw new UnsupportedOperationException();
         }
 
         @Override
         public void lower(CiLoweringTool tool) {
             StructuredGraph graph = (StructuredGraph) this.graph();
-            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), 0, offset, graph, false);
+            IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, value.kind(), displacement, offset, graph, false);
             WriteNode write = graph.add(new WriteNode(object, value, location));
             graph.replaceFixedWithFixed(this, write);
         }
     }
 
     @Fold
+    private static int wordSize() {
+        return CompilerImpl.getInstance().getTarget().wordSize;
+    }
+
+    @Fold
+    private static int arrayHeaderSizeFor(CiKind elementKind) {
+        return CompilerImpl.getInstance().getConfig().getArrayOffset(elementKind);
+    }
+
+    @Fold
     private static int cardTableShift() {
         return CompilerImpl.getInstance().getConfig().cardtableShift;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/UnsafeSnippets.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/UnsafeSnippets.java	Fri Apr 20 13:44:06 2012 +0200
@@ -35,19 +35,19 @@
 public class UnsafeSnippets implements SnippetsInterface {
 
     public boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x);
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
     }
 
     public boolean compareAndSwapInt(Object o, long offset, int expected, int x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x);
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
     }
 
     public boolean compareAndSwapLong(Object o, long offset, long expected, long x) {
-        return CompareAndSwapNode.compareAndSwap(o, offset, expected, x);
+        return CompareAndSwapNode.compareAndSwap(o, 0, offset, expected, x);
     }
 
     public Object getObject(Object o, long offset) {
-        return UnsafeLoadNode.load(o, offset, CiKind.Object);
+        return UnsafeLoadNode.load(o, 0, offset, CiKind.Object);
     }
 
     public Object getObjectVolatile(Object o, long offset) {
@@ -58,7 +58,7 @@
     }
 
     public void putObject(Object o, long offset, Object x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Object);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Object);
     }
 
     public void putObjectVolatile(Object o, long offset, Object x) {
@@ -68,7 +68,7 @@
     }
 
     public int getInt(Object o, long offset) {
-        Integer value = UnsafeLoadNode.load(o, offset, CiKind.Int);
+        Integer value = UnsafeLoadNode.load(o, 0, offset, CiKind.Int);
         return value;
     }
 
@@ -80,7 +80,7 @@
     }
 
     public void putInt(Object o, long offset, int x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Int);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Int);
     }
 
     public void putIntVolatile(Object o, long offset, int x) {
@@ -91,7 +91,7 @@
 
     public boolean getBoolean(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Boolean result = UnsafeLoadNode.load(o, offset, CiKind.Boolean);
+        Boolean result = UnsafeLoadNode.load(o, 0, offset, CiKind.Boolean);
         return result;
     }
 
@@ -103,7 +103,7 @@
     }
 
     public void putBoolean(Object o, long offset, boolean x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Boolean);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Boolean);
     }
 
     public void putBooleanVolatile(Object o, long offset, boolean x) {
@@ -114,7 +114,7 @@
 
     public byte getByte(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Byte result = UnsafeLoadNode.load(o, offset, CiKind.Byte);
+        Byte result = UnsafeLoadNode.load(o, 0, offset, CiKind.Byte);
         return result;
     }
 
@@ -126,7 +126,7 @@
     }
 
     public void putByte(Object o, long offset, byte x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Byte);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Byte);
     }
 
     public void putByteVolatile(Object o, long offset, byte x) {
@@ -137,7 +137,7 @@
 
     public short getShort(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Short result = UnsafeLoadNode.load(o, offset, CiKind.Short);
+        Short result = UnsafeLoadNode.load(o, 0, offset, CiKind.Short);
         return result;
     }
 
@@ -149,7 +149,7 @@
     }
 
     public void putShort(Object o, long offset, short x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Short);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Short);
     }
 
     public void putShortVolatile(Object o, long offset, short x) {
@@ -160,7 +160,7 @@
 
     public char getChar(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Character result = UnsafeLoadNode.load(o, offset, CiKind.Char);
+        Character result = UnsafeLoadNode.load(o, 0, offset, CiKind.Char);
         return result;
     }
 
@@ -172,7 +172,7 @@
     }
 
     public void putChar(Object o, long offset, char x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Char);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Char);
     }
 
     public void putCharVolatile(Object o, long offset, char x) {
@@ -183,7 +183,7 @@
 
     public long getLong(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Long result = UnsafeLoadNode.load(o, offset, CiKind.Long);
+        Long result = UnsafeLoadNode.load(o, 0, offset, CiKind.Long);
         return result;
     }
 
@@ -195,7 +195,7 @@
     }
 
     public void putLong(Object o, long offset, long x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Long);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Long);
     }
 
     public void putLongVolatile(Object o, long offset, long x) {
@@ -206,7 +206,7 @@
 
     public float getFloat(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Float result = UnsafeLoadNode.load(o, offset, CiKind.Float);
+        Float result = UnsafeLoadNode.load(o, 0, offset, CiKind.Float);
         return result;
     }
 
@@ -218,7 +218,7 @@
     }
 
     public void putFloat(Object o, long offset, float x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Float);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Float);
     }
 
     public void putFloatVolatile(Object o, long offset, float x) {
@@ -229,7 +229,7 @@
 
     public double getDouble(Object o, long offset) {
         @JavacBug(id = 6995200)
-        Double result = UnsafeLoadNode.load(o, offset, CiKind.Double);
+        Double result = UnsafeLoadNode.load(o, 0, offset, CiKind.Double);
         return result;
     }
 
@@ -241,7 +241,7 @@
     }
 
     public void putDouble(Object o, long offset, double x) {
-        UnsafeStoreNode.store(o, offset, x, CiKind.Double);
+        UnsafeStoreNode.store(o, 0, offset, x, CiKind.Double);
     }
 
     public void putDoubleVolatile(Object o, long offset, double x) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64SafepointOp.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.target.amd64;
+
+import static com.oracle.graal.hotspot.ri.HotSpotXirGenerator.*;
+import static com.oracle.max.asm.target.amd64.AMD64.*;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * Emits a safepoint poll.
+ */
+public class AMD64SafepointOp extends AMD64LIRInstruction {
+
+    private final HotSpotVMConfig config;
+
+    public AMD64SafepointOp(LIRDebugInfo info, HotSpotVMConfig config) {
+        super("SAFEPOINT", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+        this.config = config;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler asm) {
+        CiRegister scratch = tasm.frameMap.registerConfig.getScratchRegister();
+        int pos = asm.codeBuffer.position();
+        if (config.isPollingPageFar) {
+            asm.movq(scratch, config.safepointPollingAddress);
+            tasm.recordMark(MARK_POLL_FAR);
+            tasm.recordSafepoint(pos, info);
+            asm.movq(scratch, new CiAddress(tasm.target.wordKind, scratch.asValue()));
+        } else {
+            tasm.recordMark(MARK_POLL_NEAR);
+            tasm.recordSafepoint(pos, info);
+            asm.movq(scratch, new CiAddress(tasm.target.wordKind, rip.asValue()));
+        }
+    }
+
+    @Override
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        throw GraalInternalError.shouldNotReachHere();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.target.amd64;
+
+import static com.oracle.graal.hotspot.ri.HotSpotXirGenerator.*;
+import static com.oracle.max.asm.target.amd64.AMD64.*;
+import static com.oracle.max.cri.ci.CiCallingConvention.Type.*;
+import static com.oracle.max.cri.ci.CiValueUtil.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.compiler.target.amd64.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.ri.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.max.asm.*;
+import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ci.CiCallingConvention.Type;
+import com.oracle.max.cri.ci.CiRegister.RegisterFlag;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.xir.*;
+
+public class HotSpotAMD64Backend extends Backend {
+
+    public HotSpotAMD64Backend(RiRuntime runtime, CiTarget target) {
+        super(runtime, target);
+    }
+
+    @Override
+    public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
+        return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir) {
+            @Override
+            public void visitLoopEnd(LoopEndNode x) {
+                if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) {
+                    LIRDebugInfo info = state();
+                    if (!info.topFrame.method.noSafepointPolls()) {
+                        append(new AMD64SafepointOp(info, ((HotSpotRuntime) runtime).config));
+                    }
+                }
+            }
+            @Override
+            public void visitExceptionObject(ExceptionObjectNode x) {
+                HotSpotVMConfig config = ((HotSpotRuntime) runtime).config;
+                CiRegisterValue thread = r15.asValue();
+                CiAddress exceptionAddress = new CiAddress(CiKind.Object, thread, config.threadExceptionOopOffset);
+                CiAddress pcAddress = new CiAddress(CiKind.Long, thread, config.threadExceptionPcOffset);
+                CiValue exception = emitLoad(exceptionAddress, false);
+                emitStore(exceptionAddress, CiConstant.NULL_OBJECT, false);
+                emitStore(pcAddress, CiConstant.LONG_0, false);
+                setResult(x, exception);
+            }
+        };
+    }
+
+    @Override
+    public AMD64XirAssembler newXirAssembler() {
+        return new AMD64XirAssembler(target);
+    }
+
+    class HotSpotFrameContext implements FrameContext {
+
+        @Override
+        public void enter(TargetMethodAssembler tasm) {
+            FrameMap frameMap = tasm.frameMap;
+            int frameSize = frameMap.frameSize();
+
+            AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
+            emitStackOverflowCheck(tasm, false);
+            asm.push(rbp);
+            asm.movq(rbp, rsp);
+            asm.decrementq(rsp, frameSize - 8); // account for the push of RBP above
+            if (GraalOptions.ZapStackOnMethodEntry) {
+                final int intSize = 4;
+                for (int i = 0; i < frameSize / intSize; ++i) {
+                    asm.movl(new CiAddress(CiKind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1);
+                }
+            }
+            CiCalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout();
+            if (csl != null && csl.size != 0) {
+                int frameToCSA = frameMap.offsetToCalleeSaveArea();
+                assert frameToCSA >= 0;
+                asm.save(csl, frameToCSA);
+            }
+        }
+
+        @Override
+        public void leave(TargetMethodAssembler tasm) {
+            int frameSize = tasm.frameMap.frameSize();
+            AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
+            CiCalleeSaveLayout csl = tasm.frameMap.registerConfig.getCalleeSaveLayout();
+            RiRegisterConfig regConfig = tasm.frameMap.registerConfig;
+
+            if (csl != null && csl.size != 0) {
+                tasm.targetMethod.setRegisterRestoreEpilogueOffset(asm.codeBuffer.position());
+                // saved all registers, restore all registers
+                int frameToCSA = tasm.frameMap.offsetToCalleeSaveArea();
+                asm.restore(csl, frameToCSA);
+            }
+
+            asm.incrementq(rsp, frameSize - 8); // account for the pop of RBP below
+            asm.pop(rbp);
+
+            if (GraalOptions.GenSafepoints) {
+                HotSpotVMConfig config = ((HotSpotRuntime) runtime).config;
+
+                // If at the return point, then the frame has already been popped
+                // so deoptimization cannot be performed here. The HotSpot runtime
+                // detects this case - see the definition of frame::should_be_deoptimized()
+
+                CiRegister scratch = regConfig.getScratchRegister();
+                if (config.isPollingPageFar) {
+                    asm.movq(scratch, config.safepointPollingAddress);
+                    tasm.recordMark(MARK_POLL_RETURN_FAR);
+                    asm.movq(scratch, new CiAddress(tasm.target.wordKind, scratch.asValue()));
+                } else {
+                    tasm.recordMark(MARK_POLL_RETURN_NEAR);
+                    asm.movq(scratch, new CiAddress(tasm.target.wordKind, rip.asValue()));
+                }
+            }
+        }
+    }
+
+    @Override
+    public TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir) {
+        // Omit the frame if the method:
+        //  - has no spill slots or other slots allocated during register allocation
+        //  - has no callee-saved registers
+        //  - has no incoming arguments passed on the stack
+        //  - has no instructions with debug info
+        boolean canOmitFrame =
+            frameMap.frameSize() == frameMap.initialFrameSize &&
+            frameMap.registerConfig.getCalleeSaveLayout().registers.length == 0 &&
+            !lir.hasArgInCallerFrame() &&
+            !lir.hasDebugInfo();
+
+        AbstractAssembler masm = new AMD64MacroAssembler(target, frameMap.registerConfig);
+        HotSpotFrameContext frameContext = canOmitFrame ? null : new HotSpotFrameContext();
+        TargetMethodAssembler tasm = new TargetMethodAssembler(target, runtime, frameMap, masm, frameContext);
+        tasm.setFrameSize(frameMap.frameSize());
+        tasm.targetMethod.setCustomStackAreaOffset(frameMap.offsetToCustomArea());
+        return tasm;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, RiResolvedMethod method, LIR lir) {
+        AMD64MacroAssembler asm = (AMD64MacroAssembler) tasm.asm;
+        FrameMap frameMap = tasm.frameMap;
+        RiRegisterConfig regConfig = frameMap.registerConfig;
+        HotSpotVMConfig config = ((HotSpotRuntime) runtime).config;
+        Label unverifiedStub = new Label();
+
+        // Emit the prefix
+        tasm.recordMark(MARK_OSR_ENTRY);
+        tasm.recordMark(MARK_UNVERIFIED_ENTRY);
+
+        boolean isStatic = Modifier.isStatic(method.accessFlags());
+        if (!isStatic) {
+            CiCallingConvention cc = regConfig.getCallingConvention(JavaCallee, new CiKind[] {CiKind.Object}, target, false);
+            CiRegister inlineCacheKlass = rax; // see definition of IC_Klass in c1_LIRAssembler_x86.cpp
+            CiRegister receiver = asRegister(cc.locations[0]);
+            CiAddress src = new CiAddress(target.wordKind, receiver.asValue(), config.hubOffset);
+
+            asm.cmpq(inlineCacheKlass, src);
+            asm.jcc(ConditionFlag.notEqual, unverifiedStub);
+        }
+
+        asm.align(config.codeEntryAlignment);
+        tasm.recordMark(MARK_VERIFIED_ENTRY);
+
+        // Emit code for the LIR
+        lir.emitCode(tasm);
+
+        boolean frameOmitted = tasm.frameContext == null;
+        if (!frameOmitted) {
+            CiRegister thread = r15;
+            CiRegister exceptionOop = regConfig.getCallingConventionRegisters(Type.RuntimeCall, RegisterFlag.CPU)[0];
+            Label unwind = new Label();
+            asm.bind(unwind);
+            tasm.recordMark(MARK_UNWIND_ENTRY);
+            CiAddress exceptionOopField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionOopOffset);
+            CiAddress exceptionPcField = new CiAddress(CiKind.Object, thread.asValue(), config.threadExceptionPcOffset);
+            asm.movq(exceptionOop, exceptionOopField);
+            asm.movslq(exceptionOopField, 0);
+            asm.movslq(exceptionPcField, 0);
+
+            AMD64Call.directCall(tasm, asm, config.unwindExceptionStub, null);
+            AMD64Call.shouldNotReachHere(tasm, asm);
+
+            tasm.recordMark(MARK_EXCEPTION_HANDLER_ENTRY);
+            AMD64Call.directCall(tasm, asm, config.handleExceptionStub, null);
+            AMD64Call.shouldNotReachHere(tasm, asm);
+
+            tasm.recordMark(MARK_DEOPT_HANDLER_ENTRY);
+            AMD64Call.directCall(tasm, asm, config.handleDeoptStub, null);
+            AMD64Call.shouldNotReachHere(tasm, asm);
+        } else {
+            // No need to emit the stubs for entries back into the method since
+            // it has no calls that can cause such "return" entries
+            assert !frameMap.accessesCallerFrame();
+        }
+
+        if (!isStatic) {
+            asm.bind(unverifiedStub);
+            AMD64Call.directJmp(tasm, asm, config.inlineCacheMissStub);
+        }
+
+        for (int i = 0; i < GraalOptions.MethodEndBreakpointGuards; ++i) {
+            asm.int3();
+        }
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Fri Apr 20 13:44:06 2012 +0200
@@ -121,12 +121,14 @@
         public int endBci;
         public boolean isExceptionEntry;
         public boolean isLoopHeader;
+        public int loopId;
         public int blockID;
 
         public FixedWithNextNode firstInstruction;
         public FrameStateBuilder entryState;
 
         public ArrayList<Block> successors = new ArrayList<>(2);
+        public long exits;
         public int normalSuccessors;
 
         private boolean visited;
@@ -191,6 +193,7 @@
     private final BytecodeStream stream;
     private final RiExceptionHandler[] exceptionHandlers;
     private Block[] blockMap;
+    public Block[] loopHeaders;
 
     /**
      * Creates a new BlockMap instance from bytecode of the given method .
@@ -204,6 +207,7 @@
         this.blockMap = new Block[method.codeSize()];
         this.canTrap = new BitSet(blockMap.length);
         this.blocks = new ArrayList<>();
+        this.loopHeaders = new Block[64];
     }
 
     public RiExceptionHandler[] exceptionHandlers() {
@@ -223,7 +227,11 @@
             }
             createJsrAlternatives(blockMap[0]);
         }
+        if (Debug.isLogEnabled()) {
+            this.log("Before BlockOrder");
+        }
         computeBlockOrder();
+        fixLoopBits();
 
         initializeBlockIds();
 
@@ -231,7 +239,9 @@
 
         // Discard big arrays so that they can be GCed
         blockMap = null;
-
+        if (Debug.isLogEnabled()) {
+            this.log("Before LivenessAnalysis");
+        }
         if (GraalOptions.OptLivenessAnalysis) {
             Debug.scope("LivenessAnalysis", new Runnable() {
                 @Override
@@ -541,6 +551,26 @@
         }
     }
 
+    private boolean loopChanges;
+
+    private void fixLoopBits() {
+        do {
+            loopChanges = false;
+            for (Block b : blocks) {
+                b.visited = false;
+            }
+
+            long loop = fixLoopBits(blockMap[0]);
+
+            if (loop != 0) {
+                // There is a path from a loop end to the method entry that does not pass the loop header.
+                // Therefore, the loop is non reducible (has more than one entry).
+                // We don't want to compile such methods because the IR only supports structured loops.
+                throw new CiBailout("Non-reducible loop");
+            }
+        } while (loopChanges);
+    }
+
     private void computeBlockOrder() {
         long loop = computeBlockOrder(blockMap[0]);
 
@@ -555,6 +585,64 @@
         Collections.reverse(blocks);
     }
 
+    public void log(String name) {
+        if (Debug.isLogEnabled()) {
+            String n = System.lineSeparator();
+            StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :");
+            sb.append(n);
+            Iterable<Block> it;
+            if (blocks.isEmpty()) {
+                it = new HashSet<>(Arrays.asList(blockMap));
+            } else {
+                it = blocks;
+            }
+            for (Block b : it) {
+                if (b == null) {
+                    continue;
+                }
+                sb.append("B").append(b.blockID).append(" (").append(b.startBci).append(" -> ").append(b.endBci).append(")");
+                if (b.isLoopHeader) {
+                    sb.append(" LoopHeader");
+                }
+                if (b.isExceptionEntry) {
+                    sb.append(" ExceptionEntry");
+                }
+                sb.append(n).append("  Sux : ");
+                for (Block s : b.successors) {
+                    sb.append("B").append(s.blockID).append(" (").append(s.startBci).append(" -> ").append(s.endBci).append(")");
+                    if (s.isExceptionEntry) {
+                        sb.append("!");
+                    }
+                    sb.append(" ");
+                }
+                sb.append(n).append("  Loop : ");
+                long l = b.loops;
+                int pos = 0;
+                while (l != 0) {
+                    int lMask = 1 << pos;
+                    if ((l & lMask) != 0) {
+                        sb.append("B").append(loopHeaders[pos].blockID).append(" ");
+                        l &= ~lMask;
+                    }
+                    pos++;
+                }
+                sb.append(n).append("  Exits : ");
+                l = b.exits;
+                pos = 0;
+                while (l != 0) {
+                    int lMask = 1 << pos;
+                    if ((l & lMask) != 0) {
+                        sb.append("B").append(loopHeaders[pos].blockID).append(" ");
+                        l &= ~lMask;
+                    }
+                    pos++;
+                }
+                sb.append(n);
+            }
+            Debug.log(sb.toString());
+        }
+    }
+
     /**
      * The next available loop number.
      */
@@ -581,6 +669,9 @@
 
             assert block.loops == 0;
             block.loops = (long) 1 << (long) nextLoop;
+            Debug.log("makeLoopHeader(%s) -> %x", block, block.loops);
+            loopHeaders[nextLoop] = block;
+            block.loopId = nextLoop;
             nextLoop++;
         }
         assert Long.bitCount(block.loops) == 1;
@@ -596,9 +687,13 @@
             if (block.active) {
                 // Reached block via backward branch.
                 makeLoopHeader(block);
+                // Return cached loop information for this block.
+                return block.loops;
+            } else if (block.isLoopHeader) {
+                return block.loops & ~(1L << block.loopId);
+            } else {
+                return block.loops;
             }
-            // Return cached loop information for this block.
-            return block.loops;
         }
 
         block.visited = true;
@@ -610,18 +705,50 @@
             loops |= computeBlockOrder(successor);
         }
 
+        block.loops = loops;
+        Debug.log("computeBlockOrder(%s) -> %x", block, block.loops);
+
         if (block.isLoopHeader) {
-            assert Long.bitCount(block.loops) == 1;
-            loops &= ~block.loops;
+            loops &= ~(1L << block.loopId);
         }
 
-        block.loops = loops;
         block.active = false;
         blocks.add(block);
 
         return loops;
     }
 
+    private long fixLoopBits(Block block) {
+        if (block.visited) {
+            // Return cached loop information for this block.
+            if (block.isLoopHeader) {
+                return block.loops & ~(1L << block.loopId);
+            } else {
+                return block.loops;
+            }
+        }
+
+        block.visited = true;
+        long loops = block.loops;
+        for (Block successor : block.successors) {
+            // Recursively process successors.
+            loops |= fixLoopBits(successor);
+        }
+        for (Block successor : block.successors) {
+            successor.exits = loops & ~successor.loops;
+        }
+        if (block.loops != loops) {
+            loopChanges = true;
+            block.loops = loops;
+            Debug.log("fixLoopBits0(%s) -> %x", block, block.loops);
+        }
+
+        if (block.isLoopHeader) {
+            loops &= ~(1L << block.loopId);
+        }
+
+        return loops;
+    }
 
     private void computeLiveness() {
         for (Block block : blocks) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Fri Apr 20 13:44:06 2012 +0200
@@ -28,6 +28,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
@@ -200,15 +201,40 @@
         }
         // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles).
         List<PhiNode> phiUsages = phi.usages().filter(PhiNode.class).snapshot();
+        List<ValueProxyNode> vpnUsages = phi.usages().filter(ValueProxyNode.class).snapshot();
 
         // Remove the phi function from all FrameStates where it is used and then delete it.
-        assert phi.usages().filter(isNotA(FrameState.class).nor(PhiNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
+        assert phi.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
         phi.replaceAtUsages(null);
         phi.safeDelete();
 
         for (PhiNode phiUsage : phiUsages) {
             deletePhi(phiUsage);
         }
+        for (ValueProxyNode proxyUsage : vpnUsages) {
+            deleteProxy(proxyUsage);
+        }
+    }
+
+    private void deleteProxy(ValueProxyNode proxy) {
+        if (proxy.isDeleted()) {
+            return;
+        }
+        // Collect all phi functions that use this phi so that we can delete them recursively (after we delete ourselfs to avoid circles).
+        List<PhiNode> phiUsages = proxy.usages().filter(PhiNode.class).snapshot();
+        List<ValueProxyNode> vpnUsages = proxy.usages().filter(ValueProxyNode.class).snapshot();
+
+        // Remove the proxy function from all FrameStates where it is used and then delete it.
+        assert proxy.usages().filter(isNotA(FrameState.class).nor(PhiNode.class).nor(ValueProxyNode.class)).isEmpty() : "phi function that gets deletes must only be used in frame states";
+        proxy.replaceAtUsages(null);
+        proxy.safeDelete();
+
+        for (PhiNode phiUsage : phiUsages) {
+            deletePhi(phiUsage);
+        }
+        for (ValueProxyNode proxyUsage : vpnUsages) {
+            deleteProxy(proxyUsage);
+        }
     }
 
     public void insertLoopPhis(LoopBeginNode loopBegin) {
@@ -220,6 +246,23 @@
         }
     }
 
+    public void insertProxies(LoopExitNode loopExit, FrameStateBuilder loopEntryState) {
+        for (int i = 0; i < localsSize(); i++) {
+            ValueNode value = localAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeLocal(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)));
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            ValueNode value = stackAt(i);
+            if (value != null && (!loopEntryState.contains(value) || loopExit.loopBegin().isPhiAtMerge(value))) {
+                Debug.log(" inserting proxy for %s", value);
+                storeStack(i, graph.unique(new ValueProxyNode(value, loopExit, PhiType.Value)));
+            }
+        }
+    }
+
     private PhiNode createLoopPhi(MergeNode block, ValueNode value) {
         if (value == null) {
             return null;
@@ -545,4 +588,18 @@
         assert kind != CiKind.Void && kind != CiKind.Illegal;
         return kind == CiKind.Long || kind == CiKind.Double;
     }
+
+    public boolean contains(ValueNode value) {
+        for (int i = 0; i < localsSize(); i++) {
+            if (localAt(i) == value) {
+                return true;
+            }
+        }
+        for (int i = 0; i < stackSize(); i++) {
+            if (stackAt(i) == value) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Apr 20 13:44:06 2012 +0200
@@ -43,6 +43,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.cri.ri.RiType.Representation;
@@ -104,6 +105,8 @@
         }
     }
 
+    private Block[] loopHeaders;
+
     public GraphBuilderPhase(RiRuntime runtime, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
@@ -156,6 +159,7 @@
         this.canTrapBitSet = blockMap.canTrap;
 
         exceptionHandlers = blockMap.exceptionHandlers();
+        loopHeaders = blockMap.loopHeaders;
 
         lastInstr = currentGraph.start();
         if (isSynchronized(method.accessFlags())) {
@@ -1197,6 +1201,67 @@
         return x;
     }
 
+    private static class Target {
+        FixedNode fixed;
+        FrameStateBuilder state;
+        public Target(FixedNode fixed, FrameStateBuilder state) {
+            this.fixed = fixed;
+            this.state = state;
+        }
+    }
+
+    private Target checkLoopExit(FixedNode traget, Block targetBlock, FrameStateBuilder state) {
+        if (currentBlock != null) {
+            long exits = currentBlock.loops & ~targetBlock.loops;
+            if (exits != 0) {
+                LoopExitNode firstLoopExit = null;
+                LoopExitNode lastLoopExit = null;
+
+                int pos = 0;
+                ArrayList<Block> exitLoops = new ArrayList<>(Long.bitCount(exits));
+                do {
+                    int lMask = 1 << pos;
+                    if ((exits & lMask) != 0) {
+                        exitLoops.add(loopHeaders[pos]);
+                        exits &= ~lMask;
+                    }
+                    pos++;
+                } while (exits != 0);
+
+                Collections.sort(exitLoops, new Comparator<Block>() {
+                    @Override
+                    public int compare(Block o1, Block o2) {
+                        return Long.bitCount(o2.loops) - Long.bitCount(o1.loops);
+                    }
+                });
+
+                int bci = targetBlock.startBci;
+                if (targetBlock instanceof ExceptionBlock) {
+                    bci = ((ExceptionBlock) targetBlock).deoptBci;
+                }
+                FrameStateBuilder newState = state.copy();
+                for (Block loop : exitLoops) {
+                    LoopBeginNode loopBegin = (LoopBeginNode) loop.firstInstruction;
+                    LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin));
+                    if (lastLoopExit != null) {
+                        lastLoopExit.setNext(loopExit);
+                    }
+                    if (firstLoopExit == null) {
+                        firstLoopExit = loopExit;
+                    }
+                    lastLoopExit = loopExit;
+                    Debug.log("Traget %s (%s) Exits %s, scanning framestates...", targetBlock, traget, loop);
+                    newState.insertProxies(loopExit, loop.entryState);
+                    loopExit.setStateAfter(newState.create(bci));
+                }
+
+                lastLoopExit.setNext(traget);
+                return new Target(firstLoopExit, newState);
+            }
+        }
+        return new Target(traget, state);
+    }
+
     private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         assert probability >= 0 && probability <= 1;
         if (probability == 0 && optimisticOpts.removeNeverExecutedCode()) {
@@ -1206,23 +1271,25 @@
         }
     }
 
-    private FixedNode createTarget(Block block, FrameStateBuilder stateAfter) {
-        assert block != null && stateAfter != null;
-        assert !block.isExceptionEntry || stateAfter.stackSize() == 1;
+    private FixedNode createTarget(Block block, FrameStateBuilder state) {
+        assert block != null && state != null;
+        assert !block.isExceptionEntry || state.stackSize() == 1;
 
         if (block.firstInstruction == null) {
             // This is the first time we see this block as a branch target.
             // Create and return a placeholder that later can be replaced with a MergeNode when we see this block again.
             block.firstInstruction = currentGraph.add(new BlockPlaceholderNode());
-            block.entryState = stateAfter.copy();
+            Target target = checkLoopExit(block.firstInstruction, block, state);
+            FixedNode result = target.fixed;
+            block.entryState = target.state == state ? state.copy() : target.state;
             block.entryState.clearNonLiveLocals(block.localsLiveIn);
 
             Debug.log("createTarget %s: first visit, result: %s", block, block.firstInstruction);
-            return block.firstInstruction;
+            return result;
         }
 
         // We already saw this block before, so we have to merge states.
-        if (!block.entryState.isCompatibleWith(stateAfter)) {
+        if (!block.entryState.isCompatibleWith(state)) {
             throw new CiBailout("stacks do not match; bytecodes would not verify");
         }
 
@@ -1230,8 +1297,9 @@
             assert block.isLoopHeader && currentBlock.blockID >= block.blockID : "must be backward branch";
             // Backward loop edge. We need to create a special LoopEndNode and merge with the loop begin node created before.
             LoopBeginNode loopBegin = (LoopBeginNode) block.firstInstruction;
-            LoopEndNode result = currentGraph.add(new LoopEndNode(loopBegin));
-            block.entryState.merge(loopBegin, stateAfter);
+            Target target = checkLoopExit(currentGraph.add(new LoopEndNode(loopBegin)), block, state);
+            FixedNode result = target.fixed;
+            block.entryState.merge(loopBegin, target.state);
 
             Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
             return result;
@@ -1260,9 +1328,11 @@
         MergeNode mergeNode = (MergeNode) block.firstInstruction;
 
         // The EndNode for the newly merged edge.
-        EndNode result = currentGraph.add(new EndNode());
-        block.entryState.merge(mergeNode, stateAfter);
-        mergeNode.addForwardEnd(result);
+        EndNode newEnd = currentGraph.add(new EndNode());
+        Target target = checkLoopExit(newEnd, block, state);
+        FixedNode result = target.fixed;
+        block.entryState.merge(mergeNode, target.state);
+        mergeNode.addForwardEnd(newEnd);
 
         Debug.log("createTarget %s: merging state, result: %s", block, result);
         return result;
@@ -1274,9 +1344,7 @@
      */
     private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         FixedNode target = createTarget(probability, block, stateAfter);
-        assert !(target instanceof BeginNode);
-        BeginNode begin = currentGraph.add(new BeginNode());
-        begin.setNext(target);
+        BeginNode begin = BeginNode.begin(target);
 
         assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) :
             "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize to a bci _before_ the actual if, so that the interpreter can update the profiling information.";
@@ -1340,25 +1408,7 @@
                 assert begin.forwardEndCount() == 1;
                 currentGraph.reduceDegenerateLoopBegin(begin);
             } else {
-                // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either the same or the phi itself.
-                for (PhiNode phi : begin.phis().snapshot()) {
-                    checkRedundantPhi(phi);
-                }
-            }
-        }
-    }
-
-    private static void checkRedundantPhi(PhiNode phiNode) {
-        if (phiNode.isDeleted() || phiNode.valueCount() == 1) {
-            return;
-        }
-
-        ValueNode singleValue = phiNode.singleValue();
-        if (singleValue != null) {
-            Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
-            ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue);
-            for (PhiNode phi : phiUsages) {
-                checkRedundantPhi(phi);
+                GraphUtil.normalizeLoopBegin(begin);
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop15.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.jtt.loop;
+
+import org.junit.*;
+
+public class Loop15 {
+
+    public static int test(int arg) {
+        Object o = null;
+        int result = 10;
+        for (int k = 0; k < arg; ++k) {
+            if (o == null) {
+                o = new Object();
+            }
+            if (k >= 5) {
+                break;
+            }
+            result++;
+        }
+        return result + (o == null ? 0 : 1);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(16, test(5));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        Assert.assertEquals(10, test(0));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        Assert.assertEquals(12, test(1));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        Assert.assertEquals(16, test(10));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop16.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package com.oracle.graal.jtt.loop;
+
+import org.junit.*;
+
+/*
+ * Tests exiting 2 loops at the same time with escape-analysed values flowing out of loops
+ */
+public class Loop16 {
+
+    public int a;
+    public int b;
+    public int c;
+
+    public static int test(int count) {
+        return new Loop16().run(count);
+    }
+
+    public int run(int count) {
+    l1: for (int i = 0; i <= count; i++) {
+            if (i > 5) {
+                for (int j = 0; j < i; j++) {
+                    a += i;
+                    if (a > 500) {
+                        break l1;
+                    }
+                }
+            } else if (i > 7) {
+                b += i;
+            } else {
+                    c += i;
+            }
+        }
+        return a + b + c;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(526, test(40));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/Loop17.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Checkstyle: stop
+package com.oracle.graal.jtt.loop;
+
+import org.junit.*;
+
+/*
+ * Test around an object that escapes directly from inside a loop (no virtual phi on the loop)
+ */
+public class Loop17 {
+
+    private static class L {
+        public int a;
+        public int b;
+        public int c;
+        public L(int a, int b, int c) {
+            this.a = a;
+            this.b = b;
+            this.c = c;
+        }
+    }
+
+
+    public static int test(int count) {
+        int i = 0;
+        L l;
+        do {
+            l = new L(i, i+1, i+2);
+        } while (++i < count);
+
+        return l.a + l.b * 10 + l.c * 100;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(543, test(new L(4,4,4).a));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopLastIndexOf.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.jtt.loop;
+
+import org.junit.*;
+
+/*
+ * see java.lang.String.lastIndexOf(char[], int, int, char[], int ,int, int)
+ */
+public class LoopLastIndexOf {
+
+    private final char[] v1 = new char[]{'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'};
+    private final char[] v2 = new char[]{'d', 'a'};
+    private final char[] v3 = new char[]{'d', 'b', 'c'};
+    private final char[] v4 = new char[]{'z', 'a', 'b', 'c'};
+
+    public static int test(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) {
+        int rightIndex = sourceCount - targetCount;
+        if (fromIndex < 0) {
+            return -1;
+        }
+        if (fromIndex > rightIndex) {
+            fromIndex = rightIndex;
+        }
+        /* Empty string always matches. */
+        if (targetCount == 0) {
+            return fromIndex;
+        }
+
+        int strLastIndex = targetOffset + targetCount - 1;
+        char strLastChar = target[strLastIndex];
+        int min = sourceOffset + targetCount - 1;
+        int i = min + fromIndex;
+
+        startSearchForLastChar: while (true) {
+            while (i >= min && source[i] != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - (targetCount - 1);
+            int k = strLastIndex - 1;
+
+            while (j > start) {
+                if (source[j--] != target[k--]) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start - sourceOffset + 1;
+        }
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(7, test(v1, 0, v1.length, v2, 0, v2.length, 10));
+    }
+
+    @Test
+    public void run1() throws Throwable {
+        Assert.assertEquals(-1, test(v1, 0, v1.length, v3, 0, v3.length, 10));
+    }
+
+    @Test
+    public void run2() throws Throwable {
+        Assert.assertEquals(-1, test(v1, 0, v1.length, v4, 0, v4.length, 10));
+    }
+
+    @Test
+    public void run3() throws Throwable {
+        Assert.assertEquals(-1, test(v1, 1, v1.length - 1, v3, 0, v3.length, 10));
+    }
+
+    @Test(expected = ArrayIndexOutOfBoundsException.class)
+    public void run4() throws Throwable {
+        Assert.assertEquals(-1, test(v1, 1, v1.length, v3, 0, v3.length, 10));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/loop/LoopParseLong.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.jtt.loop;
+
+import org.junit.*;
+
+public class LoopParseLong {
+
+    public static long test(String s, int radix) throws NumberFormatException {
+        if (s == null) {
+            throw new NumberFormatException("null");
+        }
+        if (radix < Character.MIN_RADIX) {
+            throw new NumberFormatException("radix " + radix + " less than Character.MIN_RADIX");
+        }
+        if (radix > Character.MAX_RADIX) {
+            throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX");
+        }
+        long result = 0;
+        boolean negative = false;
+        int i = 0;
+        int len = s.length();
+        long limit = -Long.MAX_VALUE;
+        long multmin;
+        int digit;
+        if (len > 0) {
+            char firstChar = s.charAt(0);
+            if (firstChar < '0') {
+                if (firstChar == '-') {
+                    negative = true;
+                    limit = Long.MIN_VALUE;
+                } else if (firstChar != '+') {
+                    throw new NumberFormatException();
+                }
+                if (len == 1) {
+                    throw new NumberFormatException();
+                }
+                i++;
+            }
+            multmin = limit / radix;
+            while (i < len) {
+                digit = Character.digit(s.charAt(i++), radix);
+                if (digit < 0) {
+                    throw new NumberFormatException();
+                }
+                if (result < multmin) {
+                    throw new NumberFormatException();
+                }
+                result *= radix;
+                if (result < limit + digit) {
+                    throw new NumberFormatException();
+                }
+                result -= digit;
+            }
+        } else {
+            throw new NumberFormatException();
+        }
+        return negative ? result : -result;
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        Assert.assertEquals(Character.digit('7', 10), test("7", 10));
+        Assert.assertEquals(-100, test("-100", 10));
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Fri Apr 20 13:44:06 2012 +0200
@@ -510,7 +510,7 @@
         masm.bind(slowPath.continuation);
     }
 
-    private static class ConvertSlowPath extends AMD64SlowPath {
+    private static class ConvertSlowPath extends AMD64Code {
         public final Label start = new Label();
         public final Label continuation = new Label();
         private final CiValue result;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Code.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method.
+ */
+public abstract class AMD64Code implements LIR.Code {
+    @Override
+    public final void emitCode(TargetMethodAssembler tasm) {
+        emitCode(tasm, (AMD64MacroAssembler) tasm.asm);
+    }
+
+    public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm);
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri Apr 20 13:44:06 2012 +0200
@@ -46,6 +46,9 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+            if (tasm.frameContext != null) {
+                tasm.frameContext.leave(tasm);
+            }
             masm.ret(0);
         }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SlowPath.java	Fri Apr 13 15:52:25 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.amd64;
-
-import com.oracle.max.asm.target.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method.
- */
-public abstract class AMD64SlowPath implements LIR.SlowPath {
-    @Override
-    public final void emitCode(TargetMethodAssembler tasm) {
-        emitCode(tasm, (AMD64MacroAssembler) tasm.asm);
-    }
-
-    public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FrameMap.java	Fri Apr 20 13:44:06 2012 +0200
@@ -85,6 +85,12 @@
     public final RiRegisterConfig registerConfig;
 
     /**
+     * The initial frame size, not including the size of the return address.
+     * This is the constant space reserved by the runtime for all compiled methods.
+     */
+    public final int initialFrameSize;
+
+    /**
      * The final frame size, not including the size of the return address.
      * The value is only set after register allocation is complete, i.e., after all spill slots have been allocated.
      */
@@ -112,6 +118,11 @@
     private final CiStackSlot customArea;
 
     /**
+     * Records whether an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}.
+     */
+    private boolean accessesCallerFrame;
+
+    /**
      * Creates a new frame map for the specified method.
      */
     public FrameMap(RiRuntime runtime, CiTarget target, RiRegisterConfig registerConfig) {
@@ -123,9 +134,9 @@
         this.outgoingSize = runtime.getMinimumOutgoingSize();
         this.objectStackBlocks = new ArrayList<>();
         this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false);
+        this.initialFrameSize = currentFrameSize();
     }
 
-
     private int returnAddressSize() {
         return target.arch.returnAddressSize;
     }
@@ -136,6 +147,13 @@
     }
 
     /**
+     * Determines if an offset to an incoming stack argument was ever returned by {@link #offsetForStackSlot(CiStackSlot)}.
+     */
+    public boolean accessesCallerFrame() {
+        return accessesCallerFrame;
+    }
+
+    /**
      * Gets the frame size of the compiled frame, not including the size of the return address.
      * @return The size of the frame (in bytes).
      */
@@ -153,20 +171,20 @@
     }
 
     /**
-     * Sets the frame size for this frame.
-     * @param frameSize The frame size (in bytes).
+     * Gets the current size of this frame. This is the size that would be returned by
+     * {@link #frameSize()} if {@link #finish()} were called now.
      */
-    public void setFrameSize(int frameSize) {
-        assert this.frameSize == -1 : "must only be set once";
-        this.frameSize = frameSize;
+    public int currentFrameSize() {
+        return target.alignFrameSize(outgoingSize + spillSize - returnAddressSize());
     }
 
     /**
-     * Computes the frame size for this frame. After this method has been called, methods that change the
+     * Computes the final size of this frame. After this method has been called, methods that change the
      * frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can be requested.
      */
     public void finish() {
-        setFrameSize(target.alignFrameSize(outgoingSize + spillSize - returnAddressSize()));
+        assert this.frameSize == -1 : "must only be set once";
+        frameSize = currentFrameSize();
     }
 
     /**
@@ -180,6 +198,9 @@
         assert (!slot.rawAddFrameSize() && slot.rawOffset() < outgoingSize) ||
             (slot.rawAddFrameSize() && slot.rawOffset() < 0 && -slot.rawOffset() <= spillSize) ||
             (slot.rawAddFrameSize() && slot.rawOffset() >= 0);
+        if (slot.inCallerFrame()) {
+            accessesCallerFrame = true;
+        }
         return slot.offset(totalFrameSize());
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Fri Apr 20 13:44:06 2012 +0200
@@ -42,7 +42,7 @@
      * The nodes for the blocks.
      * TODO: This should go away, we want all nodes connected with a next-pointer.
      */
-    private final BlockMap<List<Node>> nodesFor;
+    private final BlockMap<List<Node>> blockToNodesMap;
 
     /**
      * The linear-scan ordered list of blocks.
@@ -54,15 +54,9 @@
      */
     private final List<Block> codeEmittingOrder;
 
-
-    public final List<SlowPath> slowPaths;
-
-    public final List<SlowPath> deoptimizationStubs;
+    public final List<Code> slowPaths;
 
-    /**
-     * The last slow path emitted, which can be used emit marker bytes.
-     */
-    public SlowPath methodEndMarker;
+    public final List<Code> deoptimizationStubs;
 
     private int numVariables;
 
@@ -73,7 +67,12 @@
         LIRInstruction createExchange(CiValue input1, CiValue input2);
     }
 
-    public interface SlowPath {
+    private boolean hasArgInCallerFrame;
+
+    /**
+     * An opaque chunk of machine code.
+     */
+    public interface Code {
         void emitCode(TargetMethodAssembler tasm);
     }
 
@@ -82,9 +81,9 @@
      * @param numLoops number of loops
      * @param compilation the compilation
      */
-    public LIR(ControlFlowGraph cfg, BlockMap<List<Node>> nodesFor, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
+    public LIR(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, List<Block> linearScanOrder, List<Block> codeEmittingOrder) {
         this.cfg = cfg;
-        this.nodesFor = nodesFor;
+        this.blockToNodesMap = blockToNodesMap;
         this.codeEmittingOrder = codeEmittingOrder;
         this.linearScanOrder = linearScanOrder;
 
@@ -92,8 +91,25 @@
         deoptimizationStubs = new ArrayList<>();
     }
 
+    /**
+     * Gets the nodes in a given block.
+     */
     public List<Node> nodesFor(Block block) {
-        return nodesFor.get(block);
+        return blockToNodesMap.get(block);
+    }
+
+    /**
+     * Determines if any instruction in the LIR has any debug info associated with it.
+     */
+    public boolean hasDebugInfo() {
+        for (Block b : linearScanOrder()) {
+            for (LIRInstruction op : b.lir) {
+                if (op.info != null) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
     /**
@@ -117,20 +133,25 @@
     }
 
     public void emitCode(TargetMethodAssembler tasm) {
+        if (tasm.frameContext != null) {
+            tasm.frameContext.enter(tasm);
+        }
+
         for (Block b : codeEmittingOrder()) {
             emitBlock(tasm, b);
         }
 
         // generate code for slow cases
-        for (SlowPath sp : slowPaths) {
+        for (Code sp : slowPaths) {
+            emitSlowPath(tasm, sp);
+        }
+        for (Code sp : tasm.slowPaths) {
             emitSlowPath(tasm, sp);
         }
         // generate deoptimization stubs
-        for (SlowPath sp : deoptimizationStubs) {
+        for (Code sp : deoptimizationStubs) {
             emitSlowPath(tasm, sp);
         }
-        // generate traps at the end of the method
-        emitSlowPath(tasm, methodEndMarker);
     }
 
     private static void emitBlock(TargetMethodAssembler tasm, Block block) {
@@ -161,13 +182,25 @@
         }
     }
 
-    private static void emitSlowPath(TargetMethodAssembler tasm, SlowPath sp) {
+    private static void emitSlowPath(TargetMethodAssembler tasm, Code sp) {
         if (Debug.isDumpEnabled()) {
             tasm.blockComment(String.format("slow case %s", sp.getClass().getName()));
         }
         sp.emitCode(tasm);
     }
 
+    public void setHasArgInCallerFrame() {
+        hasArgInCallerFrame = true;
+    }
+
+    /**
+     * Determines if any of the parameters to the method are passed via the stack
+     * where the parameters are located in the caller's frame.
+     */
+    public boolean hasArgInCallerFrame() {
+        return hasArgInCallerFrame;
+    }
+
 /*
     private int lastDecodeStart;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/FrameContext.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.asm;
+
+
+/**
+ * Code for managing a method's native frame.
+ */
+public interface FrameContext {
+    /**
+     * Emits code common to all entry points of a method. This may include:
+     * <ul>
+     * <li>setting up the stack frame</li>
+     * <li>saving callee-saved registers</li>
+     * <li>stack overflow checking</li>
+     * </ul>
+     */
+    void enter(TargetMethodAssembler tasm);
+
+    /**
+     * Emits code to be executed just prior to returning from a method. This may include:
+     * <ul>
+     * <li>restoring callee-saved registers</li>
+     * <li>performing a safepoint</li>
+     * <li>destroying the stack frame</li>
+     * </ul>
+     */
+    void leave(TargetMethodAssembler tasm);
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -51,18 +51,25 @@
     public final CiTarget target;
     public final RiRuntime runtime;
     public final FrameMap frameMap;
-    public final List<SlowPath> slowPaths;
+    public final List<Code> slowPaths;
+
+    /**
+     * The object that emits code for managing a method's frame.
+     * If null, no frame is used by the method.
+     */
+    public final FrameContext frameContext;
 
     private List<ExceptionInfo> exceptionInfoList;
     private int lastSafepointPos;
 
-    public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, List<SlowPath> slowPaths, AbstractAssembler asm) {
+    public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, AbstractAssembler asm, FrameContext frameContext) {
         this.target = target;
         this.runtime = runtime;
         this.frameMap = frameMap;
-        this.slowPaths = slowPaths;
+        this.slowPaths = new ArrayList<>();
         this.asm = asm;
         this.targetMethod = new CiTargetMethod();
+        this.frameContext = frameContext;
         // 0 is a valid pc for safepoints in template methods
         this.lastSafepointPos = -1;
     }
@@ -71,6 +78,10 @@
         targetMethod.setFrameSize(frameSize);
     }
 
+    public CiTargetMethod.Mark recordMark(Object id) {
+        return targetMethod.recordMark(asm.codeBuffer.position(), id, null);
+    }
+
     public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) {
         return targetMethod.recordMark(asm.codeBuffer.position(), id, references);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java	Fri Apr 20 13:44:06 2012 +0200
@@ -46,7 +46,7 @@
                 assert dominated.getDominator() == block;
             }
 
-            assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block;
+            assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block : block.beginNode;
         }
 
         if (cfg.getLoops() != null) {
@@ -58,8 +58,16 @@
 
                     Loop blockLoop = block.getLoop();
                     while (blockLoop != loop) {
+                        assert blockLoop != null;
                         blockLoop = blockLoop.parent;
-                        assert blockLoop != null;
+                    }
+
+                    if (!(block.isLoopHeader() && block.getLoop() == loop)) {
+                        for (Block pred : block.getPredecessors()) {
+                            if (!loop.blocks.contains(pred)) {
+                                return false;
+                            }
+                        }
                     }
                 }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/ControlFlowGraph.java	Fri Apr 20 13:44:06 2012 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
@@ -201,26 +202,51 @@
                 Loop loop = new Loop(block.getLoop(), loopsList.size(), block);
                 loopsList.add(loop);
 
-                for (LoopEndNode end : ((LoopBeginNode) beginNode).loopEnds()) {
+                LoopBeginNode loopBegin = (LoopBeginNode) beginNode;
+                for (LoopEndNode end : loopBegin.loopEnds()) {
                     Block endBlock = nodeToBlock.get(end);
                     computeLoopBlocks(endBlock, loop);
                 }
+
+                for (LoopExitNode exit : loopBegin.loopExits()) {
+                    Block exitBlock = nodeToBlock.get(exit);
+                    List<Block> predecessors = exitBlock.getPredecessors();
+                    assert predecessors.size() == 1;
+                    computeLoopBlocks(predecessors.get(0), loop);
+                    loop.exits.add(exitBlock);
+                }
+                List<Block> unexpected = new LinkedList<>();
+                for (Block b : loop.blocks) {
+                    for (Block sux : b.getSuccessors()) {
+                        if (sux.loop != loop) {
+                            BeginNode begin = sux.getBeginNode();
+                            if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
+                                Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux);
+                                unexpected.add(sux);
+                            }
+                        }
+                    }
+                }
+                for (Block b : unexpected) {
+                    addBranchToLoop(loop, b);
+                }
             }
         }
         loops = loopsList.toArray(new Loop[loopsList.size()]);
+    }
 
-        for (Loop loop : loops) {
-            for (Block block : loop.blocks) {
-                for (Block sux : block.getSuccessors()) {
-                    if (sux.getLoopDepth() < loop.depth) {
-                        loop.exits.add(sux);
-                    }
-                }
-            }
+    private static void addBranchToLoop(Loop l, Block b) {
+        if (l.blocks.contains(b)) {
+            return;
+        }
+        l.blocks.add(b);
+        b.loop = l;
+        for (Block sux : b.getSuccessors()) {
+            addBranchToLoop(l, sux);
         }
     }
 
-    private void computeLoopBlocks(Block block, Loop loop) {
+    private static void computeLoopBlocks(Block block, Loop loop) {
         if (block.getLoop() == loop) {
             return;
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Loop.java	Fri Apr 20 13:44:06 2012 +0200
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import com.oracle.graal.nodes.*;
+
 public class Loop {
     public final Loop parent;
     public final List<Loop> children;
@@ -53,4 +55,8 @@
     public String toString() {
         return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : "");
     }
+
+    public LoopBeginNode loopBegin() {
+        return (LoopBeginNode) header.getBeginNode();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/GraalRuntime.java	Fri Apr 20 13:44:06 2012 +0200
@@ -24,10 +24,10 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
 
 /**
  * Graal-specific extensions for the runtime interface that must be implemented by the VM.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+
 import java.util.*;
 
 import com.oracle.graal.graph.*;
@@ -59,28 +61,45 @@
             // This begin node is necessary.
         } else {
             // This begin node can be removed and all guards moved up to the preceding begin node.
-            if (!usages().isEmpty()) {
-                Node prevBegin = prev;
-                while (!(prevBegin instanceof BeginNode)) {
-                    prevBegin = prevBegin.predecessor();
-                }
-                for (Node usage : usages()) {
-                    tool.addToWorkList(usage);
-                }
-                replaceAtUsages(prevBegin);
-            }
+            prepareDelete();
             ((StructuredGraph) graph()).removeFixed(this);
         }
     }
 
-    public void evacuateGuards() {
+    public static BeginNode prevBegin(FixedNode from) {
+        Node prevBegin = from;
+        while (prevBegin != null) {
+            if (prevBegin instanceof BeginNode) {
+                return (BeginNode) prevBegin;
+            }
+            prevBegin = prevBegin.predecessor();
+        }
+        return null;
+    }
+
+    public void evacuateGuards(FixedNode evacuateFrom) {
         if (!usages().isEmpty()) {
-            Node prevBegin = predecessor();
+            BeginNode prevBegin = prevBegin(evacuateFrom);
             assert prevBegin != null;
-            while (!(prevBegin instanceof BeginNode)) {
-                prevBegin = prevBegin.predecessor();
+            for (Node anchored : anchored().snapshot()) {
+                anchored.replaceFirstInput(this, prevBegin);
             }
-            replaceAtUsages(prevBegin);
+        }
+    }
+
+    public void prepareDelete() {
+        prepareDelete((FixedNode) predecessor());
+    }
+
+    public void prepareDelete(FixedNode evacuateFrom) {
+        removeProxies();
+        evacuateGuards(evacuateFrom);
+    }
+
+    public void removeProxies() {
+        StructuredGraph graph = (StructuredGraph) graph();
+        for (ValueProxyNode vpn : proxies().snapshot()) {
+            graph.replaceFloating(vpn, vpn.value());
         }
     }
 
@@ -98,4 +117,53 @@
     public NodeIterable<GuardNode> guards() {
         return usages().filter(GuardNode.class);
     }
+
+    public NodeIterable<Node> anchored() {
+        return usages().filter(isNotA(ValueProxyNode.class));
+    }
+
+    public NodeIterable<ValueProxyNode> proxies() {
+        return usages().filter(ValueProxyNode.class);
+    }
+
+    public NodeIterable<FixedNode> getBlockNodes() {
+        return new NodeIterable<FixedNode>() {
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new BlockNodeIterator(BeginNode.this);
+            }
+        };
+    }
+
+    private class BlockNodeIterator implements Iterator<FixedNode> {
+        private FixedNode current;
+
+        public BlockNodeIterator(FixedNode next) {
+            this.current = next;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        @Override
+        public FixedNode next() {
+            FixedNode ret = current;
+            if (ret == null) {
+                throw new NoSuchElementException();
+            }
+            if (!(current instanceof FixedWithNextNode) || (current instanceof BeginNode && current != BeginNode.this)) {
+                current = null;
+            } else {
+                current = ((FixedWithNextNode) current).next();
+            }
+            return ret;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -53,4 +53,9 @@
         return properties;
     }
 
+    @Override
+    public boolean verify() {
+        assertTrue(this.successors().isNotEmpty() || this.predecessor() != null, "FixedNode should not float");
+        return super.verify();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Fri Apr 20 13:44:06 2012 +0200
@@ -161,7 +161,7 @@
     }
 
     public void addVirtualObjectMapping(Node virtualObject) {
-        assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode : virtualObject;
+        assert virtualObject instanceof VirtualObjectFieldNode || virtualObject instanceof PhiNode || virtualObject instanceof ValueProxyNode : virtualObject;
         virtualObjectMappings.add(virtualObject);
     }
 
@@ -184,6 +184,13 @@
         return duplicate(newBci, false);
     }
 
+    /**
+     * Gets a copy of this frame state.
+     */
+    public FrameState duplicate() {
+        return duplicate(bci);
+    }
+
     public FrameState duplicate(int newBci, boolean duplicateOuter) {
         FrameState other = graph().add(new FrameState(method, newBci, localsSize, stackSize, rethrowException, duringCall));
         other.values.setAll(values);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -161,14 +161,16 @@
         EndNode falseEnd = (EndNode) falseSuccessor.next();
         assert trueEnd.merge() == falseEnd.merge();
 
+        FixedWithNextNode pred = (FixedWithNextNode) predecessor();
         MergeNode merge = trueEnd.merge();
+        merge.prepareDelete(pred);
         assert merge.usages().isEmpty();
 
         FixedNode next = merge.next();
         merge.setNext(null);
         setTrueSuccessor(null);
         setFalseSuccessor(null);
-        ((FixedWithNextNode) predecessor()).setNext(next);
+        pred.setNext(next);
         safeDelete();
         trueSuccessor.safeDelete();
         falseSuccessor.safeDelete();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+
 import java.util.*;
 
 import com.oracle.graal.graph.*;
@@ -49,8 +51,17 @@
         return usages().filter(LoopEndNode.class);
     }
 
+    public NodeIterable<LoopExitNode> loopExits() {
+        return usages().filter(LoopExitNode.class);
+    }
+
+    @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(isNotA(LoopEndNode.class).nor(LoopExitNode.class));
+    }
+
     public List<LoopEndNode> orderedLoopEnds() {
-        List<LoopEndNode> snapshot = usages().filter(LoopEndNode.class).snapshot();
+        List<LoopEndNode> snapshot = loopEnds().snapshot();
         Collections.sort(snapshot, new Comparator<LoopEndNode>() {
             @Override
             public int compare(LoopEndNode o1, LoopEndNode o2) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+
+public class LoopExitNode extends BeginNode {
+    @Input(notDataflow = true) private LoopBeginNode loopBegin;
+    public LoopExitNode(LoopBeginNode loop) {
+        assert loop != null;
+        loopBegin = loop;
+    }
+
+    public LoopBeginNode loopBegin() {
+        return loopBegin;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        //
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -115,34 +115,57 @@
     }
 
     public NodeIterable<PhiNode> phis() {
-        return this.usages().filter(new NodePredicate() {
+        return this.usages().filter(PhiNode.class).filter(new NodePredicate() {
             @Override
             public boolean apply(Node n) {
-                return n instanceof PhiNode && ((PhiNode) n).merge() == MergeNode.this;
+                return ((PhiNode) n).merge() == MergeNode.this;
             }
-        }).filter(PhiNode.class);
+        });
+    }
+
+    @Override
+    public NodeIterable<Node> anchored() {
+        return super.anchored().filter(isNotA(PhiNode.class).or(new NodePredicate() {
+            @Override
+            public boolean apply(Node n) {
+                return ((PhiNode) n).merge() != MergeNode.this;
+            }
+        }));
     }
 
     @Override
     public void simplify(SimplifierTool tool) {
         FixedNode next = next();
-        if (next instanceof LoopEndNode) {
-            LoopEndNode origLoopEnd = (LoopEndNode) next;
-            LoopBeginNode begin = origLoopEnd.loopBegin();
+        if (next instanceof EndNode) {
+            EndNode origLoopEnd = (EndNode) next;
+            MergeNode merge = origLoopEnd.merge();
+            if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) {
+                return;
+            }
+            // in order to move anchored values to the other merge we would need to check if the anchors are used by phis of the other merge
+            if (this.anchored().isNotEmpty()) {
+                return;
+            }
             for (PhiNode phi : phis()) {
                 for (Node usage : phi.usages().filter(isNotA(FrameState.class))) {
-                    if (!begin.isPhiAtMerge(usage)) {
+                    if (!merge.isPhiAtMerge(usage)) {
                         return;
                     }
                 }
             }
-            Debug.log("Split %s into loop ends for %s", this, begin);
+            Debug.log("Split %s into ends for %s.", this, merge);
             int numEnds = this.forwardEndCount();
             StructuredGraph graph = (StructuredGraph) graph();
             for (int i = 0; i < numEnds - 1; i++) {
                 EndNode end = forwardEndAt(numEnds - 1 - i);
-                LoopEndNode loopEnd = graph.add(new LoopEndNode(begin));
-                for (PhiNode phi : begin.phis()) {
+                EndNode newEnd;
+                if (merge instanceof LoopBeginNode) {
+                    newEnd = graph.add(new LoopEndNode((LoopBeginNode) merge));
+                } else {
+                    newEnd = graph.add(new EndNode());
+                    merge.addForwardEnd(newEnd);
+                }
+                for (PhiNode phi : merge.phis()) {
                     ValueNode v = phi.valueAt(origLoopEnd);
                     ValueNode newInput;
                     if (isPhiAtMerge(v)) {
@@ -154,9 +177,9 @@
                     phi.addInput(newInput);
                 }
                 this.removeEnd(end);
-                end.replaceAtPredecessors(loopEnd);
+                end.replaceAtPredecessors(newEnd);
                 end.safeDelete();
-                tool.addToWorkList(loopEnd.predecessor());
+                tool.addToWorkList(newEnd.predecessor()); // ?
             }
             graph.reduceTrivialMerge(this);
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -33,22 +33,15 @@
  * and a variable.
  */
 public final class PhiNode extends FloatingNode implements Canonicalizable, Node.IterableNodeType {
-
-    @Input(notDataflow = true) private MergeNode merge;
-
-    @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
-
-    public MergeNode merge() {
-        return merge;
-    }
-
     public static enum PhiType {
         Value, // normal value phis
         Memory, // memory phis
         Virtual // phis used for VirtualObjectField merges
     }
 
-    private final PhiType type;
+    @Input(notDataflow = true) private MergeNode merge;
+    @Input private final NodeInputList<ValueNode> values = new NodeInputList<>(this);
+    @Data private final PhiType type;
 
     public PhiNode(CiKind kind, MergeNode merge, PhiType type) {
         super(StampFactory.forKind(kind));
@@ -60,6 +53,10 @@
         return type;
     }
 
+    public MergeNode merge() {
+        return merge;
+    }
+
     public NodeInputList<ValueNode> values() {
         return values;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri Apr 20 13:44:06 2012 +0200
@@ -168,6 +168,9 @@
 
     public void removeFixed(FixedWithNextNode node) {
         assert node != null;
+        if (node instanceof BeginNode) {
+            ((BeginNode) node).prepareDelete();
+        }
         assert node.usages().isEmpty() : node + " " + node.usages();
         FixedNode next = node.next();
         node.setNext(null);
@@ -208,15 +211,11 @@
         assert node.usages().isEmpty();
         assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
         BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        begin.evacuateGuards();
-        FixedNode next = begin.next();
-        begin.setNext(null);
         for (int i = 0; i < node.blockSuccessorCount(); i++) {
             node.setBlockSuccessor(i, null);
         }
-        node.replaceAtPredecessors(next);
+        node.replaceAtPredecessors(begin);
         node.safeDelete();
-        begin.safeDelete();
     }
 
     public void removeSplitPropagate(ControlSplitNode node, int survivingSuccessor) {
@@ -224,9 +223,6 @@
         assert node.usages().isEmpty();
         assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
         BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        begin.evacuateGuards();
-        FixedNode next = begin.next();
-        begin.setNext(null);
         for (int i = 0; i < node.blockSuccessorCount(); i++) {
             BeginNode successor = node.blockSuccessor(i);
             node.setBlockSuccessor(i, null);
@@ -234,10 +230,9 @@
                 GraphUtil.killCFG(successor);
             }
         }
-        if (next.isAlive()) {
-            node.replaceAtPredecessors(next);
+        if (begin.isAlive()) {
+            node.replaceAtPredecessors(begin);
             node.safeDelete();
-            begin.safeDelete();
         } else {
             assert node.isDeleted();
         }
@@ -257,31 +252,23 @@
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
         BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        begin.evacuateGuards();
-        FixedNode next = begin.next();
-        begin.setNext(null);
         for (int i = 0; i < node.blockSuccessorCount(); i++) {
             node.setBlockSuccessor(i, null);
         }
-        replacement.setNext(next);
+        replacement.setNext(begin);
         node.replaceAndDelete(replacement);
-        begin.safeDelete();
     }
 
     public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, int survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor >= 0 && survivingSuccessor < node.blockSuccessorCount() : "invalid surviving successor " + survivingSuccessor + " for " + node;
         BeginNode begin = node.blockSuccessor(survivingSuccessor);
-        begin.evacuateGuards();
-        FixedNode next = begin.next();
-        begin.setNext(null);
         for (int i = 0; i < node.blockSuccessorCount(); i++) {
             node.setBlockSuccessor(i, null);
         }
-        node.replaceAtPredecessors(next);
+        node.replaceAtPredecessors(begin);
         node.replaceAtUsages(replacement);
         node.safeDelete();
-        begin.safeDelete();
     }
 
     public void addAfterFixed(FixedWithNextNode node, FixedWithNextNode newNode) {
@@ -325,14 +312,15 @@
         EndNode singleEnd = merge.forwardEndAt(0);
         FixedNode sux = merge.next();
         FrameState stateAfter = merge.stateAfter();
+        // remove loop exits
+        if (merge instanceof LoopBeginNode) {
+            for (LoopExitNode exit : ((LoopBeginNode) merge).loopExits().snapshot()) {
+                exit.removeProxies();
+                replaceFixedWithFixed(exit, this.add(new BeginNode()));
+            }
+        }
         // evacuateGuards
-        Node prevBegin = singleEnd.predecessor();
-        assert prevBegin != null;
-        while (!(prevBegin instanceof BeginNode)) {
-            prevBegin = prevBegin.predecessor();
-        }
-        merge.replaceAtUsages(prevBegin);
-
+        merge.prepareDelete((FixedNode) singleEnd.predecessor());
         merge.safeDelete();
         if (stateAfter != null && stateAfter.usages().isEmpty()) {
             stateAfter.safeDelete();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.Node.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.calc.*;
+
+
+
+public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable {
+    @Input(notDataflow = true) private BeginNode proxyPoint;
+    @Input private ValueNode value;
+    @Data private final PhiType type;
+
+    public ValueProxyNode(ValueNode value, BeginNode exit, PhiType type) {
+        super(value.stamp());
+        this.type = type;
+        assert exit != null;
+        this.proxyPoint = exit;
+        this.value = value;
+    }
+
+    public ValueNode value() {
+        return value;
+    }
+
+    public BeginNode proxyPoint() {
+        return proxyPoint;
+    }
+
+    public PhiType type() {
+        return type;
+    }
+
+    @Override
+    public boolean verify() {
+        assert value != null;
+        assert proxyPoint != null;
+        return super.verify();
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -52,7 +52,7 @@
                 return x();
             }
             if (c == 0) {
-                return ConstantNode.forInt(0, graph());
+                return ConstantNode.defaultForKind(kind(), graph());
             }
             if (c > 0 && CiUtil.isPowerOf2(c)) {
                 return graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(CiUtil.log2(c), graph())));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -50,10 +50,6 @@
         return offset;
     }
 
-    public UnsafeLoadNode(ValueNode object, ValueNode offset, CiKind kind) {
-        this(object, 0, offset, kind);
-    }
-
     public UnsafeLoadNode(ValueNode object, int displacement, ValueNode offset, CiKind kind) {
         super(StampFactory.forKind(kind.stackKind()));
         this.object = object;
@@ -73,7 +69,7 @@
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static <T> T load(Object object, long offset, @ConstantNodeParameter CiKind kind) {
+    public static <T> T load(Object object, @ConstantNodeParameter int displacement, long offset, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
 
 /**
  * Store of a value at a location specified as an offset relative to an object.
@@ -39,10 +39,6 @@
     @Data private final int displacement;
     @Data private final CiKind storeKind;
 
-    public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, CiKind kind) {
-        this(object, 0, offset, value, kind);
-    }
-
     public UnsafeStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value, CiKind kind) {
         super(StampFactory.illegal());
         assert kind != CiKind.Void && kind != CiKind.Illegal;
@@ -81,55 +77,56 @@
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, Object value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, Object value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, boolean value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, boolean value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, byte value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, byte value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, char value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, char value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, double value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, double value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, float value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, float value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, int value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, int value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, long value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, long value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static void store(Object object, long offset, short value, @ConstantNodeParameter CiKind kind) {
+    public static void store(Object object, @ConstantNodeParameter int displacement, long offset, short value, @ConstantNodeParameter CiKind kind) {
         throw new UnsupportedOperationException();
     }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -36,6 +36,8 @@
 
     @Input private ValueNode index;
     @Input private ValueNode length;
+    @Data private final CiKind elementType;
+    private final long leafGraphId;
 
     public ValueNode index() {
         return index;
@@ -45,9 +47,6 @@
         return length;
     }
 
-    private final CiKind elementType;
-    private final long leafGraphId;
-
     /**
      * Create an new AccessIndexedNode.
      * @param kind the result kind of the access
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -39,7 +39,7 @@
  */
 public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable {
 
-    @Input protected final FixedNode anchor;
+    @Input(notDataflow = true) protected final FixedNode anchor;
     @Data  protected final boolean emitCode;
 
     public FixedNode anchor() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
 
 /**
  * Represents an atomic compare-and-swap operation
@@ -39,6 +39,7 @@
     @Input private ValueNode offset;
     @Input private ValueNode expected;
     @Input private ValueNode newValue;
+    @Data private final int displacement;
 
     public ValueNode object() {
         return object;
@@ -56,13 +57,18 @@
         return newValue;
     }
 
-    public CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue) {
+    public int displacement() {
+        return displacement;
+    }
+
+    public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) {
         super(StampFactory.forKind(CiKind.Boolean.stackKind()));
         assert expected.kind() == newValue.kind();
         this.object = object;
         this.offset = offset;
         this.expected = expected;
         this.newValue = newValue;
+        this.displacement = displacement;
     }
 
     @Override
@@ -78,19 +84,19 @@
     // specialized on value type until boxing/unboxing is sorted out in intrinsification
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, Object expected, Object newValue) {
+    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, Object expected, Object newValue) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, long expected, long newValue) {
+    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, long expected, long newValue) {
         throw new UnsupportedOperationException();
     }
 
     @SuppressWarnings("unused")
     @NodeIntrinsic
-    public static boolean compareAndSwap(Object object, long offset, int expected, int newValue) {
+    public static boolean compareAndSwap(Object object, @ConstantNodeParameter int displacement, long offset, int expected, int newValue) {
         throw new UnsupportedOperationException();
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -22,16 +22,16 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
 
 /**
  * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler.
  */
-public final class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint {
+public class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint {
 
     /**
      * Constructs a new ExceptionObject instruction.
@@ -44,4 +44,10 @@
     public void generate(LIRGeneratorTool gen) {
         gen.visitExceptionObject(this);
     }
+
+    @Override
+    public boolean verify() {
+        assertTrue(stateAfter() != null, "an exception handler needs a frame state");
+        return super.verify();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.types.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * The {@code NewArrayNode} class is the base of all instructions that allocate arrays.
@@ -130,7 +131,7 @@
         public int updateState(Node node, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState) {
             if (current instanceof AccessIndexedNode) {
                 AccessIndexedNode x = (AccessIndexedNode) current;
-                if (x.array() == node) {
+                if (GraphUtil.unProxify(x.array()) == node) {
                     int index = ((AccessIndexedNode) current).index().asConstant().asInt();
                     if (current instanceof LoadIndexedNode) {
                         x.replaceAtUsages(fieldState[index]);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -29,6 +29,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * The {@code NewInstanceNode} represents the allocation of an instance class object.
@@ -110,7 +111,7 @@
         public int updateState(Node node, Node current, Map<Object, Integer> fieldIndex, ValueNode[] fieldState) {
             if (current instanceof AccessFieldNode) {
                 AccessFieldNode x = (AccessFieldNode) current;
-                if (x.object() == node) {
+                if (GraphUtil.unProxify(x.object()) == node) {
                     int field = fieldIndex.get(x.field());
                     StructuredGraph graph = (StructuredGraph) x.graph();
                     if (current instanceof LoadFieldNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Fri Apr 20 13:44:06 2012 +0200
@@ -81,6 +81,13 @@
         } else if (usage instanceof ArrayLengthNode) {
             assert ((ArrayLengthNode) usage).array() == node;
             return false;
+        } else if (usage instanceof ValueProxyNode) {
+            for (Node vpnUsage : usage.usages().snapshot()) {
+                if (escape(usage, vpnUsage)) {
+                    return true;
+                }
+            }
+            return false;
         } else {
             return true;
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Fri Apr 20 13:44:06 2012 +0200
@@ -98,14 +98,11 @@
     public abstract void visitEndNode(EndNode i);
     public abstract void visitLoopEnd(LoopEndNode i);
 
-    // The CompareAndSwapNode in its current form needs to be lowered to several Nodes before code generation to separate three parts:
-    // * The write barriers (and possibly read barriers) when accessing an object field
-    // * The distinction of returning a boolean value (semantic similar to a BooleanNode to be used as a condition?) or the old value being read
-    // * The actual compare-and-swap
     public abstract void visitCompareAndSwap(CompareAndSwapNode i);
 
     // Functionality that is currently implemented in XIR.
-    // These methods will go away eventually when lowering is done via snippets in the front end.
+    // Some of these methods will go away when lowering is done via snippets in the front end.
+    // The remainder will define the contract a runtime specific backend must provide.
     public abstract void visitCheckCast(CheckCastNode i);
     public abstract void visitMonitorEnter(MonitorEnterNode i);
     public abstract void visitMonitorExit(MonitorExitNode i);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Apr 20 13:44:06 2012 +0200
@@ -27,8 +27,10 @@
 import java.util.*;
 
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.virtual.*;
 
 public class GraphUtil {
 
@@ -40,7 +42,11 @@
             killEnd(end);
         } else {
             // Normal control flow node.
-            for (Node successor : node.successors().snapshot()) {
+            /* We do not take a successor snapshot because this iterator supports concurrent modifications
+             * as long as they do not change the size of the successor list. Not tasking a snapshot allows
+             * us to see modifications to other branches that may happen while processing one branch.
+             */
+            for (Node successor : node.successors()) {
                 killCFG((FixedNode) successor);
             }
         }
@@ -50,28 +56,39 @@
     private static void killEnd(EndNode end) {
         MergeNode merge = end.merge();
         merge.removeEnd(end);
+        StructuredGraph graph = (StructuredGraph) end.graph();
         if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { //dead loop
             for (PhiNode phi : merge.phis().snapshot()) {
                 propagateKill(phi);
             }
             LoopBeginNode begin = (LoopBeginNode) merge;
-            // disconnect and delete loop ends
+            // disconnect and delete loop ends & loop exits
             for (LoopEndNode loopend : begin.loopEnds().snapshot()) {
                 loopend.predecessor().replaceFirstSuccessor(loopend, null);
                 loopend.safeDelete();
             }
+            for (LoopExitNode loopexit : begin.loopExits().snapshot()) {
+                for (ValueProxyNode vpn : loopexit.proxies().snapshot()) {
+                    graph.replaceFloating(vpn, vpn.value());
+                }
+                graph.replaceFixedWithFixed(loopexit, graph.add(new BeginNode()));
+            }
             killCFG(begin.next());
             begin.safeDelete();
         } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { // not a loop anymore
-            ((StructuredGraph) end.graph()).reduceDegenerateLoopBegin((LoopBeginNode) merge);
+            graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
         } else if (merge.phiPredecessorCount() == 1) { // not a merge anymore
-            ((StructuredGraph) end.graph()).reduceTrivialMerge(merge);
+            graph.reduceTrivialMerge(merge);
         }
     }
 
+    public static NodePredicate isFloatingNode() {
+        return isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class).or(VirtualObjectFieldNode.class).or(VirtualObjectNode.class);
+    }
+
     public static void propagateKill(Node node) {
         if (node != null && node.isAlive()) {
-            List<Node> usagesSnapshot = node.usages().filter(isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class)).snapshot();
+            List<Node> usagesSnapshot = node.usages().filter(isFloatingNode()).snapshot();
 
             // null out remaining usages
             node.replaceAtUsages(null);
@@ -91,7 +108,7 @@
     }
 
     public static void killUnusedFloatingInputs(Node node) {
-        List<Node> floatingInputs = node.inputs().filter(isA(FloatingNode.class).or(CallTargetNode.class).or(FrameState.class)).snapshot();
+        List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
         node.safeDelete();
 
         for (Node in : floatingInputs) {
@@ -100,4 +117,70 @@
             }
         }
     }
+
+    public static void checkRedundantPhi(PhiNode phiNode) {
+        if (phiNode.isDeleted() || phiNode.valueCount() == 1) {
+            return;
+        }
+
+        ValueNode singleValue = phiNode.singleValue();
+        if (singleValue != null) {
+            Collection<PhiNode> phiUsages = phiNode.usages().filter(PhiNode.class).snapshot();
+            Collection<ValueProxyNode> proxyUsages = phiNode.usages().filter(ValueProxyNode.class).snapshot();
+            ((StructuredGraph) phiNode.graph()).replaceFloating(phiNode, singleValue);
+            for (PhiNode phi : phiUsages) {
+                checkRedundantPhi(phi);
+            }
+            for (ValueProxyNode proxy : proxyUsages) {
+                checkRedundantProxy(proxy);
+            }
+        }
+    }
+
+    public static void checkRedundantProxy(ValueProxyNode vpn) {
+        BeginNode proxyPoint = vpn.proxyPoint();
+        if (proxyPoint instanceof LoopExitNode) {
+            LoopExitNode exit = (LoopExitNode) proxyPoint;
+            LoopBeginNode loopBegin = exit.loopBegin();
+            ValueNode vpnValue = vpn.value();
+            for (ValueNode v : loopBegin.stateAfter().values()) {
+                ValueNode v2 = v;
+                if (loopBegin.isPhiAtMerge(v2)) {
+                    v2 = ((PhiNode) v2).valueAt(loopBegin.forwardEnd());
+                }
+                if (vpnValue == v2) {
+                    Collection<PhiNode> phiUsages = vpn.usages().filter(PhiNode.class).snapshot();
+                    Collection<ValueProxyNode> proxyUsages = vpn.usages().filter(ValueProxyNode.class).snapshot();
+                    ((StructuredGraph) vpn.graph()).replaceFloating(vpn, vpnValue);
+                    for (PhiNode phi : phiUsages) {
+                        checkRedundantPhi(phi);
+                    }
+                    for (ValueProxyNode proxy : proxyUsages) {
+                        checkRedundantProxy(proxy);
+                    }
+                    return;
+                }
+            }
+        }
+    }
+
+    public static void normalizeLoopBegin(LoopBeginNode begin) {
+        // Delete unnecessary loop phi functions, i.e., phi functions where all inputs are either the same or the phi itself.
+        for (PhiNode phi : begin.phis().snapshot()) {
+            GraphUtil.checkRedundantPhi(phi);
+        }
+        for (LoopExitNode exit : begin.loopExits()) {
+            for (ValueProxyNode vpn : exit.proxies().snapshot()) {
+                GraphUtil.checkRedundantProxy(vpn);
+            }
+        }
+    }
+
+    public static ValueNode unProxify(ValueNode proxy) {
+        ValueNode v = proxy;
+        while (v instanceof ValueProxyNode) {
+            v = ((ValueProxyNode) v).value();
+        }
+        return v;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectFieldNode.java	Fri Apr 20 13:44:06 2012 +0200
@@ -66,6 +66,13 @@
     }
 
     @Override
+    public boolean verify() {
+        assertTrue(object != null, "No object");
+        assertTrue(input != null, "No input");
+        return super.verify();
+    }
+
+    @Override
     public Map<Object, Object> getDebugProperties() {
         Map<Object, Object> properties = super.getDebugProperties();
         properties.put("index", index);
@@ -74,7 +81,7 @@
 
     @Override
     public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name && object().fields() != null) {
+        if (verbosity == Verbosity.Name && object() != null && object().fields() != null) {
             return super.toString(Verbosity.Name) + " " + object().fields()[index].name();
         } else {
             return super.toString(verbosity);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri Apr 20 13:44:06 2012 +0200
@@ -109,7 +109,7 @@
             cfgPrinter.printCFG(message, Arrays.asList(cfgPrinter.cfg.getBlocks()));
 
         } else if (object instanceof CiTargetMethod) {
-            cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), null);
+            cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), message);
 
         } else if (object instanceof Interval[]) {
             cfgPrinter.printIntervals(message, (Interval[]) object);
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/NodeClassSnippets.java	Fri Apr 20 13:44:06 2012 +0200
@@ -35,19 +35,19 @@
 
 
     private static Node getNode(Node node, long offset) {
-        return UnsafeCastNode.cast(UnsafeLoadNode.load(node, offset, CiKind.Object), Node.class);
+        return UnsafeCastNode.cast(UnsafeLoadNode.load(node, 0, offset, CiKind.Object), Node.class);
     }
 
     private static NodeList<Node> getNodeList(Node node, long offset) {
-        return UnsafeCastNode.cast(UnsafeLoadNode.load(node, offset, CiKind.Object), NodeList.class);
+        return UnsafeCastNode.cast(UnsafeLoadNode.load(node, 0, offset, CiKind.Object), NodeList.class);
     }
 
     private static void putNode(Node node, long offset, Node value) {
-        UnsafeStoreNode.store(node, offset, value, CiKind.Object);
+        UnsafeStoreNode.store(node, 0, offset, value, CiKind.Object);
     }
 
     private static void putNodeList(Node node, long offset, NodeList value) {
-        UnsafeStoreNode.store(node, offset, value, CiKind.Object);
+        UnsafeStoreNode.store(node, 0, offset, value, CiKind.Object);
     }
 
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/nodes/ArrayHeaderSizeNode.java	Fri Apr 13 15:52:25 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.snippets.nodes;
-
-import com.oracle.max.cri.ci.*;
-import com.oracle.graal.cri.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class ArrayHeaderSizeNode extends FloatingNode implements Lowerable {
-    @Data private final CiKind elementKind;
-
-    public ArrayHeaderSizeNode(CiKind elementKind) {
-        super(StampFactory.forKind(CiKind.Long));
-        this.elementKind = elementKind;
-    }
-
-    @Override
-    public void lower(CiLoweringTool tool) {
-        tool.getRuntime().lower(this, tool);
-    }
-
-    public CiKind elementKind() {
-        return elementKind;
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static long sizeFor(@ConstantNodeParameter CiKind kind) {
-        throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
-    }
-}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Fri Apr 20 13:44:06 2012 +0200
@@ -46,6 +46,11 @@
         return arg1 + " " + arg2 + " " + arg3;
     }
 
+    Object f1;
+    public Object testMethodVirtual(Object arg1, Object arg2, Object arg3) {
+        return f1 + " " + arg1 + " " + arg2 + " " + arg3;
+    }
+
     @Test
     public void test1() {
         Method method = getMethod("testMethod");
@@ -71,7 +76,37 @@
         } catch (MethodInvalidatedException t) {
             Assert.fail("method invalidated");
         }
+    }
 
+    @Test
+    public void test3() {
+        Method method = getMethod("testMethod");
+        final StructuredGraph graph = parse(method);
+        final RiResolvedMethod riMethod = runtime.getRiMethod(method);
+        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
+        RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        try {
+            Object result = compiledMethod.executeVarargs("1", "2", "3");
+            Assert.assertEquals("1 2 3", result);
+        } catch (MethodInvalidatedException t) {
+            Assert.fail("method invalidated");
+        }
+    }
+
+    @Test
+    public void test4() {
+        Method method = getMethod("testMethodVirtual");
+        final StructuredGraph graph = parse(method);
+        final RiResolvedMethod riMethod = runtime.getRiMethod(method);
+        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
+        RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        try {
+            f1 = "0";
+            Object result = compiledMethod.executeVarargs(this, "1", "2", "3");
+            Assert.assertEquals("0 1 2 3", result);
+        } catch (MethodInvalidatedException t) {
+            Assert.fail("method invalidated");
+        }
     }
 
     @Test
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Fri Apr 20 13:44:06 2012 +0200
@@ -226,7 +226,7 @@
                 System.out.print(succ + " ");
             }
             System.out.println();
-            for (Node node : schedule.getNodesFor().get(block)) {
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
                 System.out.println("  " + node + "    (" + node.usages().size() + ")");
             }
         }
--- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -54,6 +54,14 @@
 
     protected abstract void patchJumpTarget(int branch, int jumpTarget);
 
+    /**
+     * Emits instruction(s) that access an address specified by a given displacement from the stack pointer
+     * in the direction that the stack grows (which is down on most architectures).
+     *
+     * @param disp the displacement from the stack pointer at which the stack should be accessed
+     */
+    public abstract void bangStack(int disp);
+
     protected final void emitByte(int x) {
         codeBuffer.emitByte(x);
     }
--- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -2985,4 +2985,9 @@
     public void fstp(int i) {
         emitx87(0xDD, 0xD8, i);
     }
+
+    @Override
+    public void bangStack(int disp) {
+        movq(new CiAddress(target.wordKind, AMD64.RSP, -disp), AMD64.rax);
+    }
 }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiUtil.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiUtil.java	Fri Apr 20 13:44:06 2012 +0200
@@ -410,14 +410,6 @@
     }
 
     /**
-     * Gets a stack trace element for a given method and bytecode index.
-     */
-    public static StackTraceElement toStackTraceElement(RiMethod method, @SuppressWarnings("unused") int bci) {
-        // TODO (thomaswue): Look if we can use bci to get the line number.
-        return new StackTraceElement(CiUtil.toJavaName(method.holder()), method.name(), null, -1);
-    }
-
-    /**
      * Converts a Java source-language class name into the internal form.
      *
      * @param className the class name
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiCompiledMethod.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiCompiledMethod.java	Fri Apr 20 13:44:06 2012 +0200
@@ -44,4 +44,6 @@
     boolean isValid();
 
     Object execute(Object arg1, Object arg2, Object arg3);
+
+    Object executeVarargs(Object... args);
 }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/CiXirAssembler.java	Fri Apr 20 13:44:06 2012 +0200
@@ -553,26 +553,6 @@
          */
         Safepoint,
         /**
-         * Align the code following this instruction to a multiple of (int)extra.
-         */
-        Align,
-        /**
-         * Creates the stack banging overflow check.
-         */
-        StackOverflowCheck,
-        /**
-         * Creates the stack frame for the method and spills callee-save registers (if any) to the {@linkplain CiRegisterSaveArea register save area}.
-         */
-        PushFrame,
-        /**
-         * Restores all callee-save registers (if any) and removes the stack frame of the method.
-         */
-        PopFrame,
-        /**
-         * Inserts an array of bytes directly into the code output.
-         */
-        RawBytes,
-        /**
          * Pushes a value onto the stack.
          */
         Push,
@@ -769,27 +749,6 @@
         append(new XirInstruction(CiKind.Void, null, Safepoint, null));
     }
 
-    public void align(int multiple) {
-        assert multiple > 0;
-        append(new XirInstruction(CiKind.Void, multiple, Align, null));
-    }
-
-    public void stackOverflowCheck() {
-        append(new XirInstruction(CiKind.Void, null, StackOverflowCheck, null));
-    }
-
-    public void pushFrame() {
-        append(new XirInstruction(CiKind.Void, null, PushFrame, null));
-    }
-
-    public void popFrame() {
-        append(new XirInstruction(CiKind.Void, null, PopFrame, null));
-    }
-
-    public void rawBytes(byte[] bytes) {
-        append(new XirInstruction(CiKind.Void, bytes, RawBytes, null));
-    }
-
     public void push(XirOperand value) {
         append(new XirInstruction(CiKind.Void, Push, VOID, value));
     }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Apr 13 15:52:25 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Apr 20 13:44:06 2012 +0200
@@ -31,20 +31,6 @@
  */
 public interface RiXirGenerator {
 
-    /**
-     * Note: may return {@code null}.
-     */
-    XirSnippet genPrologue(XirSite site, RiResolvedMethod method);
-
-    /**
-     * Note: may return {@code null} in which case the compiler will not emit a return instruction.
-     */
-    XirSnippet genEpilogue(XirSite site, RiResolvedMethod method);
-
-    XirSnippet genSafepointPoll(XirSite site);
-
-    XirSnippet genExceptionObject(XirSite site);
-
     XirSnippet genInvokeInterface(XirSite site, XirArgument receiver, RiMethod method);
 
     XirSnippet genInvokeVirtual(XirSite site, XirArgument receiver, RiMethod method, boolean megamorph);
--- a/hotspot/.project	Fri Apr 13 15:52:25 2012 +0200
+++ b/hotspot/.project	Fri Apr 20 13:44:06 2012 +0200
@@ -23,7 +23,7 @@
 				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
-					<value>product</value>
+					<value>ide-build-target</value>
 				</dictionary>
 				<dictionary>
 					<key>org.eclipse.cdt.make.core.buildArguments</key>
@@ -86,9 +86,14 @@
 	</natures>
 	<linkedResources>
 		<link>
-			<name>cpu</name>
+			<name>x86</name>
 			<type>2</type>
-			<locationURI>PARENT-1-PROJECT_LOC/src/cpu/x86</locationURI>
+			<locationURI>PARENT-1-PROJECT_LOC/src/cpu/x86/vm</locationURI>
+		</link>
+		<link>
+			<name>sparc</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/src/cpu/sparc/vm</locationURI>
 		</link>
 		<link>
 			<name>generated</name>
@@ -101,14 +106,19 @@
 			<locationURI>WORKSPACE_LOC/make</locationURI>
 		</link>
 		<link>
-			<name>os</name>
+			<name>linux</name>
 			<type>2</type>
-			<locationURI>PARENT-1-PROJECT_LOC/src/os/linux</locationURI>
+			<locationURI>PARENT-1-PROJECT_LOC/src/os/linux/vm</locationURI>
 		</link>
 		<link>
-			<name>os_cpu</name>
+			<name>linux_x86</name>
 			<type>2</type>
-			<locationURI>PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86</locationURI>
+			<locationURI>PARENT-1-PROJECT_LOC/src/os_cpu/linux_x86/vm</locationURI>
+		</link>
+		<link>
+			<name>linux_sparc</name>
+			<type>2</type>
+			<locationURI>PARENT-1-PROJECT_LOC/src/os_cpu/linux_sparc/vm</locationURI>
 		</link>
 		<link>
 			<name>vm</name>
--- a/mx/commands.py	Fri Apr 13 15:52:25 2012 +0200
+++ b/mx/commands.py	Fri Apr 20 13:44:06 2012 +0200
@@ -49,6 +49,8 @@
 
 _jacoco = 'off'
 
+_make_eclipse_launch = False
+
 _jacocoExcludes = ['com.oracle.graal.hotspot.snippets.ArrayCopySnippets',
                    'com.oracle.graal.snippets.DoubleSnippets',
                    'com.oracle.graal.snippets.FloatSnippets',
@@ -89,6 +91,9 @@
     if opts.native:
         os.environ.update(ARCH_DATA_MODEL='64', LANG='C', HOTSPOT_BUILD_JOBS='16')
         mx.run([mx.gmake_cmd(), 'clean'], cwd=join(_graal_home, 'make'))
+        jdks = join(_graal_home, 'jdk' + mx.java().version)
+        if exists(jdks):
+            shutil.rmtree(jdks)
 
 def export(args):
     """create a GraalVM zip file for distribution"""
@@ -183,7 +188,6 @@
     DaCapo harness."""
 
     numTests = {}
-    
     if len(args) > 0:
         level = getattr(sanitycheck.SanityCheckLevel, args[0], None)
         if level is not None:
@@ -216,17 +220,18 @@
     
     # The remainder are VM options 
     vmOpts = [arg for arg in args if not arg.startswith('@')]
+    vm = _vm
     
     failed = []
     for (test, n) in numTests.items():
-        if not sanitycheck.getDacapo(test, n, dacapoArgs).test('graal', opts=vmOpts):
+        if not sanitycheck.getDacapo(test, n, dacapoArgs).test(vm, opts=vmOpts):
             failed.append(test)
     
     if len(failed) != 0:
         mx.abort('DaCapo failures: ' + str(failed))
     
 def intro(args):
-    """"run a simple program and visualize its compilation in the Graal Visualizer"""
+    """run a simple program and visualize its compilation in the Graal Visualizer"""
     # Start the visualizer in a separate thread
     t = Thread(target=gv, args=([[]]))
     t.start()
@@ -235,7 +240,7 @@
     mx.log('Waiting 5 seconds for visualizer to start')
     time.sleep(5)
     
-    vm(['-G:Dump=HelloWorld', '-G:MethodFilter=main', '-Xcomp', '-XX:CompileOnly=HelloWorld::main', '-cp', mx.classpath('com.oracle.graal.examples')] + args + ['examples.HelloWorld'])
+    vm(['-G:Dump=', '-G:MethodFilter=greet', '-Xcomp', '-XX:CompileOnly=HelloWorld::greet', '-cp', mx.classpath('com.oracle.graal.examples')] + args + ['examples.HelloWorld'])
 
 def scaladacapo(args):
     """run one or all Scala DaCapo benchmarks
@@ -278,10 +283,11 @@
     
     # The remainder are VM options 
     vmOpts = [arg for arg in args if not arg.startswith('@')]
+    vm = _vm;
     
     failed = []
     for (test, n) in numTests.items():
-        if not sanitycheck.getScalaDacapo(test, n, dacapoArgs).test('graal', opts=vmOpts):
+        if not sanitycheck.getScalaDacapo(test, n, dacapoArgs).test(vm, opts=vmOpts):
             failed.append(test)
     
     if len(failed) != 0:
@@ -455,7 +461,30 @@
                 mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': add missing projects to declaration:\n    ' + '\n    '.join(missing))
             if len(extra) != 0:
                 mx.abort(fp.name + ':' + str(source[:start].count('\n') + 1) + ': remove projects from declaration:\n    ' + '\n    '.join(extra))
-                
+
+        # Check if a build really needs to be done
+        timestampFile = join(vmDir, '.build-timestamp')
+        if opts2.force or not exists(timestampFile):
+            mustBuild = True 
+        else:
+            mustBuild = False 
+            timestamp = os.path.getmtime(timestampFile)
+            sources = []
+            for d in ['src', 'make']:
+                for root, dirnames, files in os.walk(join(_graal_home, d)):
+                    # ignore <graal>/src/share/tools
+                    if root == join(_graal_home, 'src', 'share'):
+                        dirnames.remove('tools')
+                    sources += [join(root, name) for name in files]
+            for f in sources:
+                if len(f) != 0 and os.path.getmtime(f) > timestamp:
+                    mustBuild = True
+                    break
+                    
+        if not mustBuild:
+            mx.log('[all files in src and make directories are older than ' + timestampFile[len(_graal_home) + 1:] + ' - skipping native build]')
+            continue
+
         if platform.system() == 'Windows':
             compilelogfile = _graal_home + '/graalCompile.log'
             mksHome = mx.get_env('MKS_HOME', 'C:\\cygwin\\bin')
@@ -512,7 +541,12 @@
             with open(jvmCfg, 'w') as f:
                 for line in lines:
                     f.write(line)
-    
+
+        if exists(timestampFile):
+            os.utime(timestampFile, None)
+        else:
+            file(timestampFile, 'a')
+
 def vm(args, vm=None, nonZeroIsFatal=True, out=None, err=None, cwd=None, timeout=None, vmbuild=None):
     """run the VM selected by the '--vm' option"""
 
@@ -520,7 +554,11 @@
         vm = _vm
         
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'
-    mx.expand_project_in_args(args)  
+    mx.expand_project_in_args(args)
+    if _make_eclipse_launch:
+        mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True))
+    if len([a for a in args if 'PrintAssembly' in a]) != 0:
+        hsdis([])
     if mx.java().debug_port is not None:
         args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args
     if _jacoco == 'on' or _jacoco == 'append':
@@ -681,6 +719,7 @@
             return self
              
     parser = ArgumentParser(prog='mx gate');
+    parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
     parser.add_argument('-n', '--omit-native-build', action='store_false', dest='buildNative', help='omit cleaning and building native code')
     parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM')
     parser.add_argument('--jacocout', help='specify the output directory for jacoco report')
@@ -692,7 +731,12 @@
     try:
         
         t = Task('Clean')
-        clean([] if args.buildNative else ['--no-native'])
+        cleanArgs = []
+        if not args.buildNative:
+            cleanArgs.append('--no-native')
+        if not args.cleanJava:
+            cleanArgs.append('--no-java')
+        clean(cleanArgs)
         tasks.append(t.stop())
         
         t = Task('BuildJava')
@@ -732,7 +776,7 @@
             for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
                 t = Task(str(test) + ':' + vmbuild)
                 if not test.test('graal'):
-                    t.abort(test.group + ' ' + test.name + ' Failed')
+                    t.abort(test.name + ' Failed')
                 tasks.append(t.stop())
         
         if args.jacocout is not None:
@@ -845,9 +889,10 @@
             benchmarks += [sanitycheck.getSPECjvm2008([specjvm], True, 120, 120)]
     
     for test in benchmarks:
-        if not results.has_key(test.group):
-            results[test.group] = {}
-        results[test.group].update(test.bench(vm))
+        for (group, res) in test.bench(vm).items():
+            if not results.has_key(group):
+                results[group] = {};
+            results[group].update(res)
     mx.log(json.dumps(results))
     if resultFile:
         with open(resultFile, 'w') as f:
@@ -882,7 +927,8 @@
             mx.abort('-it (Iteration time) needs a numeric value (seconds)')
         vmArgs.remove('-it')
         benchArgs.remove(args[itIdx+1])
-    sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench('graal', opts=vmArgs)
+    vm = _vm;
+    sanitycheck.getSPECjvm2008(benchArgs, skipValid, wt, it).bench(vm, opts=vmArgs)
     
 def hsdis(args):
     """install the hsdis library
@@ -895,8 +941,19 @@
     build = _vmbuild if _vmSourcesAvailable else 'product'
     lib = mx.lib_suffix('hsdis-amd64')
     path = join(_vmLibDirInJdk(_jdk(build)), lib)
-    mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib])
+    if not exists(path):
+        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavor + "/" + lib])
     
+def hcfdis(args):
+    """disassembles HexCodeFiles embedded in text files
+
+    Run a tool over the input files to convert all embedded HexCodeFiles
+    to a disassembled format."""
+    path = join(_graal_home, 'lib', 'hcfdis.jar')
+    if not exists(path):
+        mx.download(path, ['http://lafo.ssw.uni-linz.ac.at/hcfdis.jar'])
+    mx.run_java(['-jar', path] + args)
+
 def jacocoreport(args):
     """creates a JaCoCo coverage report
 
@@ -917,6 +974,7 @@
         'buildvms': [buildvms, '[-options]'],
         'clean': [clean, ''],
         'hsdis': [hsdis, '[att]'],
+        'hcfdis': [hcfdis, ''],
         'igv' : [igv, ''],
         'intro': [intro, ''],
         'jdkhome': [jdkhome, ''],
@@ -940,6 +998,7 @@
         mx.add_argument('--product', action='store_const', dest='vmbuild', const='product', help='select the product build of the VM')
         mx.add_argument('--debug', action='store_const', dest='vmbuild', const='debug', help='select the debug build of the VM')
         mx.add_argument('--fastdebug', action='store_const', dest='vmbuild', const='fastdebug', help='select the fast debug build of the VM')
+        mx.add_argument('--ecl', action='store_true', dest='make_eclipse_launch', help='create launch configuration for running VM execution(s) in Eclipse')
         
         commands.update({
             'export': [export, '[-options] [zipfile]'],
@@ -964,5 +1023,7 @@
         if hasattr(opts, 'vmbuild') and opts.vmbuild is not None:
             global _vmbuild
             _vmbuild = opts.vmbuild
+        global _make_eclipse_launch
+        _make_eclipse_launch = getattr(opts, 'make_eclipse_launch', False)
     global _jacoco
     _jacoco = opts.jacoco
--- a/mx/projects	Fri Apr 13 15:52:25 2012 +0200
+++ b/mx/projects	Fri Apr 20 13:44:06 2012 +0200
@@ -31,7 +31,7 @@
 
 # graal.graph
 project@com.oracle.graal.graph@subDir=graal
-project@com.oracle.graal.graph@sourceDirs=src
+project@com.oracle.graal.graph@sourceDirs=src,test
 project@com.oracle.graal.graph@dependencies=com.oracle.graal.debug,JUNIT
 project@com.oracle.graal.graph@javaCompliance=1.7
 
--- a/mx/sanitycheck.py	Fri Apr 13 15:52:25 2012 +0200
+++ b/mx/sanitycheck.py	Fri Apr 20 13:44:06 2012 +0200
@@ -106,7 +106,7 @@
     error = re.compile(r"^Errors in benchmark: ")
     # The ' ops/m' at the end of the success string is important : it's how you can tell valid and invalid runs apart
     success = re.compile(r"^(Noncompliant c|C)omposite result: [0-9]+(,|\.)[0-9]+( SPECjvm2008 (Base|Peak))? ops/m$")
-    matcher = Matcher(score, {'const:name' : 'benchmark', 'const:score' : 'score'}, startNewLine=True)
+    matcher = Matcher(score, {'const:group' : "const:SPECjvm2008", 'const:name' : 'benchmark', 'const:score' : 'score'}, startNewLine=True)
     
     opts = []
     if warmupTime is not None:
@@ -116,7 +116,7 @@
     if skipKitValidation:
         opts += ['-ikv']
     
-    return Test("SPECjvm2008", "SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC'], defaultCwd=specjvm2008)
+    return Test("SPECjvm2008", ['-jar', 'SPECjvm2008.jar'] + opts + benchArgs, [success], [error], [matcher], vmOpts=['-Xms3g', '-XX:+UseSerialGC'], defaultCwd=specjvm2008)
 
 def getDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]):
     checks = []
@@ -143,10 +143,12 @@
     dacapoSuccess = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) PASSED in ([0-9]+) msec =====$")
     dacapoFail = re.compile(r"^===== DaCapo 9\.12 ([a-zA-Z0-9_]+) FAILED (warmup|) =====$")
     dacapoTime = re.compile(r"===== DaCapo 9\.12 (?P<benchmark>[a-zA-Z0-9_]+) PASSED in (?P<time>[0-9]+) msec =====")
+    dacapoTime1 = re.compile(r"===== DaCapo 9\.12 (?P<benchmark>[a-zA-Z0-9_]+) completed warmup 1 in (?P<time>[0-9]+) msec =====")
     
-    dacapoMatcher = Matcher(dacapoTime, {'const:name' : 'benchmark', 'const:score' : 'time'})
+    dacapoMatcher = Matcher(dacapoTime, {'const:group' : "const:DaCapo", 'const:name' : 'benchmark', 'const:score' : 'time'}, startNewLine=True)
+    dacapoMatcher1 = Matcher(dacapoTime1, {'const:group' : "const:DaCapo-1stRun", 'const:name' : 'benchmark', 'const:score' : 'time'})
     
-    return Test("DaCapo-" + name, "DaCapo", ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:MaxPermSize=256m', '-XX:+UseSerialGC'])
+    return Test("DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher, dacapoMatcher1], ['-Xms2g', '-XX:MaxPermSize=256m', '-XX:+UseSerialGC'])
 
 def getScalaDacapos(level=SanityCheckLevel.Normal, gateBuildLevel=None, dacapoArgs=[]):
     checks = []
@@ -174,25 +176,26 @@
     dacapoFail = re.compile(r"^===== DaCapo 0\.1\.0(-SNAPSHOT)? ([a-zA-Z0-9_]+) FAILED (warmup|) =====$")
     dacapoTime = re.compile(r"===== DaCapo 0\.1\.0(-SNAPSHOT)? (?P<benchmark>[a-zA-Z0-9_]+) PASSED in (?P<time>[0-9]+) msec =====")
     
-    dacapoMatcher = Matcher(dacapoTime, {'const:name' : 'benchmark', 'const:score' : 'time'})
+    dacapoMatcher = Matcher(dacapoTime, {'const:group' : "const:Scala-DaCapo", 'const:name' : 'benchmark', 'const:score' : 'time'})
     
-    return Test("Scala-DaCapo-" + name, "Scala-DaCapo", ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:MaxPermSize=256m', '-XX:+UseSerialGC'])
+    return Test("Scala-DaCapo-" + name, ['-jar', dacapo, name, '-n', str(n), ] + dacapoArgs, [dacapoSuccess], [dacapoFail], [dacapoMatcher], ['-Xms2g', '-XX:MaxPermSize=256m', '-XX:+UseSerialGC'])
 
 def getBootstraps():
     time = re.compile(r"Bootstrapping Graal\.+ in (?P<time>[0-9]+) ms")
-    scoreMatcher = Matcher(time, {'const:name' : 'const:BootstrapTime', 'const:score' : 'time'})
+    scoreMatcher = Matcher(time, {'const:group' : 'const:Bootstrap', 'const:name' : 'const:BootstrapTime', 'const:score' : 'time'})
+    scoreMatcherBig = Matcher(time, {'const:group' : 'const:Bootstrap-bigHeap', 'const:name' : 'const:BootstrapTime', 'const:score' : 'time'})
+    
     tests = []
-    tests.append(Test("Bootstrap", "Bootstrap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher], ingoreVms=['client', 'server']))
-    tests.append(Test("Bootstrap-bigHeap", "Bootstrap-bigHeap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher], vmOpts=['-Xms2g'], ingoreVms=['client', 'server']))
+    tests.append(Test("Bootstrap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcher], ingoreVms=['client', 'server']))
+    tests.append(Test("Bootstrap-bigHeap", ['-version'], successREs=[time], scoreMatchers=[scoreMatcherBig], vmOpts=['-Xms2g'], ingoreVms=['client', 'server']))
     return tests
 
 """
 Encapsulates a single program that is a sanity test and/or a benchmark.
 """
 class Test:
-    def __init__(self, name, group, cmd, successREs=[], failureREs=[], scoreMatchers=[], vmOpts=[], defaultCwd=None, ingoreVms=[]):
+    def __init__(self, name, cmd, successREs=[], failureREs=[], scoreMatchers=[], vmOpts=[], defaultCwd=None, ingoreVms=[]):
         self.name = name
-        self.group = group
         self.successREs = successREs
         self.failureREs = failureREs + [re.compile(r"Exception occured in scope: ")]
         self.scoreMatchers = scoreMatchers
@@ -274,12 +277,15 @@
         passed = False;
         
         for line in parsed:
-            assert (line.has_key('name') and line.has_key('score')) or line.has_key('passed')
+            assert (line.has_key('name') and line.has_key('score') and line.has_key('group')) or line.has_key('passed') or line.has_key('failed')
             if line.has_key('failed') and line['failed'] is '1':
                 mx.abort("Benchmark failed")
             if line.has_key('passed') and line['passed'] is '1':
                 passed = True
-            ret[line['name']] = line['score']
+            if line.has_key('name') and line.has_key('score') and line.has_key('group'):
+                if not ret.has_key(line['group']):
+                    ret[line['group']] = {};
+                ret[line['group']][line['name']] = line['score']
         
         if not passed:
             mx.abort("Benchmark failed (not passed)")
--- a/mxtool/mx.py	Fri Apr 13 15:52:25 2012 +0200
+++ b/mxtool/mx.py	Fri Apr 20 13:44:06 2012 +0200
@@ -129,7 +129,7 @@
 from collections import Callable
 from threading import Thread
 from argparse import ArgumentParser, REMAINDER
-from os.path import join, dirname, exists, getmtime, isabs, expandvars, isdir, isfile
+from os.path import join, basename, dirname, exists, getmtime, isabs, expandvars, isdir, isfile
 
 DEFAULT_JAVA_ARGS = '-ea -Xss2m -Xmx1g'
 
@@ -401,6 +401,73 @@
                 abort('cannot redefine library  ' + l.name)
             _libs[l.name] = l
 
+class XMLElement(xml.dom.minidom.Element):
+    def writexml(self, writer, indent="", addindent="", newl=""):
+        writer.write(indent+"<" + self.tagName)
+    
+        attrs = self._get_attributes()
+        a_names = attrs.keys()
+        a_names.sort()
+    
+        for a_name in a_names:
+            writer.write(" %s=\"" % a_name)
+            xml.dom.minidom._write_data(writer, attrs[a_name].value)
+            writer.write("\"")
+        if self.childNodes:
+            if not self.ownerDocument.padTextNodeWithoutSiblings and len(self.childNodes) == 1 and isinstance(self.childNodes[0], xml.dom.minidom.Text):
+                # if the only child of an Element node is a Text node, then the
+                # text is printed without any indentation or new line padding  
+                writer.write(">")
+                self.childNodes[0].writexml(writer)
+                writer.write("</%s>%s" % (self.tagName,newl))
+            else:
+                writer.write(">%s"%(newl))
+                for node in self.childNodes:
+                    node.writexml(writer,indent+addindent,addindent,newl)
+                writer.write("%s</%s>%s" % (indent,self.tagName,newl))
+        else:
+            writer.write("/>%s"%(newl))
+
+class XMLDoc(xml.dom.minidom.Document):
+
+    def __init__(self):
+        xml.dom.minidom.Document.__init__(self)
+        self.current = self
+        self.padTextNodeWithoutSiblings = False
+
+    def createElement(self, tagName):
+        # overwritten to create XMLElement
+        e = XMLElement(tagName)
+        e.ownerDocument = self
+        return e
+    
+    def open(self, tag, attributes={}, data=None):
+        element = self.createElement(tag)
+        for key, value in attributes.items():
+            element.setAttribute(key, value)
+        self.current.appendChild(element)
+        self.current = element
+        if data is not None:
+            element.appendChild(self.createTextNode(data))
+        return self
+
+    def close(self, tag):
+        assert self.current != self
+        assert tag == self.current.tagName, str(tag) + ' != ' + self.current.tagName  
+        self.current = self.current.parentNode
+        return self
+    
+    def element(self, tag, attributes={}, data=None):
+        return self.open(tag, attributes, data).close(tag)
+            
+    def xml(self, indent='', newl='', escape=False):
+        assert self.current == self
+        result = self.toprettyxml(indent, newl, encoding="UTF-8")
+        if escape:
+            entities = { '"':  "&quot;", "'":  "&apos;", '\n': '&#10;' }
+            result = xml.sax.saxutils.escape(result, entities)
+        return result
+
 def get_os():
     """
     Get a canonical form of sys.platform.
@@ -728,8 +795,10 @@
     os = get_os();
     if os == 'windows':
         return name + '.dll'
-    if os == 'linux':
+    if os == 'linux' or os == 'solaris':
         return name + '.so'
+    if os == 'darwin':
+        return name + '.dylib'
     return name
 
 """
@@ -972,7 +1041,7 @@
     defaultEcjPath = join(_mainSuite.dir, 'mx', 'ecj.jar')
     
     parser = parser if parser is not None else ArgumentParser(prog='mx build')
-    parser.add_argument('-f', action='store_true', dest='force', help='force compilation even if class files are up to date')
+    parser.add_argument('-f', action='store_true', dest='force', help='force build (disables timestamp checking)')
     parser.add_argument('-c', action='store_true', dest='clean', help='removes existing build output')
     parser.add_argument('--source', dest='compliance', help='Java compliance level', default=str(javaCompliance))
     parser.add_argument('--Wapi', action='store_true', dest='warnAPI', help='show warnings about using internal APIs')
@@ -1208,7 +1277,9 @@
                 log('[no Java sources in {0} - skipping]'.format(sourceDir))
                 continue
 
-            timestampFile = join(p.suite.dir, 'mx', '.checkstyle' + sourceDir[len(p.suite.dir):].replace(os.sep, '_') + '.timestamp')
+            timestampFile = join(p.suite.dir, 'mx', 'checkstyle-timestamps', sourceDir[len(p.suite.dir) + 1:].replace(os.sep, '_') + '.timestamp')
+            if not exists(dirname(timestampFile)):
+                os.makedirs(dirname(timestampFile))
             mustCheck = False
             if exists(timestampFile):
                 timestamp = os.path.getmtime(timestampFile)
@@ -1369,6 +1440,116 @@
         for dep in p.canonical_deps():
             print '"' + p.name + '"->"' + dep + '"'
     print '}'
+    
+    
+def _source_locator_memento(deps):
+    slm = XMLDoc()
+    slm.open('sourceLookupDirector')
+    slm.open('sourceContainers', {'duplicates' : 'false'})
+
+    for dep in deps:
+        if dep.isLibrary():
+            if hasattr(dep, 'eclipse.container'):
+                memento = XMLDoc().element('classpathContainer', {'path' : getattr(dep, 'eclipse.container')}).xml()
+                slm.element('classpathContainer', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.classpathContainer'})
+        else:
+            memento = XMLDoc().element('javaProject', {'name' : dep.name}).xml()
+            slm.element('container', {'memento' : memento, 'typeId':'org.eclipse.jdt.launching.sourceContainer.javaProject'})
+
+    slm.close('sourceContainers')
+    slm.close('sourceLookupDirector')
+    return slm
+
+def make_eclipse_attach(hostname, port, name=None, deps=[]):
+    """
+    Creates an Eclipse launch configuration file for attaching to a Java process.
+    """
+    slm = _source_locator_memento(deps)
+    launch = XMLDoc()
+    launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.remoteJavaApplication'})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'})
+    launch.element('booleanAttribute', {'key' : 'org.eclipse.jdt.launching.ALLOW_TERMINATE', 'value' : 'true'})
+    launch.open('mapAttribute', {'key' : 'org.eclipse.jdt.launching.CONNECT_MAP'})
+    launch.element('mapEntry', {'key' : 'hostname', 'value' : hostname})
+    launch.element('mapEntry', {'key' : 'port', 'value' : port})
+    launch.close('mapAttribute')
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_CONNECTOR_ID', 'value' : 'org.eclipse.jdt.launching.socketAttachConnector'})
+    launch.close('launchConfiguration')
+    launch = launch.xml(newl='\n') % slm.xml(escape=True)
+    
+    if name is None:
+        name = 'attach-' + hostname + '-' + port
+    eclipseLaunches = join('mx', 'eclipse-launches')
+    if not exists(eclipseLaunches):
+        os.makedirs(eclipseLaunches)
+    return update_file(join(eclipseLaunches, name + '.launch'), launch)
+
+def make_eclipse_launch(javaArgs, jre, name=None, deps=[]):
+    """
+    Creates an Eclipse launch configuration file for running/debugging a Java command.
+    """
+    mainClass = None
+    vmArgs = []
+    appArgs = []
+    cp = None
+    argsCopy = list(reversed(javaArgs))
+    while len(argsCopy) != 0:
+        a = argsCopy.pop()
+        if a == '-jar':
+            mainClass = '-jar'
+            appArgs = list(reversed(argsCopy))
+            break
+        if a == '-cp' or a == '-classpath':
+            assert len(argsCopy) != 0
+            cp = argsCopy.pop()
+            vmArgs.append(a)
+            vmArgs.append(cp)
+        elif a.startswith('-'):
+            vmArgs.append(a)
+        else:
+            mainClass = a
+            appArgs = list(reversed(argsCopy))
+            break
+    
+    if mainClass is None:
+        log('Cannot create Eclipse launch configuration without main class or jar file: java ' + ' '.join(javaArgs))
+        return False
+    
+    if name is None:
+        if mainClass == '-jar':
+            name = basename(appArgs[0])
+            if len(appArgs) > 1 and not appArgs[1].startswith('-'):
+                name = name + '_' + appArgs[1]
+        else:
+            name = mainClass
+        name = time.strftime('%Y-%m-%d-%H%M%S_' + name)
+
+    if cp is not None:
+        for e in cp.split(os.pathsep):
+            for s in suites():
+                deps += [p for p in s.projects if e == p.output_dir()]
+                deps += [l for l in s.libs if e == l.get_path(False)]
+    
+    slm = _source_locator_memento(deps)
+    
+    launch = XMLDoc()
+    launch.open('launchConfiguration', {'type' : 'org.eclipse.jdt.launching.localJavaApplication'})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_id', 'value' : 'org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector'})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.debug.core.source_locator_memento', 'value' : '%s'})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.JRE_CONTAINER', 'value' : 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/' + jre})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.MAIN_TYPE', 'value' : mainClass})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROGRAM_ARGUMENTS', 'value' : ' '.join(appArgs)})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.PROJECT_ATTR', 'value' : ''})
+    launch.element('stringAttribute', {'key' : 'org.eclipse.jdt.launching.VM_ARGUMENTS', 'value' : ' '.join(vmArgs)})
+    launch.close('launchConfiguration')
+    launch = launch.xml(newl='\n') % slm.xml(escape=True)
+
+    eclipseLaunches = join('mx', 'eclipse-launches')
+    if not exists(eclipseLaunches):
+        os.makedirs(eclipseLaunches)
+    return update_file(join(eclipseLaunches, name + '.launch'), launch)
 
 def eclipseinit(args, suite=None):
     """(re)generate Eclipse project configurations"""
@@ -1376,12 +1557,6 @@
     if suite is None:
         suite = _mainSuite
 
-    def println(out, obj):
-        out.write(str(obj) + '\n')
-
-    source_locator_memento = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<sourceLookupDirector><sourceContainers duplicates="false">'
-    entities = { '"':  "&quot;", "'":  "&apos;", '\n': '&#10;' }
-
     for p in projects():
         if p.native:
             continue
@@ -1389,18 +1564,17 @@
         if not exists(p.dir):
             os.makedirs(p.dir)
 
-        out = StringIO.StringIO()
-
-        println(out, '<?xml version="1.0" encoding="UTF-8"?>')
-        println(out, '<classpath>')
+        out = XMLDoc()
+        out.open('classpath')
+        
         for src in p.srcDirs:
             srcDir = join(p.dir, src)
             if not exists(srcDir):
                 os.mkdir(srcDir)
-            println(out, '\t<classpathentry kind="src" path="' + src + '"/>')
+            out.element('classpathentry', {'kind' : 'src', 'path' : src})
 
         # Every Java program depends on the JRE
-        println(out, '\t<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>')
+        out.element('classpathentry', {'kind' : 'con', 'path' : 'org.eclipse.jdt.launching.JRE_CONTAINER'})
 
         for dep in p.all_deps([], True):
             if dep == p:
@@ -1408,92 +1582,82 @@
 
             if dep.isLibrary():
                 if hasattr(dep, 'eclipse.container'):
-                    println(out, '\t<classpathentry exported="true" kind="con" path="' + getattr(dep, 'eclipse.container') + '"/>')
+                    out.element('classpathentry', {'exported' : 'true', 'kind' : 'con', 'path' : getattr(dep, 'eclipse.container')})
                 elif hasattr(dep, 'eclipse.project'):
-                    println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + getattr(dep, 'eclipse.project') + '"/>')
+                    out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + getattr(dep, 'eclipse.project')})
                 else:
                     path = dep.path
                     if dep.mustExist:
                         dep.get_path(resolve=True)
                         if isabs(path):
-                            println(out, '\t<classpathentry exported="true" kind="lib" path="' + path + '"/>')
+                            out.element('classpathentry', {'exported' : 'true', 'kind' : 'lib', 'path' : path})
                         else:
                             # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
                             # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
                             # safest to simply use absolute paths.
-                            println(out, '\t<classpathentry exported="true" kind="lib" path="' + join(suite.dir, path) + '"/>')
+                            out.element('classpathentry', {'exported' : 'true', 'kind' : 'lib', 'path' : join(suite.dir, path)})
             else:
-                println(out, '\t<classpathentry combineaccessrules="false" exported="true" kind="src" path="/' + dep.name + '"/>')
+                out.element('classpathentry', {'combineaccessrules' : 'false', 'exported' : 'true', 'kind' : 'src', 'path' : '/' + dep.name})
 
-        println(out, '\t<classpathentry kind="output" path="' + getattr(p, 'eclipse.output', 'bin') + '"/>')
-        println(out, '</classpath>')
-        update_file(join(p.dir, '.classpath'), out.getvalue())
-        out.close()
+        out.element('classpathentry', {'kind' : 'output', 'path' : getattr(p, 'eclipse.output', 'bin')})
+        out.close('classpath')
+        update_file(join(p.dir, '.classpath'), out.xml(indent='\t', newl='\n'))
 
         csConfig = join(project(p.checkstyleProj).dir, '.checkstyle_checks.xml')
         if exists(csConfig):
-            out = StringIO.StringIO()
+            out = XMLDoc()
 
             dotCheckstyle = join(p.dir, ".checkstyle")
             checkstyleConfigPath = '/' + p.checkstyleProj + '/.checkstyle_checks.xml'
-            println(out, '<?xml version="1.0" encoding="UTF-8"?>')
-            println(out, '<fileset-config file-format-version="1.2.0" simple-config="true">')
-            println(out, '\t<local-check-config name="Checks" location="' + checkstyleConfigPath + '" type="project" description="">')
-            println(out, '\t\t<additional-data name="protect-config-file" value="false"/>')
-            println(out, '\t</local-check-config>')
-            println(out, '\t<fileset name="all" enabled="true" check-config-name="Checks" local="true">')
-            println(out, '\t\t<file-match-pattern match-pattern="." include-pattern="true"/>')
-            println(out, '\t</fileset>')
-            println(out, '\t<filter name="FileTypesFilter" enabled="true">')
-            println(out, '\t\t<filter-data value="java"/>')
-            println(out, '\t</filter>')
+            out.open('fileset-config', {'file-format-version' : '1.2.0', 'simple-config' : 'true'})
+            out.open('local-check-config', {'name' : 'Checks', 'location' : checkstyleConfigPath, 'type' : 'project', 'description' : ''})
+            out.element('additional-data', {'name' : 'protect-config-file', 'value' : 'false'})
+            out.close('local-check-config')
+            out.open('fileset', {'name' : 'all', 'enabled' : 'true', 'check-config-name' : 'Checks', 'local' : 'true'})
+            out.element('file-match-pattern', {'match-pattern' : '.', 'include-pattern' : 'true'})
+            out.close('fileset')
+            out.open('filter', {'name' : 'all', 'enabled' : 'true', 'check-config-name' : 'Checks', 'local' : 'true'})
+            out.element('filter-data', {'value' : 'java'})
+            out.close('filter')
 
             exclude = join(p.dir, '.checkstyle.exclude')
             if exists(exclude):
-                println(out, '\t<filter name="FilesFromPackage" enabled="true">')
+                out.open('filter', {'name' : 'FilesFromPackage', 'enabled' : 'true'})
                 with open(exclude) as f:
                     for line in f:
                         if not line.startswith('#'):
                             line = line.strip()
                             exclDir = join(p.dir, line)
                             assert isdir(exclDir), 'excluded source directory listed in ' + exclude + ' does not exist or is not a directory: ' + exclDir
-                        println(out, '\t\t<filter-data value="' + line + '"/>')
-                println(out, '\t</filter>')
+                        out.element('filter-data', {'value' : line})
+                out.close('filter')
 
-            println(out, '</fileset-config>')
-            update_file(dotCheckstyle, out.getvalue())
-            out.close()
-
-
-        out = StringIO.StringIO()
+            out.close('fileset-config')
+            update_file(dotCheckstyle, out.xml(indent='  ', newl='\n'))
 
-        println(out, '<?xml version="1.0" encoding="UTF-8"?>')
-        println(out, '<projectDescription>')
-        println(out, '\t<name>' + p.name + '</name>')
-        println(out, '\t<comment></comment>')
-        println(out, '\t<projects>')
-        println(out, '\t</projects>')
-        println(out, '\t<buildSpec>')
-        println(out, '\t\t<buildCommand>')
-        println(out, '\t\t\t<name>org.eclipse.jdt.core.javabuilder</name>')
-        println(out, '\t\t\t<arguments>')
-        println(out, '\t\t\t</arguments>')
-        println(out, '\t\t</buildCommand>')
+        out = XMLDoc()
+        out.open('projectDescription')
+        out.element('name', data=p.name)
+        out.element('comment', data='')
+        out.element('projects', data='')
+        out.open('buildSpec')
+        out.open('buildCommand')
+        out.element('name', data='org.eclipse.jdt.core.javabuilder')
+        out.element('arguments', data='')
+        out.close('buildCommand')
         if exists(csConfig):
-            println(out, '\t\t<buildCommand>')
-            println(out, '\t\t\t<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>')
-            println(out, '\t\t\t<arguments>')
-            println(out, '\t\t\t</arguments>')
-            println(out, '\t\t</buildCommand>')
-        println(out, '\t</buildSpec>')
-        println(out, '\t<natures>')
-        println(out, '\t\t<nature>org.eclipse.jdt.core.javanature</nature>')
+            out.open('buildCommand')
+            out.element('name', data='net.sf.eclipsecs.core.CheckstyleBuilder')
+            out.element('arguments', data='')
+            out.close('buildCommand')
+        out.close('buildSpec')
+        out.open('natures')
+        out.element('nature', data='org.eclipse.jdt.core.javanature')
         if exists(csConfig):
-            println(out, '\t\t<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>')
-        println(out, '\t</natures>')
-        println(out, '</projectDescription>')
-        update_file(join(p.dir, '.project'), out.getvalue())
-        out.close()
+            out.element('nature', data='net.sf.eclipsecs.core.CheckstyleNature')
+        out.close('natures')
+        out.close('projectDescription')
+        update_file(join(p.dir, '.project'), out.xml(indent='\t', newl='\n'))
 
         settingsDir = join(p.dir, ".settings")
         if not exists(settingsDir):
@@ -1508,24 +1672,8 @@
                         content = f.read()
                     content = content.replace('${javaCompliance}', str(p.javaCompliance))
                     update_file(join(settingsDir, name), content)
-                    
-        memento = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<javaProject name="' + p.name + '"/>\n'
-        source_locator_memento += '\n<container memento="' + xml.sax.saxutils.escape(memento, entities) + '" typeId="org.eclipse.jdt.launching.sourceContainer.javaProject"/>'
-        
-    source_locator_memento += '</sourceContainers>\n</sourceLookupDirector>'
-    launch = r"""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<launchConfiguration type="org.eclipse.jdt.launching.remoteJavaApplication">
-<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
-<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="{0}"/>
-<booleanAttribute key="org.eclipse.jdt.launching.ALLOW_TERMINATE" value="true"/>
-<mapAttribute key="org.eclipse.jdt.launching.CONNECT_MAP">
-<mapEntry key="hostname" value="localhost"/>
-<mapEntry key="port" value="8000"/>
-</mapAttribute>
-<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value=""/>
-<stringAttribute key="org.eclipse.jdt.launching.VM_CONNECTOR_ID" value="org.eclipse.jdt.launching.socketAttachConnector"/>
-</launchConfiguration>""".format(xml.sax.saxutils.escape(source_locator_memento, entities))
-    update_file(join(suite.dir, 'mx', 'attach-8000.launch'), launch)
+
+    make_eclipse_attach('localhost', '8000', deps=projects())                    
 
 def netbeansinit(args, suite=None):
     """(re)generate NetBeans project configurations"""
@@ -1533,9 +1681,6 @@
     if suite is None:
         suite = _mainSuite
 
-    def println(out, obj):
-        out.write(str(obj) + '\n')
-
     updated = False
     for p in projects():
         if p.native:
@@ -1544,32 +1689,28 @@
         if not exists(join(p.dir, 'nbproject')):
             os.makedirs(join(p.dir, 'nbproject'))
 
-        out = StringIO.StringIO()
-
-        println(out, '<?xml version="1.0" encoding="UTF-8"?>')
-        println(out, '<project name="' + p.name + '" default="default" basedir=".">')
-        println(out, '\t<description>Builds, tests, and runs the project ' + p.name + '.</description>')
-        println(out, '\t<import file="nbproject/build-impl.xml"/>')
-        println(out, '</project>')
-        updated = update_file(join(p.dir, 'build.xml'), out.getvalue()) or updated
-        out.close()
+        out = XMLDoc()
+        out.open('project', {'name' : p.name, 'default' : 'default', 'basedir' : '.'})
+        out.element('description', data='Builds, tests, and runs the project ' + p.name + '.')
+        out.element('import', {'file' : 'nbproject/build-impl.xml'})
+        out.close('project')
+        updated = update_file(join(p.dir, 'build.xml'), out.xml(indent='\t', newl='\n')) or updated
 
-        out = StringIO.StringIO()
-        println(out, '<?xml version="1.0" encoding="UTF-8"?>')
-        println(out, '<project xmlns="http://www.netbeans.org/ns/project/1">')
-        println(out, '    <type>org.netbeans.modules.java.j2seproject</type>')
-        println(out, '    <configuration>')
-        println(out, '        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">')
-        println(out, '            <name>' + p.name+ '</name>')
-        println(out, '            <explicit-platform explicit-source-supported="true"/>')
-        println(out, '            <source-roots>')
-        println(out, '                <root id="src.dir"/>')
-        println(out, '            </source-roots>')
-        println(out, '            <test-roots>')
-        println(out, '                <root id="test.src.dir"/>')
-        println(out, '            </test-roots>')
-        println(out, '        </data>')
-
+        out = XMLDoc()
+        out.open('project', {'xmlns' : 'http://www.netbeans.org/ns/project/1'})
+        out.element('type', data='org.netbeans.modules.java.j2seproject')
+        out.open('configuration')
+        out.open('data', {'xmlns' : 'http://www.netbeans.org/ns/j2se-project/3'})
+        out.element('name', data=p.name)
+        out.element('explicit-platform', {'explicit-source-supported' : 'true'})
+        out.open('source-roots')
+        out.element('root', {'id' : 'src.dir'})
+        out.close('source-roots')
+        out.open('test-roots')
+        out.element('root', {'id' : 'test.src.dir'})
+        out.close('test-roots')
+        out.close('data')
+        
         firstDep = True
         for dep in p.all_deps([], True):
             if dep == p:
@@ -1578,28 +1719,26 @@
             if not dep.isLibrary():
                 n = dep.name.replace('.', '_')
                 if firstDep:
-                    println(out, '        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">')
+                    out.open('references', {'xmlns' : 'http://www.netbeans.org/ns/ant-project-references/1'})
                     firstDep = False
 
-                println(out, '            <reference>')
-                println(out, '                <foreign-project>' + n + '</foreign-project>')
-                println(out, '                <artifact-type>jar</artifact-type>')
-                println(out, '                <script>build.xml</script>')
-                println(out, '                <target>jar</target>')
-                println(out, '                <clean-target>clean</clean-target>')
-                println(out, '                <id>jar</id>')
-                println(out, '            </reference>')
+                out.open('reference')
+                out.element('foreign-project', data=n)
+                out.element('artifact-type', data='jar')
+                out.element('script', data='build.xml')
+                out.element('target', data='jar')
+                out.element('clean-target', data='clean')
+                out.element('id', data='jar')
+                out.close('reference')
 
         if not firstDep:
-            println(out, '        </references>')
+            out.close('references')
 
-        println(out, '    </configuration>')
-        println(out, '</project>')
-        updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.getvalue()) or updated
-        out.close()
+        out.close('configuration')
+        out.close('project')
+        updated = update_file(join(p.dir, 'nbproject', 'project.xml'), out.xml(indent='    ', newl='\n')) or updated
 
         out = StringIO.StringIO()
-
         jdkPlatform = 'JDK_' + java().version
 
         content = """
@@ -1675,7 +1814,7 @@
     ${build.test.classes.dir}
 test.src.dir=
 source.encoding=UTF-8""".replace(':', os.pathsep).replace('/', os.sep)
-        println(out, content)
+        print >> out, content
 
         mainSrc = True
         for src in p.srcDirs:
@@ -1683,12 +1822,12 @@
             if not exists(srcDir):
                 os.mkdir(srcDir)
             ref = 'file.reference.' + p.name + '-' + src
-            println(out, ref + '=' + src)
+            print >> out, ref + '=' + src
             if mainSrc:
-                println(out, 'src.dir=${' + ref + '}')
+                print >> out, 'src.dir=${' + ref + '}'
                 mainSrc = False
             else:
-                println(out, 'src.' + src + '.dir=${' + ref + '}')
+                print >> out, 'src.' + src + '.dir=${' + ref + '}'
 
         javacClasspath = []
         for dep in p.all_deps([], True):
@@ -1702,18 +1841,18 @@
                 if os.sep == '\\':
                     path = path.replace('\\', '\\\\')
                 ref = 'file.reference.' + dep.name + '-bin'
-                println(out, ref + '=' + path)
+                print >> out, ref + '=' + path
 
             else:
                 n = dep.name.replace('.', '_')
                 relDepPath = os.path.relpath(dep.dir, p.dir).replace(os.sep, '/')
                 ref = 'reference.' + n + '.jar'
-                println(out, 'project.' + n + '=' + relDepPath)
-                println(out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar')
+                print >> out, 'project.' + n + '=' + relDepPath
+                print >> out, ref + '=${project.' + n + '}/dist/' + dep.name + '.jar'
 
             javacClasspath.append('${' + ref + '}')
 
-        println(out, 'javac.classpath=\\\n    ' + (os.pathsep + '\\\n    ').join(javacClasspath))
+        print >> out, 'javac.classpath=\\\n    ' + (os.pathsep + '\\\n    ').join(javacClasspath)
 
 
         updated = update_file(join(p.dir, 'nbproject', 'project.properties'), out.getvalue()) or updated
--- a/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Fri Apr 13 15:52:25 2012 +0200
+++ b/src/cpu/x86/vm/c1_Runtime1_x86.cpp	Fri Apr 20 13:44:06 2012 +0200
@@ -1909,7 +1909,7 @@
 		__ enter();
 		oop_maps = new OopMapSet();
 		OopMap* oop_map = save_live_registers(sasm, 0);
-		int call_offset = __ call_RT(rax, noreg, (address)graal_create_out_of_bounds_exception, c_rarg0);
+		int call_offset = __ call_RT(rax, noreg, (address)graal_create_out_of_bounds_exception, j_rarg0);
 		oop_maps->add_gc_map(call_offset, oop_map);
 		__ leave();
 		__ ret(0);
--- a/src/share/vm/code/nmethod.cpp	Fri Apr 13 15:52:25 2012 +0200
+++ b/src/share/vm/code/nmethod.cpp	Fri Apr 20 13:44:06 2012 +0200
@@ -833,19 +833,28 @@
     _consts_offset           = content_offset()      + code_buffer->total_offset_of(code_buffer->consts());
     _stub_offset             = content_offset()      + code_buffer->total_offset_of(code_buffer->stubs());
 
-    // Exception handler and deopt handler are in the stub section
-    assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
-    assert(offsets->value(CodeOffsets::Deopt     ) != -1, "must be set");
 #ifdef GRAAL
       // graal produces no (!) stub section
-      _exception_offset        = code_offset()          + offsets->value(CodeOffsets::Exceptions);
-      _deoptimize_offset       = code_offset()          + offsets->value(CodeOffsets::Deopt);
+      if (offsets->value(CodeOffsets::Exceptions) != -1) {
+        _exception_offset        = code_offset()          + offsets->value(CodeOffsets::Exceptions);
+      } else {
+        _exception_offset = -1;
+      }
+      if (offsets->value(CodeOffsets::Deopt) != -1) {
+        _deoptimize_offset       = code_offset()          + offsets->value(CodeOffsets::Deopt);
+      } else {
+        _deoptimize_offset = -1;
+      }
       if (offsets->value(CodeOffsets::DeoptMH) != -1) {
         _deoptimize_mh_offset  = code_offset()          + offsets->value(CodeOffsets::DeoptMH);
       } else {
         _deoptimize_mh_offset  = -1;
       }
 #else
+    // Exception handler and deopt handler are in the stub section
+    assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set");
+    assert(offsets->value(CodeOffsets::Deopt     ) != -1, "must be set");
+
       _exception_offset        = _stub_offset          + offsets->value(CodeOffsets::Exceptions);
       _deoptimize_offset       = _stub_offset          + offsets->value(CodeOffsets::Deopt);
       if (offsets->value(CodeOffsets::DeoptMH) != -1) {
--- a/src/share/vm/code/nmethod.hpp	Fri Apr 13 15:52:25 2012 +0200
+++ b/src/share/vm/code/nmethod.hpp	Fri Apr 20 13:44:06 2012 +0200
@@ -340,6 +340,9 @@
   bool is_compiled_by_c2() const;
   bool is_compiled_by_shark() const;
 
+
+#define CHECK_POSITIVE(val) assert(val, "should be positive")
+
   // boundaries for different parts
   address consts_begin          () const          { return           header_begin() + _consts_offset        ; }
   address consts_end            () const          { return           header_begin() +  code_offset()        ; }
@@ -347,8 +350,8 @@
   address insts_end             () const          { return           header_begin() + _stub_offset          ; }
   address stub_begin            () const          { return           header_begin() + _stub_offset          ; }
   address stub_end              () const          { return           header_begin() + _oops_offset          ; }
-  address exception_begin       () const          { return           header_begin() + _exception_offset     ; }
-  address deopt_handler_begin   () const          { return           header_begin() + _deoptimize_offset    ; }
+  address exception_begin       () const          { assert(_exception_offset >= 0, "no exception handler"); return header_begin() + _exception_offset ; }
+  address deopt_handler_begin   () const          { assert(_deoptimize_offset >= 0, "no deopt handler"); return header_begin() + _deoptimize_offset ; }
   address deopt_mh_handler_begin() const          { return           header_begin() + _deoptimize_mh_offset ; }
   address unwind_handler_begin  () const          { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : NULL; }
   oop*    oops_begin            () const          { return (oop*)   (header_begin() + _oops_offset)         ; }
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 13 15:52:25 2012 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Apr 20 13:44:06 2012 +0200
@@ -953,6 +953,93 @@
   return JNIHandles::make_local(result());
 }
 
+// public StackTraceElement RiMethod_toStackTraceElement(HotSpotMethodResolved method, int bci);
+JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1toStackTraceElement(JNIEnv *env, jobject, jobject hotspot_method, int bci) {
+  TRACE_graal_3("CompilerToVM::RiMethod_toStackTraceElement");
+
+  VM_ENTRY_MARK;
+  ResourceMark rm;
+  HandleMark hm;
+
+  methodHandle method = getMethodFromHotSpotMethod(hotspot_method);
+  oop element = java_lang_StackTraceElement::create(method, bci, CHECK_NULL);
+  return JNIHandles::make_local(element);
+}
+
+class JavaArgumentPusher : public SignatureIterator {
+ protected:
+  JavaCallArguments*  _jca;
+  arrayOop _args;
+  int _index;
+
+  oop next_arg(BasicType expectedType) {
+    assert(_index < _args->length(), "out of bounds");
+    oop arg = ((oop*) _args->base(T_OBJECT))[_index++];
+    assert(expectedType == T_OBJECT || java_lang_boxing_object::is_instance(arg, expectedType), "arg type mismatch");
+    return arg;
+  }
+
+ public:
+  JavaArgumentPusher(Symbol* signature, JavaCallArguments*  jca, arrayOop args, bool is_static) : SignatureIterator(signature) {
+    this->_return_type = T_ILLEGAL;
+    _jca = jca;
+    _index = 0;
+    _args = args;
+    if (!is_static) {
+      _jca->push_oop(next_arg(T_OBJECT));
+    }
+    iterate();
+    assert(_index == args->length(), "arg count mismatch with signature");
+  }
+
+  inline void do_bool()   { if (!is_return_type()) _jca->push_int(next_arg(T_BOOLEAN)->bool_field(java_lang_boxing_object::value_offset_in_bytes(T_BOOLEAN))); }
+  inline void do_char()   { if (!is_return_type()) _jca->push_int(next_arg(T_CHAR)->char_field(java_lang_boxing_object::value_offset_in_bytes(T_CHAR))); }
+  inline void do_short()  { if (!is_return_type()) _jca->push_int(next_arg(T_SHORT)->short_field(java_lang_boxing_object::value_offset_in_bytes(T_SHORT))); }
+  inline void do_byte()   { if (!is_return_type()) _jca->push_int(next_arg(T_BYTE)->byte_field(java_lang_boxing_object::value_offset_in_bytes(T_BYTE))); }
+  inline void do_int()    { if (!is_return_type()) _jca->push_int(next_arg(T_INT)->int_field(java_lang_boxing_object::value_offset_in_bytes(T_INT))); }
+
+  inline void do_long()   { if (!is_return_type()) _jca->push_long(next_arg(T_LONG)->long_field(java_lang_boxing_object::value_offset_in_bytes(T_LONG))); }
+  inline void do_float()  { if (!is_return_type()) _jca->push_float(next_arg(T_FLOAT)->float_field(java_lang_boxing_object::value_offset_in_bytes(T_FLOAT))); }
+  inline void do_double() { if (!is_return_type()) _jca->push_double(next_arg(T_DOUBLE)->double_field(java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE))); }
+
+  inline void do_object() { _jca->push_oop(next_arg(T_OBJECT)); }
+  inline void do_object(int begin, int end) { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); }
+  inline void do_array(int begin, int end)  { if (!is_return_type()) _jca->push_oop(next_arg(T_OBJECT)); }
+  inline void do_void()                     { }
+};
+
+// public Object executeCompiledMethodVarargs(HotSpotCompiledMethod method, Object... args);
+JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_executeCompiledMethodVarargs(JNIEnv *env, jobject, jobject method, jobject args) {
+  TRACE_graal_3("CompilerToVM::executeCompiledMethod");
+
+  VM_ENTRY_MARK;
+  ResourceMark rm;
+  HandleMark hm;
+
+  assert(method != NULL, "just checking");
+  methodHandle mh = getMethodFromHotSpotMethod(HotSpotCompiledMethod::method(method));
+  Symbol* signature = mh->signature();
+  JavaCallArguments jca;
+
+  JavaArgumentPusher jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static());
+  JavaValue result(jap.get_ret_type());
+
+  nmethod* nm = (nmethod*) HotSpotCompiledMethod::nmethod(method);
+  if (nm == NULL || !nm->is_alive()) {
+    THROW_0(vmSymbols::MethodInvalidatedException());
+  }
+  JavaCalls::call(&result, mh, nm, &jca, CHECK_NULL);
+
+  if (jap.get_ret_type() == T_VOID) {
+    return NULL;
+  } else if (jap.get_ret_type() == T_OBJECT) {
+    return JNIHandles::make_local((oop) result.get_jobject());
+  } else {
+    oop o = java_lang_boxing_object::create(jap.get_ret_type(), (jvalue *) result.get_value_addr(), CHECK_NULL);
+    return JNIHandles::make_local(o);
+  }
+}
+
 // public Object executeCompiledMethod(HotSpotCompiledMethod method, Object arg1, Object arg2, Object arg3);
 JNIEXPORT jobject JNICALL Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_executeCompiledMethod(JNIEnv *env, jobject, jobject method, jobject arg1, jobject arg2, jobject arg3) {
   TRACE_graal_3("CompilerToVM::executeCompiledMethod");
@@ -1035,6 +1122,7 @@
 #define STRING          "Ljava/lang/String;"
 #define OBJECT          "Ljava/lang/Object;"
 #define CLASS           "Ljava/lang/Class;"
+#define STACK_TRACE_ELEMENT "Ljava/lang/StackTraceElement;"
 
 JNINativeMethod CompilerToVM_methods[] = {
   {CC"RiMethod_code",                     CC"("RESOLVED_METHOD")[B",                            FN_PTR(RiMethod_1code)},
@@ -1070,7 +1158,9 @@
   {CC"installStub",                       CC"("TARGET_METHOD")"PROXY,                           FN_PTR(installStub)},
   {CC"disassembleNative",                 CC"([BJ)"STRING,                                      FN_PTR(disassembleNative)},
   {CC"disassembleJava",                   CC"("RESOLVED_METHOD")"STRING,                        FN_PTR(disassembleJava)},
+  {CC"RiMethod_toStackTraceElement",      CC"("RESOLVED_METHOD"I)"STACK_TRACE_ELEMENT,          FN_PTR(RiMethod_1toStackTraceElement)},
   {CC"executeCompiledMethod",             CC"("HS_COMP_METHOD OBJECT OBJECT OBJECT")"OBJECT,    FN_PTR(executeCompiledMethod)},
+  {CC"executeCompiledMethodVarargs",      CC"("HS_COMP_METHOD "["OBJECT")"OBJECT,               FN_PTR(executeCompiledMethodVarargs)},
   {CC"RiMethod_vtableEntryOffset",        CC"("RESOLVED_METHOD")I",                             FN_PTR(RiMethod_vtableEntryOffset)},
   {CC"getDeoptedLeafGraphIds",            CC"()[J",                                             FN_PTR(getDeoptedLeafGraphIds)},
 };
--- a/src/share/vm/graal/graalEnv.cpp	Fri Apr 13 15:52:25 2012 +0200
+++ b/src/share/vm/graal/graalEnv.cpp	Fri Apr 20 13:44:06 2012 +0200
@@ -477,9 +477,6 @@
       return NULL;
     }
 
-    assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry");
-    assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry");
-
     nm =  nmethod::new_nmethod(method,
                                compile_id,
                                entry_bci,
@@ -531,13 +528,13 @@
               old->make_not_entrant();
             }
           }
-          if (TraceNMethodInstalls ) {
+          if (TraceNMethodInstalls) {
             ResourceMark rm;
             char *method_name = method->name_and_sig_as_C_string();
             ttyLocker ttyl;
-            tty->print_cr("Installing method (%d) %s ",
+            tty->print_cr("Installing method (%d) %s [entry point: %p]",
                           comp_level,
-                          method_name);
+                          method_name, nm->entry_point());
           }
           // Allow the code to be executed
           method->set_code(method, nm);