changeset 10860:1b11e3c8529c

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 23 Jul 2013 17:48:17 +0200
parents 7a0ba9b20fec (current diff) f2008a93ad54 (diff)
children 6872c61c1d3e
files
diffstat 45 files changed, 1083 insertions(+), 394 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DebugInfo.java	Tue Jul 23 17:48:17 2013 +0200
@@ -31,7 +31,7 @@
  * <ul>
  * <li>a {@linkplain #getBytecodePosition() bytecode position}</li>
  * <li>a reference map for {@linkplain #getRegisterRefMap() registers}</li>
- * <li>a reference map for {@linkplain #getRegisterRefMap() stack slots} in the current frame</li>
+ * <li>a reference map for {@linkplain #getFrameRefMap() stack slots} in the current frame</li>
  * <li>a map from bytecode locals and operand stack slots to their values or locations from which
  * their values can be read</li>
  * <li>a map from the registers (in the caller's frame) to the slots where they are saved in the
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Tue Jul 23 17:48:17 2013 +0200
@@ -395,7 +395,7 @@
         }
 
         public void verify() {
-            assert (disp30 & DISP30_MASK) == 0;
+            assert isDisp30(disp30) : disp30;
         }
     }
 
@@ -1316,15 +1316,41 @@
         return x & ((1 << nbits) - 1);
     }
 
-    private static final int max13 = ((1 << 12) - 1);
-    private static final int min13 = -(1 << 12);
-
-    public static boolean isSimm13(int src) {
-        return min13 <= src && src <= max13;
+    /**
+     * Minimum value for signed immediate ranges.
+     */
+    public static long minSimm(long nbits) {
+        return -(1L << (nbits - 1));
+    }
+
+    /**
+     * Maximum value for signed immediate ranges.
+     */
+    public static long maxSimm(long nbits) {
+        return (1L << (nbits - 1)) - 1;
     }
 
-    public static boolean isSimm13(long src) {
-        return NumUtil.isInt(src) && min13 <= src && src <= max13;
+    /**
+     * Test if imm is within signed immediate range for nbits.
+     */
+    public static boolean isSimm(long imm, int nbits) {
+        return minSimm(nbits) <= imm && imm <= maxSimm(nbits);
+    }
+
+    public static boolean isSimm13(int imm) {
+        return isSimm(imm, 13);
+    }
+
+    public static boolean isSimm13(long imm) {
+        return NumUtil.isInt(imm) && isSimm(imm, 13);
+    }
+
+    public static boolean isDisp30(long imm) {
+        return isSimm(imm, 30);
+    }
+
+    public static boolean isWordDisp30(long imm) {
+        return isSimm(imm, 30 + 2);
     }
 
     public static final int hi22(int x) {
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Tue Jul 23 17:48:17 2013 +0200
@@ -324,19 +324,24 @@
         }
     }
 
-    public static class Setx {
+    /**
+     * This instruction is like sethi but for 64-bit values.
+     */
+    public static class Sethix {
+
+        private static final int INSTRUCTION_SIZE = 7;
 
         private long value;
         private Register dst;
         private boolean forceRelocatable;
 
-        public Setx(long value, Register dst, boolean forceRelocatable) {
+        public Sethix(long value, Register dst, boolean forceRelocatable) {
             this.value = value;
             this.dst = dst;
             this.forceRelocatable = forceRelocatable;
         }
 
-        public Setx(long value, Register dst) {
+        public Sethix(long value, Register dst) {
             this(value, dst, false);
         }
 
@@ -344,28 +349,6 @@
             int hi = (int) (value >> 32);
             int lo = (int) (value & ~0);
 
-// if (isSimm13(lo) && value == lo) {
-// new Or(g0, lo, dst).emit(masm);
-// } else if (hi == 0) {
-// new Sethi(lo, dst).emit(masm); // hardware version zero-extends to upper 32
-// if (lo10(lo) != 0) {
-// new Or(dst, lo10(lo), dst).emit(masm);
-// }
-// } else if (hi == -1) {
-// new Sethi(~lo, dst).emit(masm); // hardware version zero-extends to upper 32
-// new Xor(dst, ~lo10(~0), dst).emit(masm);
-// new Add(dst, lo10(lo), dst).emit(masm);
-// } else if (lo == 0) {
-// if (isSimm13(hi)) {
-// new Or(g0, hi, dst).emit(masm);
-// } else {
-// new Sethi(hi, dst).emit(masm); // hardware version zero-extends to upper 32
-// if (lo10(hi) != 0) {
-// new Or(dst, lo10(hi), dst).emit(masm);
-// }
-// }
-// new Sllx(dst, 32, dst).emit(masm);
-
             // This is the same logic as MacroAssembler::internal_set.
             final int startPc = masm.codeBuffer.position();
 
@@ -402,10 +385,32 @@
             }
             // Pad out the instruction sequence so it can be patched later.
             if (forceRelocatable) {
-                while (masm.codeBuffer.position() < (startPc + (7 * 4))) {
+                while (masm.codeBuffer.position() < (startPc + (INSTRUCTION_SIZE * 4))) {
                     new Nop().emit(masm);
                 }
             }
+        }
+    }
+
+    public static class Setx {
+
+        private long value;
+        private Register dst;
+        private boolean forceRelocatable;
+
+        public Setx(long value, Register dst, boolean forceRelocatable) {
+            this.value = value;
+            this.dst = dst;
+            this.forceRelocatable = forceRelocatable;
+        }
+
+        public Setx(long value, Register dst) {
+            this(value, dst, false);
+        }
+
+        public void emit(SPARCMacroAssembler masm) {
+            new Sethix(value, dst, forceRelocatable).emit(masm);
+            int lo = (int) (value & ~0);
             if (lo10(lo) != 0 || forceRelocatable) {
                 new Add(dst, lo10(lo), dst).emit(masm);
             }
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java	Tue Jul 23 17:48:17 2013 +0200
@@ -690,7 +690,7 @@
     }
 
     @Override
-    public void visitCompareAndSwap(CompareAndSwapNode node) {
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Tue Jul 23 17:48:17 2013 +0200
@@ -62,7 +62,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.Condition;
 import com.oracle.graal.nodes.calc.ConvertNode;
-import com.oracle.graal.nodes.java.CompareAndSwapNode;
+import com.oracle.graal.nodes.java.*;
 
 /**
  * This class implements the PTX specific portion of the LIR generator.
@@ -731,7 +731,7 @@
     }
 
     @Override
-    public void visitCompareAndSwap(CompareAndSwapNode node) {
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Jul 23 17:48:17 2013 +0200
@@ -54,13 +54,11 @@
 import com.oracle.graal.lir.sparc.SPARCControlFlow.SequentialSwitchOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.SwitchRangesOp;
 import com.oracle.graal.lir.sparc.SPARCControlFlow.TableSwitchOp;
-import com.oracle.graal.lir.sparc.SPARCMove.LoadOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MembarOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveFromRegOp;
 import com.oracle.graal.lir.sparc.SPARCMove.MoveToRegOp;
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StackLoadAddressOp;
-import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
@@ -94,6 +92,32 @@
     }
 
     @Override
+    public boolean canStoreConstant(Constant c) {
+        // SPARC can only store integer null constants (via g0)
+        switch (c.getKind()) {
+            case Float:
+            case Double:
+                return false;
+            default:
+                return c.isNull();
+        }
+    }
+
+    @Override
+    public boolean canInlineConstant(Constant c) {
+        switch (c.getKind()) {
+            case Int:
+                return SPARCAssembler.isSimm13(c.asInt()) && !runtime.needsDataPatch(c);
+            case Long:
+                return SPARCAssembler.isSimm13(c.asLong()) && !runtime.needsDataPatch(c);
+            case Object:
+                return c.isNull();
+            default:
+                return true;
+        }
+    }
+
+    @Override
     public Variable emitMove(Value input) {
         Variable result = newVariable(input.getKind());
         emitMove(result, input);
@@ -117,6 +141,87 @@
     }
 
     @Override
+    public SPARCAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
+        AllocatableValue baseRegister;
+        long finalDisp = displacement;
+        if (isConstant(base)) {
+            if (asConstant(base).isNull()) {
+                baseRegister = Value.ILLEGAL;
+            } else if (asConstant(base).getKind() != Kind.Object) {
+                finalDisp += asConstant(base).asLong();
+                baseRegister = Value.ILLEGAL;
+            } else {
+                baseRegister = load(base);
+            }
+        } else {
+            baseRegister = asAllocatable(base);
+        }
+
+        AllocatableValue indexRegister;
+        if (!index.equals(Value.ILLEGAL) && scale != 0) {
+            if (isConstant(index)) {
+                finalDisp += asConstant(index).asLong() * scale;
+                indexRegister = Value.ILLEGAL;
+            } else {
+                if (scale != 1) {
+                    Variable longIndex = newVariable(Kind.Long);
+                    emitMove(longIndex, index);
+                    indexRegister = emitMul(longIndex, Constant.forLong(scale));
+                } else {
+                    indexRegister = asAllocatable(index);
+                }
+
+                // if (baseRegister.equals(Value.ILLEGAL)) {
+                // baseRegister = asAllocatable(indexRegister);
+                // } else {
+                // Variable newBase = newVariable(Kind.Long);
+                // emitMove(newBase, baseRegister);
+                // baseRegister = newBase;
+                // baseRegister = emitAdd(baseRegister, indexRegister);
+                // }
+            }
+        } else {
+            indexRegister = Value.ILLEGAL;
+        }
+
+        int displacementInt;
+
+        // If we don't have an index register we can use a displacement, otherwise load the
+        // displacement into a register and add it to the base.
+        if (indexRegister.equals(Value.ILLEGAL)) {
+            // TODO What if displacement if too big?
+            displacementInt = (int) finalDisp;
+        } else {
+            displacementInt = 0;
+            AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
+            if (baseRegister.equals(Value.ILLEGAL)) {
+                baseRegister = displacementRegister;
+            } else {
+                Variable longBase = newVariable(Kind.Long);
+                emitMove(longBase, baseRegister);
+                baseRegister = emitAdd(longBase, displacementRegister);
+            }
+        }
+
+        return new SPARCAddressValue(target().wordKind, baseRegister, indexRegister, displacementInt);
+    }
+
+    protected SPARCAddressValue asAddressValue(Value address) {
+        if (address instanceof SPARCAddressValue) {
+            return (SPARCAddressValue) address;
+        } else {
+            return emitAddress(address, 0, Value.ILLEGAL, 0);
+        }
+    }
+
+    @Override
+    public Value emitAddress(StackSlot address) {
+        Variable result = newVariable(target().wordKind);
+        append(new StackLoadAddressOp(result, address));
+        return result;
+    }
+
+    @Override
     protected boolean peephole(ValueNode valueNode) {
         // No peephole optimizations for now
         return false;
@@ -267,7 +372,12 @@
 
     @Override
     protected void emitForeignCall(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
-        throw new InternalError("NYI");
+        long maxOffset = linkage.getMaxCallTargetOffset();
+        if (SPARCAssembler.isWordDisp30(maxOffset)) {
+            append(new SPARCCall.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
+        } else {
+            append(new SPARCCall.DirectFarForeignCallOp(this, linkage, result, arguments, temps, info));
+        }
     }
 
     @Override
@@ -354,121 +464,6 @@
     }
 
     @Override
-    public boolean canInlineConstant(Constant c) {
-        switch (c.getKind()) {
-            case Int:
-                return SPARCAssembler.isSimm13(c.asInt()) && !runtime.needsDataPatch(c);
-            case Long:
-                return SPARCAssembler.isSimm13(c.asLong()) && !runtime.needsDataPatch(c);
-            case Object:
-                return c.isNull();
-            default:
-                return true;
-        }
-    }
-
-    @Override
-    public boolean canStoreConstant(Constant c) {
-        throw new InternalError("NYI");
-    }
-
-    @Override
-    public SPARCAddressValue emitAddress(Value base, long displacement, Value index, int scale) {
-        AllocatableValue baseRegister;
-        long finalDisp = displacement;
-        if (isConstant(base)) {
-            if (asConstant(base).isNull()) {
-                baseRegister = Value.ILLEGAL;
-            } else if (asConstant(base).getKind() != Kind.Object) {
-                finalDisp += asConstant(base).asLong();
-                baseRegister = Value.ILLEGAL;
-            } else {
-                baseRegister = load(base);
-            }
-        } else {
-            baseRegister = asAllocatable(base);
-        }
-
-        AllocatableValue indexRegister;
-        if (!index.equals(Value.ILLEGAL) && scale != 0) {
-            if (isConstant(index)) {
-                finalDisp += asConstant(index).asLong() * scale;
-                indexRegister = Value.ILLEGAL;
-            } else {
-                if (scale != 1) {
-                    Variable longIndex = newVariable(Kind.Long);
-                    emitMove(longIndex, index);
-                    indexRegister = emitMul(longIndex, Constant.forLong(scale));
-                } else {
-                    indexRegister = asAllocatable(index);
-                }
-
-// if (baseRegister.equals(Value.ILLEGAL)) {
-// baseRegister = asAllocatable(indexRegister);
-// } else {
-// Variable newBase = newVariable(Kind.Long);
-// emitMove(newBase, baseRegister);
-// baseRegister = newBase;
-// baseRegister = emitAdd(baseRegister, indexRegister);
-// }
-            }
-        } else {
-            indexRegister = Value.ILLEGAL;
-        }
-
-        int displacementInt;
-
-        // If we don't have an index register we can use a displacement, otherwise load the
-        // displacement into a register and add it to the base.
-        if (indexRegister.equals(Value.ILLEGAL)) {
-            // TODO What if displacement if too big?
-            displacementInt = (int) finalDisp;
-        } else {
-            displacementInt = 0;
-            AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
-            if (baseRegister.equals(Value.ILLEGAL)) {
-                baseRegister = displacementRegister;
-            } else {
-                Variable longBase = newVariable(Kind.Long);
-                emitMove(longBase, baseRegister);
-                baseRegister = emitAdd(longBase, displacementRegister);
-            }
-        }
-
-        return new SPARCAddressValue(target().wordKind, baseRegister, indexRegister, displacementInt);
-    }
-
-    private SPARCAddressValue asAddress(Value address) {
-        if (address instanceof SPARCAddressValue) {
-            return (SPARCAddressValue) address;
-        } else {
-            return emitAddress(address, 0, Value.ILLEGAL, 0);
-        }
-    }
-
-    @Override
-    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode deopting) {
-        SPARCAddressValue loadAddress = asAddress(address);
-        Variable result = newVariable(kind);
-        append(new LoadOp(kind, result, loadAddress, deopting != null ? state(deopting) : null));
-        return result;
-    }
-
-    @Override
-    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode deopting) {
-        SPARCAddressValue storeAddress = asAddress(address);
-        Variable input = load(inputVal);
-        append(new StoreOp(kind, storeAddress, input, deopting != null ? state(deopting) : null));
-    }
-
-    @Override
-    public Value emitAddress(StackSlot address) {
-        Variable result = newVariable(target().wordKind);
-        append(new StackLoadAddressOp(result, address));
-        return result;
-    }
-
-    @Override
     public Value emitNegate(Value input) {
         Variable result = newVariable(input.getKind());
         switch (input.getKind()) {
@@ -680,7 +675,7 @@
                 append(new Op2Stack(ISHL, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHL, result, loadNonConst(b)));
+                append(new Op2Stack(LSHL, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -696,7 +691,7 @@
                 append(new Op2Stack(ISHR, result, a, loadNonConst(b)));
                 break;
             case Long:
-                append(new Op1Stack(LSHR, result, loadNonConst(b)));
+                append(new Op2Stack(LSHR, result, a, loadNonConst(b)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -808,7 +803,7 @@
     }
 
     @Override
-    public void visitCompareAndSwap(CompareAndSwapNode i) {
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Tue Jul 23 17:48:17 2013 +0200
@@ -39,6 +39,8 @@
  */
 public class ConditionalEliminationTest extends GraalCompilerTest {
 
+    public static Object field;
+
     static class Entry {
 
         final String name;
@@ -108,7 +110,7 @@
                 }
             } else {
                 if (b == null) {
-                    return 3;
+                    return -3;
                 } else {
                     return 4;
                 }
@@ -196,4 +198,34 @@
         assertEquals(InvokeKind.Special, ((MethodCallTargetNode) invoke.callTarget()).invokeKind());
     }
 
+    public static void testTypeMergingSnippet(Object o, boolean b) {
+        if (b) {
+            if (!(o instanceof Double)) {
+                return;
+            }
+        } else {
+            if (!(o instanceof Integer)) {
+                return;
+            }
+        }
+
+        /*
+         * For this test the conditional elimination has to correctly merge the type information it
+         * has about o, so that it can remove the check on Number.
+         */
+        if (!(o instanceof Number)) {
+            field = o;
+        }
+    }
+
+    @Test
+    public void testTypeMerging() {
+        StructuredGraph graph = parse("testTypeMergingSnippet");
+        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+        new ConditionalEliminationPhase(runtime()).apply(graph);
+        new CanonicalizerPhase.Instance(runtime(), null, true).apply(graph);
+
+        assertEquals(0, graph.getNodes().filter(StoreFieldNode.class).count());
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Tue Jul 23 17:48:17 2013 +0200
@@ -468,31 +468,19 @@
     }
 
     @Override
-    public void visitCompareAndSwap(CompareAndSwapNode node) {
-        Kind kind = node.newValue().kind();
-        assert kind == node.expected().kind();
-
-        Value expected = loadNonConst(operand(node.expected()));
-        Variable newValue = load(operand(node.newValue()));
-
-        AMD64AddressValue address;
-        int displacement = node.displacement();
-        Value index = operand(node.offset());
-        if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) {
-            assert !runtime.needsDataPatch(asConstant(index));
-            displacement += (int) asConstant(index).asLong();
-            address = new AMD64AddressValue(kind, load(operand(node.object())), displacement);
-        } else {
-            address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement);
-        }
-
+    public void visitCompareAndSwap(LoweredCompareAndSwapNode node, Value address) {
+        Kind kind = node.getNewValue().kind();
+        assert kind == node.getExpectedValue().kind();
+        Value expected = loadNonConst(operand(node.getExpectedValue()));
+        Variable newValue = load(operand(node.getNewValue()));
+        AMD64AddressValue addressValue = asAddressValue(address);
         RegisterValue raxRes = AMD64.rax.asValue(kind);
         emitMove(raxRes, expected);
         if (runtime().config.useCompressedOops && node.isCompressible()) {
             Variable scratch = newVariable(Kind.Long);
-            append(new CompareAndSwapCompressedOp(raxRes, address, raxRes, newValue, scratch, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment));
+            append(new CompareAndSwapCompressedOp(raxRes, addressValue, raxRes, newValue, scratch, runtime().config.narrowOopBase, runtime().config.narrowOopShift, runtime().config.logMinObjAlignment));
         } else {
-            append(new CompareAndSwapOp(raxRes, address, raxRes, newValue));
+            append(new CompareAndSwapOp(raxRes, addressValue, raxRes, newValue));
         }
         Variable result = newVariable(node.kind());
         append(new CondMoveOp(result, Condition.EQ, load(Constant.TRUE), Constant.FALSE));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -29,7 +29,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
@@ -60,6 +59,6 @@
         Register returnAddress = asRegister(cc.getArgument(1));
         masm.movq(returnAddress, new AMD64Address(rsp, 0));
 
-        AMD64Call.directJmp(tasm, masm, tasm.runtime.lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER));
+        AMD64Call.directJmp(tasm, masm, linkage);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Tue Jul 23 17:48:17 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import java.util.*;
+
 import sun.misc.*;
 
 import com.oracle.graal.api.code.*;
@@ -36,6 +38,7 @@
 import com.oracle.graal.hotspot.stubs.Stub;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
 
 import static com.oracle.graal.sparc.SPARC.*;
@@ -93,7 +96,7 @@
         }
     }
 
-    class HotSpotFrameContext implements FrameContext {
+    public class HotSpotFrameContext implements FrameContext {
 
         final boolean isStub;
 
@@ -138,6 +141,7 @@
     public TargetMethodAssembler newAssembler(LIRGenerator lirGen, CompilationResult compilationResult) {
         SPARCHotSpotLIRGenerator gen = (SPARCHotSpotLIRGenerator) lirGen;
         FrameMap frameMap = gen.frameMap;
+        assert gen.deoptimizationRescueSlot == null || frameMap.frameNeedsAllocating() : "method that can deoptimize must have a frame";
 
         Stub stub = gen.getStub();
         AbstractAssembler masm = createAssembler(frameMap);
@@ -150,6 +154,12 @@
             tasm.compilationResult.setCustomStackAreaOffset(frameMap.offsetForStackSlot(deoptimizationRescueSlot));
         }
 
+        if (stub != null) {
+            // SPARC stubs always enter a frame which saves the registers.
+            final Set<Register> definedRegisters = new HashSet<>();
+            stub.initDestroyedRegisters(definedRegisters);
+        }
+
         return tasm;
     }
 
@@ -165,13 +175,15 @@
 
         if (unverifiedStub != null) {
             tasm.recordMark(Marks.MARK_UNVERIFIED_ENTRY);
-            CallingConvention cc = regConfig.getCallingConvention(JavaCallee, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false);
+            // We need to use JavaCall here because we haven't entered the frame yet.
+            CallingConvention cc = regConfig.getCallingConvention(JavaCall, null, new JavaType[]{runtime().lookupJavaType(Object.class)}, target, false);
             Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
+            Register scratch = g3;
             Register receiver = asRegister(cc.getArgument(0));
             SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
 
-            new Ldx(src, g0).emit(masm);
-            new Cmp(inlineCacheKlass, g0).emit(masm);
+            new Ldx(src, scratch).emit(masm);
+            new Cmp(scratch, inlineCacheKlass).emit(masm);
             new Bpne(CC.Xcc, unverifiedStub).emit(masm);
             new Nop().emit(masm);  // delay slot
         }
@@ -186,10 +198,9 @@
         HotSpotFrameContext frameContext = (HotSpotFrameContext) tasm.frameContext;
         if (frameContext != null && !frameContext.isStub) {
             tasm.recordMark(Marks.MARK_EXCEPTION_HANDLER_ENTRY);
-// SPARCCall.directCall(tasm, asm, runtime().lookupForeignCall(EXCEPTION_HANDLER), null, false,
-// null);
+            SPARCCall.directCall(tasm, masm, runtime().lookupForeignCall(EXCEPTION_HANDLER), null, false, null);
             tasm.recordMark(Marks.MARK_DEOPT_HANDLER_ENTRY);
-// SPARCCall.directCall(tasm, asm, runtime().lookupForeignCall(DEOPT_HANDLER), null, false, null);
+            SPARCCall.directCall(tasm, masm, runtime().lookupForeignCall(DEOPT_HANDLER), null, false, null);
         } else {
             // No need to emit the stubs for entries back into the method since
             // it has no calls that can cause such "return" entries
@@ -198,8 +209,8 @@
 
         if (unverifiedStub != null) {
             masm.bind(unverifiedStub);
-// SPARCCall.directJmp(tasm, asm, runtime().lookupForeignCall(IC_MISS_HANDLER));
-            // throw new InternalError("g0 must be scratch register");
+            Register scratch = g3;
+            SPARCCall.indirectJmp(tasm, masm, scratch, runtime().lookupForeignCall(IC_MISS_HANDLER));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Removes the current frame and tail calls the uncommon trap routine.
+ */
+@Opcode("DEOPT_CALLER")
+final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp {
+
+    private final DeoptimizationAction action;
+    private final DeoptimizationReason reason;
+
+    SPARCHotSpotDeoptimizeCallerOp(DeoptimizationAction action, DeoptimizationReason reason) {
+        this.action = action;
+        this.reason = reason;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        leaveFrame(tasm);
+
+// SPARCHotSpotBackend backend = (SPARCHotSpotBackend)
+// HotSpotGraalRuntime.graalRuntime().getBackend();
+// final boolean isStub = true;
+// HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub);
+// frameContext.enter(tasm);
+
+        HotSpotGraalRuntime runtime = graalRuntime();
+        Register thread = runtime.getRuntime().threadRegister();
+
+        Register scratch = g5;
+        new Mov(tasm.runtime.encodeDeoptActionAndReason(action, reason), scratch).emit(masm);
+        new Stw(scratch, new SPARCAddress(thread, runtime.getConfig().pendingDeoptimizationOffset)).emit(masm);
+
+        SPARCCall.indirectJmp(tasm, masm, scratch, tasm.runtime.lookupForeignCall(UNCOMMON_TRAP));
+
+// frameContext.leave(tasm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Superclass for operations that leave a method's frame.
+ */
+abstract class SPARCHotSpotEpilogueOp extends SPARCLIRInstruction {
+
+    protected void leaveFrame(TargetMethodAssembler tasm) {
+        if (tasm.frameContext != null) {
+            tasm.frameContext.leave(tasm);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Sets up the arguments for an exception handler in the callers frame, removes the current frame
+ * and jumps to the handler.
+ */
+@Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
+final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp {
+
+    @Use(REG) AllocatableValue handlerInCallerPc;
+    @Use(REG) AllocatableValue exception;
+    @Use(REG) AllocatableValue exceptionPc;
+
+    SPARCHotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc) {
+        this.handlerInCallerPc = handlerInCallerPc;
+        this.exception = exception;
+        this.exceptionPc = exceptionPc;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        leaveFrame(tasm);
+
+        // Restore SP from L7 if the exception PC is a method handle call site.
+        Register thread = graalRuntime().getRuntime().threadRegister();
+        int isMethodHandleReturnOffset = graalRuntime().getConfig().threadIsMethodHandleReturnOffset;
+        SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset);
+        new Lduw(dst, o7).emit(masm);
+        new Cmp(o7, o7).emit(masm);
+        new Movcc(ConditionFlag.NotZero, CC.Icc, l7, sp).emit(masm);
+
+        new Jmpl(asRegister(handlerInCallerPc), 0, g0).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Tue Jul 23 17:48:17 2013 +0200
@@ -23,17 +23,21 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
 
 import java.lang.reflect.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.sparc.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.lir.sparc.SPARCMove.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -55,6 +59,32 @@
      */
     StackSlot deoptimizationRescueSlot;
 
+    @SuppressWarnings("hiding")
+    @Override
+    protected DebugInfoBuilder createDebugInfoBuilder(NodeMap<Value> nodeOperands) {
+        assert runtime().config.basicLockSize == 8;
+        HotSpotLockStack lockStack = new HotSpotLockStack(frameMap, Kind.Long);
+        return new HotSpotDebugInfoBuilder(nodeOperands, lockStack);
+    }
+
+    @Override
+    public StackSlot getLockSlot(int lockDepth) {
+        return ((HotSpotDebugInfoBuilder) debugInfoBuilder).lockStack().makeLockSlot(lockDepth);
+    }
+
+    @Override
+    protected boolean needOnlyOopMaps() {
+        // Stubs only need oop maps
+        return graph.start() instanceof StubStartNode;
+    }
+
+    Stub getStub() {
+        if (graph.start() instanceof StubStartNode) {
+            return ((StubStartNode) graph.start()).getStub();
+        }
+        return null;
+    }
+
     @Override
     public void visitSafepointNode(SafepointNode i) {
         LIRFrameState info = state(i);
@@ -62,8 +92,37 @@
     }
 
     @Override
+    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
+        Kind kind = x.newValue().kind();
+        assert kind == x.expectedValue().kind();
+
+        Variable address = load(operand(x.object()));
+        Value offset = operand(x.offset());
+        Variable cmpValue = (Variable) loadNonConst(operand(x.expectedValue()));
+        Variable newValue = load(operand(x.newValue()));
+
+        if (ValueUtil.isConstant(offset)) {
+            assert !runtime.needsDataPatch(asConstant(offset));
+            Variable longAddress = newVariable(Kind.Long);
+            emitMove(longAddress, address);
+            address = emitAdd(longAddress, asConstant(offset));
+        } else {
+            if (isLegal(offset)) {
+                address = emitAdd(address, offset);
+            }
+        }
+
+        append(new CompareAndSwapOp(address, cmpValue, newValue));
+
+        Variable result = newVariable(x.kind());
+        emitMove(result, newValue);
+        setResult(x, result);
+    }
+
+    @Override
     public void emitTailcall(Value[] args, Value address) {
-        throw new InternalError("NYI");
+// append(new AMD64TailcallOp(args, address));
+        throw GraalInternalError.unimplemented();
     }
 
     @Override
@@ -89,57 +148,120 @@
 // emitMove(targetAddress, operand(callTarget.computedAddress()));
 // append(new AMD64IndirectCallOp(callTarget.target(), result, parameters, temps, metaspaceMethod,
 // targetAddress, callState));
-        throw new InternalError("NYI");
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public void emitUnwind(Value exception) {
+        ForeignCallLinkage linkage = getRuntime().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention linkageCc = linkage.getCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionParameter = (RegisterValue) linkageCc.getArgument(0);
+        emitMove(exceptionParameter, exception);
+        append(new SPARCHotSpotUnwindOp(exceptionParameter));
+        throw GraalInternalError.unimplemented();
+    }
+
+    @Override
+    public void emitDeoptimize(DeoptimizationAction action, DeoptimizingNode deopting) {
+// append(new AMD64DeoptimizeOp(action, deopting.getDeoptimizationReason(), state(deopting)));
+        throw GraalInternalError.unimplemented();
     }
 
     @Override
     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
-        throw new InternalError("NYI");
+        append(new SPARCHotSpotDeoptimizeCallerOp(action, reason));
     }
 
     @Override
     public void emitPatchReturnAddress(ValueNode address) {
-        throw new InternalError("NYI");
+        append(new SPARCHotSpotPatchReturnAddressOp(load(operand(address))));
     }
 
     @Override
     public void emitJumpToExceptionHandlerInCaller(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
-        throw new InternalError("NYI");
+        Variable handler = load(operand(handlerInCallerPc));
+        ForeignCallLinkage linkage = getRuntime().lookupForeignCall(EXCEPTION_HANDLER_IN_CALLER);
+        CallingConvention linkageCc = linkage.getCallingConvention();
+        assert linkageCc.getArgumentCount() == 2;
+        RegisterValue exceptionFixed = (RegisterValue) linkageCc.getArgument(0);
+        RegisterValue exceptionPcFixed = (RegisterValue) linkageCc.getArgument(1);
+        emitMove(exceptionFixed, operand(exception));
+        emitMove(exceptionPcFixed, operand(exceptionPc));
+        SPARCHotSpotJumpToExceptionHandlerInCallerOp op = new SPARCHotSpotJumpToExceptionHandlerInCallerOp(handler, exceptionFixed, exceptionPcFixed);
+        append(op);
+    }
+
+    private static boolean isCompressCandidate(DeoptimizingNode access) {
+        return access != null && ((HeapAccess) access).isCompressible();
+    }
+
+    @Override
+    public Variable emitLoad(Kind kind, Value address, DeoptimizingNode access) {
+        SPARCAddressValue loadAddress = asAddressValue(address);
+        Variable result = newVariable(kind);
+        assert access == null || access instanceof HeapAccess;
+        if (isCompressCandidate(access)) {
+            if (runtime().config.useCompressedOops && kind == Kind.Object) {
+// append(new LoadCompressedPointer(kind, result, loadAddress, access != null ? state(access) :
+// null, runtime().config.narrowOopBase, runtime().config.narrowOopShift,
+// runtime().config.logMinObjAlignment));
+                throw GraalInternalError.unimplemented();
+            } else if (runtime().config.useCompressedKlassPointers && kind == Kind.Long) {
+// append(new LoadCompressedPointer(kind, result, loadAddress, access != null ? state(access) :
+// null, runtime().config.narrowKlassBase, runtime().config.narrowKlassShift,
+// runtime().config.logKlassAlignment));
+                throw GraalInternalError.unimplemented();
+            } else {
+                append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+            }
+        } else {
+            append(new LoadOp(kind, result, loadAddress, access != null ? state(access) : null));
+        }
+        return result;
     }
 
     @Override
-    public void visitDirectCompareAndSwap(DirectCompareAndSwapNode x) {
-        Kind kind = x.newValue().kind();
-        assert kind == x.expectedValue().kind();
-
-        Variable address = load(operand(x.object()));
-        Value offset = operand(x.offset());
-        Variable cmpValue = (Variable) loadNonConst(operand(x.expectedValue()));
-        Variable newValue = load(operand(x.newValue()));
-
-        if (ValueUtil.isConstant(offset)) {
-            assert !runtime.needsDataPatch(asConstant(offset));
-            address = emitAdd(address, asConstant(offset));
-        } else {
-            if (isLegal(offset)) {
-                address = emitAdd(address, offset);
+    public void emitStore(Kind kind, Value address, Value inputVal, DeoptimizingNode access) {
+        SPARCAddressValue storeAddress = asAddressValue(address);
+        LIRFrameState state = access != null ? state(access) : null;
+        if (isConstant(inputVal)) {
+            Constant c = asConstant(inputVal);
+            if (canStoreConstant(c)) {
+                if (inputVal.getKind() == Kind.Object) {
+                    append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedOops && isCompressCandidate(access)));
+                } else if (inputVal.getKind() == Kind.Long) {
+                    append(new StoreConstantOp(kind, storeAddress, c, state, runtime().config.useCompressedKlassPointers && isCompressCandidate(access)));
+                } else {
+                    append(new StoreConstantOp(kind, storeAddress, c, state, false));
+                }
+                return;
             }
         }
-
-        append(new CompareAndSwapOp(address, cmpValue, newValue));
-
-        Variable result = newVariable(x.kind());
-        emitMove(result, newValue);
-        setResult(x, result);
+        Variable input = load(inputVal);
+        if (isCompressCandidate(access)) {
+            if (runtime().config.useCompressedOops && kind == Kind.Object) {
+// if (input.getKind() == Kind.Object) {
+// Variable scratch = newVariable(Kind.Long);
+// append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state,
+// runtime().config.narrowOopBase, runtime().config.narrowOopShift,
+// runtime().config.logMinObjAlignment));
+// } else {
+// // the input oop is already compressed
+// append(new StoreOp(input.getKind(), storeAddress, input, state));
+// }
+                throw GraalInternalError.unimplemented();
+            } else if (runtime().config.useCompressedKlassPointers && kind == Kind.Long) {
+// Variable scratch = newVariable(Kind.Long);
+// append(new StoreCompressedPointer(kind, storeAddress, input, scratch, state,
+// runtime().config.narrowKlassBase, runtime().config.narrowKlassShift,
+// runtime().config.logKlassAlignment));
+                throw GraalInternalError.unimplemented();
+            } else {
+                append(new StoreOp(kind, storeAddress, input, state));
+            }
+        } else {
+            append(new StoreOp(kind, storeAddress, input, state));
+        }
     }
-
-    @Override
-    public StackSlot getLockSlot(int lockDepth) {
-        throw new InternalError("NYI");
-    }
-
-    public Stub getStub() {
-        throw new InternalError("NYI");
-    }
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Patch the return address of the current frame.
+ */
+@Opcode("PATCH_RETURN")
+final class SPARCHotSpotPatchReturnAddressOp extends SPARCLIRInstruction {
+
+    @Use(REG) AllocatableValue address;
+
+    SPARCHotSpotPatchReturnAddressOp(AllocatableValue address) {
+        this.address = address;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        // FIXME This is non-trivial. On SPARC we need to flush all register windows first before we
+        // can patch the return address (see: frame::patch_pc).
+        // int frameSize = tasm.frameMap.frameSize();
+        // new Stx(asRegister(address), new SPARCAddress(sp, frameSize));
+        new Ldx(new SPARCAddress(g0, g0), g0).emit(masm);
+    }
+}
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Tue Jul 23 17:48:17 2013 +0200
@@ -95,14 +95,16 @@
         // @formatter:off
         if (reserveForHeapBase) {
             registers = new Register[] {
-                    // TODO this is not complete
+                        // TODO this is not complete
+                        o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ i7,
                         f0, f1, f2, f3, f4, f5, f6, f7
                       };
         } else {
             registers = new Register[] {
-                    // TODO this is not complete
+                        // TODO this is not complete
+                        o0, o1, o2, o3, o4, o5, /*o6,*/ o7,
                         l0, l1, l2, l3, l4, l5, l6, l7,
                         i0, i1, i2, i3, i4, i5, /*i6,*/ i7,
                         f0, f1, f2, f3, f4, f5, f6, f7
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRuntime.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRuntime.java	Tue Jul 23 17:48:17 2013 +0200
@@ -76,7 +76,7 @@
 
     @Override
     public Register stackPointerRegister() {
-        throw new InternalError("NYI: SPARC: Define stack pointer register.");
+        return sp;
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot.sparc;
+
+import static com.oracle.graal.sparc.SPARC.*;
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Mov;
+import com.oracle.graal.hotspot.stubs.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.sparc.*;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * Removes the current frame and jumps to the {@link UnwindExceptionToCallerStub}.
+ */
+@Opcode("UNWIND")
+final class SPARCHotSpotUnwindOp extends SPARCHotSpotEpilogueOp {
+
+    @Use({REG}) protected RegisterValue exception;
+
+    SPARCHotSpotUnwindOp(RegisterValue exception) {
+        this.exception = exception;
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, SPARCMacroAssembler masm) {
+        leaveFrame(tasm);
+
+        ForeignCallLinkage linkage = tasm.runtime.lookupForeignCall(UNWIND_EXCEPTION_TO_CALLER);
+        CallingConvention cc = linkage.getCallingConvention();
+        assert cc.getArgumentCount() == 2;
+        assert exception.equals(cc.getArgument(0));
+
+        // Get return address (is in o7 after leave).
+        Register returnAddress = asRegister(cc.getArgument(1));
+        new Mov(o7, returnAddress).emit(masm);
+
+        Register scratch = g5;
+        SPARCCall.indirectJmp(tasm, masm, scratch, linkage);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Jul 23 17:48:17 2013 +0200
@@ -580,11 +580,9 @@
             // Separate out GC barrier semantics
             CompareAndSwapNode cas = (CompareAndSwapNode) n;
             LocationNode location = IndexedLocationNode.create(ANY_LOCATION, cas.expected().kind(), cas.displacement(), cas.offset(), graph, 1);
-            cas.setLocation(location);
-            cas.setBarrierType(getCompareAndSwapBarrier(cas));
-            if (cas.expected().kind() == Kind.Object) {
-                cas.setCompressible();
-            }
+            LoweredCompareAndSwapNode atomicNode = graph.add(new LoweredCompareAndSwapNode(cas.object(), location, cas.expected(), cas.newValue(), getCompareAndSwapBarrier(cas),
+                            cas.expected().kind() == Kind.Object));
+            graph.replaceFixedWithFixed(cas, atomicNode);
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
             GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierAdditionPhase.java	Tue Jul 23 17:48:17 2013 +0200
@@ -43,7 +43,7 @@
         for (WriteNode node : graph.getNodes(WriteNode.class)) {
             addWriteNodeBarriers(node, graph);
         }
-        for (CompareAndSwapNode node : graph.getNodes(CompareAndSwapNode.class)) {
+        for (LoweredCompareAndSwapNode node : graph.getNodes(LoweredCompareAndSwapNode.class)) {
             addCASBarriers(node, graph);
         }
         for (ArrayRangeWriteNode node : graph.getNodes(ArrayRangeWriteNode.class)) {
@@ -93,19 +93,19 @@
 
     }
 
-    private static void addCASBarriers(CompareAndSwapNode node, StructuredGraph graph) {
+    private static void addCASBarriers(LoweredCompareAndSwapNode node, StructuredGraph graph) {
         BarrierType barrierType = node.getBarrierType();
         if (barrierType == BarrierType.PRECISE) {
             if (useG1GC()) {
-                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.expected(), node.getLocation(), false, false)));
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.newValue(), node.getLocation(), true)));
+                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.getExpectedValue(), node.getLocation(), false, false)));
+                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.getNewValue(), node.getLocation(), true)));
             } else {
                 graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.getLocation(), true)));
             }
         } else if (barrierType == BarrierType.IMPRECISE) {
             if (useG1GC()) {
-                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.expected(), node.getLocation(), false, false)));
-                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.newValue(), node.getLocation(), false)));
+                graph.addBeforeFixed(node, graph.add(new G1PreWriteBarrier(node.object(), node.getExpectedValue(), node.getLocation(), false, false)));
+                graph.addAfterFixed(node, graph.add(new G1PostWriteBarrier(node.object(), node.getNewValue(), node.getLocation(), false)));
             } else {
                 graph.addAfterFixed(node, graph.add(new SerialWriteBarrier(node.object(), node.getLocation(), false)));
             }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/WriteBarrierVerificationPhase.java	Tue Jul 23 17:48:17 2013 +0200
