changeset 8185:3bbdf34536bc

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 10 Mar 2013 19:51:32 +0100
parents d982f1469cba (current diff) 4b11a0983557 (diff)
children bf1c9ae73775
files graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64Address.java graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTXAddress.java
diffstat 50 files changed, 1470 insertions(+), 848 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Sun Mar 10 19:51:32 2013 +0100
@@ -24,12 +24,11 @@
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.api.code.Register.RegisterFlag.*;
-import static com.oracle.graal.api.meta.Kind.*;
 
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.*;
+import com.oracle.graal.api.code.Register.RegisterFlag;
 
 /**
  * Represents the AMD64 architecture.
@@ -106,8 +105,6 @@
         rip
     };
 
-    public static final RegisterValue RSP = rsp.asValue(Long);
-
     public AMD64() {
         super("AMD64",
               8,
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64Address.java	Sun Mar 10 19:51:18 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2010, 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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents an address in target machine memory, specified via some combination of a base
- * register, an index register, a displacement and a scale. Note that the base and index registers
- * may be a variable that will get a register assigned later by the register allocator.
- */
-public final class AMD64Address extends Address {
-
-    private static final long serialVersionUID = -4101548147426595051L;
-
-    private final Value[] baseIndex;
-    private final Scale scale;
-    private final int displacement;
-
-    /**
-     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     */
-    public AMD64Address(Kind kind, Value base) {
-        this(kind, base, ILLEGAL, Scale.Times1, 0);
-    }
-
-    /**
-     * Creates an {@link AMD64Address} with given base register, no scaling and a given
-     * displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param displacement the displacement
-     */
-    public AMD64Address(Kind kind, Value base, int displacement) {
-        this(kind, base, ILLEGAL, Scale.Times1, displacement);
-    }
-
-    /**
-     * Creates an {@link AMD64Address} with given base and index registers, scaling and
-     * displacement. This is the most general constructor.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param index the index register
-     * @param scale the scaling factor
-     * @param displacement the displacement
-     */
-    public AMD64Address(Kind kind, Value base, Value index, Scale scale, int displacement) {
-        super(kind);
-        this.baseIndex = new Value[2];
-        this.setBase(base);
-        this.setIndex(index);
-        this.scale = scale;
-        this.displacement = displacement;
-
-        assert !isConstant(base) && !isStackSlot(base);
-        assert !isConstant(index) && !isStackSlot(index);
-    }
-
-    /**
-     * A scaling factor used in the SIB addressing mode.
-     */
-    public enum Scale {
-        Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3);
-
-        private Scale(int value, int log2) {
-            this.value = value;
-            this.log2 = log2;
-        }
-
-        /**
-         * The value (or multiplier) of this scale.
-         */
-        public final int value;
-
-        /**
-         * The {@linkplain #value value} of this scale log 2.
-         */
-        public final int log2;
-
-        public static Scale fromInt(int scale) {
-            switch (scale) {
-                case 1:
-                    return Times1;
-                case 2:
-                    return Times2;
-                case 4:
-                    return Times4;
-                case 8:
-                    return Times8;
-                default:
-                    throw new IllegalArgumentException(String.valueOf(scale));
-            }
-        }
-    }
-
-    @Override
-    public Value[] components() {
-        return baseIndex;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append(getKind().getJavaName()).append("[");
-        String sep = "";
-        if (isLegal(getBase())) {
-            s.append(getBase());
-            sep = " + ";
-        }
-        if (isLegal(getIndex())) {
-            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
-            sep = " + ";
-        }
-        if (getDisplacement() < 0) {
-            s.append(" - ").append(-getDisplacement());
-        } else if (getDisplacement() > 0) {
-            s.append(sep).append(getDisplacement());
-        }
-        s.append("]");
-        return s.toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof AMD64Address) {
-            AMD64Address addr = (AMD64Address) obj;
-            return getKind() == addr.getKind() && getDisplacement() == addr.getDisplacement() && getBase().equals(addr.getBase()) && getScale() == addr.getScale() &&
-                            getIndex().equals(addr.getIndex());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getBase().hashCode() ^ getIndex().hashCode() ^ (getDisplacement() << 4) ^ (getScale().value << 8) ^ (getKind().ordinal() << 12);
-    }
-
-    /**
-     * @return Base register that defines the start of the address computation. If not present, is
-     *         denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getBase() {
-        return baseIndex[0];
-    }
-
-    public void setBase(Value base) {
-        this.baseIndex[0] = base;
-    }
-
-    /**
-     * @return Index register, the value of which (possibly scaled by {@link #scale}) is added to
-     *         {@link #getBase}. If not present, is denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getIndex() {
-        return baseIndex[1];
-    }
-
-    public void setIndex(Value index) {
-        this.baseIndex[1] = index;
-    }
-
-    /**
-     * @return Scaling factor for indexing, dependent on target operand size.
-     */
-    public Scale getScale() {
-        return scale;
-    }
-
-    /**
-     * @return Optional additive displacement.
-     */
-    public int getDisplacement() {
-        return displacement;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AbstractAddress.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * 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.api.code;
+
+/**
+ * Abstract base class that represents a platform specific address.
+ */
+public abstract class AbstractAddress {
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java	Sun Mar 10 19:51:18 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010, 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.api.code;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Base class to represent an address in target machine memory. The concrete representation of the
- * address is platform dependent.
- */
-public abstract class Address extends Value {
-
-    private static final long serialVersionUID = -1003772042519945089L;
-
-    public Address(Kind kind) {
-        super(kind);
-    }
-
-    /**
-     * The values that this address is composed of. Used by the register allocator to manipulate
-     * addresses in a platform independent way.
-     */
-    public abstract Value[] components();
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Sun Mar 10 19:51:32 2013 +0100
@@ -78,16 +78,6 @@
         return (StackSlot) value;
     }
 
-    public static boolean isAddress(Value value) {
-        assert value != null;
-        return value instanceof Address;
-    }
-
-    public static Address asAddress(Value value) {
-        assert value != null;
-        return (Address) value;
-    }
-
     public static boolean isRegister(Value value) {
         assert value != null;
         return value instanceof RegisterValue;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2010, 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.asm.amd64;
+
+import com.oracle.graal.api.code.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base
+ * register, an index register, a displacement and a scale. Note that the base and index registers
+ * may be a variable that will get a register assigned later by the register allocator.
+ */
+public final class AMD64Address extends AbstractAddress {
+
+    private final Register base;
+    private final Register index;
+    private final Scale scale;
+    private final int displacement;
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
+     * 
+     * @param base the base register
+     */
+    public AMD64Address(Register base) {
+        this(base, Register.None, Scale.Times1, 0);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and a given
+     * displacement.
+     * 
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, int displacement) {
+        this(base, Register.None, Scale.Times1, displacement);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base and index registers, scaling and
+     * displacement. This is the most general constructor.
+     * 
+     * @param base the base register
+     * @param index the index register
+     * @param scale the scaling factor
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, Register index, Scale scale, int displacement) {
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+    }
+
+    /**
+     * A scaling factor used in the SIB addressing mode.
+     */
+    public enum Scale {
+        Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3);
+
+        private Scale(int value, int log2) {
+            this.value = value;
+            this.log2 = log2;
+        }
+
+        /**
+         * The value (or multiplier) of this scale.
+         */
+        public final int value;
+
+        /**
+         * The {@linkplain #value value} of this scale log 2.
+         */
+        public final int log2;
+
+        public static Scale fromInt(int scale) {
+            switch (scale) {
+                case 1:
+                    return Times1;
+                case 2:
+                    return Times2;
+                case 4:
+                    return Times4;
+                case 8:
+                    return Times8;
+                default:
+                    throw new IllegalArgumentException(String.valueOf(scale));
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("[");
+        String sep = "";
+        if (getBase() != Register.None) {
+            s.append(getBase());
+            sep = " + ";
+        }
+        if (getIndex() != Register.None) {
+            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
+            sep = " + ";
+        }
+        if (getDisplacement() < 0) {
+            s.append(" - ").append(-getDisplacement());
+        } else if (getDisplacement() > 0) {
+            s.append(sep).append(getDisplacement());
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Register#None}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to
+     *         {@link #getBase}. If not present, is denoted by {@link Register#None}.
+     */
+    public Register getIndex() {
+        return index;
+    }
+
+    /**
+     * @return Scaling factor for indexing, dependent on target operand size.
+     */
+    public Scale getScale() {
+        return scale;
+    }
+
+    /**
+     * @return Optional additive displacement.
+     */
+    public int getDisplacement() {
+        return displacement;
+    }
+}
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -24,13 +24,11 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.asm.NumUtil.*;
 import static com.oracle.graal.asm.amd64.AMD64AsmOptions.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 
 /**
@@ -38,19 +36,13 @@
  */
 public class AMD64Assembler extends AbstractAssembler {
 
-    /**
-     * The kind for pointers and raw registers. Since we know we are 64 bit here, we can hardcode
-     * it.
-     */
-    private static final Kind Word = Kind.Long;
-
     private static final int MinEncodingNeedsRex = 8;
 
     /**
      * A sentinel value used as a place holder in an instruction stream for an address that will be
      * patched.
      */
-    private static final AMD64Address Placeholder = new AMD64Address(Kind.Illegal, rip.asValue());
+    private static final AMD64Address Placeholder = new AMD64Address(rip);
 
     /**
      * The x86 condition codes used for conditional jumps/moves.
@@ -232,8 +224,8 @@
         assert (reg & 0x07) == reg;
         int regenc = reg << 3;
 
-        Register base = isLegal(addr.getBase()) ? asRegister(addr.getBase()) : Register.None;
-        Register index = isLegal(addr.getIndex()) ? asRegister(addr.getIndex()) : Register.None;
+        Register base = addr.getBase();
+        Register index = addr.getIndex();
 
         AMD64Address.Scale scale = addr.getScale();
         int disp = addr.getDisplacement();
@@ -1784,8 +1776,8 @@
         }
     }
 
-    private static boolean needsRex(Value value) {
-        return isRegister(value) && asRegister(value).encoding >= MinEncodingNeedsRex;
+    private static boolean needsRex(Register reg) {
+        return reg.encoding >= MinEncodingNeedsRex;
     }
 
     private void prefix(AMD64Address adr) {
@@ -2252,7 +2244,7 @@
                 // the code where this idiom is used, in particular the
                 // orderAccess code.
                 lock();
-                addl(new AMD64Address(Word, RSP, 0), 0); // Assert the lock# signal here
+                addl(new AMD64Address(rsp, 0), 0); // Assert the lock# signal here
             }
         }
     }
@@ -2293,7 +2285,7 @@
     }
 
     public void nullCheck(Register r) {
-        testl(AMD64.rax, new AMD64Address(Word, r.asValue(Word), 0));
+        testl(AMD64.rax, new AMD64Address(r, 0));
     }
 
     @Override
@@ -2374,8 +2366,8 @@
     }
 
     @Override
-    public AMD64Address makeAddress(Kind kind, Value base, int displacement) {
-        return new AMD64Address(kind, base, displacement);
+    public AMD64Address makeAddress(Register base, int displacement) {
+        return new AMD64Address(base, displacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 
 /**
  * This class implements commonly used X86 code patterns.
@@ -222,7 +221,7 @@
      * volatile field!
      */
     public final void movlong(AMD64Address dst, long src) {
-        AMD64Address high = new AMD64Address(dst.getKind(), dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
+        AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
         movl(dst, (int) (src & 0xFFFFFFFF));
         movl(high, (int) (src >> 32));
     }
@@ -230,7 +229,7 @@
     public final void flog(Register dest, Register value, boolean base10) {
         assert dest.isFpu() && value.isFpu();
 
-        AMD64Address tmp = new AMD64Address(Kind.Double, AMD64.RSP);
+        AMD64Address tmp = new AMD64Address(AMD64.rsp);
         if (base10) {
             fldlg2();
         } else {
@@ -264,7 +263,7 @@
 
     private AMD64Address trigPrologue(Register value) {
         assert value.isFpu();
-        AMD64Address tmp = new AMD64Address(Kind.Double, AMD64.RSP);
+        AMD64Address tmp = new AMD64Address(AMD64.rsp);
         subq(AMD64.rsp, 8);
         movsd(tmp, value);
         fld(tmp);
@@ -286,18 +285,16 @@
      * @param frameToCSA offset from the frame pointer to the CSA
      */
     public final void save(CalleeSaveLayout csl, int frameToCSA) {
-        RegisterValue frame = frameRegister.asValue();
         for (Register r : csl.registers) {
             int offset = csl.offsetOf(r);
-            movq(new AMD64Address(target.wordKind, frame, frameToCSA + offset), r);
+            movq(new AMD64Address(frameRegister, frameToCSA + offset), r);
         }
     }
 
     public final void restore(CalleeSaveLayout csl, int frameToCSA) {
-        RegisterValue frame = frameRegister.asValue();
         for (Register r : csl.registers) {
             int offset = csl.offsetOf(r);
-            movq(r, new AMD64Address(target.wordKind, frame, frameToCSA + offset));
+            movq(r, new AMD64Address(frameRegister, frameToCSA + offset));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,72 @@
+/*
+ * 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.asm.ptx;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base register
+ * and a displacement.
+ */
+public final class PTXAddress extends AbstractAddress {
+
+    private final Register base;
+    private final long displacement;
+
+    /**
+     * Creates an {@link PTXAddress} with given base register and no displacement.
+     * 
+     * @param base the base register
+     */
+    public PTXAddress(Register base) {
+        this(base, 0);
+    }
+
+    /**
+     * Creates an {@link PTXAddress} with given base register and a displacement. This is the most
+     * general constructor.
+     * 
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public PTXAddress(Register base, long displacement) {
+        this.base = base;
+        this.displacement = displacement;
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Value#ILLEGAL}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Optional additive displacement.
+     */
+    public long getDisplacement() {
+        return displacement;
+    }
+}
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -23,8 +23,6 @@
 package com.oracle.graal.asm.ptx;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.ptx.*;
 
 public class PTXAssembler extends AbstractPTXAssembler {
 
@@ -177,7 +175,7 @@
         emitString("exit;" + " " + "");
     }
 
-    public final void ld_global_b8(Register d, Register a, int immOff) {
+    public final void ld_global_b8(Register d, Register a, long immOff) {
         emitString("ld.global.b8" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + "");
     }
 
@@ -742,8 +740,8 @@
     }
 
     @Override
-    public PTXAddress makeAddress(Kind kind, Value base, int displacement) {
-        return new PTXAddress(kind, base, displacement);
+    public PTXAddress makeAddress(Register base, int displacement) {
+        return new PTXAddress(base, displacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.asm.sparc;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.sparc.*;
 
@@ -55,13 +54,13 @@
     }
 
     @Override
-    public Address makeAddress(Kind kind, Value base, int displacement) {
+    public AbstractAddress makeAddress(Register base, int displacement) {
         // SPARC: Implement address calculation.
         return null;
     }
 
     @Override
-    public Address getPlaceholder() {
+    public AbstractAddress getPlaceholder() {
         // SPARC: Implement address patching.
         return null;
     }
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -25,7 +25,6 @@
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 
 /**
  * The platform-independent base class for the assembler.
@@ -87,12 +86,12 @@
 
     /**
      * This is used by the TargetMethodAssembler to convert a {@link StackSlot} to an
-     * {@link Address}.
+     * {@link AbstractAddress}.
      */
-    public abstract Address makeAddress(Kind kind, Value base, int displacement);
+    public abstract AbstractAddress makeAddress(Register base, int displacement);
 
     /**
      * Returns a target specific placeholder address that can be used for code patching.
      */
-    public abstract Address getPlaceholder();
+    public abstract AbstractAddress getPlaceholder();
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Sun Mar 10 19:51:32 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
@@ -158,56 +159,64 @@
         append(createMove(dst, src));
     }
 
-    private AMD64Address prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
-        Value baseRegister = base;
+    private AMD64AddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        AllocatableValue baseRegister;
         int finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
             } else if (asConstant(base).getKind() != Kind.Object) {
                 long newDisplacement = displacement + asConstant(base).asLong();
                 if (NumUtil.isInt(newDisplacement)) {
                     assert !runtime.needsDataPatch(asConstant(base));
                     finalDisp = (int) newDisplacement;
-                    baseRegister = Value.ILLEGAL;
+                    baseRegister = AllocatableValue.UNUSED;
                 } else {
-                    Value newBase = newVariable(Kind.Long);
+                    Variable newBase = newVariable(Kind.Long);
                     emitMove(newBase, base);
                     baseRegister = newBase;
                 }
+            } else {
+                baseRegister = load(base);
             }
+        } else if (base == Value.ILLEGAL) {
+            baseRegister = AllocatableValue.UNUSED;
+        } else {
+            baseRegister = asAllocatable(base);
         }
 
-        Value indexRegister = index;
-        AMD64Address.Scale scaleEnum;
-        if (index != Value.ILLEGAL && scale > 0) {
-            scaleEnum = AMD64Address.Scale.fromInt(scale);
+        AllocatableValue indexRegister;
+        Scale scaleEnum;
+        if (index != Value.ILLEGAL && scale != 0) {
+            scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
                 long newDisplacement = finalDisp + asConstant(index).asLong() * scale;
                 // only use the constant index if the resulting displacement fits into a 32 bit
                 // offset
                 if (NumUtil.isInt(newDisplacement)) {
                     finalDisp = (int) newDisplacement;
-                    indexRegister = Value.ILLEGAL;
+                    indexRegister = AllocatableValue.UNUSED;
                 } else {
                     // create a temporary variable for the index, the pointer load cannot handle a
                     // constant index
-                    Value newIndex = newVariable(Kind.Long);
+                    Variable newIndex = newVariable(Kind.Long);
                     emitMove(newIndex, index);
                     indexRegister = newIndex;
                 }
+            } else {
+                indexRegister = asAllocatable(index);
             }
         } else {
-            indexRegister = Value.ILLEGAL;
-            scaleEnum = AMD64Address.Scale.Times1;
+            indexRegister = AllocatableValue.UNUSED;
+            scaleEnum = Scale.Times1;
         }
 
-        return new AMD64Address(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
+        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
     }
 
     @Override
     public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
-        AMD64Address loadAddress = prepareAddress(kind, base, displacement, index, scale);
+        AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
@@ -215,7 +224,7 @@
 
     @Override
     public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
-        AMD64Address storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         LIRFrameState state = canTrap ? state() : null;
 
         if (isConstant(inputVal)) {
@@ -233,7 +242,7 @@
     @Override
     public Variable emitLea(Value base, int displacement, Value index, int scale) {
         Variable result = newVariable(target().wordKind);
-        AMD64Address address = prepareAddress(result.getKind(), base, displacement, index, scale);
+        AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale);
         append(new LeaOp(result, address));
         return result;
     }
@@ -922,15 +931,15 @@
         Value expected = loadNonConst(operand(node.expected()));
         Variable newValue = load(operand(node.newValue()));
 
-        AMD64Address address;
+        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 AMD64Address(kind, load(operand(node.object())), displacement);
+            address = new AMD64AddressValue(kind, load(operand(node.object())), displacement);
         } else {
-            address = new AMD64Address(kind, load(operand(node.object())), load(index), AMD64Address.Scale.Times1, displacement);
+            address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement);
         }
 
         RegisterValue rax = AMD64.rax.asValue(kind);
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Sun Mar 10 19:51:32 2013 +0100
@@ -36,11 +36,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Reg;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.ShiftOp;
-import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXCompare.CompareOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp;
@@ -51,7 +51,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.ptx.*;
 
 /**
  * This class implements the PTX specific portion of the LIR generator.
@@ -114,40 +113,49 @@
         }
     }
 
-    private PTXAddress prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
-        Value baseRegister = base;
+    private PTXAddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
             } else if (asConstant(base).getKind() != Kind.Object) {
                 finalDisp += asConstant(base).asLong();
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
+            } else {
+                baseRegister = load(base);
             }
+        } else if (base == Value.ILLEGAL) {
+            baseRegister = AllocatableValue.UNUSED;
+        } else {
+            baseRegister = asAllocatable(base);
         }
 
         if (index != Value.ILLEGAL) {
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
             } else {
-                Value indexRegister = index;
+                Value indexRegister;
                 if (scale != 1) {
                     indexRegister = emitMul(index, Constant.forInt(scale));
+                } else {
+                    indexRegister = index;
                 }
-                if (baseRegister == Value.ILLEGAL) {
-                    baseRegister = indexRegister;
+
+                if (baseRegister == AllocatableValue.UNUSED) {
+                    baseRegister = asAllocatable(indexRegister);
                 } else {
                     baseRegister = emitAdd(baseRegister, indexRegister);
                 }
             }
         }
 
-        return new PTXAddress(kind, baseRegister, finalDisp);
+        return new PTXAddressValue(kind, baseRegister, finalDisp);
     }
 
     @Override
     public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
-        PTXAddress loadAddress = prepareAddress(kind, base, displacement, index, scale);
+        PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
@@ -155,7 +163,7 @@
 
     @Override
     public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
-        PTXAddress storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable input = load(inputVal);
         append(new StoreOp(storeAddress, input, canTrap ? state() : null));
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sun Mar 10 19:51:32 2013 +0100
@@ -348,7 +348,7 @@
 
         final int id = compilationId++;
 
-        InstalledCode installedCode = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable<InstalledCode>() {
+        InstalledCode installedCode = Debug.scope("Compiling", new Object[]{runtime, new DebugDumpScope(String.valueOf(id), true)}, new Callable<InstalledCode>() {
 
             public InstalledCode call() throws Exception {
                 final boolean printCompilation = GraalOptions.PrintCompilation && !TTY.isSuppressed();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Sun Mar 10 19:51:32 2013 +0100
@@ -417,8 +417,8 @@
     public final int operandNumber;
 
     /**
-     * The {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or
-     * {@linkplain Address address} assigned to this interval.
+     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
+     * interval.
      */
     private Value location;
 
@@ -515,8 +515,8 @@
     }
 
     /**
-     * Gets the {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or
-     * {@linkplain Address address} assigned to this interval.
+     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
+     * this interval.
      */
     public Value location() {
         return location;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Sun Mar 10 19:51:32 2013 +0100
@@ -192,10 +192,10 @@
 
     // Traverse assignment graph in depth first order and generate moves in post order
     // ie. two assignments: b := c, a := b start with node c:
-    // Call graph: move(NULL, c) -> move(c, b) -> move(b, a)
+    // Call graph: move(c, NULL) -> move(b, c) -> move(a, b)
     // Generates moves in this order: move b to a and move c to b
     // ie. cycle a := b, b := a start with node a
-    // Call graph: move(NULL, a) -> move(a, b) -> move(b, a)
+    // Call graph: move(a, NULL) -> move(b, a) -> move(a, b)
     // Generates moves in this order: move b to temp, move a to b, move temp to a
     private void move(PhiResolverNode dest, PhiResolverNode src) {
         if (!dest.visited) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sun Mar 10 19:51:32 2013 +0100
@@ -32,11 +32,12 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
@@ -128,14 +129,14 @@
             Variable newVal = load(operand(x.newValue()));
 
             int disp = 0;
-            AMD64Address address;
+            AMD64AddressValue address;
             Value index = operand(x.offset());
             if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
                 assert !runtime.needsDataPatch(asConstant(index));
                 disp += (int) ValueUtil.asConstant(index).asLong();
-                address = new AMD64Address(kind, load(operand(x.object())), disp);
+                address = new AMD64AddressValue(kind, load(operand(x.object())), disp);
             } else {
-                address = new AMD64Address(kind, load(operand(x.object())), load(index), AMD64Address.Scale.Times1, disp);
+                address = new AMD64AddressValue(kind, load(operand(x.object())), load(index), Scale.Times1, disp);
             }
 
             RegisterValue rax = AMD64.rax.asValue(kind);
@@ -203,7 +204,7 @@
                         disp -= frameSize;
                     }
                     tasm.blockComment("[stack overflow check]");
-                    asm.movq(new AMD64Address(asm.target.wordKind, AMD64.RSP, -disp), AMD64.rax);
+                    asm.movq(new AMD64Address(rsp, -disp), AMD64.rax);
                 }
             }
         }
@@ -223,7 +224,7 @@
             if (GraalOptions.ZapStackOnMethodEntry) {
                 final int intSize = 4;
                 for (int i = 0; i < frameSize / intSize; ++i) {
-                    asm.movl(new AMD64Address(Kind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1);
+                    asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1);
                 }
             }
             CalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout();
@@ -287,7 +288,7 @@
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
                                              // c1_LIRAssembler_x86.cpp
             Register receiver = asRegister(cc.getArgument(0));
-            AMD64Address src = new AMD64Address(target.wordKind, receiver.asValue(), config.hubOffset);
+            AMD64Address src = new AMD64Address(receiver, config.hubOffset);
 
             asm.cmpq(inlineCacheKlass, src);
             asm.jcc(ConditionFlag.NotEqual, unverifiedStub);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRuntime.java	Sun Mar 10 19:51:32 2013 +0100
@@ -43,8 +43,14 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.amd64.snippets.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.snippets.*;
 
 public class AMD64HotSpotRuntime extends HotSpotRuntime {
 
@@ -186,6 +192,24 @@
 
     }
 
+    private AMD64ConvertSnippets.Templates convertSnippets;
+
+    @Override
+    public void installSnippets(Backend backend, SnippetInstaller installer, Assumptions assumptions) {
+        installer.installSnippets(AMD64ConvertSnippets.class);
+        convertSnippets = new AMD64ConvertSnippets.Templates(this, assumptions, graalRuntime.getTarget());
+        super.installSnippets(backend, installer, assumptions);
+    }
+
+    @Override
+    public void lower(Node n, LoweringTool tool) {
+        if (n instanceof ConvertNode) {
+            convertSnippets.lower((ConvertNode) n, tool);
+        } else {
+            super.lower(n, tool);
+        }
+    }
+
     @Override
     public Register threadRegister() {
         return r15;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Sun Mar 10 19:51:32 2013 +0100
@@ -26,7 +26,6 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 import sun.misc.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
@@ -65,13 +64,13 @@
             asm.movq(scratch.getRegister(), config.safepointPollingAddress + offset);
             tasm.recordMark(Marks.MARK_POLL_FAR);
             tasm.recordSafepoint(pos, state);
-            asm.movq(scratch.getRegister(), new AMD64Address(tasm.target.wordKind, scratch));
+            asm.movq(scratch.getRegister(), new AMD64Address(scratch.getRegister()));
         } else {
             tasm.recordMark(Marks.MARK_POLL_NEAR);
             tasm.recordSafepoint(pos, state);
             // The C++ code transforms the polling page offset into an RIP displacement
             // to the real address at that offset in the polling page.
-            asm.movq(scratch.getRegister(), new AMD64Address(tasm.target.wordKind, rip.asValue(), offset));
+            asm.movq(scratch.getRegister(), new AMD64Address(rip, offset));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/snippets/AMD64ConvertSnippets.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,191 @@
+/*
+ * 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.hotspot.amd64.snippets;
+
+import static com.oracle.graal.snippets.SnippetTemplate.*;
+import static com.oracle.graal.snippets.SnippetTemplate.Arguments.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.ConvertNode.Op;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.graal.snippets.Snippet.Parameter;
+import com.oracle.graal.snippets.SnippetTemplate.AbstractTemplates;
+import com.oracle.graal.snippets.SnippetTemplate.Arguments;
+import com.oracle.graal.snippets.SnippetTemplate.Key;
+
+/**
+ * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match
+ * the semantics of the JVM specification.
+ */
+public class AMD64ConvertSnippets implements SnippetsInterface {
+
+    /**
+     * Converts a float to an int.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the
+     * conversion. If the float value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and
+     * extra tests are required on the float value to return the correct int value.
+     * 
+     * @param input the float being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static int f2i(@Parameter("input") float input, @Parameter("result") int result) {
+        if (result == Integer.MIN_VALUE) {
+            if (Float.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0f) {
+                // input is > 0 -> return max int
+                return Integer.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a float to a long.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the
+     * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns
+     * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct
+     * long value.
+     * 
+     * @param input the float being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static long f2l(@Parameter("input") float input, @Parameter("result") long result) {
+        if (result == Long.MIN_VALUE) {
+            if (Float.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0f) {
+                // input is > 0 -> return max int
+                return Long.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a double to an int.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the
+     * conversion. If the double value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and
+     * extra tests are required on the double value to return the correct int value.
+     * 
+     * @param input the double being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static int d2i(@Parameter("input") double input, @Parameter("result") int result) {
+        if (result == Integer.MIN_VALUE) {
+            if (Double.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0d) {
+                // input is positive -> return maxInt
+                return Integer.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Converts a double to a long.
+     * <p>
+     * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the
+     * conversion. If the double value is a NaN, infinity or if the result of the conversion is
+     * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra
+     * tests are required on the double value to return the correct long value.
+     * 
+     * @param input the double being converted
+     * @param result the result produced by the CVTTSS2SI instruction
+     */
+    @Snippet
+    public static long d2l(@Parameter("input") double input, @Parameter("result") long result) {
+        if (result == Long.MIN_VALUE) {
+            if (Double.isNaN(input)) {
+                // input is NaN -> return 0
+                return 0;
+            } else if (input > 0.0d) {
+                // input is positive -> return maxInt
+                return Long.MAX_VALUE;
+            }
+        }
+        return result;
+    }
+
+    public static class Templates extends AbstractTemplates<AMD64ConvertSnippets> {
+
+        private final ResolvedJavaMethod f2i;
+        private final ResolvedJavaMethod f2l;
+        private final ResolvedJavaMethod d2i;
+        private final ResolvedJavaMethod d2l;
+
+        public Templates(CodeCacheProvider runtime, Assumptions assumptions, TargetDescription target) {
+            super(runtime, assumptions, target, AMD64ConvertSnippets.class);
+            f2i = snippet("f2i", float.class, int.class);
+            f2l = snippet("f2l", float.class, long.class);
+            d2i = snippet("d2i", double.class, int.class);
+            d2l = snippet("d2l", double.class, long.class);
+        }
+
+        public void lower(ConvertNode convert, LoweringTool tool) {
+            if (convert.opcode == Op.F2I) {
+                lower0(convert, tool, f2i);
+            } else if (convert.opcode == Op.F2L) {
+                lower0(convert, tool, f2l);
+            } else if (convert.opcode == Op.D2I) {
+                lower0(convert, tool, d2i);
+            } else if (convert.opcode == Op.D2L) {
+                lower0(convert, tool, d2l);
+            }
+        }
+
+        private void lower0(ConvertNode convert, LoweringTool tool, ResolvedJavaMethod snippet) {
+            StructuredGraph graph = (StructuredGraph) convert.graph();
+
+            // Insert a unique placeholder node in place of the Convert node so that the
+            // Convert node can be used as an input to the snippet. All usage of the
+            // Convert node are replaced by the placeholder which in turn is replaced by the
+            // snippet.
+
+            LocalNode replacee = graph.add(new LocalNode(Integer.MAX_VALUE, convert.stamp()));
+            convert.replaceAtUsages(replacee);
+            Key key = new Key(snippet);
+            Arguments arguments = arguments("input", convert.value()).add("result", convert);
+            SnippetTemplate template = cache.get(key, assumptions);
+            Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.opcode, graph, convert, template, arguments);
+            template.instantiate(runtime, replacee, DEFAULT_REPLACER, tool, arguments);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_d2l03.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.jtt.bytecode;
+
+import com.oracle.graal.jtt.*;
+import org.junit.*;
+
+/*
+ */
+public class BC_d2l03 extends JTTTest {
+
+    public static long test(double divider) {
+        return (long) (((long) divider) * divider);
+    }
+
+    @Test
+    public void run0() throws Throwable {
+        runTest("test", 34.5D);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+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.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
+import com.oracle.graal.lir.*;
+
+public class AMD64AddressValue extends CompositeValue {
+
+    private static final long serialVersionUID = -4444600052487578694L;
+
+    @Component({REG, UNUSED}) protected AllocatableValue base;
+    @Component({REG, UNUSED}) protected AllocatableValue index;
+    protected final Scale scale;
+    protected final int displacement;
+
+    public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) {
+        this(kind, base, AllocatableValue.UNUSED, Scale.Times1, displacement);
+    }
+
+    public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
+        super(kind);
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+    }
+
+    private static Register toRegister(AllocatableValue value) {
+        if (value == AllocatableValue.UNUSED) {
+            return Register.None;
+        } else {
+            RegisterValue reg = (RegisterValue) value;
+            return reg.getRegister();
+        }
+    }
+
+    public AMD64Address toAddress() {
+        return new AMD64Address(toRegister(base), toRegister(index), scale, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append(getKind().getJavaName()).append("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (isLegal(index)) {
+            s.append(sep).append(index).append(" * ").append(scale.value);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof AMD64AddressValue) {
+            AMD64AddressValue addr = (AMD64AddressValue) obj;
+            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ (getKind().ordinal() << 12);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sun Mar 10 19:51:32 2013 +0100
@@ -28,8 +28,6 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
@@ -44,10 +42,15 @@
     INEG, LNEG,
     I2L, L2I, I2B, I2C, I2S,
     F2D, D2F,
-    I2F, I2D, F2I, D2I,
-    L2F, L2D, F2L, D2L,
-    MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L;
+    I2F, I2D,
+    L2F, L2D,
+    MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L,
 
+    /*
+     * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics
+     * when the input is a NaN, infinity or the conversion result is greater than Integer.MAX_VALUE/Long.MAX_VALUE.
+     */
+    F2I, D2I, F2L, D2L;
 
     /**
      * Unary operation with separate source and destination operand. 
@@ -339,19 +342,15 @@
                 case L2D: masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src)); break;
                 case F2I:
                     masm.cvttss2sil(asIntReg(dst), asFloatReg(src));
-                    emitConvertFixup(tasm, masm, dst, src);
                     break;
                 case D2I:
                     masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src));
-                    emitConvertFixup(tasm, masm, dst, src);
                     break;
                 case F2L:
                     masm.cvttss2siq(asLongReg(dst), asFloatReg(src));
-                    emitConvertFixup(tasm, masm, dst, src);
                     break;
                 case D2L:
                     masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src));
-                    emitConvertFixup(tasm, masm, dst, src);
                     break;
                 case MOV_I2F: masm.movdl(asFloatReg(dst), asIntReg(src)); break;
                 case MOV_L2D: masm.movdq(asDoubleReg(dst), asLongReg(src)); break;
@@ -466,63 +465,6 @@
         }
     }
 
-    private static void emitConvertFixup(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Value result, Value x) {
-        ConvertSlowPath slowPath = new ConvertSlowPath(result, x);
-        tasm.stubs.add(slowPath);
-        switch (result.getKind()) {
-            case Int:  masm.cmpl(asIntReg(result),  Integer.MIN_VALUE); break;
-            case Long: masm.cmpq(asLongReg(result), (AMD64Address) tasm.asLongConstRef(Constant.forLong(java.lang.Long.MIN_VALUE))); break;
-            default:   throw GraalInternalError.shouldNotReachHere();
-        }
-        masm.jcc(ConditionFlag.Equal, slowPath.start);
-        masm.bind(slowPath.continuation);
-    }
-
-    private static class ConvertSlowPath extends AMD64Code {
-        public final Label start = new Label();
-        public final Label continuation = new Label();
-        private final Value result;
-        private final Value x;
-
-        public ConvertSlowPath(Value result, Value x) {
-            this.result = result;
-            this.x = x;
-        }
-
-        @Override
-        public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.bind(start);
-            switch (x.getKind()) {
-                case Float:  masm.ucomiss(asFloatReg(x),  (AMD64Address) tasm.asFloatConstRef(Constant.FLOAT_0)); break;
-                case Double: masm.ucomisd(asDoubleReg(x), (AMD64Address) tasm.asDoubleConstRef(Constant.DOUBLE_0)); break;
-                default:     throw GraalInternalError.shouldNotReachHere();
-            }
-            Label nan = new Label();
-            masm.jcc(ConditionFlag.Parity, nan);
-            masm.jcc(ConditionFlag.Below, continuation);
-
-            // input is > 0 -> return maxInt
-            // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff
-            switch (result.getKind()) {
-                case Int:  masm.decrementl(asIntReg(result),  1); break;
-                case Long: masm.decrementq(asLongReg(result), 1); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
-            }
-            masm.jmp(continuation);
-
-            // input is NaN -> return 0
-            masm.bind(nan);
-            masm.xorptr(asRegister(result), asRegister(result));
-            masm.jmp(continuation);
-        }
-
-        @Override
-        public String description() {
-            return "convert " + x + " to " + result;
-        }
-    }
-
-
     private static void verifyKind(AMD64Arithmetic opcode, Value result, Value x, Value y) {
         assert (opcode.name().startsWith("I") && result.getKind() == Kind.Int && x.getKind().getStackKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
             || (opcode.name().startsWith("L") && result.getKind() == Kind.Long && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sun Mar 10 19:51:32 2013 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.lir.amd64;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.asm.*;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Sun Mar 10 19:51:32 2013 +0100
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Sun Mar 10 19:51:32 2013 +0100
@@ -26,13 +26,13 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.amd64.*;
-import com.oracle.graal.amd64.AMD64Address.Scale;
+import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
@@ -338,11 +338,11 @@
 
         // Set scratch to address of jump table
         int leaPos = buf.position();
-        masm.leaq(scratch, new AMD64Address(tasm.target.wordKind, AMD64.rip.asValue(), 0));
+        masm.leaq(scratch, new AMD64Address(AMD64.rip, 0));
         int afterLea = buf.position();
 
         // Load jump table entry into scratch and jump to it
-        masm.movslq(value, new AMD64Address(Kind.Int, scratch.asValue(), value.asValue(), Scale.Times4, 0));
+        masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0));
         masm.addq(scratch, value);
         masm.jmp(scratch);
 
@@ -354,7 +354,7 @@
         // Patch LEA instruction above now that we know the position of the jump table
         int jumpTablePos = buf.position();
         buf.setPosition(leaPos);
-        masm.leaq(scratch, new AMD64Address(tasm.target.wordKind, AMD64.rip.asValue(), jumpTablePos - afterLea));
+        masm.leaq(scratch, new AMD64Address(AMD64.rip, jumpTablePos - afterLea));
         buf.setPosition(jumpTablePos);
 
         // Emit jump table entries
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sun Mar 10 19:51:32 2013 +0100
@@ -97,10 +97,10 @@
 
     public abstract static class MemOp extends AMD64LIRInstruction {
 
-        @Use({ADDR}) protected AMD64Address address;
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
         @State protected LIRFrameState state;
 
-        public MemOp(AMD64Address address, LIRFrameState state) {
+        public MemOp(AMD64AddressValue address, LIRFrameState state) {
             this.address = address;
             this.state = state;
         }
@@ -120,7 +120,7 @@
 
         @Def({REG}) protected AllocatableValue result;
 
-        public LoadOp(AllocatableValue result, AMD64Address address, LIRFrameState state) {
+        public LoadOp(AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
             super(address, state);
             this.result = result;
         }
@@ -130,28 +130,28 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movsxb(asRegister(result), address);
+                    masm.movsxb(asRegister(result), address.toAddress());
                     break;
                 case Char:
-                    masm.movzxl(asRegister(result), address);
+                    masm.movzxl(asRegister(result), address.toAddress());
                     break;
                 case Short:
-                    masm.movswl(asRegister(result), address);
+                    masm.movswl(asRegister(result), address.toAddress());
                     break;
                 case Int:
-                    masm.movslq(asRegister(result), address);
+                    masm.movslq(asRegister(result), address.toAddress());
                     break;
                 case Long:
-                    masm.movq(asRegister(result), address);
+                    masm.movq(asRegister(result), address.toAddress());
                     break;
                 case Float:
-                    masm.movflt(asFloatReg(result), address);
+                    masm.movflt(asFloatReg(result), address.toAddress());
                     break;
                 case Double:
-                    masm.movdbl(asDoubleReg(result), address);
+                    masm.movdbl(asDoubleReg(result), address.toAddress());
                     break;
                 case Object:
-                    masm.movq(asRegister(result), address);
+                    masm.movq(asRegister(result), address.toAddress());
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -163,7 +163,7 @@
 
         @Use({REG}) protected AllocatableValue input;
 
-        public StoreOp(AMD64Address address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(AMD64AddressValue address, AllocatableValue input, LIRFrameState state) {
             super(address, state);
             this.input = input;
         }
@@ -174,26 +174,26 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movb(address, asRegister(input));
+                    masm.movb(address.toAddress(), asRegister(input));
                     break;
                 case Char:
                 case Short:
-                    masm.movw(address, asRegister(input));
+                    masm.movw(address.toAddress(), asRegister(input));
                     break;
                 case Int:
-                    masm.movl(address, asRegister(input));
+                    masm.movl(address.toAddress(), asRegister(input));
                     break;
                 case Long:
-                    masm.movq(address, asRegister(input));
+                    masm.movq(address.toAddress(), asRegister(input));
                     break;
                 case Float:
-                    masm.movflt(address, asFloatReg(input));
+                    masm.movflt(address.toAddress(), asFloatReg(input));
                     break;
                 case Double:
-                    masm.movsd(address, asDoubleReg(input));
+                    masm.movsd(address.toAddress(), asDoubleReg(input));
                     break;
                 case Object:
-                    masm.movq(address, asRegister(input));
+                    masm.movq(address.toAddress(), asRegister(input));
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -205,7 +205,7 @@
 
         protected final Constant input;
 
-        public StoreConstantOp(AMD64Address address, Constant input, LIRFrameState state) {
+        public StoreConstantOp(AMD64AddressValue address, Constant input, LIRFrameState state) {
             super(address, state);
             this.input = input;
         }
@@ -215,30 +215,30 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movb(address, input.asInt() & 0xFF);
+                    masm.movb(address.toAddress(), input.asInt() & 0xFF);
                     break;
                 case Char:
                 case Short:
-                    masm.movw(address, input.asInt() & 0xFFFF);
+                    masm.movw(address.toAddress(), input.asInt() & 0xFFFF);
                     break;
                 case Int:
-                    masm.movl(address, input.asInt());
+                    masm.movl(address.toAddress(), input.asInt());
                     break;
                 case Long:
                     if (NumUtil.isInt(input.asLong())) {
-                        masm.movslq(address, (int) input.asLong());
+                        masm.movslq(address.toAddress(), (int) input.asLong());
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                     }
                     break;
                 case Float:
-                    masm.movl(address, floatToRawIntBits(input.asFloat()));
+                    masm.movl(address.toAddress(), floatToRawIntBits(input.asFloat()));
                     break;
                 case Double:
                     throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                 case Object:
                     if (input.isNull()) {
-                        masm.movptr(address, 0);
+                        masm.movptr(address.toAddress(), 0);
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                     }
@@ -252,16 +252,16 @@
     public static class LeaOp extends AMD64LIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR, UNINITIALIZED}) protected AMD64Address address;
+        @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address;
 
-        public LeaOp(AllocatableValue result, AMD64Address address) {
+        public LeaOp(AllocatableValue result, AMD64AddressValue address) {
             this.result = result;
             this.address = address;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.leaq(asLongReg(result), address);
+            masm.leaq(asLongReg(result), address.toAddress());
         }
     }
 
@@ -316,11 +316,11 @@
     public static class CompareAndSwapOp extends AMD64LIRInstruction {
 
         @Def protected AllocatableValue result;
-        @Use({ADDR}) protected AMD64Address address;
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
         @Use protected AllocatableValue cmpValue;
         @Use protected AllocatableValue newValue;
 
-        public CompareAndSwapOp(AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
+        public CompareAndSwapOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -523,7 +523,7 @@
         }
     }
 
-    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
         assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax;
 
         if (tasm.target.isMP) {
@@ -531,11 +531,11 @@
         }
         switch (cmpValue.getKind()) {
             case Int:
-                masm.cmpxchgl(asRegister(newValue), address);
+                masm.cmpxchgl(asRegister(newValue), address.toAddress());
                 break;
             case Long:
             case Object:
-                masm.cmpxchgq(asRegister(newValue), address);
+                masm.cmpxchgq(asRegister(newValue), address.toAddress());
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Sun Mar 10 19:51:32 2013 +0100
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ptx;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+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.ptx.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base register
+ * and a displacement.
+ */
+public final class PTXAddressValue extends CompositeValue {
+
+    private static final long serialVersionUID = 1802222435353022623L;
+
+    @Component({REG, UNUSED}) private AllocatableValue base;
+    private final long displacement;
+
+    /**
+     * Creates an {@link PTXAddressValue} with given base register and no displacement.
+     * 
+     * @param kind the kind of the value being addressed
+     * @param base the base register
+     */
+    public PTXAddressValue(Kind kind, AllocatableValue base) {
+        this(kind, base, 0);
+    }
+
+    /**
+     * Creates an {@link PTXAddressValue} with given base register and a displacement. This is the
+     * most general constructor.
+     * 
+     * @param kind the kind of the value being addressed
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public PTXAddressValue(Kind kind, AllocatableValue base, long displacement) {
+        super(kind);
+        this.base = base;
+        this.displacement = displacement;
+
+        assert !isStackSlot(base);
+    }
+
+    public PTXAddress toAddress() {
+        Register baseReg = base == AllocatableValue.UNUSED ? Register.None : asRegister(base);
+        return new PTXAddress(baseReg, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append(getKind().getJavaName()).append("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof PTXAddressValue) {
+            PTXAddressValue addr = (PTXAddressValue) obj;
+            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ ((int) displacement << 4) ^ (getKind().ordinal() << 12);
+    }
+}
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java	Sun Mar 10 19:51:32 2013 +0100
@@ -36,7 +36,7 @@
 
     @Opcode private final IntrinsicOpcode opcode;
     @Def protected Value result;
-    @Use({OperandFlag.REG, OperandFlag.ADDR}) protected Value input;
+    @Use({OperandFlag.REG}) protected Value input;
 
     public PTXBitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) {
         this.opcode = opcode;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Sun Mar 10 19:51:32 2013 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.ptx.*;
 
 public class PTXMove {
 
@@ -121,10 +120,10 @@
     public static class LoadOp extends PTXLIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadOp(AllocatableValue result, PTXAddress address, LIRFrameState state) {
+        public LoadOp(AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
             this.result = result;
             this.address = address;
             this.state = state;
@@ -132,14 +131,13 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            Register a = asRegister(address.getBase());
-            long immOff = address.getDisplacement();
+            PTXAddress addr = address.toAddress();
             switch (address.getKind()) {
                 case Int:
-                    masm.ld_global_s32(asRegister(result), a, immOff);
+                    masm.ld_global_s32(asRegister(result), addr.getBase(), addr.getDisplacement());
                     break;
                 case Object:
-                    masm.ld_global_u32(asRegister(result), a, immOff);
+                    masm.ld_global_u32(asRegister(result), addr.getBase(), addr.getDisplacement());
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -149,11 +147,11 @@
 
     public static class StoreOp extends PTXLIRInstruction {
 
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
-        public StoreOp(PTXAddress address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
             this.address = address;
             this.input = input;
             this.state = state;
@@ -161,13 +159,11 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            Register a = asRegister(address.getBase());
-            long immOff = address.getDisplacement();
-
             assert isRegister(input);
+            PTXAddress addr = address.toAddress();
             switch (address.getKind()) {
                 case Int:
-                    masm.st_global_s32(a, immOff, asRegister(input));
+                    masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input));
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -178,9 +174,9 @@
     public static class LeaOp extends PTXLIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR, UNINITIALIZED}) protected PTXAddress address;
+        @Use({COMPOSITE, UNINITIALIZED}) protected PTXAddressValue address;
 
-        public LeaOp(AllocatableValue result, PTXAddress address) {
+        public LeaOp(AllocatableValue result, PTXAddressValue address) {
             this.result = result;
             this.address = address;
         }
@@ -211,11 +207,11 @@
     public static class CompareAndSwapOp extends PTXLIRInstruction {
 
         @Def protected AllocatableValue result;
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @Use protected AllocatableValue cmpValue;
         @Use protected AllocatableValue newValue;
 
-        public CompareAndSwapOp(AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
+        public CompareAndSwapOp(AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -276,7 +272,7 @@
     }
 
     @SuppressWarnings("unused")
-    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
         throw new InternalError("NYI");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+/**
+ * Base class to represent values that need to be stored in more than one register.
+ */
+public abstract class CompositeValue extends Value {
+
+    private static final long serialVersionUID = -169180052684126180L;
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Component {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    private final CompositeValueClass valueClass;
+
+    public CompositeValue(Kind kind) {
+        super(kind);
+        valueClass = CompositeValueClass.get(getClass());
+    }
+
+    public final void forEachComponent(OperandMode mode, ValueProcedure proc) {
+        valueClass.forEachComponent(this, mode, proc);
+    }
+
+    @Override
+    public String toString() {
+        return valueClass.toString(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+public class CompositeValueClass extends LIRIntrospection {
+
+    public static final CompositeValueClass get(Class<? extends CompositeValue> c) {
+        CompositeValueClass clazz = (CompositeValueClass) allClasses.get(c);
+        if (clazz != null) {
+            return clazz;
+        }
+
+        // We can have a race of multiple threads creating the LIRInstructionClass at the same time.
+        // However, only one will be put into the map, and this is the one returned by all threads.
+        clazz = new CompositeValueClass(c);
+        CompositeValueClass oldClazz = (CompositeValueClass) allClasses.putIfAbsent(c, clazz);
+        if (oldClazz != null) {
+            return oldClazz;
+        } else {
+            return clazz;
+        }
+    }
+
+    private final int directComponentCount;
+    private final long[] componentOffsets;
+    private final EnumSet<OperandFlag>[] componentFlags;
+
+    @SuppressWarnings("unchecked")
+    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+        super(clazz);
+
+        ValueFieldScanner scanner = new ValueFieldScanner(new DefaultCalcOffset());
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
+        directComponentCount = mode.scalarOffsets.size();
+        componentOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        componentFlags = arrayUsingSortedOffsets(mode.flags, componentOffsets, new EnumSet[componentOffsets.length]);
+
+        dataOffsets = sortedLongCopy(scanner.dataOffsets);
+
+        fieldNames = scanner.fieldNames;
+        fieldTypes = scanner.fieldTypes;
+    }
+
+    @Override
+    protected void rescanFieldOffsets(CalcOffset calc) {
+        ValueFieldScanner scanner = new ValueFieldScanner(calc);
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
+        copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+
+        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
+
+        fieldNames.clear();
+        fieldNames.putAll(scanner.fieldNames);
+        fieldTypes.clear();
+        fieldTypes.putAll(scanner.fieldTypes);
+    }
+
+    private static class ValueFieldScanner extends FieldScanner {
+
+        public ValueFieldScanner(CalcOffset calc) {
+            super(calc);
+
+            valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
+        }
+
+        @Override
+        protected void scan(Class<?> clazz) {
+            super.scan(clazz);
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
+            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
+            if (field.isAnnotationPresent(CompositeValue.Component.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value()));
+            } else {
+                GraalInternalError.shouldNotReachHere();
+            }
+            return result;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" component[");
+        for (int i = 0; i < componentOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
+        }
+        str.append("] data[");
+        for (int i = 0; i < dataOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
+        }
+        str.append("]");
+        return str.toString();
+    }
+
+    public final void forEachComponent(CompositeValue obj, OperandMode mode, ValueProcedure proc) {
+        forEach(obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
+    }
+
+    public String toString(CompositeValue obj) {
+        StringBuilder result = new StringBuilder();
+
+        appendValues(result, obj, "", "", "{", "}", new String[]{""}, componentOffsets);
+
+        for (int i = 0; i < dataOffsets.length; i++) {
+            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+        }
+
+        return result.toString();
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sun Mar 10 19:51:32 2013 +0100
@@ -166,9 +166,9 @@
         STACK,
 
         /**
-         * The value can be a {@link Address}.
+         * The value can be a {@link CompositeValue}.
          */
-        ADDR,
+        COMPOSITE,
 
         /**
          * The value can be a {@link Constant}.
@@ -205,10 +205,10 @@
 
     static {
         ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
-        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, CONST, ILLEGAL, HINT));
-        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
+        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, UNUSED, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, UNUSED, HINT));
     }
 
     /**
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Sun Mar 10 19:51:32 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -22,12 +22,8 @@
  */
 package com.oracle.graal.lir;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.Map.Entry;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -37,7 +33,7 @@
 import com.oracle.graal.lir.LIRInstruction.StateProcedure;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
-public class LIRInstructionClass extends FieldIntrospection {
+public class LIRInstructionClass extends LIRIntrospection {
 
     public static final LIRInstructionClass get(Class<? extends LIRInstruction> c) {
         LIRInstructionClass clazz = (LIRInstructionClass) allClasses.get(c);
@@ -56,11 +52,8 @@
         }
     }
 
-    private static final Class<?> INSTRUCTION_CLASS = LIRInstruction.class;
-    private static final Class<?> VALUE_CLASS = Value.class;
-    private static final Class<?> CONSTANT_CLASS = Constant.class;
-    private static final Class<?> VALUE_ARRAY_CLASS = Value[].class;
-    private static final Class<?> STATE_CLASS = LIRFrameState.class;
+    private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
+    private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
 
     private final int directUseCount;
     private final long[] useOffsets;
@@ -81,11 +74,11 @@
     private long opcodeOffset;
 
     @SuppressWarnings("unchecked")
-    public LIRInstructionClass(Class<?> clazz) {
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        FieldScanner scanner = new FieldScanner(new DefaultCalcOffset());
+        InstructionFieldScanner scanner = new InstructionFieldScanner(new DefaultCalcOffset());
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
@@ -120,7 +113,7 @@
 
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
-        FieldScanner scanner = new FieldScanner(calc);
+        InstructionFieldScanner scanner = new InstructionFieldScanner(calc);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
@@ -144,44 +137,22 @@
         opcodeOffset = scanner.opcodeOffset;
     }
 
-    private static class OperandModeAnnotation {
-
-        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
-        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
-        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
-    }
-
-    protected static class FieldScanner extends BaseFieldScanner {
-
-        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
-        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+    private static class InstructionFieldScanner extends FieldScanner {
 
         private String opcodeConstant;
         private long opcodeOffset;
 
-        public FieldScanner(CalcOffset calc) {
+        public InstructionFieldScanner(CalcOffset calc) {
             super(calc);
 
-            valueAnnotations = new HashMap<>();
-            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); // LIRInstruction.Use.class));
-            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); // LIRInstruction.Alive.class));
-            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); // LIRInstruction.Temp.class));
-            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); // LIRInstruction.Def.class));
+            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation());
         }
 
-        private OperandModeAnnotation getOperandModeAnnotation(Field field) {
-            OperandModeAnnotation result = null;
-            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) {
-                Annotation annotation = field.getAnnotation(entry.getKey());
-                if (annotation != null) {
-                    assert result == null : "Field has two operand mode annotations: " + field;
-                    result = entry.getValue();
-                }
-            }
-            return result;
-        }
-
-        private static EnumSet<OperandFlag> getFlags(Field field) {
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
             EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
             // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so
             // we have to duplicate the code for every operand mode.
@@ -220,25 +191,12 @@
 
         @Override
         protected void scanField(Field field, Class<?> type, long offset) {
-            if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
-                assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
-                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
-                assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.scalarOffsets.add(offset);
-                annotation.flags.put(offset, getFlags(field));
-            } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
-                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
-                assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.arrayOffsets.add(offset);
-                annotation.flags.put(offset, getFlags(field));
-            } else if (STATE_CLASS.isAssignableFrom(type)) {
+            if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
                 stateOffsets.add(offset);
             } else {
-                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
-                assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
-                dataOffsets.add(offset);
+                super.scanField(field, type, offset);
             }
 
             if (field.getAnnotation(LIRInstruction.Opcode.class) != null) {
@@ -334,39 +292,6 @@
         }
     }
 
-    private static void forEach(LIRInstruction obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
-
-            if (i < directCount) {
-                Value value = getValue(obj, offsets[i]);
-                if (isAddress(value)) {
-                    doAddress(asAddress(value), mode, flags[i], proc);
-                } else {
-                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
-                }
-            } else {
-                Value[] values = getValueArray(obj, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
-                    if (isAddress(value)) {
-                        doAddress(asAddress(value), mode, flags[i], proc);
-                    } else {
-                        values[j] = proc.doValue(value, mode, flags[i]);
-                    }
-                }
-            }
-        }
-    }
-
-    private static void doAddress(Address address, OperandMode mode, EnumSet<OperandFlag> flags, ValueProcedure proc) {
-        assert flags.contains(OperandFlag.ADDR);
-        Value[] components = address.components();
-        for (int i = 0; i < components.length; i++) {
-            components[i] = proc.doValue(components[i], mode, LIRInstruction.ADDRESS_FLAGS);
-        }
-    }
-
     public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, ValueProcedure proc) {
         int hintDirectCount = 0;
         long[] hintOffsets = null;
@@ -401,18 +326,6 @@
         return null;
     }
 
-    private static Value getValue(LIRInstruction obj, long offset) {
-        return (Value) unsafe.getObject(obj, offset);
-    }
-
-    private static void setValue(LIRInstruction obj, long offset, Value value) {
-        unsafe.putObject(obj, offset, value);
-    }
-
-    private static Value[] getValueArray(LIRInstruction obj, long offset) {
-        return (Value[]) unsafe.getObject(obj, offset);
-    }
-
     private static LIRFrameState getState(LIRInstruction obj, long offset) {
         return (LIRFrameState) unsafe.getObject(obj, offset);
     }
@@ -447,65 +360,4 @@
 
         return result.toString();
     }
-
-    private void appendValues(StringBuilder result, LIRInstruction obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
-        int total = 0;
-        for (long[] offsets : moffsets) {
-            total += offsets.length;
-        }
-        if (total == 0) {
-            return;
-        }
-
-        result.append(start);
-        if (total > 1) {
-            result.append(startMultiple);
-        }
-        String sep = "";
-        for (int i = 0; i < moffsets.length; i++) {
-            long[] offsets = moffsets[i];
-
-            for (int j = 0; j < offsets.length; j++) {
-                result.append(sep).append(prefix[i]);
-                long offset = offsets[j];
-                if (total > 1) {
-                    result.append(fieldNames.get(offset)).append(": ");
-                }
-                result.append(getFieldString(obj, offset));
-                sep = ", ";
-            }
-        }
-        if (total > 1) {
-            result.append(endMultiple);
-        }
-        result.append(end);
-    }
-
-    private String getFieldString(Object obj, long offset) {
-        Class<?> type = fieldTypes.get(offset);
-        if (type == int.class) {
-            return String.valueOf(unsafe.getInt(obj, offset));
-        } else if (type == long.class) {
-            return String.valueOf(unsafe.getLong(obj, offset));
-        } else if (type == boolean.class) {
-            return String.valueOf(unsafe.getBoolean(obj, offset));
-        } else if (type == float.class) {
-            return String.valueOf(unsafe.getFloat(obj, offset));
-        } else if (type == double.class) {
-            return String.valueOf(unsafe.getDouble(obj, offset));
-        } else if (!type.isPrimitive()) {
-            Object value = unsafe.getObject(obj, offset);
-            if (!type.isArray()) {
-                return String.valueOf(value);
-            } else if (type == int[].class) {
-                return Arrays.toString((int[]) value);
-            } else if (type == double[].class) {
-                return Arrays.toString((double[]) value);
-            } else if (!type.getComponentType().isPrimitive()) {
-                return Arrays.toString((Object[]) value);
-            }
-        }
-        assert false : "unhandled field type: " + type;
-        return "";
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,198 @@
+/*
+ * 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.lir;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+abstract class LIRIntrospection extends FieldIntrospection {
+
+    private static final Class<Value> VALUE_CLASS = Value.class;
+    private static final Class<Constant> CONSTANT_CLASS = Constant.class;
+    private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class;
+
+    public LIRIntrospection(Class<?> clazz) {
+        super(clazz);
+    }
+
+    protected static class OperandModeAnnotation {
+
+        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
+        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
+        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
+    }
+
+    protected abstract static class FieldScanner extends BaseFieldScanner {
+
+        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
+        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+
+        public FieldScanner(CalcOffset calc) {
+            super(calc);
+
+            valueAnnotations = new HashMap<>();
+        }
+
+        protected OperandModeAnnotation getOperandModeAnnotation(Field field) {
+            OperandModeAnnotation result = null;
+            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) {
+                Annotation annotation = field.getAnnotation(entry.getKey());
+                if (annotation != null) {
+                    assert result == null : "Field has two operand mode annotations: " + field;
+                    result = entry.getValue();
+                }
+            }
+            return result;
+        }
+
+        protected abstract EnumSet<OperandFlag> getFlags(Field field);
+
+        @Override
+        protected void scanField(Field field, Class<?> type, long offset) {
+            if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
+                assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                annotation.scalarOffsets.add(offset);
+                annotation.flags.put(offset, getFlags(field));
+            } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                annotation.arrayOffsets.add(offset);
+                annotation.flags.put(offset, getFlags(field));
+            } else {
+                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
+                dataOffsets.add(offset);
+            }
+        }
+    }
+
+    protected static void forEach(Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
+        for (int i = 0; i < offsets.length; i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+
+            if (i < directCount) {
+                Value value = getValue(obj, offsets[i]);
+                if (value instanceof CompositeValue) {
+                    CompositeValue composite = (CompositeValue) value;
+                    composite.forEachComponent(mode, proc);
+                } else {
+                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
+                }
+            } else {
+                Value[] values = getValueArray(obj, offsets[i]);
+                for (int j = 0; j < values.length; j++) {
+                    Value value = values[j];
+                    if (value instanceof CompositeValue) {
+                        CompositeValue composite = (CompositeValue) value;
+                        composite.forEachComponent(mode, proc);
+                    } else {
+                        values[j] = proc.doValue(value, mode, flags[i]);
+                    }
+                }
+            }
+        }
+    }
+
+    protected static Value getValue(Object obj, long offset) {
+        return (Value) unsafe.getObject(obj, offset);
+    }
+
+    protected static void setValue(Object obj, long offset, Value value) {
+        unsafe.putObject(obj, offset, value);
+    }
+
+    protected static Value[] getValueArray(Object obj, long offset) {
+        return (Value[]) unsafe.getObject(obj, offset);
+    }
+
+    protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
+        int total = 0;
+        for (long[] offsets : moffsets) {
+            total += offsets.length;
+        }
+        if (total == 0) {
+            return;
+        }
+
+        result.append(start);
+        if (total > 1) {
+            result.append(startMultiple);
+        }
+        String sep = "";
+        for (int i = 0; i < moffsets.length; i++) {
+            long[] offsets = moffsets[i];
+
+            for (int j = 0; j < offsets.length; j++) {
+                result.append(sep).append(prefix[i]);
+                long offset = offsets[j];
+                if (total > 1) {
+                    result.append(fieldNames.get(offset)).append(": ");
+                }
+                result.append(getFieldString(obj, offset));
+                sep = ", ";
+            }
+        }
+        if (total > 1) {
+            result.append(endMultiple);
+        }
+        result.append(end);
+    }
+
+    protected String getFieldString(Object obj, long offset) {
+        Class<?> type = fieldTypes.get(offset);
+        if (type == int.class) {
+            return String.valueOf(unsafe.getInt(obj, offset));
+        } else if (type == long.class) {
+            return String.valueOf(unsafe.getLong(obj, offset));
+        } else if (type == boolean.class) {
+            return String.valueOf(unsafe.getBoolean(obj, offset));
+        } else if (type == float.class) {
+            return String.valueOf(unsafe.getFloat(obj, offset));
+        } else if (type == double.class) {
+            return String.valueOf(unsafe.getDouble(obj, offset));
+        } else if (!type.isPrimitive()) {
+            Object value = unsafe.getObject(obj, offset);
+            if (!type.isArray()) {
+                return String.valueOf(value);
+            } else if (type == int[].class) {
+                return Arrays.toString((int[]) value);
+            } else if (type == double[].class) {
+                return Arrays.toString((double[]) value);
+            } else if (!type.getComponentType().isPrimitive()) {
+                return Arrays.toString((Object[]) value);
+            }
+        }
+        assert false : "unhandled field type: " + type;
+        return "";
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Sun Mar 10 19:51:32 2013 +0100
@@ -150,7 +150,7 @@
         compilationResult.recordSafepoint(pos, debugInfo);
     }
 
-    public Address recordDataReferenceInCode(Constant data, int alignment, boolean inlined) {
+    public AbstractAddress recordDataReferenceInCode(Constant data, int alignment, boolean inlined) {
         assert data != null;
         int pos = asm.codeBuffer.position();
         Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString());
@@ -176,11 +176,11 @@
     /**
      * Returns the address of a float constant that is embedded as a data references into the code.
      */
-    public Address asFloatConstRef(Value value) {
+    public AbstractAddress asFloatConstRef(Value value) {
         return asFloatConstRef(value, 4);
     }
 
-    public Address asFloatConstRef(Value value, int alignment) {
+    public AbstractAddress asFloatConstRef(Value value, int alignment) {
         assert value.getKind() == Kind.Float && isConstant(value);
         return recordDataReferenceInCode((Constant) value, alignment, false);
     }
@@ -188,11 +188,11 @@
     /**
      * Returns the address of a double constant that is embedded as a data references into the code.
      */
-    public Address asDoubleConstRef(Value value) {
+    public AbstractAddress asDoubleConstRef(Value value) {
         return asDoubleConstRef(value, 8);
     }
 
-    public Address asDoubleConstRef(Value value, int alignment) {
+    public AbstractAddress asDoubleConstRef(Value value, int alignment) {
         assert value.getKind() == Kind.Double && isConstant(value);
         return recordDataReferenceInCode((Constant) value, alignment, false);
     }
@@ -200,41 +200,39 @@
     /**
      * Returns the address of a long constant that is embedded as a data references into the code.
      */
-    public Address asLongConstRef(Value value) {
+    public AbstractAddress asLongConstRef(Value value) {
         assert value.getKind() == Kind.Long && isConstant(value);
         return recordDataReferenceInCode((Constant) value, 8, false);
     }
 
-    public Address asIntAddr(Value value) {
+    public AbstractAddress asIntAddr(Value value) {
         assert value.getKind() == Kind.Int;
         return asAddress(value);
     }
 
-    public Address asLongAddr(Value value) {
+    public AbstractAddress asLongAddr(Value value) {
         assert value.getKind() == Kind.Long;
         return asAddress(value);
     }
 
-    public Address asObjectAddr(Value value) {
+    public AbstractAddress asObjectAddr(Value value) {
         assert value.getKind() == Kind.Object;
         return asAddress(value);
     }
 
-    public Address asFloatAddr(Value value) {
+    public AbstractAddress asFloatAddr(Value value) {
         assert value.getKind() == Kind.Float;
         return asAddress(value);
     }
 
-    public Address asDoubleAddr(Value value) {
+    public AbstractAddress asDoubleAddr(Value value) {
         assert value.getKind() == Kind.Double;
         return asAddress(value);
     }
 
-    public Address asAddress(Value value) {
-        if (isStackSlot(value)) {
-            StackSlot slot = (StackSlot) value;
-            return asm.makeAddress(slot.getKind(), frameMap.registerConfig.getFrameRegister().asValue(), frameMap.offsetForStackSlot(slot));
-        }
-        return (Address) value;
+    public AbstractAddress asAddress(Value value) {
+        assert isStackSlot(value);
+        StackSlot slot = asStackSlot(value);
+        return asm.makeAddress(frameMap.registerConfig.getFrameRegister(), frameMap.offsetForStackSlot(slot));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Sun Mar 10 19:51:32 2013 +0100
@@ -32,7 +32,7 @@
 /**
  * The {@code ConvertNode} class represents a conversion between primitive types.
  */
-public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable {
+public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable, Lowerable {
 
     public enum Op {
         I2L(Int, Long),
@@ -162,6 +162,11 @@
     }
 
     @Override
+    public void lower(LoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.setResult(this, gen.emitConvert(opcode, gen.operand(value())));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sun Mar 10 19:51:32 2013 +0100
@@ -48,4 +48,9 @@
      * Gets the closest fixed node preceding the node currently being lowered.
      */
     FixedWithNextNode lastFixedNode();
+
+    /**
+     * Sets the closest fixed node preceding the next node to be lowered.
+     */
+    void setLastFixedNode(FixedWithNextNode n);
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sun Mar 10 19:51:32 2013 +0100
@@ -104,6 +104,11 @@
         public FixedWithNextNode lastFixedNode() {
             return lastFixedNode;
         }
+
+        public void setLastFixedNode(FixedWithNextNode n) {
+            assert n == null || n.isAlive() : n;
+            lastFixedNode = n;
+        }
     }
 
     private final TargetDescription target;
@@ -187,15 +192,15 @@
         List<ScheduledNode> nodes = schedule.nodesFor(b);
 
         for (Node node : nodes) {
-            FixedNode lastFixedNext = null;
-            if (node instanceof FixedWithNextNode) {
+            FixedNode nextFixedNode = null;
+            if (node instanceof FixedWithNextNode && node.isAlive()) {
                 FixedWithNextNode fixed = (FixedWithNextNode) node;
-                lastFixedNext = fixed.next();
-                loweringTool.lastFixedNode = fixed;
+                nextFixedNode = fixed.next();
+                loweringTool.setLastFixedNode(fixed);
             }
 
             if (node.isAlive() && !processed.isMarked(node) && node instanceof Lowerable) {
-                if (loweringTool.lastFixedNode == null) {
+                if (loweringTool.lastFixedNode() == null) {
                     // We cannot lower the node now because we don't have a fixed node to anchor the
                     // replacements.
                     // This can happen when previous lowerings in this lowering iteration deleted
@@ -209,17 +214,17 @@
                 }
             }
 
-            if (loweringTool.lastFixedNode == node && !node.isAlive()) {
-                if (lastFixedNext == null) {
-                    loweringTool.lastFixedNode = null;
+            if (loweringTool.lastFixedNode() == node && !node.isAlive()) {
+                if (nextFixedNode == null || !nextFixedNode.isAlive()) {
+                    loweringTool.setLastFixedNode(null);
                 } else {
-                    Node prev = lastFixedNext.predecessor();
+                    Node prev = nextFixedNode.predecessor();
                     if (prev != node && prev instanceof FixedWithNextNode) {
-                        loweringTool.lastFixedNode = (FixedWithNextNode) prev;
-                    } else if (lastFixedNext instanceof FixedWithNextNode) {
-                        loweringTool.lastFixedNode = (FixedWithNextNode) lastFixedNext;
+                        loweringTool.setLastFixedNode((FixedWithNextNode) prev);
+                    } else if (nextFixedNode instanceof FixedWithNextNode) {
+                        loweringTool.setLastFixedNode((FixedWithNextNode) nextFixedNode);
                     } else {
-                        loweringTool.lastFixedNode = null;
+                        loweringTool.setLastFixedNode(null);
                     }
                 }
             }
--- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTXAddress.java	Sun Mar 10 19:51:18 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * 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.ptx;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents an address in target machine memory, specified via some combination of a base register
- * and a displacement.
- */
-public final class PTXAddress extends Address {
-
-    private static final long serialVersionUID = 8343625682010474837L;
-
-    private final Value[] base;
-    private final long displacement;
-
-    /**
-     * Creates an {@link PTXAddress} with given base register and no displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     */
-    public PTXAddress(Kind kind, Value base) {
-        this(kind, base, 0);
-    }
-
-    /**
-     * Creates an {@link PTXAddress} with given base register and a displacement. This is the most
-     * general constructor.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param displacement the displacement
-     */
-    public PTXAddress(Kind kind, Value base, long displacement) {
-        super(kind);
-        this.base = new Value[1];
-        this.setBase(base);
-        this.displacement = displacement;
-
-        assert !isConstant(base) && !isStackSlot(base);
-    }
-
-    @Override
-    public Value[] components() {
-        return base;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append(getKind().getJavaName()).append("[");
-        String sep = "";
-        if (isLegal(getBase())) {
-            s.append(getBase());
-            sep = " + ";
-        }
-        if (getDisplacement() < 0) {
-            s.append(" - ").append(-getDisplacement());
-        } else if (getDisplacement() > 0) {
-            s.append(sep).append(getDisplacement());
-        }
-        s.append("]");
-        return s.toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof PTXAddress) {
-            PTXAddress addr = (PTXAddress) obj;
-            return getKind() == addr.getKind() && getDisplacement() == addr.getDisplacement() && getBase().equals(addr.getBase());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getBase().hashCode() ^ ((int) getDisplacement() << 4) ^ (getKind().ordinal() << 12);
-    }
-
-    /**
-     * @return Base register that defines the start of the address computation. If not present, is
-     *         denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getBase() {
-        return base[0];
-    }
-
-    public void setBase(Value base) {
-        this.base[0] = base;
-    }
-
-    /**
-     * @return Optional additive displacement.
-     */
-    public long getDisplacement() {
-        return displacement;
-    }
-}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/InstanceOfSnippetsTemplates.java	Sun Mar 10 19:51:32 2013 +0100
@@ -95,7 +95,7 @@
             } else {
                 KeyAndArguments keyAndArguments = getKeyAndArguments(replacer, tool);
                 SnippetTemplate template = cache.get(keyAndArguments.key, assumptions);
-                template.instantiate(runtime, instanceOf, replacer, tool.lastFixedNode(), keyAndArguments.arguments);
+                template.instantiate(runtime, instanceOf, replacer, tool, keyAndArguments.arguments);
             }
         }
 
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetInstaller.java	Sun Mar 10 19:51:32 2013 +0100
@@ -198,7 +198,8 @@
             public StructuredGraph call() throws Exception {
                 StructuredGraph graph = parseGraph(method, policy);
 
-                new SnippetIntrinsificationPhase(runtime, pool, SnippetTemplate.hasConstantParameter(method)).apply(graph);
+                new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
+                assert SnippetTemplate.hasConstantParameter(method) || SnippetIntrinsificationVerificationPhase.verify(graph);
 
                 new SnippetFrameStateCleanupPhase().apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
@@ -232,7 +233,7 @@
 
         new WordTypeVerificationPhase(runtime, target.wordKind).apply(graph);
 
-        new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
+        new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
 
         for (Invoke invoke : graph.getInvokes()) {
             MethodCallTargetNode callTarget = invoke.methodCallTarget();
@@ -260,7 +261,7 @@
             }
         }
 
-        new SnippetIntrinsificationPhase(runtime, pool, true).apply(graph);
+        new SnippetIntrinsificationPhase(runtime, pool).apply(graph);
 
         new WordTypeRewriterPhase(runtime, target.wordKind).apply(graph);
 
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationPhase.java	Sun Mar 10 19:51:32 2013 +0100
@@ -43,45 +43,21 @@
 
     private final MetaAccessProvider runtime;
     private final BoxingMethodPool pool;
-    private final boolean intrinsificationOrFoldingCanBeDeferred;
 
-    /**
-     * @param intrinsificationOrFoldingCanBeDeferred if true, then {@link NonConstantParameterError}
-     *            s are not fatal
-     */
-    public SnippetIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool, boolean intrinsificationOrFoldingCanBeDeferred) {
+    public SnippetIntrinsificationPhase(MetaAccessProvider runtime, BoxingMethodPool pool) {
         this.runtime = runtime;
         this.pool = pool;
-        this.intrinsificationOrFoldingCanBeDeferred = intrinsificationOrFoldingCanBeDeferred;
     }
 
     @Override
     protected void run(StructuredGraph graph) {
         for (Invoke i : graph.getInvokes()) {
-            try {
-                if (i.callTarget() instanceof MethodCallTargetNode) {
-                    tryIntrinsify(i);
-                }
-            } catch (NonConstantParameterError t) {
-                if (!intrinsificationOrFoldingCanBeDeferred) {
-                    throw t;
-                }
+            if (i.callTarget() instanceof MethodCallTargetNode) {
+                tryIntrinsify(i);
             }
         }
     }
 
-    /**
-     * Exception raised when an argument to a {@linkplain Fold foldable} or {@link NodeIntrinsic}
-     * method is not a constant.
-     */
-    @SuppressWarnings("serial")
-    public static class NonConstantParameterError extends Error {
-
-        public NonConstantParameterError(String message) {
-            super(message);
-        }
-    }
-
     public static Class<?>[] signatureToTypes(Signature signature, ResolvedJavaType accessingClass) {
         int count = signature.getParameterCount(false);
         Class<?>[] result = new Class<?>[count];
@@ -91,7 +67,7 @@
         return result;
     }
 
-    private void tryIntrinsify(Invoke invoke) {
+    private boolean tryIntrinsify(Invoke invoke) {
         ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod();
         NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
         ResolvedJavaType declaringClass = target.getDeclaringClass();
@@ -104,6 +80,9 @@
 
             // Prepare the arguments for the reflective constructor call on the node class.
             Object[] nodeConstructorArguments = prepareArguments(invoke, parameterTypes, target, false);
+            if (nodeConstructorArguments == null) {
+                return false;
+            }
 
             // Create the new node instance.
             Class<?> c = getNodeClass(target, intrinsic);
@@ -120,6 +99,9 @@
 
             // Prepare the arguments for the reflective method call
             Object[] arguments = prepareArguments(invoke, parameterTypes, target, true);
+            if (arguments == null) {
+                return false;
+            }
             Object receiver = null;
             if (!invoke.methodCallTarget().isStatic()) {
                 receiver = arguments[0];
@@ -142,6 +124,7 @@
                 invoke.intrinsify(null);
             }
         }
+        return true;
     }
 
     /**
@@ -149,6 +132,8 @@
      * to a reflective invocation of a Java constructor or method.
      * 
      * @param folding specifies if the invocation is for handling a {@link Fold} annotation
+     * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
+     *         that is expected to be constant isn't
      */
     private Object[] prepareArguments(Invoke invoke, Class<?>[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
         NodeInputList<ValueNode> arguments = invoke.callTarget().arguments();
@@ -161,8 +146,7 @@
             ValueNode argument = tryBoxingElimination(parameterIndex, target, arguments.get(i));
             if (folding || MetaUtil.getParameterAnnotation(ConstantNodeParameter.class, parameterIndex, target) != null) {
                 if (!(argument instanceof ConstantNode)) {
-                    throw new NonConstantParameterError("parameter " + parameterIndex + " must be a compile time constant for calling " + invoke.methodCallTarget().targetMethod() + " at " +
-                                    sourceLocation(invoke.node()) + ": " + argument);
+                    return null;
                 }
                 ConstantNode constantNode = (ConstantNode) argument;
                 Constant constant = constantNode.asConstant();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetIntrinsificationVerificationPhase.java	Sun Mar 10 19:51:32 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.snippets.Snippet.Fold;
+
+/**
+ * Checks that a graph contains no calls to {@link NodeIntrinsic} or {@link Fold} methods.
+ */
+public class SnippetIntrinsificationVerificationPhase extends Phase {
+
+    public static boolean verify(StructuredGraph graph) {
+        new SnippetIntrinsificationVerificationPhase().apply(graph);
+        return true;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (Invoke i : graph.getInvokes()) {
+            if (i.callTarget() instanceof MethodCallTargetNode) {
+                checkInvoke(i);
+            }
+        }
+    }
+
+    private static void checkInvoke(Invoke invoke) {
+        ResolvedJavaMethod target = invoke.methodCallTarget().targetMethod();
+        NodeIntrinsic intrinsic = target.getAnnotation(Node.NodeIntrinsic.class);
+        if (intrinsic != null) {
+            throw new GraalInternalError("Illegal call to node intrinsic in " + invoke.graph() + ": " + invoke);
+        } else if (target.getAnnotation(Fold.class) != null) {
+            throw new GraalInternalError("Illegal call to foldable method in " + invoke.graph() + ": " + invoke);
+        }
+    }
+}
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Sun Mar 10 19:51:18 2013 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Sun Mar 10 19:51:32 2013 +0100
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
@@ -282,11 +283,12 @@
         Debug.dump(snippetCopy, "Before specialization");
         if (!replacements.isEmpty()) {
             // Do deferred intrinsification of node intrinsics
-            new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime), false).apply(snippetCopy);
+            new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime)).apply(snippetCopy);
             new WordTypeRewriterPhase(runtime, target.wordKind).apply(snippetCopy);
 
             new CanonicalizerPhase(runtime, assumptions, 0, null).apply(snippetCopy);
         }
+        assert SnippetIntrinsificationVerificationPhase.verify(snippetCopy);
 
         // Gather the template parameters
         parameters = new HashMap<>();
@@ -628,10 +630,9 @@
      * @param runtime
      * @param replacee the node that will be replaced
      * @param replacer object that replaces the usages of {@code replacee}
-     * @param lastFixedNode the CFG of the snippet is inserted after this node
      * @param args the arguments to be bound to the flattened positional parameters of the snippet
      */
-    public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, FixedWithNextNode lastFixedNode, SnippetTemplate.Arguments args) {
+    public void instantiate(MetaAccessProvider runtime, FloatingNode replacee, UsageReplacer replacer, LoweringTool tool, SnippetTemplate.Arguments args) {
 
         // Inline the snippet nodes, replacing parameters with the given args in the process
         String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}";
@@ -643,7 +644,8 @@
         Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
         Debug.dump(replaceeGraph, "After inlining snippet %s", snippetCopy.method());
 
-        assert lastFixedNode != null : replaceeGraph;
+        FixedWithNextNode lastFixedNode = tool.lastFixedNode();
+        assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph;
         FixedNode next = lastFixedNode.next();
         lastFixedNode.setNext(null);
         FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
@@ -672,10 +674,14 @@
         assert returnValue != null || replacee.usages().isEmpty();
         replacer.replace(replacee, returnValue);
 
+        tool.setLastFixedNode(null);
         Node returnDuplicate = duplicates.get(returnNode);
         if (returnDuplicate.isAlive()) {
             returnDuplicate.clearInputs();
             returnDuplicate.replaceAndDelete(next);
+            if (next != null && next.predecessor() instanceof FixedWithNextNode) {
+                tool.setLastFixedNode((FixedWithNextNode) next.predecessor());
+            }
         }
 
         Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this);
--- a/mx/commands.py	Sun Mar 10 19:51:18 2013 +0100
+++ b/mx/commands.py	Sun Mar 10 19:51:32 2013 +0100
@@ -385,7 +385,11 @@
         for e in os.listdir(jdks):
             jreLibDir = join(jdks, e, 'jre', 'lib')
             if exists(jreLibDir):
-                shutil.copyfile(graalJar, join(jreLibDir, 'graal.jar'))
+                # do a copy and then a move to get atomic updating (on Unix) of graal.jar in the JRE
+                fd, tmp = tempfile.mkstemp(suffix='', prefix='graal.jar', dir=jreLibDir)
+                shutil.copyfile(graalJar, tmp)
+                os.close(fd)
+                shutil.move(tmp, join(jreLibDir, 'graal.jar'))
 
 # run a command in the windows SDK Debug Shell
 def _runInDebugShell(cmd, workingDir, logFile=None, findInOutput=None, respondTo={}):
--- a/mx/projects	Sun Mar 10 19:51:18 2013 +0100
+++ b/mx/projects	Sun Mar 10 19:51:32 2013 +0100
@@ -248,7 +248,7 @@
 # graal.compiler.ptx.test
 project@com.oracle.graal.compiler.ptx.test@subDir=graal
 project@com.oracle.graal.compiler.ptx.test@sourceDirs=src
-project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test
+project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test,com.oracle.graal.ptx
 project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7
 
@@ -331,7 +331,7 @@
 # graal.asm.ptx
 project@com.oracle.graal.asm.ptx@subDir=graal
 project@com.oracle.graal.asm.ptx@sourceDirs=src
-project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm,com.oracle.graal.ptx
+project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm
 project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.asm.ptx@javaCompliance=1.7
 
--- a/mxtool/mx.py	Sun Mar 10 19:51:18 2013 +0100
+++ b/mxtool/mx.py	Sun Mar 10 19:51:32 2013 +0100
@@ -1651,7 +1651,8 @@
         if name.startswith('@'):
             dname = name[1:]
             d = distribution(dname)
-            zf = zipfile.ZipFile(d.path, 'w')
+            fd, tmp = tempfile.mkstemp(suffix='', prefix=basename(d.path) + '.', dir=dirname(d.path))
+            zf = zipfile.ZipFile(tmp, 'w')
             for p in sorted_deps(d.deps):
                 outputDir = p.output_dir()
                 for root, _, files in os.walk(outputDir):
@@ -1660,19 +1661,26 @@
                         arcname = join(relpath, f).replace(os.sep, '/')
                         zf.write(join(root, f), arcname)
             zf.close()
+            os.close(fd)
+            # Atomic on Unix
+            shutil.move(tmp, d.path)
+            #print time.time(), 'move:', tmp, '->', d.path
             d.notify_updated()
 
         else:
             p = project(name)
             outputDir = p.output_dir()
-            jar = join(p.dir, p.name + '.jar')
-            zf = zipfile.ZipFile(jar, 'w')
+            fd, tmp = tempfile.mkstemp(suffix='', prefix=p.name, dir=p.dir)
+            zf = zipfile.ZipFile(tmp, 'w')
             for root, _, files in os.walk(outputDir):
                 for f in files:
                     relpath = root[len(outputDir) + 1:]
                     arcname = join(relpath, f).replace(os.sep, '/')
                     zf.write(join(root, f), arcname)
             zf.close()
+            os.close(fd)
+            # Atomic on Unix
+            shutil.move(tmp, join(p.dir, p.name + '.jar'))
 
 def canonicalizeprojects(args):
     """process all project files to canonicalize the dependencies
@@ -2255,13 +2263,18 @@
     
     return False
 
-def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False):
+def _genEclipseBuilder(dotProjectDoc, p, name, mxCommand, refresh=True, async=False, logToConsole=False):
     launchOut = XMLDoc();
+    consoleOn = 'true' if logToConsole else 'false'
     launchOut.open('launchConfiguration', {'type' : 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType'})
+    launchOut.open('mapAttribute', {'key' : 'org.eclipse.debug.core.environmentVariables'})
+    launchOut.element('mapEntry', {'key' : 'JAVA_HOME',	'value' : java().jdk})
+    launchOut.close('mapAttribute')
+    
     if refresh:
         launchOut.element('stringAttribute',  {'key' : 'org.eclipse.debug.core.ATTR_REFRESH_SCOPE',            'value': '${project}'})
-    launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output',                'value': 'false'})
-    launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON',          'value': 'false'})
+    launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON',          'value': consoleOn})
+    launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.core.capture_output',                'value': consoleOn})
     if async:
         launchOut.element('booleanAttribute', {'key' : 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND',       'value': 'true'})