@@ -113,7 +113,7 @@
 
     private static boolean isObjectWrite(Node node) {
         if ((node instanceof WriteNode && (((WriteNode) node).getBarrierType() != BarrierType.NONE)) ||
-                        (node instanceof CompareAndSwapNode && (((CompareAndSwapNode) node).getBarrierType() != BarrierType.NONE))) {
+                        (node instanceof LoweredCompareAndSwapNode && (((LoweredCompareAndSwapNode) node).getBarrierType() != BarrierType.NONE))) {
             return true;
         }
         return false;
@@ -146,9 +146,9 @@
         if (write instanceof WriteNode) {
             writtenObject = ((WriteNode) write).object();
             writtenLocation = ((WriteNode) write).location();
-        } else if (write instanceof CompareAndSwapNode) {
-            writtenObject = ((CompareAndSwapNode) write).object();
-            writtenLocation = ((CompareAndSwapNode) write).getLocation();
+        } else if (write instanceof LoweredCompareAndSwapNode) {
+            writtenObject = ((LoweredCompareAndSwapNode) write).object();
+            writtenLocation = ((LoweredCompareAndSwapNode) write).getLocation();
         } else {
             assert false : "Node must be of type requiring a write barrier";
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Jul 23 17:48:17 2013 +0200
@@ -195,7 +195,7 @@
                 return null;
             }
 
-            PhiNode phi = graph.unique(new PhiNode(currentValue.kind(), block));
+            PhiNode phi = graph.add(new PhiNode(currentValue.kind(), block));
             for (int i = 0; i < block.phiPredecessorCount(); i++) {
                 phi.addInput(currentValue);
             }
@@ -290,7 +290,7 @@
         }
         assert !block.isPhiAtMerge(value) : "phi function for this block already created";
 
-        PhiNode phi = graph.unique(new PhiNode(value.kind(), block));
+        PhiNode phi = graph.add(new PhiNode(value.kind(), block));
         phi.addInput(value);
         return phi;
     }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Tue Jul 23 17:48:17 2013 +0200
@@ -264,10 +264,10 @@
                     new Add(asIntReg(src2), -(tasm.asIntConst(src1)), asIntReg(dst)).emit(masm);
                     break;
                 case IAND:
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                 case IDIV:
                     assert isSimm13(tasm.asIntConst(src1));
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                     // new Sdivx(masm, asIntReg(src1), asIntReg(src2),
                     // asIntReg(dst));
                 case FSUB:
@@ -311,6 +311,14 @@
                     assert isSimm13(tasm.asIntConst(src2));
                     new Xor(asIntReg(src1), tasm.asIntConst(src2), asIntReg(dst)).emit(masm);
                     break;
+                case LADD:
+                    assert isSimm13(tasm.asIntConst(src2));
+                    new Add(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
+                    break;
+                case LSUB:
+                    assert isSimm13(tasm.asIntConst(src2));
+                    new Sub(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
+                    break;
                 case LMUL:
                     assert isSimm13(tasm.asIntConst(src2));
                     new Mulx(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
@@ -319,6 +327,10 @@
                     assert isSimm13(tasm.asIntConst(src2));
                     new Add(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
                     break;
+                case LSHL:
+                    assert isSimm13(tasm.asIntConst(src2));
+                    new Sll(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
+                    break;
                 case LUSHR:
                     assert isSimm13(tasm.asIntConst(src2));
                     new Srl(asLongReg(src1), tasm.asIntConst(src2), asLongReg(dst)).emit(masm);
@@ -365,7 +377,7 @@
                     new Sra(asIntReg(src1), asIntReg(src2), asIntReg(dst)).emit(masm);
                     break;
                 case IREM:
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                 case LADD:
                     new Add(asLongReg(src1), asLongReg(src2), asLongReg(dst)).emit(masm);
                     break;
@@ -400,7 +412,7 @@
                 case LUDIV:
                 case LUREM:
                 case LREM:
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                 case FADD:
                     new Fadds(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm);
                     break;
@@ -414,7 +426,7 @@
                     new Fdivs(asFloatReg(src1), asFloatReg(src2), asFloatReg(dst)).emit(masm);
                     break;
                 case FREM:
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                 case DADD:
                     new Faddd(asDoubleReg(src1), asDoubleReg(src2), asDoubleReg(dst)).emit(masm);
                     break;
@@ -428,7 +440,7 @@
                     new Fdivd(asDoubleReg(src1), asDoubleReg(src2), asDoubleReg(dst)).emit(masm);
                     break;
                 case DREM:
-                    throw new InternalError("NYI");
+                    throw GraalInternalError.unimplemented();
                 default:
                     throw GraalInternalError.shouldNotReachHere("missing: " + opcode);
             }
@@ -507,7 +519,7 @@
                 rk = result.getKind();
                 xsk = x.getKind().getStackKind();
                 ysk = y.getKind().getStackKind();
-                assert rk == Kind.Int && xsk == Kind.Int && ysk == Kind.Int : "opcode=" + opcode + ", rk=" + rk + ", xsk=" + xsk + ", ysk=" + ysk;
+                assert rk == Kind.Int && xsk == Kind.Int && ysk == Kind.Int;
                 break;
             case LADD:
             case LSUB:
@@ -517,13 +529,18 @@
             case LAND:
             case LOR:
             case LXOR:
+                rk = result.getKind();
+                xk = x.getKind();
+                yk = y.getKind();
+                assert rk == Kind.Long && xk == Kind.Long && yk == Kind.Long;
+                break;
             case LSHL:
             case LSHR:
             case LUSHR:
                 rk = result.getKind();
                 xk = x.getKind();
                 yk = y.getKind();
-                assert rk == Kind.Long && xk == Kind.Long && yk == Kind.Long;
+                assert rk == Kind.Long && xk == Kind.Long && (yk == Kind.Int || yk == Kind.Long);
                 break;
             case FADD:
             case FSUB:
@@ -543,10 +560,10 @@
                 rk = result.getKind();
                 xk = x.getKind();
                 yk = y.getKind();
-                assert rk == Kind.Double && xk == Kind.Double && yk == Kind.Double;
+                assert rk == Kind.Double && xk == Kind.Double && yk == Kind.Double : "opcode=" + opcode + ", result kind=" + rk + ", x kind=" + xk + ", y kind=" + yk;
                 break;
             default:
-                throw new InternalError("NYI: " + opcode);
+                throw GraalInternalError.shouldNotReachHere("missing: " + opcode);
         }
     }
 }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Tue Jul 23 17:48:17 2013 +0200
@@ -153,14 +153,13 @@
         }
         int before = masm.codeBuffer.position();
         if (scratch != null) {
-// // offset might not fit a 32-bit immediate, generate an
-// // indirect call with a 64-bit immediate
-// masm.movq(scratch, 0L);
-// masm.call(scratch);
-// } else {
-// masm.call();
+            // offset might not fit a 30-bit displacement, generate an
+            // indirect call with a 64-bit immediate
+            new Sethix(0L, scratch, true).emit(masm);
+            new Jmpl(scratch, 0, r15).emit(masm);
+        } else {
+            new Call(0).emit(masm);
         }
-        new Call(0).emit(masm);
         int after = masm.codeBuffer.position();
         tasm.recordDirectCall(before, after, callTarget, info);
         tasm.recordExceptionHandlers(after, info);
@@ -168,14 +167,14 @@
         new Nop().emit(masm);  // delay slot
     }
 
-    public static void directJmp(TargetMethodAssembler tasm, SPARCMacroAssembler masm, InvokeTarget target) {
+    public static void indirectJmp(TargetMethodAssembler tasm, SPARCMacroAssembler masm, Register dst, InvokeTarget target) {
         int before = masm.codeBuffer.position();
-// masm.jmp(0, true);
+        new Sethix(0L, dst, true).emit(masm);
+        new Jmp(new SPARCAddress(dst, 0)).emit(masm);
         int after = masm.codeBuffer.position();
-        tasm.recordDirectCall(before, after, target, null);
+        tasm.recordIndirectCall(before, after, target, null);
 // masm.ensureUniquePC();
         new Nop().emit(masm);  // delay slot
-        throw new InternalError("NYI");
     }
 
     public static void indirectCall(TargetMethodAssembler tasm, SPARCMacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Tue Jul 23 17:48:17 2013 +0200
@@ -73,6 +73,9 @@
                 case GT:
                     new Bpg(CC.Xcc, destination.label()).emit(masm);
                     break;
+                case AT:
+                    new Bpgu(CC.Xcc, destination.label()).emit(masm);
+                    break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Tue Jul 23 17:48:17 2013 +0200
@@ -264,6 +264,51 @@
         }
     }
 
+    public static class StoreConstantOp extends MemOp {
+
+        protected final Constant input;
+        private final boolean compress;
+
+        public StoreConstantOp(Kind kind, SPARCAddressValue address, Constant input, LIRFrameState state, boolean compress) {
+            super(kind, address, state);
+            this.input = input;
+            this.compress = compress;
+            if (input.isNonNull()) {
+                throw GraalInternalError.shouldNotReachHere("Can only store null constants to memory");
+            }
+        }
+
+        @Override
+        public void emitMemAccess(SPARCMacroAssembler masm) {
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                    new Stb(g0, address.toAddress()).emit(masm);
+                    break;
+                case Char:
+                case Short:
+                    new Sth(g0, address.toAddress()).emit(masm);
+                    break;
+                case Int:
+                    new Stw(g0, address.toAddress()).emit(masm);
+                    break;
+                case Long:
+                case Object:
+                    if (compress) {
+                        new Stw(g0, address.toAddress()).emit(masm);
+                    } else {
+                        new Stx(g0, address.toAddress()).emit(masm);
+                    }
+                    break;
+                case Float:
+                case Double:
+                    throw GraalInternalError.shouldNotReachHere("Cannot store float constants to memory");
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
     public static void move(TargetMethodAssembler tasm, SPARCMacroAssembler masm, Value result, Value input) {
         if (isRegister(input)) {
             if (isRegister(result)) {
@@ -314,9 +359,11 @@
                 new Stw(asRegister(input), dest).emit(masm);
                 break;
             case Long:
+            case Object:
+                new Stx(asRegister(input), dest).emit(masm);
+                break;
             case Float:
             case Double:
-            case Object:
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
@@ -342,21 +389,25 @@
             case Int:
                 if (tasm.runtime.needsDataPatch(input)) {
                     tasm.recordDataReferenceInCode(input, 0, true);
+                    new Setuw(input.asInt(), asRegister(result)).emit(masm);
+                } else {
+                    if (input.isDefaultForKind()) {
+                        new Clr(asRegister(result)).emit(masm);
+                    } else {
+                        new Setuw(input.asInt(), asRegister(result)).emit(masm);
+                    }
                 }
-                new Setuw(input.asInt(), asRegister(result)).emit(masm);
                 break;
             case Long: {
                 if (tasm.runtime.needsDataPatch(input)) {
-                    new Nop().emit(masm);
                     tasm.recordDataReferenceInCode(input, 0, true);
                     new Setx(input.asLong(), asRegister(result), true).emit(masm);
-                    new Nop().emit(masm);
                 } else {
-                    new Nop().emit(masm);
-                    new Nop().emit(masm);
-                    new Setx(input.asLong(), asRegister(result)).emit(masm);
-                    new Nop().emit(masm);
-                    new Nop().emit(masm);
+                    if (input.isDefaultForKind()) {
+                        new Clr(asRegister(result)).emit(masm);
+                    } else {
+                        new Setx(input.asLong(), asRegister(result)).emit(masm);
+                    }
                 }
                 break;
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Tue Jul 23 17:48:17 2013 +0200
@@ -25,7 +25,6 @@
 import static com.oracle.graal.graph.UnsafeAccess.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,7 +34,7 @@
  * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
  * value matched the expected value.
  */
-public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint.Single, Node.IterableNodeType, HeapAccess {
+public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, Lowerable, MemoryCheckpoint.Single {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
@@ -43,8 +42,6 @@
     @Input private ValueNode newValue;
     @Input private LocationNode location;
     private final int displacement;
-    private BarrierType barrierType;
-    private boolean compressible;
 
     public ValueNode object() {
         return object;
@@ -75,24 +72,6 @@
         this.location = location;
     }
 
-    @Override
-    public BarrierType getBarrierType() {
-        return barrierType;
-    }
-
-    public void setBarrierType(BarrierType type) {
-        this.barrierType = type;
-    }
-
-    @Override
-    public boolean isCompressible() {
-        return compressible;
-    }
-
-    public void setCompressible() {
-        this.compressible = true;
-    }
-
     public CompareAndSwapNode(ValueNode object, int displacement, ValueNode offset, ValueNode expected, ValueNode newValue) {
         super(StampFactory.forKind(Kind.Boolean.getStackKind()));
         assert expected.kind() == newValue.kind();
@@ -101,8 +80,6 @@
         this.expected = expected;
         this.newValue = newValue;
         this.displacement = displacement;
-        this.barrierType = BarrierType.NONE;
-        this.compressible = false;
     }
 
     @Override
@@ -111,11 +88,6 @@
     }
 
     @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.visitCompareAndSwap(this);
-    }
-
-    @Override
     public void lower(LoweringTool tool, LoweringType loweringType) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Tue Jul 23 17:48:17 2013 +0200
@@ -22,8 +22,11 @@
  */
 package com.oracle.graal.nodes.java;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -57,11 +60,15 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         MetaAccessProvider runtime = tool.runtime();
-        if (tool.canonicalizeReads()) {
+        if (tool.canonicalizeReads() && runtime != null) {
             ConstantNode constant = asConstant(runtime);
             if (constant != null) {
                 return constant;
             }
+            PhiNode phi = asPhi(runtime);
+            if (phi != null) {
+                return phi;
+            }
         }
         return this;
     }
@@ -70,16 +77,34 @@
      * Gets a constant value for this load if possible.
      */
     public ConstantNode asConstant(MetaAccessProvider runtime) {
-        if (runtime != null) {
-            Constant constant = null;
-            if (isStatic()) {
-                constant = field().readConstantValue(null);
-            } else if (object().isConstant() && !object().isNullConstant()) {
-                constant = field().readConstantValue(object().asConstant());
+        Constant constant = null;
+        if (isStatic()) {
+            constant = field().readConstantValue(null);
+        } else if (object().isConstant() && !object().isNullConstant()) {
+            constant = field().readConstantValue(object().asConstant());
+        }
+        if (constant != null) {
+            return ConstantNode.forConstant(constant, runtime, graph());
+        }
+        return null;
+    }
+
+    private PhiNode asPhi(MetaAccessProvider runtime) {
+        if (!isStatic() && Modifier.isFinal(field.getModifiers()) && object() instanceof PhiNode && ((PhiNode) object()).values().filter(NodePredicates.isNotA(ConstantNode.class)).isEmpty()) {
+            PhiNode phi = (PhiNode) object();
+            Constant[] constants = new Constant[phi.valueCount()];
+            for (int i = 0; i < phi.valueCount(); i++) {
+                Constant constantValue = field().readConstantValue(phi.valueAt(i).asConstant());
+                if (constantValue == null) {
+                    return null;
+                }
+                constants[i] = constantValue;
             }
-            if (constant != null) {
-                return ConstantNode.forConstant(constant, runtime, graph());
+            PhiNode newPhi = graph().add(new PhiNode(stamp(), phi.merge()));
+            for (int i = 0; i < phi.valueCount(); i++) {
+                newPhi.addInput(ConstantNode.forConstant(constants[i], runtime, graph()));
             }
+            return newPhi;
         }
         return null;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Tue Jul 23 17:48:17 2013 +0200
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
+ */
+public class LoweredCompareAndSwapNode extends AccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single, Node.IterableNodeType {
+
+    @Input private ValueNode object;
+    @Input private ValueNode expectedValue;
+    @Input private ValueNode newValue;
+    @Input private LocationNode location;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public ValueNode getObject() {
+        return object;
+    }
+
+    public ValueNode getExpectedValue() {
+        return expectedValue;
+    }
+
+    public ValueNode getNewValue() {
+        return newValue;
+    }
+
+    public LocationNode getLocation() {
+        return location;
+    }
+
+    public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType, boolean compressible) {
+        super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType, compressible);
+        assert expectedValue.kind() == newValue.kind();
+        this.object = object;
+        this.expectedValue = expectedValue;
+        this.newValue = newValue;
+        this.location = location;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return location.getLocationIdentity();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        gen.visitCompareAndSwap(this, getLocation().generateAddress(gen, gen.operand(getObject())));
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraalCodeCacheProvider.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/GraalCodeCacheProvider.java	Tue Jul 23 17:48:17 2013 +0200
@@ -48,7 +48,7 @@
     void lower(Node n, LoweringTool tool);
 
     /**
-     * Reconstruct the array index from a location node that was created as a lowering of an indexed
+     * Reconstructs the array index from a location node that was created as a lowering of an indexed
      * access to an array.
      * 
      * @param location a location pointing to an element in an array
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Jul 23 17:48:17 2013 +0200
@@ -118,7 +118,7 @@
 
     void visitLoopEnd(LoopEndNode i);
 
-    void visitCompareAndSwap(CompareAndSwapNode i);
+    void visitCompareAndSwap(LoweredCompareAndSwapNode i, Value address);
 
     // These methods define the contract a runtime specific backend must provide.
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Tue Jul 23 17:48:17 2013 +0200
@@ -158,7 +158,10 @@
                 int mark = graph.getMark();
                 if (!tryKillUnused(node)) {
                     if (!tryCanonicalize(node, graph)) {
-                        tryInferStamp(node, graph);
+                        if (tryInferStamp(node, graph)) {
+                            // the improved stamp may enable additional canonicalization
+                            tryCanonicalize(node, graph);
+                        }
                     }
                 }
 
@@ -296,7 +299,7 @@
          * this method also checks if the stamp now describes a constant integer value, in which
          * case the node is replaced with a constant.
          */
-        private void tryInferStamp(Node node, StructuredGraph graph) {
+        private boolean tryInferStamp(Node node, StructuredGraph graph) {
             if (node.isAlive() && node instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) node;
                 METRIC_INFER_STAMP_CALLED.increment();
@@ -310,9 +313,11 @@
                         for (Node usage : valueNode.usages()) {
                             workList.addAgain(usage);
                         }
+                        return true;
                     }
                 }
             }
+            return false;
         }
 
         private final class Tool implements SimplifierTool {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Jul 23 17:48:17 2013 +0200
@@ -114,7 +114,7 @@
                         break;
                     }
                 }
-                if (type == null && type != node.objectStamp().type()) {
+                if (type != null && type != node.objectStamp().type()) {
                     newKnownTypes.put(node, type);
                 }
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Jul 23 17:48:17 2013 +0200
@@ -609,7 +609,7 @@
 
             PhiNode returnValuePhi = null;
             if (invoke.asNode().kind() != Kind.Void) {
-                returnValuePhi = graph.unique(new PhiNode(invoke.asNode().kind(), returnMerge));
+                returnValuePhi = graph.add(new PhiNode(invoke.asNode().kind(), returnMerge));
             }
 
             MergeNode exceptionMerge = null;
@@ -622,7 +622,7 @@
 
                 FixedNode exceptionSux = exceptionEdge.next();
                 graph.addBeforeFixed(exceptionSux, exceptionMerge);
-                exceptionObjectPhi = graph.unique(new PhiNode(Kind.Object, exceptionMerge));
+                exceptionObjectPhi = graph.add(new PhiNode(Kind.Object, exceptionMerge));
                 exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
             }
 
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARC.java	Tue Jul 23 17:48:17 2013 +0200
@@ -41,38 +41,38 @@
     public static final RegisterCategory FPU = new RegisterCategory("FPU");
 
     // General purpose registers
-    public static final Register r0  = new Register(0, 0, "r0", CPU);
-    public static final Register r1  = new Register(1, 1, "r1", CPU);
-    public static final Register r2  = new Register(2, 2, "r2", CPU);
-    public static final Register r3  = new Register(3, 3, "r3", CPU);
-    public static final Register r4  = new Register(4, 4, "r4", CPU);
-    public static final Register r5  = new Register(5, 5, "r5", CPU);
-    public static final Register r6  = new Register(6, 6, "r6", CPU);
-    public static final Register r7  = new Register(7, 7, "r7", CPU);
-    public static final Register r8  = new Register(8, 8, "r8", CPU);
-    public static final Register r9  = new Register(9, 9, "r9", CPU);
-    public static final Register r10 = new Register(10, 10, "r10", CPU);
-    public static final Register r11 = new Register(11, 11, "r11", CPU);
-    public static final Register r12 = new Register(12, 12, "r12", CPU);
-    public static final Register r13 = new Register(13, 13, "r13", CPU);
-    public static final Register r14 = new Register(14, 14, "r14", CPU);
-    public static final Register r15 = new Register(15, 15, "r15", CPU);
-    public static final Register r16 = new Register(16, 16, "r16", CPU);
-    public static final Register r17 = new Register(17, 17, "r17", CPU);
-    public static final Register r18 = new Register(18, 18, "r18", CPU);
-    public static final Register r19 = new Register(19, 19, "r19", CPU);
-    public static final Register r20 = new Register(20, 20, "r20", CPU);
-    public static final Register r21 = new Register(21, 21, "r21", CPU);
-    public static final Register r22 = new Register(22, 22, "r22", CPU);
-    public static final Register r23 = new Register(23, 23, "r23", CPU);
-    public static final Register r24 = new Register(24, 24, "r24", CPU);
-    public static final Register r25 = new Register(25, 25, "r25", CPU);
-    public static final Register r26 = new Register(26, 26, "r26", CPU);
-    public static final Register r27 = new Register(27, 27, "r27", CPU);
-    public static final Register r28 = new Register(28, 28, "r28", CPU);
-    public static final Register r29 = new Register(29, 29, "r29", CPU);
-    public static final Register r30 = new Register(30, 30, "r30", CPU);
-    public static final Register r31 = new Register(31, 31, "r31", CPU);
+    public static final Register r0  = new Register(0, 0, "g0", CPU);
+    public static final Register r1  = new Register(1, 1, "g1", CPU);
+    public static final Register r2  = new Register(2, 2, "g2", CPU);
+    public static final Register r3  = new Register(3, 3, "g3", CPU);
+    public static final Register r4  = new Register(4, 4, "g4", CPU);
+    public static final Register r5  = new Register(5, 5, "g5", CPU);
+    public static final Register r6  = new Register(6, 6, "g6", CPU);
+    public static final Register r7  = new Register(7, 7, "g7", CPU);
+    public static final Register r8  = new Register(8, 8, "o0", CPU);
+    public static final Register r9  = new Register(9, 9, "o1", CPU);
+    public static final Register r10 = new Register(10, 10, "o2", CPU);
+    public static final Register r11 = new Register(11, 11, "o3", CPU);
+    public static final Register r12 = new Register(12, 12, "o4", CPU);
+    public static final Register r13 = new Register(13, 13, "o5", CPU);
+    public static final Register r14 = new Register(14, 14, "o6", CPU);
+    public static final Register r15 = new Register(15, 15, "o7", CPU);
+    public static final Register r16 = new Register(16, 16, "l0", CPU);
+    public static final Register r17 = new Register(17, 17, "l1", CPU);
+    public static final Register r18 = new Register(18, 18, "l2", CPU);
+    public static final Register r19 = new Register(19, 19, "l3", CPU);
+    public static final Register r20 = new Register(20, 20, "l4", CPU);
+    public static final Register r21 = new Register(21, 21, "l5", CPU);
+    public static final Register r22 = new Register(22, 22, "l6", CPU);
+    public static final Register r23 = new Register(23, 23, "l7", CPU);
+    public static final Register r24 = new Register(24, 24, "i0", CPU);
+    public static final Register r25 = new Register(25, 25, "i1", CPU);
+    public static final Register r26 = new Register(26, 26, "i2", CPU);
+    public static final Register r27 = new Register(27, 27, "i3", CPU);
+    public static final Register r28 = new Register(28, 28, "i4", CPU);
+    public static final Register r29 = new Register(29, 29, "i5", CPU);
+    public static final Register r30 = new Register(30, 30, "i6", CPU);
+    public static final Register r31 = new Register(31, 31, "i7", CPU);
 
     public static final Register g0 = r0;
     public static final Register g1 = r1;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Tue Jul 23 17:48:17 2013 +0200
@@ -50,7 +50,7 @@
         this.originalInvokeCounter = compilationThreshold;
         this.rootNode.setCallTarget(this);
 
-        if (TruffleProfiling.getValue()) {
+        if (TruffleCallTargetProfiling.getValue()) {
             registerCallTarget(this);
         }
     }
@@ -64,6 +64,7 @@
 
     // TruffleProfiling
     private int callCount;
+    private int invalidationCount;
 
     // TraceTruffleCompilation
     long timeCompilationStarted;
@@ -75,7 +76,7 @@
 
     @Override
     public Object call(PackedFrame caller, Arguments args) {
-        if (TruffleProfiling.getValue()) {
+        if (TruffleCallTargetProfiling.getValue()) {
             callCount++;
         }
         if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, compiledMethod != null)) {
@@ -90,19 +91,22 @@
     }
 
     private Object compiledCodeInvalidated(PackedFrame caller, Arguments args) {
+        CompilerAsserts.neverPartOfCompilation();
         compiledMethod = null;
         int invalidationReprofileCount = TruffleInvalidationReprofileCount.getValue();
         invokeCounter = invalidationReprofileCount;
+        invalidationCount++;
         if (TruffleFunctionInlining.getValue()) {
             originalInvokeCounter += invalidationReprofileCount;
         }
         if (TraceTruffleCompilation.getValue()) {
-            OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6);
+            OUT.printf("[truffle] invalidated %-48s |Alive %5.0fms |Inv %d\n", rootNode, (System.nanoTime() - timeCompilationFinished) / 1e6, invalidationCount);
         }
         return call(caller, args);
     }
 
     private Object interpreterCall(PackedFrame caller, Arguments args) {
+        CompilerAsserts.neverPartOfCompilation();
         invokeCounter--;
         loopAndInvokeCounter--;
         if (disableCompilation || loopAndInvokeCounter > 0 || invokeCounter > 0) {
@@ -138,7 +142,7 @@
                                     (timeCompilationFinished - timeCompilationStarted) / 1e6, (timePartialEvaluationFinished - timeCompilationStarted) / 1e6,
                                     (timeCompilationFinished - timePartialEvaluationFinished) / 1e6, nodeCountPartialEval, nodeCountLowered, codeSize);
                 }
-                if (TruffleProfiling.getValue()) {
+                if (TruffleCallTargetProfiling.getValue()) {
                     resetProfiling();
                 }
             }
@@ -237,16 +241,16 @@
             return inlined;
         }
 
-        private void printCallSiteInfo(InliningPolicy policy, List<InlinableCallSiteInfo> inlinableCallSites, String msg) {
+        private static void printCallSiteInfo(InliningPolicy policy, List<InlinableCallSiteInfo> inlinableCallSites, String msg) {
             for (InlinableCallSiteInfo candidate : inlinableCallSites) {
                 printCallSiteInfo(policy, candidate, msg);
             }
         }
 
-        private void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) {
+        private static void printCallSiteInfo(InliningPolicy policy, InlinableCallSiteInfo callSite, String msg) {
             String calls = String.format("%4s/%4s", callSite.getCallCount(), policy.callerInvocationCount);
             String nodes = String.format("%3s/%3s", callSite.getInlineNodeCount(), policy.callerNodeCount);
-            OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |into %s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), target.getRootNode());
+            OUT.printf("[truffle] %-9s %-50s |Nodes %6s |Calls %6s %7.3f |%s\n", msg, callSite.getCallSite(), nodes, calls, policy.metric(callSite), callSite.getCallSite().getCallTarget());
         }
 
         private static final class InliningPolicy {
@@ -377,9 +381,10 @@
         int totalInlinedCallSiteCount = 0;
         int totalNotInlinedCallSiteCount = 0;
         int totalNodeCount = 0;
+        int totalInvalidationCount = 0;
 
         OUT.println();
-        OUT.printf("%-50s | %-10s | %s / %s | %s\n", "Call Target", "Call Count", "Calls Sites Inlined", "Not Inlined", "Node Count");
+        OUT.printf("%-50s | %-10s | %s / %s | %s | %s\n", "Call Target", "Call Count", "Calls Sites Inlined", "Not Inlined", "Node Count", "Inv");
         for (OptimizedCallTarget callTarget : sortedCallTargets) {
             if (callTarget.callCount == 0) {
                 continue;
@@ -389,14 +394,17 @@
             int nodeCount = NodeUtil.countNodes(callTarget.rootNode);
             int inlinedCallSiteCount = NodeUtil.countNodes(callTarget.rootNode, InlinedCallSite.class);
             String comment = callTarget.compiledMethod == null ? " int" : "";
-            OUT.printf("%-50s | %10s | %15s | %15s | %10s%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount, comment);
+            comment += callTarget.disableCompilation ? " fail" : "";
+            OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d%s\n", callTarget.getRootNode(), callTarget.callCount, inlinedCallSiteCount, notInlinedCallSiteCount, nodeCount,
+                            callTarget.invalidationCount, comment);
 
             totalCallCount += callTarget.callCount;
             totalInlinedCallSiteCount += inlinedCallSiteCount;
             totalNotInlinedCallSiteCount += notInlinedCallSiteCount;
             totalNodeCount += nodeCount;
+            totalInvalidationCount += callTarget.invalidationCount;
         }
-        OUT.printf("%-50s | %10s | %15s | %15s | %10s\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount);
+        OUT.printf("%-50s | %10d | %15d | %15d | %10d | %3d\n", "Total", totalCallCount, totalInlinedCallSiteCount, totalNotInlinedCallSiteCount, totalNodeCount, totalInvalidationCount);
     }
 
     private static void registerCallTarget(OptimizedCallTarget callTarget) {
@@ -405,7 +413,7 @@
 
     private static Map<OptimizedCallTarget, Integer> callTargets;
     static {
-        if (TruffleProfiling.getValue()) {
+        if (TruffleCallTargetProfiling.getValue()) {
             callTargets = new WeakHashMap<>();
 
             Runtime.getRuntime().addShutdownHook(new Thread() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Tue Jul 23 17:48:17 2013 +0200
@@ -64,7 +64,7 @@
     private final HotSpotGraalRuntime graalRuntime;
     private final TruffleCache truffleCache;
 
-    private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class, InvalidInstalledCodeException.class};
+    private static final Class[] SKIPPED_EXCEPTION_CLASSES = new Class[]{SlowPathException.class, UnexpectedResultException.class, ArithmeticException.class};
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Tue Jul 23 17:48:17 2013 +0200
@@ -88,6 +88,6 @@
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleInliningDetails = new OptionValue<>(false);
     @Option(help = "")
-    public static final OptionValue<Boolean> TruffleProfiling = new StableOptionValue<>(false);
+    public static final OptionValue<Boolean> TruffleCallTargetProfiling = new StableOptionValue<>(false);
     // @formatter:on
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Tue Jul 23 17:48:17 2013 +0200
@@ -35,6 +35,9 @@
     @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
     public static native Object interpreterCall(OptimizedCallTarget target, PackedFrame caller, Arguments args);
 
+    @MacroSubstitution(macro = NeverInlineMacroNode.class, isStatic = false)
+    public static native Object compiledCodeInvalidated(OptimizedCallTarget target, PackedFrame caller, Arguments args);
+
     @MethodSubstitution
     private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments args) {
         return NewFrameNode.allocate(descriptor, caller, args);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Tue Jul 23 17:48:17 2013 +0200
@@ -70,7 +70,7 @@
                 ValueNode cachedValue = state.getReadCache(object, store.field());
 
                 ValueNode value = state.getScalarAlias(store.value());
-                if (value == cachedValue) {
+                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                     effects.deleteFixedNode(store);
                     deleted = true;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Tue Jul 23 17:48:17 2013 +0200
@@ -36,8 +36,8 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
+import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry;
-import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
 
 public class ReadEliminationClosure extends EffectsClosure<ReadEliminationBlockState> {
 
@@ -106,6 +106,8 @@
                 }
                 state.killReadCache(write.location().getLocationIdentity());
                 state.addCacheEntry(identifier, value);
+            } else {
+                state.killReadCache(write.location().getLocationIdentity());
             }
         } else if (node instanceof MemoryCheckpoint.Single) {
             processIdentity(state, ((MemoryCheckpoint.Single) node).getLocationIdentity());
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Tue Jul 23 17:48:17 2013 +0200
@@ -33,11 +33,6 @@
  */
 public abstract class Node implements Cloneable {
 
-    /**
-     * Utility constant representing an empty node array.
-     */
-    public static final Node[] EMPTY_ARRAY = new Node[0];
-
     private Node parent;
 
     private SourceSection sourceSection;
@@ -193,6 +188,22 @@
     }
 
     /**
+     * Checks if this node is properly adopted by a parent and can be replaced.
+     * 
+     * @return {@code true} if it is safe to replace this node.
+     */
+    public final boolean isReplaceable() {
+        if (getParent() != null) {
+            for (Node sibling : getParent().getChildren()) {
+                if (sibling == this) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Intended to be implemented by subclasses of {@link Node} to receive a notification when the
      * node is rewritten. This method is invoked before the actual replace has happened.
      * 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Tue Jul 23 17:47:56 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Tue Jul 23 17:48:17 2013 +0200
@@ -344,7 +344,11 @@
         for (long fieldOffset : nodeClass.childrenOffsets) {
             Node[] children = (Node[]) unsafe.getObject(node, fieldOffset);
             if (children != null) {
-                nodes.addAll(Arrays.asList(children));
+                for (Node child : children) {
+                    if (child != null) {
+                        nodes.add(child);
+                    }
+                }
             }
         }
 
@@ -545,23 +549,25 @@
     }
 
     public static int countNodes(Node root, Class<?> clazz) {
-        NodeCountVisitor nodeCount = new NodeCountVisitor(clazz);
+        NodeCountVisitor nodeCount = new NodeCountVisitor(root, clazz);
         root.accept(nodeCount);
         return nodeCount.nodeCount;
     }
 
     private static final class NodeCountVisitor implements NodeVisitor {
 
+        int nodeCount;
+        private final Node root;
         private final Class<?> clazz;
-        int nodeCount;
 
-        private NodeCountVisitor(Class<?> clazz) {
+        private NodeCountVisitor(Node root, Class<?> clazz) {
+            this.root = root;
             this.clazz = clazz;
         }
 
         @Override
         public boolean visit(Node node) {
-            if (node instanceof RootNode && nodeCount > 0) {
+            if (node instanceof RootNode && node != root) {
                 return false;
             }
             if (clazz == null || clazz.isInstance(node)) {
@@ -589,7 +595,7 @@
             p.print("  ");
         }
         if (parent == null) {
-            p.println(node.getClass().getSimpleName());
+            p.println(nodeName(node));
         } else {
             String fieldName = "unknownField";
             NodeField[] fields = NodeClass.get(parent.getClass()).fields;
@@ -611,7 +617,7 @@
             }
             p.print(fieldName);
             p.print(" = ");
-            p.println(node.getClass().getSimpleName());
+            p.println(nodeName(node));
         }
 
         for (Node child : node.getChildren()) {
@@ -649,7 +655,7 @@
             return;
         }
 
-        p.print(node.getClass().getSimpleName());
+        p.print(nodeName(node));
 
         ArrayList<NodeField> childFields = new ArrayList<>();
         String sep = "";
@@ -704,4 +710,7 @@
         }
     }
 
+    private static String nodeName(Node node) {
+        return node.getClass().getSimpleName();
+    }
 }
--- a/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Tue Jul 23 17:47:56 2013 +0200
+++ b/src/cpu/sparc/vm/graalCodeInstaller_sparc.hpp	Tue Jul 23 17:48:17 2013 +0200
@@ -29,8 +29,14 @@
 #include "graal/graalJavaAccess.hpp"
 
 inline jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, oop method) {
-  assert(inst->is_call() || inst->is_jump(), "sanity");
-  return pc_offset + NativeCall::instruction_size;
+  if (inst->is_call() || inst->is_jump()) {
+    return pc_offset + NativeCall::instruction_size;
+  } else if (inst->is_sethi()) {
+    return pc_offset + NativeFarCall::instruction_size;
+  } else {
+    fatal("unsupported type of instruction for call site");
+    return 0;
+  }
 }
 
 inline void CodeInstaller::pd_site_DataPatch(int pc_offset, oop site) {
@@ -107,7 +113,22 @@
 }
 
 inline void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination) {
-  fatal("CodeInstaller::pd_relocate_ForeignCall - sparc unimp");
+  address pc = (address) inst;
+  if (inst->is_call()) {
+    NativeCall* call = nativeCall_at(pc);
+    call->set_destination((address) foreign_call_destination);
+    _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
+  } else if (inst->is_sethi()) {
+    NativeFarCall* call = nativeFarCall_at(pc);
+    call->set_destination((address) foreign_call_destination);
+    _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
+  } else {
+    NativeJump* jump = nativeJump_at((address) (inst));
+    jump->set_jump_destination((address) foreign_call_destination);
+    _instructions->relocate((address)inst, runtime_call_Relocation::spec());
+    fatal("CodeInstaller::pd_relocate_ForeignCall - verify me!");
+  }
+  TRACE_graal_3("relocating (foreign call) at %p", inst);
 }
 
 inline void CodeInstaller::pd_relocate_JavaMethod(oop hotspot_method, jint pc_offset) {
@@ -127,7 +148,6 @@
       NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
       call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
       _instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
-      /*, Assembler::call32_operand); */
       break;
     }
     case MARK_INVOKESTATIC: {
@@ -135,16 +155,13 @@
       NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
       call->set_destination(SharedRuntime::get_resolve_static_call_stub());
       _instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
-      /*, Assembler::call32_operand); */
       break;
     }
     case MARK_INVOKESPECIAL: {
       assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
       NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
       call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
-//      _instructions->relocate(call->instruction_address(),
-//                              relocInfo::opt_virtual_call_type, Assembler::call32_operand);
-      fatal("NYI");
+      _instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
       break;
     }
     default:
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Tue Jul 23 17:47:56 2013 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Tue Jul 23 17:48:17 2013 +0200
@@ -734,12 +734,9 @@
   
   if (target->is_a(SystemDictionary::HotSpotInstalledCode_klass())) {
     assert(inst->is_jump(), "jump expected");
-
     CodeBlob* cb = (CodeBlob*) (address) HotSpotInstalledCode::codeBlob(target);
     assert(cb != NULL, "npe");
-    
     CodeInstaller::pd_relocate_CodeBlob(cb, inst);
-
     return;
   }
 
@@ -755,7 +752,6 @@
 
   if (foreign_call != NULL) {
     jlong foreign_call_destination = HotSpotForeignCallLinkage::address(foreign_call);
-
     CodeInstaller::pd_relocate_ForeignCall(inst, foreign_call_destination);
   } else { // method != NULL
     assert(hotspot_method != NULL, "unexpected JavaMethod");
@@ -764,7 +760,9 @@
     TRACE_graal_3("method call");
     CodeInstaller::pd_relocate_JavaMethod(hotspot_method, pc_offset);
   }
+
   _next_call_type = MARK_INVOKE_INVALID;
+
   if (debug_info != NULL) {
     _debug_recorder->end_safepoint(next_pc_offset);
   }