changeset 20994:68ff637e95b1

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Thu, 16 Apr 2015 17:09:06 +0200
parents ec36daea3cf0 (current diff) e6b59c7b3991 (diff)
children 59e8737c06fd 5e78d067ebbe
files graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePositionProcedure.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java mx/mx_graal.py
diffstat 72 files changed, 1983 insertions(+), 2304 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Thu Apr 16 17:09:06 2015 +0200
@@ -25,28 +25,29 @@
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.*;
 
-public interface ReferenceMap extends Cloneable {
+public abstract class ReferenceMap implements Cloneable {
 
-    void setRegister(int idx, LIRKind kind);
+    public abstract void setRegister(int idx, LIRKind kind);
 
-    void clearRegister(int idx, LIRKind kind);
+    public abstract void clearRegister(int idx, LIRKind kind);
 
-    void setStackSlot(int offset, LIRKind kind);
+    public abstract void setStackSlot(int offset, LIRKind kind);
 
-    void clearStackSlot(int offset, LIRKind kind);
+    public abstract void clearStackSlot(int offset, LIRKind kind);
 
-    boolean hasRegisterRefMap();
+    public abstract boolean hasRegisterRefMap();
 
-    boolean hasFrameRefMap();
+    public abstract boolean hasFrameRefMap();
 
-    void appendRegisterMap(StringBuilder sb, RefMapFormatter formatterArg);
+    public abstract void appendRegisterMap(StringBuilder sb, RefMapFormatter formatterArg);
 
-    void appendFrameMap(StringBuilder sb, RefMapFormatter formatterArg);
+    public abstract void appendFrameMap(StringBuilder sb, RefMapFormatter formatterArg);
 
-    ReferenceMap clone();
+    @Override
+    public abstract ReferenceMap clone();
 
     /**
      * Updates this map with all references marked in {@code other}.
      */
-    void updateUnion(ReferenceMap other);
+    public abstract void updateUnion(ReferenceMap other);
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Apr 16 17:09:06 2015 +0200
@@ -398,6 +398,22 @@
         }
     }
 
+    public static void log(String format, int arg) {
+        log(DEFAULT_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * Prints a message to the current debug scope's logging stream if logging is enabled.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     */
+    public static void log(int logLevel, String format, int arg) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg);
+        }
+    }
+
     public static void log(String format, Object arg1, Object arg2) {
         log(DEFAULT_LOG_LEVEL, format, arg1, arg2);
     }
@@ -411,6 +427,45 @@
         }
     }
 
+    public static void log(String format, int arg1, Object arg2) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, Object arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, Object arg1, int arg2) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, Object arg1, int arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
+    public static void log(String format, int arg1, int arg2) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, int arg2) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2);
+        }
+    }
+
     public static void log(String format, Object arg1, Object arg2, Object arg3) {
         log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
     }
@@ -424,6 +479,19 @@
         }
     }
 
+    public static void log(String format, int arg1, int arg2, int arg3) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #log(int, String, Object)
+     */
+    public static void log(int logLevel, String format, int arg1, int arg2, int arg3) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3);
+        }
+    }
+
     public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
         log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
     }
@@ -695,6 +763,67 @@
         return null;
     }
 
+    public static Indent logAndIndent(String format, int arg) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg);
+    }
+
+    /**
+     * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}.
+     *
+     * @param format a format string
+     * @param arg the argument referenced by the format specifiers in {@code format}
+     * @return an object that reverts to the current indentation level when
+     *         {@linkplain Indent#close() closed} or null if debugging is disabled
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg1, Object arg2) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, Object arg2) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, int arg2) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, int arg1, int arg2) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2);
+        }
+        return null;
+    }
+
     public static Indent logAndIndent(String format, Object arg1, Object arg2) {
         return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2);
     }
@@ -723,6 +852,34 @@
         return null;
     }
 
+    public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, int arg1, int arg2, int arg3) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
+    public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) {
+        return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3);
+    }
+
+    /**
+     * @see #logAndIndent(int, String, Object)
+     */
+    public static Indent logAndIndent(int logLevel, String format, Object arg1, int arg2, int arg3) {
+        if (ENABLED) {
+            return logvAndIndent(logLevel, format, arg1, arg2, arg3);
+        }
+        return null;
+    }
+
     public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) {
         return logAndIndent(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Thu Apr 16 17:09:06 2015 +0200
@@ -30,12 +30,277 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 
-public final class HotSpotReferenceMap implements ReferenceMap, Serializable {
+public final class HotSpotReferenceMap extends ReferenceMap implements Serializable {
+
+    static final int OOP64 = 0b1010;
+    static final int OOP32 = 0b01;
+    static final int NARROW_LOW = OOP32;
+    static final int NARROW_HIGH = OOP32 << 2;
+    static final int NARROW_BOTH = NARROW_LOW | NARROW_HIGH;
+
+    private enum MapEntry {
+        NoReference(0),
+        WideOop(OOP64),
+        NarrowOopLowerHalf(NARROW_LOW),
+        NarrowOopUpperHalf(NARROW_HIGH),
+        TwoNarrowOops(NARROW_BOTH),
+        Illegal(-1);
+
+        MapEntry(int pattern) {
+            this.pattern = pattern;
+        }
+
+        final int pattern;
+
+        /**
+         * Create enum values from OopMap.
+         * <p>
+         * These bits can have the following values (MSB first):
+         *
+         * <pre>
+         * 0000 - contains no references
+         * 1010 - contains a wide oop
+         * 0001 - contains a narrow oop in the lower half
+         * 0101 - contains a narrow oop in the upper half
+         * 0101 - contains two narrow oops
+         * </pre>
+         *
+         * @see HotSpotReferenceMap#registerRefMap
+         * @see HotSpotReferenceMap#frameRefMap
+         */
+        static MapEntry getFromBits(int idx, HotSpotOopMap set) {
+            int n = set.get(idx);
+            switch (n) {
+                case 0:
+                    return NoReference;
+                case OOP64:
+                    return WideOop;
+                case NARROW_LOW:
+                    return NarrowOopLowerHalf;
+                case NARROW_HIGH:
+                    return NarrowOopUpperHalf;
+                case NARROW_BOTH:
+                    return TwoNarrowOops;
+                default:
+                    return Illegal;
+            }
+        }
+
+        String toBitString() {
+            int bits = toBit(this);
+            if (bits == -1) {
+                return "---";
+            }
+            return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0');
+        }
+
+        static int toBit(MapEntry type) {
+            return type.pattern;
+        }
+    }
+
+    /**
+     * A specialized bit set that represents both wide and narrow oops in an efficient manner. The
+     * map consists of 4 bit entries that represent 8 bytes of memory.
+     *
+     */
+    class HotSpotOopMap implements Cloneable, Serializable {
+
+        private static final long serialVersionUID = -4997600265320131213L;
+
+        /**
+         * Each entry is 4 bits long and covers 8 bytes of memory.
+         */
+        private static final int BITS_PER_ENTRY = 4;
+        private static final int BITS_PER_ELEMENT = 64;
+
+        public HotSpotOopMap(int i) {
+            words = new long[(i * BITS_PER_ENTRY + BITS_PER_ELEMENT) / BITS_PER_ELEMENT];
+        }
+
+        public HotSpotOopMap(HotSpotOopMap other) {
+            words = other.words.clone();
+        }
+
+        private long[] words;
+
+        private int get(int i) {
+            return getEntry(i);
+        }
+
+        private boolean isEmpty() {
+            for (int i = 0; i < words.length; i++) {
+                if (words[i] != 0) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public void or(HotSpotOopMap src) {
+            if (words.length < src.words.length) {
+                long[] newWords = new long[src.words.length];
+                System.arraycopy(src.words, 0, newWords, 0, src.words.length);
+                for (int i = 0; i < words.length; i++) {
+                    newWords[i] |= words[i];
+                }
+                words = newWords;
+            } else {
+                for (int i = 0; i < src.words.length; i++) {
+                    words[i] |= src.words[i];
+                }
+            }
+        }
+
+        private void setOop(int regIdx) {
+            setEntry(regIdx, OOP64);
+        }
+
+        public int size() {
+            return words.length * BITS_PER_ELEMENT / BITS_PER_ENTRY;
+        }
+
+        @Override
+        public HotSpotOopMap clone() {
+            return new HotSpotOopMap(this);
+        }
+
+        private void setNarrowOop(int offset, int index) {
+            setNarrowEntry(offset + index, OOP32);
+        }
+
+        private void setEntry(int regIdx, int value) {
+            assert regIdx % 2 == 0 : "must be alinged";
+            int bitIndex = (regIdx >> 1) * BITS_PER_ENTRY;
+            int wordIndex = bitIndex / BITS_PER_ELEMENT;
+            int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
+            if (wordIndex >= words.length) {
+                if (value == 0) {
+                    // Nothing to do since bits are clear
+                    return;
+                }
+                words = Arrays.copyOf(words, wordIndex + 1);
+            }
+            assert verifyUpdate(this, this);
+            long orig = words[wordIndex];
+            words[wordIndex] = (orig & (~(0b1111L << shift))) | ((long) value << shift);
+            assert get(regIdx / 2) == value;
+            assert verifyUpdate(this, this);
+        }
+
+        private void setNarrowEntry(int offset, int value) {
+            int regIdx = offset >> 1;
+            boolean low = offset % 2 == 0;
+            int bitIndex = regIdx * BITS_PER_ENTRY;
+            int wordIndex = bitIndex / BITS_PER_ELEMENT;
+            int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
+            if (wordIndex >= words.length) {
+                if (value == 0) {
+                    // Nothing to do since bits are clear
+                    return;
+                }
+                words = Arrays.copyOf(words, wordIndex + 1);
+            }
+            long originalValue = words[wordIndex];
+            int current = ((int) (originalValue >> shift)) & 0b1111;
+            if (current == OOP64) {
+                current = 0;
+            }
+            long newValue;
+            if (value != 0) {
+                newValue = current | (low ? value : (value << 2));
+            } else {
+                newValue = current & (low ? 0b1100 : 0b0011);
+            }
+            long masked = originalValue & (~(0b1111L << shift));
+            words[wordIndex] = masked | (newValue << shift);
+            assert verifyUpdate(this, this);
+        }
+
+        private int getEntry(int regIdx) {
+            int bitIndex = regIdx * BITS_PER_ENTRY;
+            int wordIndex = bitIndex / BITS_PER_ELEMENT;
+            int shift = bitIndex - wordIndex * BITS_PER_ELEMENT;
+            return ((int) (words[wordIndex] >>> shift)) & 0b1111;
+        }
+
+        private void clearOop(int offset) {
+            setEntry(offset, 0);
+        }
+
+        private void clearNarrowOop(int offset) {
+            setNarrowEntry(offset, 0);
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+
+            if (other instanceof HotSpotOopMap) {
+                HotSpotOopMap otherMap = (HotSpotOopMap) other;
+                int limit = Math.min(words.length, otherMap.words.length);
+                for (int i = 0; i < limit; i++) {
+                    if (words[i] != otherMap.words[i]) {
+                        return false;
+                    }
+                }
+                for (int i = limit; i < words.length; i++) {
+                    if (words[i] != 0) {
+                        return false;
+                    }
+                }
+                for (int i = limit; i < otherMap.words.length; i++) {
+                    if (otherMap.words[i] != 0) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            long h = 1234;
+            for (int i = words.length; --i >= 0;) {
+                h ^= words[i] * (i + 1);
+            }
+            return (int) ((h >> 32) ^ h);
+        }
+
+        @Override
+        public String toString() {
+            int count = 0;
+            StringBuilder sb = new StringBuilder();
+            sb.append("[");
+            for (int idx = 0; idx < size(); idx++) {
+                MapEntry dstType = MapEntry.getFromBits(idx, this);
+                if (dstType == MapEntry.NoReference) {
+                    continue;
+                }
+                if (count > 0) {
+                    sb.append(", ");
+                }
+                if (dstType == MapEntry.Illegal) {
+                    int value = get(idx);
+                    sb.append("0x");
+                    sb.append(Integer.toHexString(value));
+                } else {
+                    sb.append(idx);
+                    sb.append(':');
+                    sb.append(dstType);
+                }
+                count++;
+            }
+            sb.append("]");
+            return sb.toString();
+        }
+    }
 
     private static final long serialVersionUID = -1052183095979496819L;
 
-    public static final int BITS_PER_WORD = 3;
-
     /**
      * Contains 3 bits per scalar register, and n*3 bits per n-word vector register (e.g., on a
      * 64-bit system, a 256-bit vector register requires 12 reference map bits).
@@ -50,7 +315,7 @@
      * 111 - contains two narrow oops
      * </pre>
      */
-    private final BitSet registerRefMap;
+    private final HotSpotOopMap registerRefMap;
 
     /**
      * Contains 3 bits per stack word.
@@ -65,23 +330,23 @@
      * 111 - contains two narrow oops
      * </pre>
      */
-    private final BitSet frameRefMap;
+    private final HotSpotOopMap frameRefMap;
 
     private final TargetDescription target;
 
     public HotSpotReferenceMap(int registerCount, int frameSlotCount, TargetDescription target) {
         if (registerCount > 0) {
-            this.registerRefMap = new BitSet(registerCount * BITS_PER_WORD);
+            this.registerRefMap = new HotSpotOopMap(registerCount);
         } else {
             this.registerRefMap = null;
         }
-        this.frameRefMap = new BitSet(frameSlotCount * BITS_PER_WORD);
+        this.frameRefMap = new HotSpotOopMap(frameSlotCount);
         this.target = target;
     }
 
     private HotSpotReferenceMap(HotSpotReferenceMap other) {
-        this.registerRefMap = (BitSet) other.registerRefMap.clone();
-        this.frameRefMap = (BitSet) other.frameRefMap.clone();
+        this.registerRefMap = other.registerRefMap.clone();
+        this.frameRefMap = other.frameRefMap.clone();
         this.target = other.target;
     }
 
@@ -92,32 +357,26 @@
 
     // setters
 
-    private static void setOop(BitSet map, int startIdx, LIRKind kind) {
+    private static void setOop(HotSpotOopMap map, int startIdx, LIRKind kind) {
         int length = kind.getPlatformKind().getVectorLength();
-        map.clear(BITS_PER_WORD * startIdx, BITS_PER_WORD * (startIdx + length));
-        for (int i = 0, idx = BITS_PER_WORD * startIdx; i < length; i++, idx += BITS_PER_WORD) {
+        for (int i = 0, idx = startIdx; i < length; i++, idx += 1) {
             if (kind.isReference(i)) {
-                map.set(idx);
+                map.setOop(idx);
+            }
+
+        }
+    }
+
+    private static void setNarrowOop(HotSpotOopMap map, int offset, LIRKind kind) {
+        int length = kind.getPlatformKind().getVectorLength();
+        for (int i = 0; i < length; i++) {
+            if (kind.isReference(i)) {
+                map.setNarrowOop(offset, i);
             }
         }
     }
 
-    private static void setNarrowOop(BitSet map, int idx, LIRKind kind) {
-        int length = kind.getPlatformKind().getVectorLength();
-        int nextIdx = idx + (length + 1) / 2;
-        map.clear(BITS_PER_WORD * idx, BITS_PER_WORD * nextIdx);
-        for (int i = 0, regIdx = BITS_PER_WORD * idx; i < length; i += 2, regIdx += BITS_PER_WORD) {
-            if (kind.isReference(i)) {
-                map.set(regIdx);
-                map.set(regIdx + 1);
-            }
-            if ((i + 1) < length && kind.isReference(i + 1)) {
-                map.set(regIdx);
-                map.set(regIdx + 2);
-            }
-        }
-    }
-
+    @Override
     public void setRegister(int idx, LIRKind kind) {
         if (kind.isDerivedReference()) {
             throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap");
@@ -126,15 +385,16 @@
         PlatformKind platformKind = kind.getPlatformKind();
         int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
 
-        if (bytesPerElement == target.wordSize) {
-            setOop(registerRefMap, idx, kind);
-        } else if (bytesPerElement == target.wordSize / 2) {
-            setNarrowOop(registerRefMap, idx, kind);
+        if (bytesPerElement == 8) {
+            setOop(registerRefMap, idx * 2, kind);
+        } else if (bytesPerElement == 4) {
+            setNarrowOop(registerRefMap, idx * 2, kind);
         } else {
             assert kind.isValue() : "unsupported reference kind " + kind;
         }
     }
 
+    @Override
     public void setStackSlot(int offset, LIRKind kind) {
         if (kind.isDerivedReference()) {
             throw GraalInternalError.shouldNotReachHere("derived reference cannot be inserted in ReferenceMap");
@@ -144,109 +404,81 @@
         int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
         assert offset % bytesPerElement == 0 : "unaligned value in ReferenceMap";
 
-        if (bytesPerElement == target.wordSize) {
-            setOop(frameRefMap, offset / target.wordSize, kind);
-        } else if (bytesPerElement == target.wordSize / 2) {
-            if (platformKind.getVectorLength() > 1) {
-                setNarrowOop(frameRefMap, offset / target.wordSize, kind);
-            } else {
-                // in this case, offset / target.wordSize may not divide evenly
-                // so setNarrowOop won't work correctly
-                int idx = offset / target.wordSize;
-                if (kind.isReference(0)) {
-                    frameRefMap.set(BITS_PER_WORD * idx);
-                    if (offset % target.wordSize == 0) {
-                        frameRefMap.set(BITS_PER_WORD * idx + 1);
-                    } else {
-                        frameRefMap.set(BITS_PER_WORD * idx + 2);
-                    }
-                }
-            }
+        int index = offset / 4; // Addressing is done in increments of 4 bytes
+        if (bytesPerElement == 8) {
+            setOop(frameRefMap, index, kind);
+        } else if (bytesPerElement == 4) {
+            setNarrowOop(frameRefMap, index, kind);
         } else {
             assert kind.isValue() : "unknown reference kind " + kind;
         }
     }
 
-    public BitSet getFrameMap() {
-        return frameRefMap == null ? null : (BitSet) frameRefMap.clone();
+    public HotSpotOopMap getFrameMap() {
+        return frameRefMap == null ? null : (HotSpotOopMap) frameRefMap.clone();
     }
 
-    public BitSet getRegisterMap() {
-        return registerRefMap == null ? null : (BitSet) registerRefMap.clone();
+    public HotSpotOopMap getRegisterMap() {
+        return registerRefMap == null ? null : (HotSpotOopMap) registerRefMap.clone();
     }
 
     // clear
 
-    private static void clearOop(BitSet map, int startIdx, LIRKind kind) {
-        int length = kind.getPlatformKind().getVectorLength();
-        map.clear(BITS_PER_WORD * startIdx, BITS_PER_WORD * (startIdx + length));
+    private static void clearOop(HotSpotOopMap map, int offset, PlatformKind platformKind) {
+        int length = platformKind.getVectorLength();
+        for (int i = 0; i < length; i++) {
+            map.clearOop(offset + i * 2);
+        }
     }
 
-    private static void clearNarrowOop(BitSet map, int idx, LIRKind kind) {
-        int length = kind.getPlatformKind().getVectorLength();
-        int nextIdx = idx + (length + 1) / 2;
-        map.clear(BITS_PER_WORD * idx, BITS_PER_WORD * nextIdx);
+    private static void clearNarrowOop(HotSpotOopMap map, int offset, PlatformKind platformKind) {
+        int length = platformKind.getVectorLength();
+        for (int i = 0; i < length; i++) {
+            map.clearNarrowOop(offset + i);
+        }
     }
 
+    @Override
     public void clearRegister(int idx, LIRKind kind) {
-
         PlatformKind platformKind = kind.getPlatformKind();
         int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
 
-        if (bytesPerElement == target.wordSize) {
-            clearOop(registerRefMap, idx, kind);
-        } else if (bytesPerElement == target.wordSize / 2) {
-            clearNarrowOop(registerRefMap, idx, kind);
+        if (bytesPerElement == 8) {
+            clearOop(registerRefMap, idx * 2, platformKind);
+        } else if (bytesPerElement == 4) {
+            clearNarrowOop(registerRefMap, idx * 2, platformKind);
         } else {
             assert kind.isValue() : "unsupported reference kind " + kind;
         }
     }
 
+    @Override
     public void clearStackSlot(int offset, LIRKind kind) {
 
         PlatformKind platformKind = kind.getPlatformKind();
         int bytesPerElement = target.getSizeInBytes(platformKind) / platformKind.getVectorLength();
         assert offset % bytesPerElement == 0 : "unaligned value in ReferenceMap";
 
-        if (bytesPerElement == target.wordSize) {
-            clearOop(frameRefMap, offset / target.wordSize, kind);
-        } else if (bytesPerElement == target.wordSize / 2) {
-            if (platformKind.getVectorLength() > 1) {
-                clearNarrowOop(frameRefMap, offset / target.wordSize, kind);
-            } else {
-                // in this case, offset / target.wordSize may not divide evenly
-                // so setNarrowOop won't work correctly
-                int idx = offset / target.wordSize;
-                if (kind.isReference(0)) {
-                    if (offset % target.wordSize == 0) {
-                        frameRefMap.clear(BITS_PER_WORD * idx + 1);
-                        if (!frameRefMap.get(BITS_PER_WORD * idx + 2)) {
-                            // only reset the first bit if there is no other narrow oop
-                            frameRefMap.clear(BITS_PER_WORD * idx);
-                        }
-                    } else {
-                        frameRefMap.clear(BITS_PER_WORD * idx + 2);
-                        if (!frameRefMap.get(BITS_PER_WORD * idx + 1)) {
-                            // only reset the first bit if there is no other narrow oop
-                            frameRefMap.clear(BITS_PER_WORD * idx);
-                        }
-                    }
-                }
-            }
+        int index = offset / 4; // Addressing is done in increments of 4 bytes
+        if (bytesPerElement == 8) {
+            clearOop(frameRefMap, index, platformKind);
+        } else if (bytesPerElement == 4) {
+            clearNarrowOop(frameRefMap, index, platformKind);
         } else {
             assert kind.isValue() : "unknown reference kind " + kind;
         }
     }
 
+    @Override
     public void updateUnion(ReferenceMap otherArg) {
         HotSpotReferenceMap other = (HotSpotReferenceMap) otherArg;
         if (registerRefMap != null) {
             assert other.registerRefMap != null;
-            updateUnionBitSetRaw(registerRefMap, other.registerRefMap);
+            updateUnionOopMapRaw(registerRefMap, other.registerRefMap);
         } else {
-            assert other.registerRefMap == null || other.registerRefMap.cardinality() == 0 : "Target register reference map is empty but the source is not: " + other.registerRefMap;
+            assert other.registerRefMap == null || other.registerRefMap.isEmpty() : "Target register reference map is empty but the source is not: " + other.registerRefMap;
         }
-        updateUnionBitSetRaw(frameRefMap, other.frameRefMap);
+        updateUnionOopMapRaw(frameRefMap, other.frameRefMap);
     }
 
     /**
@@ -255,111 +487,69 @@
      * @see HotSpotReferenceMap#registerRefMap
      * @see HotSpotReferenceMap#frameRefMap
      */
-    private static void updateUnionBitSetRaw(BitSet dst, BitSet src) {
-        assert dst.size() == src.size();
-        assert UpdateUnionVerifier.verifyUpate(dst, src);
+    private static void updateUnionOopMapRaw(HotSpotOopMap dst, HotSpotOopMap src) {
+        assert verifyUpdate(dst, src);
         dst.or(src);
+        assert verifyUpdate(dst, dst);
     }
 
-    private enum UpdateUnionVerifier {
-        NoReference,
-        WideOop,
-        NarrowOopLowerHalf,
-        NarrowOopUpperHalf,
-        TwoNarrowOops,
-        Illegal;
+    static MapEntry[] entries(HotSpotOopMap fixedMap) {
+        MapEntry[] result = new MapEntry[fixedMap.size()];
+        for (int idx = 0; idx < fixedMap.size(); idx++) {
+            MapEntry dstType = MapEntry.getFromBits(idx, fixedMap);
+            result[idx] = dstType;
+        }
+        return result;
+    }
 
-        /**
-         * Create enum values from BitSet.
-         * <p>
-         * These bits can have the following values (LSB first):
-         *
-         * <pre>
-         * 000 - contains no references
-         * 100 - contains a wide oop
-         * 110 - contains a narrow oop in the lower half
-         * 101 - contains a narrow oop in the upper half
-         * 111 - contains two narrow oops
-         * </pre>
-         *
-         * @see HotSpotReferenceMap#registerRefMap
-         * @see HotSpotReferenceMap#frameRefMap
-         */
-        static UpdateUnionVerifier getFromBits(int idx, BitSet set) {
-            int n = (set.get(idx) ? 1 : 0) << 0 | (set.get(idx + 1) ? 1 : 0) << 1 | (set.get(idx + 2) ? 1 : 0) << 2;
-            switch (n) {
-                case 0:
-                    return NoReference;
-                case 1:
-                    return WideOop;
-                case 3:
-                    return NarrowOopLowerHalf;
-                case 5:
-                    return NarrowOopUpperHalf;
-                case 7:
-                    return TwoNarrowOops;
-                default:
-                    return Illegal;
+    private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src) {
+        return verifyUpdate(dst, src, true);
+    }
+
+    private static boolean verifyUpdate(HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) {
+        for (int idx = 0; idx < Math.min(src.size(), dst.size()); idx++) {
+            if (!verifyUpdateEntry(idx, dst, src, doAssert)) {
+                return false;
             }
         }
-
-        String toBitString() {
-            int bits = toBit(this);
-            if (bits == -1) {
-                return "---";
-            }
-            return String.format("%3s", Integer.toBinaryString(bits)).replace(' ', '0');
-        }
+        return true;
+    }
 
-        static int toBit(UpdateUnionVerifier type) {
-            switch (type) {
-                case NoReference:
-                    return 0;
-                case WideOop:
-                    return 1;
-                case NarrowOopLowerHalf:
-                    return 3;
-                case NarrowOopUpperHalf:
-                    return 5;
-                case TwoNarrowOops:
-                    return 7;
-                default:
-                    return -1;
-            }
-        }
+    private static boolean verifyUpdateEntry(int idx, HotSpotOopMap dst, HotSpotOopMap src, boolean doAssert) {
+        MapEntry dstType = MapEntry.getFromBits(idx, dst);
+        MapEntry srcType = MapEntry.getFromBits(idx, src);
 
-        private static boolean verifyUpate(BitSet dst, BitSet src) {
-            for (int idx = 0; idx < dst.size(); idx += BITS_PER_WORD) {
-                if (!verifyUpdateEntry(idx, dst, src)) {
-                    return false;
-                }
-            }
-            return true;
+        if (dstType == MapEntry.Illegal || srcType == MapEntry.Illegal) {
+            assert !doAssert : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+            return false;
         }
-
-        private static boolean verifyUpdateEntry(int idx, BitSet dst, BitSet src) {
-            UpdateUnionVerifier dstType = UpdateUnionVerifier.getFromBits(idx, dst);
-            UpdateUnionVerifier srcType = UpdateUnionVerifier.getFromBits(idx, src);
-
-            if (dstType == UpdateUnionVerifier.Illegal || srcType == UpdateUnionVerifier.Illegal) {
-                assert false : String.format("Illegal RefMap bit pattern: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+        switch (dstType) {
+            case NoReference:
+                return true;
+            case WideOop:
+                switch (srcType) {
+                    case NoReference:
+                    case WideOop:
+                        return true;
+                    default:
+                        assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+                        return false;
+                }
+            case TwoNarrowOops:
+            case NarrowOopLowerHalf:
+            case NarrowOopUpperHalf:
+                switch (srcType) {
+                    case TwoNarrowOops:
+                    case NarrowOopLowerHalf:
+                    case NarrowOopUpperHalf:
+                    case NoReference:
+                        return true;
+                    default:
+                        assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
+                        return false;
+                }
+            default:
                 return false;
-            }
-            switch (dstType) {
-                case NoReference:
-                    return true;
-                case WideOop:
-                    switch (srcType) {
-                        case NoReference:
-                        case WideOop:
-                            return true;
-                        default:
-                            assert false : String.format("Illegal RefMap combination: %s (0b%s), %s (0b%s)", dstType, dstType.toBitString(), srcType, srcType.toBitString());
-                            return false;
-                    }
-                default:
-                    return true;
-            }
         }
     }
 
@@ -382,23 +572,50 @@
         return false;
     }
 
+    @Override
     public boolean hasRegisterRefMap() {
         return registerRefMap != null && registerRefMap.size() > 0;
     }
 
+    @Override
     public boolean hasFrameRefMap() {
         return frameRefMap != null && frameRefMap.size() > 0;
     }
 
+    @Override
     public void appendRegisterMap(StringBuilder sb, RefMapFormatter formatter) {
-        for (int reg = registerRefMap.nextSetBit(0); reg >= 0; reg = registerRefMap.nextSetBit(reg + BITS_PER_WORD)) {
-            sb.append(' ').append(formatter.formatRegister(reg / BITS_PER_WORD));
+        for (int idx = 0; idx < registerRefMap.size(); idx++) {
+            MapEntry dstType = MapEntry.getFromBits(idx, registerRefMap);
+            if (dstType != MapEntry.NoReference) {
+                sb.append(' ').append(formatter.formatRegister(idx)).append(':').append(dstType);
+            }
         }
     }
 
+    @Override
     public void appendFrameMap(StringBuilder sb, RefMapFormatter formatter) {
-        for (int slot = frameRefMap.nextSetBit(0); slot >= 0; slot = frameRefMap.nextSetBit(slot + BITS_PER_WORD)) {
-            sb.append(' ').append(formatter.formatStackSlot(slot / BITS_PER_WORD));
+        for (int idx = 0; idx < frameRefMap.size(); idx++) {
+            MapEntry dstType = MapEntry.getFromBits(idx, frameRefMap);
+            if (dstType != MapEntry.NoReference) {
+                sb.append(' ').append(formatter.formatStackSlot(idx)).append(':').append(dstType);
+            }
         }
     }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (registerRefMap != null) {
+            sb.append("Registers = ");
+            sb.append(registerRefMap);
+        }
+        sb.append("Stack = ");
+        sb.append(frameRefMap);
+        return sb.toString();
+    }
+
+    public void verify() {
+        assert verifyUpdate(frameRefMap, frameRefMap);
+        assert registerRefMap == null || verifyUpdate(registerRefMap, registerRefMap);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java	Thu Apr 16 17:09:06 2015 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 
 public class HotSpotTargetDescription extends TargetDescription {
 
@@ -32,11 +31,6 @@
     }
 
     @Override
-    public int getSizeInBytes(PlatformKind kind) {
-        return super.getSizeInBytes(kind);
-    }
-
-    @Override
     public ReferenceMap createReferenceMap(boolean hasRegisters, int stackSlotCount) {
         return new HotSpotReferenceMap(hasRegisters ? arch.getRegisterReferenceMapSize() : 0, stackSlotCount, this);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Thu Apr 16 17:09:06 2015 +0200
@@ -26,7 +26,6 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
 
 /**
  * Represents a constant non-{@code null} object reference, within the compiler and across the
@@ -84,14 +83,6 @@
     JavaConstant getCallSiteTarget(Assumptions assumptions);
 
     /**
-     * Gets the result of {@link CompositeValueClass#create(Class)} for the {@link Class} object
-     * represented by this constant.
-     *
-     * @return {@code null} if this constant does not represent a {@link Class} object
-     */
-    JavaConstant getCompositeValueClass();
-
-    /**
      * Determines if this constant represents an {@linkplain String#intern() interned} string.
      */
     boolean isInternedString();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Apr 16 17:09:06 2015 +0200
@@ -28,9 +28,8 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.lir.*;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import edu.umd.cs.findbugs.annotations.*;
 
 /**
  * Represents a constant non-{@code null} object reference, within the compiler and across the
@@ -184,16 +183,6 @@
         return null;
     }
 
-    @SuppressWarnings("unchecked")
-    public JavaConstant getCompositeValueClass() {
-        if (object instanceof Class) {
-            Class<? extends CompositeValue> c = (Class<? extends CompositeValue>) object;
-            assert CompositeValue.class.isAssignableFrom(c) : c;
-            return HotSpotObjectConstantImpl.forObject(CompositeValueClass.create(c));
-        }
-        return null;
-    }
-
     @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want")
     public boolean isInternedString() {
         if (object instanceof String) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Thu Apr 16 17:09:06 2015 +0200
@@ -25,16 +25,16 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import java.util.*;
+
 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.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.*;
 
 public final class AMD64AddressValue extends CompositeValue {
-    public static final CompositeValueClass<AMD64AddressValue> TYPE = CompositeValueClass.create(AMD64AddressValue.class);
-
     private static final long serialVersionUID = -4444600052487578694L;
 
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
@@ -42,12 +42,14 @@
     protected final Scale scale;
     protected final int displacement;
 
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
     public AMD64AddressValue(LIRKind kind, AllocatableValue base, int displacement) {
         this(kind, base, Value.ILLEGAL, Scale.Times1, displacement);
     }
 
     public AMD64AddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
-        super(TYPE, kind);
+        super(kind);
         this.base = base;
         this.index = index;
         this.scale = scale;
@@ -56,6 +58,22 @@
         assert scale != null;
     }
 
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags);
+        if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) {
+            return new AMD64AddressValue(getLIRKind(), newBase, newIndex, scale, displacement);
+        }
+        return this;
+    }
+
+    @Override
+    protected void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, index, mode, flags);
+    }
+
     private static Register toRegister(AllocatableValue value) {
         if (value.equals(Value.ILLEGAL)) {
             return Register.None;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Thu Apr 16 17:09:06 2015 +0200
@@ -25,33 +25,52 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 public final class SPARCAddressValue extends CompositeValue {
-    public static final CompositeValueClass<SPARCAddressValue> TYPE = CompositeValueClass.create(SPARCAddressValue.class);
-
     private static final long serialVersionUID = -3583286416638228207L;
 
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
     @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
     protected final int displacement;
 
+    private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
     public SPARCAddressValue(LIRKind kind, AllocatableValue base, int displacement) {
         this(kind, base, Value.ILLEGAL, displacement);
     }
 
     public SPARCAddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, int displacement) {
-        super(TYPE, kind);
+        super(kind);
         assert isIllegal(index) || displacement == 0;
         this.base = base;
         this.index = index;
         this.displacement = displacement;
     }
 
+    @Override
+    public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+        AllocatableValue newBase = (AllocatableValue) proc.doValue(inst, base, mode, flags);
+        AllocatableValue newIndex = (AllocatableValue) proc.doValue(inst, index, mode, flags);
+        if (!base.identityEquals(newBase) || !index.identityEquals(newIndex)) {
+            return new SPARCAddressValue(getLIRKind(), newBase, newIndex, displacement);
+        }
+        return this;
+    }
+
+    @Override
+    protected void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+        proc.visitValue(inst, base, mode, flags);
+        proc.visitValue(inst, index, mode, flags);
+    }
+
     private static Register toRegister(AllocatableValue value) {
         if (isIllegal(value)) {
             return Register.None;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu Apr 16 17:09:06 2015 +0200
@@ -39,7 +39,6 @@
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Thu Apr 16 17:09:06 2015 +0200
@@ -25,11 +25,14 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 import static org.junit.Assert.*;
 
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.asm.*;
 
 /**
@@ -38,17 +41,31 @@
  */
 public class CompositeValueReplacementTest1 {
 
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
+    private static class TestCompositeValue extends CompositeValue {
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
 
-        public NestedCompositeValue(Value value) {
-            super(TYPE, LIRKind.Illegal);
+        public TestCompositeValue(Value value) {
+            super(LIRKind.Illegal);
             this.value = value;
         }
 
+        private static final EnumSet<OperandFlag> flags = EnumSet.of(OperandFlag.REG, OperandFlag.ILLEGAL);
+
+        @Override
+        public CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
+            Value newValue = proc.doValue(inst, value, mode, flags);
+            if (!value.identityEquals(newValue)) {
+                return new TestCompositeValue(newValue);
+            }
+            return this;
+        }
+
+        @Override
+        protected void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc) {
+            proc.visitValue(inst, value, mode, flags);
+        }
     }
 
     private static class DummyValue extends AbstractValue {
@@ -98,9 +115,9 @@
     private static final class TestOp extends LIRInstruction {
         public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
+        @Use({COMPOSITE}) protected TestCompositeValue compValue;
 
-        public TestOp(NestedCompositeValue compValue) {
+        public TestOp(TestCompositeValue compValue) {
             super(TYPE);
             this.compValue = compValue;
         }
@@ -112,43 +129,12 @@
 
     }
 
-    private static NestedCompositeValue createNestedCompValue(Value value, int nestingLevel) {
-        NestedCompositeValue compValue = new NestedCompositeValue(value);
-        for (int i = 0; i < nestingLevel; i++) {
-            compValue = new NestedCompositeValue(compValue);
-        }
-        return compValue;
-    }
-
     @Test
     public void replaceCompValueTest0() {
         DummyValue dummyValue1 = new DummyValue();
         DummyValue dummyValue2 = new DummyValue();
         DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 0);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue2;
-        });
-
-        op2.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue3;
-        });
-
-        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
-        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
-    }
-
-    @Test
-    public void replaceCompValueTest1() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 1);
+        TestCompositeValue compValue1 = new TestCompositeValue(dummyValue1);
         LIRInstruction op1 = new TestOp(compValue1);
         LIRInstruction op2 = new TestOp(compValue1);
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * Same as {@link CompositeValueReplacementTest1} but with value arrays.
- *
- * @see CompositeValueReplacementTest1
- */
-public class CompositeValueReplacementTest2 {
-
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
-
-        private static final long serialVersionUID = -8804214200173503527L;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value[] values;
-
-        public NestedCompositeValue(Value value) {
-            super(TYPE, LIRKind.Illegal);
-            this.values = new Value[]{value};
-        }
-
-    }
-
-    private static class DummyValue extends AbstractValue {
-
-        private static final long serialVersionUID = -645435039553382737L;
-        private final int id;
-        private static int counter = 1;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "DummyValue [id=" + id + "]";
-        }
-
-    }
-
-    private static final class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
-
-        public TestOp(NestedCompositeValue compValue) {
-            super(TYPE);
-            this.compValue = compValue;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-    }
-
-    private static NestedCompositeValue createNestedCompValue(Value value, int nestingLevel) {
-        NestedCompositeValue compValue = new NestedCompositeValue(value);
-        for (int i = 0; i < nestingLevel; i++) {
-            compValue = new NestedCompositeValue(compValue);
-        }
-        return compValue;
-    }
-
-    @Test
-    public void replaceCompValueTest0() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 0);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue2;
-        });
-
-        op2.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue3;
-        });
-
-        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
-        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
-    }
-
-    @Test
-    public void replaceCompValueTest1() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 1);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue2;
-        });
-
-        op2.forEachInput((instruction, value, mode, flags) -> {
-            assertEquals(dummyValue1, value);
-            return dummyValue3;
-        });
-
-        op1.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue2, value));
-        op2.visitEachInput((instruction, value, mode, flags) -> assertEquals(dummyValue3, value));
-    }
-}
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * Same as {@link CompositeValueReplacementTest1} but with for {@link ValuePosition}s.
- *
- * @see CompositeValueReplacementTest1
- */
-public class CompositeValueReplacementTest3 {
-
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
-
-        private static final long serialVersionUID = -8804214200173503527L;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
-
-        public NestedCompositeValue(Value value) {
-            super(TYPE, LIRKind.Illegal);
-            this.value = value;
-        }
-
-    }
-
-    private static class DummyValue extends AbstractValue {
-
-        private static final long serialVersionUID = -645435039553382737L;
-        private final int id;
-        private static int counter = 1;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "DummyValue [id=" + id + "]";
-        }
-
-    }
-
-    private static final class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
-
-        public TestOp(NestedCompositeValue compValue) {
-            super(TYPE);
-            this.compValue = compValue;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-    }
-
-    private static NestedCompositeValue createNestedCompValue(Value value, int nestingLevel) {
-        NestedCompositeValue compValue = new NestedCompositeValue(value);
-        for (int i = 0; i < nestingLevel; i++) {
-            compValue = new NestedCompositeValue(compValue);
-        }
-        return compValue;
-    }
-
-    @Test
-    public void replaceCompValueTest0() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 0);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue2);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue3);
-        });
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue2, value);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue3, value);
-        });
-    }
-
-    @Test
-    public void replaceCompValueTest1() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 1);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue2);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue3);
-        });
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue2, value);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue3, value);
-        });
-    }
-}
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * Same as {@link CompositeValueReplacementTest2} but with value arrays {@link ValuePosition}s.
- *
- * @see CompositeValueReplacementTest2
- */
-public class CompositeValueReplacementTest4 {
-
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
-
-        private static final long serialVersionUID = -8804214200173503527L;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value[] values;
-
-        public NestedCompositeValue(Value value) {
-            super(TYPE, LIRKind.Illegal);
-            this.values = new Value[]{value};
-        }
-
-    }
-
-    private static class DummyValue extends AbstractValue {
-
-        private static final long serialVersionUID = -645435039553382737L;
-        private final int id;
-        private static int counter = 1;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "DummyValue [id=" + id + "]";
-        }
-
-    }
-
-    private static class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
-
-        public TestOp(NestedCompositeValue compValue) {
-            super(TYPE);
-            this.compValue = compValue;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-    }
-
-    private static NestedCompositeValue createNestedCompValue(Value value, int nestingLevel) {
-        NestedCompositeValue compValue = new NestedCompositeValue(value);
-        for (int i = 0; i < nestingLevel; i++) {
-            compValue = new NestedCompositeValue(compValue);
-        }
-        return compValue;
-    }
-
-    @Test
-    public void replaceCompValueTest0() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 0);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue2);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue3);
-        });
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue2, value);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue3, value);
-        });
-    }
-
-    @Test
-    public void replaceCompValueTest1() {
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-        NestedCompositeValue compValue1 = createNestedCompValue(dummyValue1, 1);
-        LIRInstruction op1 = new TestOp(compValue1);
-        LIRInstruction op2 = new TestOp(compValue1);
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue2);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue1, value);
-            position.set(instruction, dummyValue3);
-        });
-
-        op1.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue2, value);
-        });
-
-        op2.forEachInputPos((instruction, position) -> {
-            Value value = position.get(instruction);
-            assertEquals(dummyValue3, value);
-        });
-    }
-}
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import java.util.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.asm.*;
-
-public class ValuePositionTest1 {
-
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
-
-        private static final long serialVersionUID = -8804214200173503527L;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
-
-        public NestedCompositeValue(Value value) {
-            super(TYPE, LIRKind.Illegal);
-            this.value = value;
-        }
-
-    }
-
-    private static class DummyValue extends AbstractValue {
-
-        private static final long serialVersionUID = -645435039553382737L;
-        private final int id;
-        private static int counter = 1;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-    }
-
-    private static final class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
-
-        public TestOp(NestedCompositeValue compValue) {
-            super(TYPE);
-            this.compValue = compValue;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-    }
-
-    private static LIRInstruction createNestedOp(Value value, int nestingLevel) {
-        NestedCompositeValue compValue = new NestedCompositeValue(value);
-        for (int i = 0; i < nestingLevel; i++) {
-            compValue = new NestedCompositeValue(compValue);
-        }
-        TestOp op = new TestOp(compValue);
-        return op;
-    }
-
-    @Test
-    public void nestedTest0() {
-        DummyValue dummyValue = new DummyValue();
-        LIRInstruction op = createNestedOp(dummyValue, 0);
-
-        List<ValuePosition> positions = new ArrayList<>();
-
-        op.forEachInputPos((instruction, position) -> positions.add(position));
-
-        assertEquals(1, positions.size());
-        assertEquals(dummyValue, positions.get(0).get(op));
-    }
-
-    @Test
-    public void nestedTest1() {
-        DummyValue dummyValue = new DummyValue();
-        LIRInstruction op = createNestedOp(dummyValue, 1);
-
-        List<ValuePosition> positions = new ArrayList<>();
-
-        op.forEachInputPos((instruction, position) -> positions.add(position));
-
-        assertEquals(1, positions.size());
-        assertEquals(dummyValue, positions.get(0).get(op));
-    }
-
-    @Test
-    public void nestedTest2() {
-        DummyValue dummyValue = new DummyValue();
-        LIRInstruction op = createNestedOp(dummyValue, 2);
-
-        List<ValuePosition> positions = new ArrayList<>();
-
-        op.forEachInputPos((instruction, position) -> positions.add(position));
-
-        assertEquals(1, positions.size());
-        assertEquals(dummyValue, positions.get(0).get(op));
-    }
-
-}
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import java.util.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.asm.*;
-
-public class ValuePositionTest2 {
-
-    private static class NestedCompositeValue extends CompositeValue {
-        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
-
-        private static final long serialVersionUID = -2243948303328857965L;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value value1;
-        @Component({REG, OperandFlag.ILLEGAL}) protected Value value2;
-
-        public NestedCompositeValue(Value value1, Value value2) {
-            super(TYPE, LIRKind.Illegal);
-            this.value1 = value1;
-            this.value2 = value2;
-        }
-
-    }
-
-    private static class DummyValue extends AbstractValue {
-
-        private static final long serialVersionUID = 3620305384660607012L;
-        private final int id;
-        private static int counter = 0;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-    }
-
-    private static class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected NestedCompositeValue compValue;
-
-        public TestOp(NestedCompositeValue compValue) {
-            super(TYPE);
-            this.compValue = compValue;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-    }
-
-    @Test
-    public void testSetGet() {
-        DummyValue dummyValue0 = new DummyValue();
-        DummyValue dummyValue1 = new DummyValue();
-        DummyValue dummyValue2 = new DummyValue();
-        DummyValue dummyValue3 = new DummyValue();
-
-        NestedCompositeValue compValue0 = new NestedCompositeValue(dummyValue0, dummyValue1);
-        NestedCompositeValue compValue1 = new NestedCompositeValue(compValue0, dummyValue2);
-        NestedCompositeValue compValue2 = new NestedCompositeValue(dummyValue3, compValue1);
-
-        LIRInstruction op = new TestOp(compValue2);
-        List<ValuePosition> positions = new ArrayList<>();
-
-        op.forEachInputPos((instruction, position) -> positions.add(position));
-
-        assertEquals(4, positions.size());
-
-        // replace values
-        List<Value> replValues = new ArrayList<>();
-        for (ValuePosition pos : positions) {
-            Value v = new DummyValue();
-            replValues.add(v);
-            pos.set(op, v);
-
-        }
-
-        // check replaced values
-        Iterator<Value> it = replValues.iterator();
-        for (ValuePosition pos : positions) {
-            Value v = pos.get(op);
-            assertEquals(it.next(), v);
-        }
-        assertFalse(it.hasNext());
-    }
-
-}
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, 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.test;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static org.junit.Assert.*;
-
-import java.util.*;
-
-import org.junit.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
-import com.oracle.graal.lir.asm.*;
-
-public class ValuePositionTest3 {
-
-    public static final class TestAddressValue extends CompositeValue {
-        public static final CompositeValueClass<TestAddressValue> TYPE = CompositeValueClass.create(TestAddressValue.class);
-
-        private static final long serialVersionUID = -2679790860680123026L;
-
-        @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue base;
-        @Component({REG, OperandFlag.ILLEGAL}) protected AllocatableValue index;
-
-        public TestAddressValue(LIRKind kind, AllocatableValue base) {
-            this(kind, base, Value.ILLEGAL);
-        }
-
-        public TestAddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index) {
-            super(TYPE, kind);
-            this.base = base;
-            this.index = index;
-        }
-    }
-
-    private static class DummyValue extends AllocatableValue {
-
-        private static final long serialVersionUID = 3620305384660607012L;
-        private final int id;
-        private static int counter = 0;
-
-        protected DummyValue() {
-            super(LIRKind.Illegal);
-            this.id = counter++;
-        }
-
-        @Override
-        public int hashCode() {
-            final int prime = 31;
-            int result = super.hashCode();
-            result = prime * result + id;
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (this == obj) {
-                return true;
-            }
-            if (!super.equals(obj)) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            DummyValue other = (DummyValue) obj;
-            if (id != other.id) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "DummyValue" + id;
-        }
-
-    }
-
-    private static class TestOp extends LIRInstruction {
-        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
-
-        @Use({COMPOSITE}) protected Value value;
-
-        public TestOp(Value value) {
-            super(TYPE);
-            this.value = value;
-        }
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb) {
-            fail("should not reach!");
-        }
-
-        @Override
-        public String toString() {
-            return "TestOp [" + value + "]";
-        }
-
-    }
-
-    @Test
-    public void test0() {
-        DummyValue dummyValue0 = new DummyValue();
-        DummyValue dummyValue1 = new DummyValue();
-
-        TestAddressValue compValue0 = new TestAddressValue(LIRKind.Illegal, dummyValue0, dummyValue1);
-
-        LIRInstruction op = new TestOp(compValue0);
-
-        HashMap<Value, EnumSet<OperandFlag>> positionMap = new HashMap<>();
-        HashMap<Value, EnumSet<OperandFlag>> normalMap = new HashMap<>();
-
-        op.forEachInputPos(new ValuePositionProcedure() {
-
-            @Override
-            public void doValue(LIRInstruction instruction, ValuePosition position) {
-                positionMap.put(position.get(instruction), position.getFlags());
-            }
-        });
-        op.visitEachInput(new InstructionValueConsumer() {
-
-            @Override
-            public void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-                normalMap.put(value, flags);
-            }
-        });
-
-        assertEquals(normalMap.size(), positionMap.size());
-        assertTrue(normalMap.keySet().containsAll(positionMap.keySet()));
-        normalMap.keySet().forEach(key -> {
-            EnumSet<OperandFlag> normal = normalMap.get(key);
-            EnumSet<OperandFlag> position = positionMap.get(key);
-            assertTrue(normal.containsAll(position));
-            assertTrue(position.containsAll(normal));
-        });
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Thu Apr 16 17:09:06 2015 +0200
@@ -23,17 +23,19 @@
 package com.oracle.graal.lir;
 
 import java.lang.annotation.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
- * Base class to represent values that need to be stored in more than one register.
+ * Base class to represent values that need to be stored in more than one register. This is mainly
+ * intended to support addresses and not general arbitrary nesting of composite values. Because of
+ * the possibility of sharing of CompositeValues they should be immutable.
  */
-public abstract class CompositeValue extends AbstractValue implements Cloneable {
+public abstract class CompositeValue extends AbstractValue {
 
     private static final long serialVersionUID = -169180052684126180L;
 
@@ -44,61 +46,69 @@
         OperandFlag[] value() default OperandFlag.REG;
     }
 
-    private final CompositeValueClass<?> valueClass;
-
     private static final DebugMetric COMPOSITE_VALUE_COUNT = Debug.metric("CompositeValues");
 
-    public CompositeValue(CompositeValueClass<? extends CompositeValue> c, LIRKind kind) {
+    public CompositeValue(LIRKind kind) {
         super(kind);
         COMPOSITE_VALUE_COUNT.increment();
-        valueClass = c;
-        assert c.getClazz() == this.getClass();
+        assert CompositeValueClass.get(getClass()) != null;
     }
 
-    final CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
-        return valueClass.forEachComponent(inst, this, mode, proc);
+    /**
+     * Invoke {@code proc} on each {@link Value} element of this {@link CompositeValue}. If
+     * {@code proc} replaces any value then a new CompositeValue should be returned.
+     *
+     * @param inst
+     * @param mode
+     * @param proc
+     * @return the original CompositeValue or a copy with any modified values
+     */
+    public abstract CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc);
+
+    /**
+     * A helper method to visit {@link Value}[] ensuring that a copy of the array is made if it's
+     * needed.
+     *
+     * @param inst
+     * @param values
+     * @param mode
+     * @param proc
+     * @param flags
+     * @return the original {@code values} array or a copy if values changed
+     */
+    protected Value[] visitValueArray(LIRInstruction inst, Value[] values, OperandMode mode, InstructionValueProcedure proc, EnumSet<OperandFlag> flags) {
+        Value[] newValues = null;
+        for (int i = 0; i < values.length; i++) {
+            Value value = values[i];
+            Value newValue = proc.doValue(inst, value, mode, flags);
+            if (!value.identityEquals(newValue)) {
+                if (newValues == null) {
+                    newValues = values.clone();
+                }
+                newValues[i] = value;
+            }
+        }
+        return newValues != null ? newValues : values;
     }
 
-    final void forEachComponent(LIRInstruction inst, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
-        valueClass.forEachComponent(inst, this, mode, proc, outerPosition);
-    }
+    protected abstract void forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueConsumer proc);
 
     @Override
     public String toString() {
-        return valueClass.toString(this);
+        return CompositeValueClass.format(this);
     }
 
     @Override
     public int hashCode() {
-        return 53 * super.hashCode() + valueClass.hashCode();
+        return 53 * super.hashCode();
     }
 
     @Override
     public boolean equals(Object obj) {
         if (obj instanceof CompositeValue) {
             CompositeValue other = (CompositeValue) obj;
-            return super.equals(other) && valueClass.equals(other.valueClass);
+            return super.equals(other);
         }
         return false;
     }
-
-    CompositeValueClass<?> getValueClass() {
-        return valueClass;
-    }
-
-    @Override
-    public final CompositeValue clone() {
-        CompositeValue compositeValue = null;
-        try {
-            compositeValue = (CompositeValue) super.clone();
-        } catch (CloneNotSupportedException e) {
-            throw new GraalInternalError(e);
-        }
-
-        // copy value arrays
-        getValueClass().copyValueArrays(compositeValue);
-
-        return compositeValue;
-    }
-
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Thu Apr 16 17:09:06 2015 +0200
@@ -25,11 +25,12 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.CompositeValue.Component;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRIntrospection.LIRFieldsScanner;
+import com.oracle.graal.lir.LIRIntrospection.OperandModeAnnotation;
+import com.oracle.graal.lir.LIRIntrospection.Values;
 
 /**
  * Lazily associated metadata for every {@link CompositeValue} type. The metadata includes:
@@ -38,20 +39,35 @@
  * such fields.</li>
  * </ul>
  */
-public class CompositeValueClass<T> extends LIRIntrospection<T> {
+public final class CompositeValueClass<T> {
+
+    /**
+     * The CompositeValueClass is only used for formatting for the most part so cache it as a
+     * ClassValue.
+     */
+    private static final ClassValue<CompositeValueClass<?>> compositeClass = new ClassValue<CompositeValueClass<?>>() {
 
-    public static final <T extends CompositeValue> CompositeValueClass<T> create(Class<T> c) {
-        return new CompositeValueClass<>(c);
+        @Override
+        protected CompositeValueClass<?> computeValue(Class<?> type) {
+            CompositeValueClass<?> compositeValueClass = new CompositeValueClass<>(type);
+            assert compositeValueClass.values.getDirectCount() == compositeValueClass.values.getCount() : "only direct fields are allowed in composites";
+            return compositeValueClass;
+        }
+
+    };
+
+    public static CompositeValueClass<?> get(Class<?> type) {
+        return compositeClass.get(type);
     }
 
-    public CompositeValueClass(Class<T> clazz) {
-        this(clazz, new FieldsScanner.DefaultCalcOffset());
-    }
+    private final Class<?> clazz;
+    private final Values values;
+    private final Fields data;
 
-    public CompositeValueClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) {
-        super(clazz);
+    private CompositeValueClass(Class<T> clazz) {
+        this.clazz = clazz;
 
-        CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(calcOffset);
+        CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(new FieldsScanner.DefaultCalcOffset());
         vfs.scan(clazz, CompositeValue.class, false);
 
         values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
@@ -80,7 +96,7 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
+        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" components[");
         values.appendFields(str);
         str.append("] data[");
         data.appendFields(str);
@@ -88,31 +104,16 @@
         return str.toString();
     }
 
-    final CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, InstructionValueProcedure proc) {
-        return super.forEachComponent(inst, obj, values, mode, proc);
-    }
-
-    final void forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
-        forEach(inst, obj, values, mode, proc, outerPosition);
-    }
-
-    public String toString(CompositeValue obj) {
+    public static String format(CompositeValue obj) {
+        CompositeValueClass<?> valueClass = compositeClass.get(obj.getClass());
         StringBuilder result = new StringBuilder();
 
-        appendValues(result, obj, "", "", "{", "}", new String[]{""}, values);
+        LIRIntrospection.appendValues(result, obj, "", "", "{", "}", new String[]{""}, valueClass.values);
 
-        for (int i = 0; i < data.getCount(); i++) {
-            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
+        for (int i = 0; i < valueClass.data.getCount(); i++) {
+            result.append(" ").append(valueClass.data.getName(i)).append(": ").append(LIRIntrospection.getFieldString(obj, i, valueClass.data));
         }
 
         return result.toString();
     }
-
-    void copyValueArrays(CompositeValue compositeValue) {
-        for (int i = values.getDirectCount(); i < values.getCount(); i++) {
-            Value[] valueArray = values.getValueArray(compositeValue, i);
-            Value[] newValueArray = Arrays.copyOf(valueArray, valueArray.length);
-            values.setValueArray(compositeValue, i, newValueArray);
-        }
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueConsumer.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueConsumer.java	Thu Apr 16 17:09:06 2015 +0200
@@ -29,10 +29,11 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
- * Non-modifying version of {@link InstructionValueProcedure}.
+ * Functional interface for iterating over a list of values without modifying them. See
+ * {@link InstructionValueProcedure} for a version that can modify values.
  */
 @FunctionalInterface
-public interface InstructionValueConsumer extends InstructionValueProcedure {
+public interface InstructionValueConsumer {
 
     /**
      * Iterator method to be overwritten.
@@ -43,9 +44,4 @@
      * @param flags A set of flags for the value.
      */
     void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags);
-
-    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-        visitValue(instruction, value, mode, flags);
-        return value;
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedure.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/InstructionValueProcedure.java	Thu Apr 16 17:09:06 2015 +0200
@@ -29,7 +29,8 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
- * Functional interface for iterating over a list of values.
+ * Functional interface for iterating over a list of values, possibly returning a value to replace
+ * the old value.
  */
 @FunctionalInterface
 public interface InstructionValueProcedure {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRFrameState.java	Thu Apr 16 17:09:06 2015 +0200
@@ -75,6 +75,22 @@
     }
 
     /**
+     * Iterates the frame state and calls the {@link InstructionValueProcedure} for every variable.
+     *
+     * @param proc The procedure called for variables.
+     */
+    public void forEachState(LIRInstruction inst, InstructionValueConsumer proc) {
+        for (BytecodeFrame cur = topFrame; cur != null; cur = cur.caller()) {
+            processValues(inst, cur.values, proc);
+        }
+        if (virtualObjects != null) {
+            for (VirtualObject obj : virtualObjects) {
+                processValues(inst, obj.getValues(), proc);
+            }
+        }
+    }
+
+    /**
      * We filter out constant and illegal values ourself before calling the procedure, so
      * {@link OperandFlag#CONST} and {@link OperandFlag#ILLEGAL} need not be set.
      */
@@ -83,29 +99,51 @@
     protected void processValues(LIRInstruction inst, Value[] values, InstructionValueProcedure proc) {
         for (int i = 0; i < values.length; i++) {
             Value value = values[i];
-            values[i] = processValue(inst, proc, value);
-        }
-    }
-
-    protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
-        if (value instanceof StackLockValue) {
-            StackLockValue monitor = (StackLockValue) value;
-            Value owner = monitor.getOwner();
-            if (owner instanceof AllocatableValue) {
-                monitor.setOwner(proc.doValue(inst, owner, OperandMode.ALIVE, STATE_FLAGS));
+            if (isIllegal(value)) {
+                continue;
             }
-            Value slot = monitor.getSlot();
-            if (isVirtualStackSlot(slot)) {
-                monitor.setSlot(asStackSlotValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
-            }
-        } else {
-            if (!isIllegal(value) && value instanceof AllocatableValue) {
-                return proc.doValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
+            if (value instanceof AllocatableValue) {
+                Value result = proc.doValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
+                if (!value.identityEquals(result)) {
+                    values[i] = result;
+                }
+            } else if (value instanceof StackLockValue) {
+                StackLockValue monitor = (StackLockValue) value;
+                Value owner = monitor.getOwner();
+                if (owner instanceof AllocatableValue) {
+                    monitor.setOwner(proc.doValue(inst, owner, OperandMode.ALIVE, STATE_FLAGS));
+                }
+                Value slot = monitor.getSlot();
+                if (isVirtualStackSlot(slot)) {
+                    monitor.setSlot(asStackSlotValue(proc.doValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS)));
+                }
             } else {
                 assert unprocessed(value);
             }
         }
-        return value;
+    }
+
+    protected void processValues(LIRInstruction inst, Value[] values, InstructionValueConsumer proc) {
+        for (int i = 0; i < values.length; i++) {
+            Value value = values[i];
+            if (isIllegal(value)) {
+                continue;
+            } else if (value instanceof AllocatableValue) {
+                proc.visitValue(inst, value, OperandMode.ALIVE, STATE_FLAGS);
+            } else if (value instanceof StackLockValue) {
+                StackLockValue monitor = (StackLockValue) value;
+                Value owner = monitor.getOwner();
+                if (owner instanceof AllocatableValue) {
+                    proc.visitValue(inst, owner, OperandMode.ALIVE, STATE_FLAGS);
+                }
+                Value slot = monitor.getSlot();
+                if (isVirtualStackSlot(slot)) {
+                    proc.visitValue(inst, slot, OperandMode.ALIVE, STATE_FLAGS);
+                }
+            } else {
+                assert unprocessed(value);
+            }
+        }
     }
 
     private boolean unprocessed(Value value) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Thu Apr 16 17:09:06 2015 +0200
@@ -37,8 +37,6 @@
  * The base class for an {@code LIRInstruction}.
  */
 public abstract class LIRInstruction {
-    public static final Value[] NO_OPERANDS = {};
-
     /**
      * Constants denoting how a LIR instruction uses an operand.
      */
@@ -211,23 +209,6 @@
         return false;
     }
 
-    // ValuePositionProcedures
-    public final void forEachInputPos(ValuePositionProcedure proc) {
-        instructionClass.forEachUsePos(this, proc);
-    }
-
-    public final void forEachAlivePos(ValuePositionProcedure proc) {
-        instructionClass.forEachAlivePos(this, proc);
-    }
-
-    public final void forEachTempPos(ValuePositionProcedure proc) {
-        instructionClass.forEachTempPos(this, proc);
-    }
-
-    public final void forEachOutputPos(ValuePositionProcedure proc) {
-        instructionClass.forEachDefPos(this, proc);
-    }
-
     // InstructionValueProcedures
     public final void forEachInput(InstructionValueProcedure proc) {
         instructionClass.forEachUse(this, proc);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Thu Apr 16 17:09:06 2015 +0200
@@ -205,22 +205,6 @@
         return false;
     }
 
-    final void forEachUsePos(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, uses, OperandMode.USE, proc, ValuePosition.ROOT_VALUE_POSITION);
-    }
-
-    final void forEachAlivePos(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, alives, OperandMode.ALIVE, proc, ValuePosition.ROOT_VALUE_POSITION);
-    }
-
-    final void forEachTempPos(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, temps, OperandMode.TEMP, proc, ValuePosition.ROOT_VALUE_POSITION);
-    }
-
-    final void forEachDefPos(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, defs, OperandMode.DEF, proc, ValuePosition.ROOT_VALUE_POSITION);
-    }
-
     final void forEachUse(LIRInstruction obj, InstructionValueProcedure proc) {
         forEach(obj, uses, OperandMode.USE, proc);
     }
@@ -237,6 +221,22 @@
         forEach(obj, defs, OperandMode.DEF, proc);
     }
 
+    final void forEachUse(LIRInstruction obj, InstructionValueConsumer proc) {
+        forEach(obj, uses, OperandMode.USE, proc);
+    }
+
+    final void forEachAlive(LIRInstruction obj, InstructionValueConsumer proc) {
+        forEach(obj, alives, OperandMode.ALIVE, proc);
+    }
+
+    final void forEachTemp(LIRInstruction obj, InstructionValueConsumer proc) {
+        forEach(obj, temps, OperandMode.TEMP, proc);
+    }
+
+    final void forEachDef(LIRInstruction obj, InstructionValueConsumer proc) {
+        forEach(obj, defs, OperandMode.DEF, proc);
+    }
+
     final void forEachState(LIRInstruction obj, InstructionValueProcedure proc) {
         for (int i = 0; i < states.getCount(); i++) {
             LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
@@ -246,6 +246,15 @@
         }
     }
 
+    final void forEachState(LIRInstruction obj, InstructionValueConsumer proc) {
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
+            if (state != null) {
+                state.forEachState(obj, proc);
+            }
+        }
+    }
+
     final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
         for (int i = 0; i < states.getCount(); i++) {
             LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Thu Apr 16 17:09:06 2015 +0200
@@ -235,83 +235,34 @@
         }
     }
 
-    protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, Values values, OperandMode mode, InstructionValueProcedure proc) {
-        CompositeValue newCompValue = null;
+    protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueConsumer proc) {
         for (int i = 0; i < values.getCount(); i++) {
             assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
             if (i < values.getDirectCount()) {
-                Value value = values.getValue(obj, i);
-                Value newValue;
+                Value value = values.getValue(inst, i);
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
-                    newValue = composite.forEachComponent(inst, mode, proc);
+                    composite.forEachComponent(inst, mode, proc);
                 } else {
-                    newValue = proc.doValue(inst, value, mode, values.getFlags(i));
-                }
-                if (!value.identityEquals(newValue)) {
-                    // lazy initialize
-                    if (newCompValue == null) {
-                        newCompValue = obj.clone();
-                    }
-                    values.setValue(newCompValue, i, newValue);
+                    proc.visitValue(inst, value, mode, values.getFlags(i));
                 }
             } else {
-                Value[] valueArray = values.getValueArray(obj, i);
-                Value[] newValues = null;
+                Value[] valueArray = values.getValueArray(inst, i);
                 for (int j = 0; j < valueArray.length; j++) {
                     Value value = valueArray[j];
-                    Value newValue;
                     if (value instanceof CompositeValue) {
                         CompositeValue composite = (CompositeValue) value;
-                        newValue = composite.forEachComponent(inst, mode, proc);
+                        composite.forEachComponent(inst, mode, proc);
                     } else {
-                        newValue = proc.doValue(inst, value, mode, values.getFlags(i));
-                    }
-                    if (!value.identityEquals(newValue)) {
-                        // lazy initialize
-                        if (newValues == null) {
-                            if (newCompValue == null) {
-                                newCompValue = obj.clone();
-                            }
-                            newValues = values.getValueArray(newCompValue, i);
-                        }
-                        newValues[j] = newValue;
+                        proc.visitValue(inst, value, mode, values.getFlags(i));
                     }
                 }
             }
         }
-        return newCompValue != null ? newCompValue : obj;
-    }
-
-    protected static void forEach(LIRInstruction inst, Object obj, Values values, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
-        for (int i = 0; i < values.getCount(); i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
-
-            if (i < values.getDirectCount()) {
-                Value value = values.getValue(obj, i);
-                doForValue(inst, values, mode, proc, outerPosition, i, ValuePosition.NO_SUBINDEX, value);
-            } else {
-                Value[] valueArray = values.getValueArray(obj, i);
-                for (int j = 0; j < valueArray.length; j++) {
-                    Value value = valueArray[j];
-                    doForValue(inst, values, mode, proc, outerPosition, i, j, value);
-                }
-            }
-        }
     }
 
-    private static void doForValue(LIRInstruction inst, Values values, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition, int index, int subIndex, Value value) {
-        ValuePosition position = new ValuePosition(values, index, subIndex, outerPosition);
-        if (value instanceof CompositeValue) {
-            CompositeValue composite = (CompositeValue) value;
-            composite.forEachComponent(inst, mode, proc, position);
-        } else {
-            proc.doValue(inst, position);
-        }
-    }
-
-    protected void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) {
+    protected static void appendValues(StringBuilder sb, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) {
         int total = 0;
         for (Fields fields : fieldsList) {
             total += fields.getCount();
@@ -343,7 +294,7 @@
         sb.append(end);
     }
 
-    protected String getFieldString(Object obj, int index, Fields fields) {
+    protected static String getFieldString(Object obj, int index, Fields fields) {
         Object value = fields.get(obj, index);
         Class<?> type = fields.getType(index);
         if (value == null || type.isPrimitive() || !type.isArray()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueConsumer.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValueConsumer.java	Thu Apr 16 17:09:06 2015 +0200
@@ -32,7 +32,7 @@
  * Non-modifying version of {@link ValueProcedure}.
  */
 @FunctionalInterface
-public interface ValueConsumer extends InstructionValueProcedure {
+public interface ValueConsumer extends InstructionValueConsumer {
 
     /**
      * Iterator method to be overwritten.
@@ -43,8 +43,7 @@
      */
     void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags);
 
-    default Value doValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+    default void visitValue(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
         visitValue(value, mode, flags);
-        return value;
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.LIRInstruction.OperandFlag;
-import com.oracle.graal.lir.LIRIntrospection.Values;
-
-/**
- * Describes an operand slot for a {@link LIRInstruction}.
- */
-public final class ValuePosition {
-
-    /**
-     * The {@linkplain Values offsets} to the fields of the containing element (either
-     * {@link LIRInstruction} or {@link CompositeValue}).
-     */
-    private final Values values;
-    /**
-     * The index into {@link #values}.
-     *
-     * @see Values#getValue(Object, int)
-     */
-    private final int index;
-    /**
-     * The sub-index if {@link #index} points to a value array, otherwise {@link #NO_SUBINDEX}.
-     *
-     * @see Values#getDirectCount()
-     * @see Values#getValueArray(Object, int)
-     */
-    private final int subIndex;
-    /**
-     * The {@link ValuePosition} of the containing {@link CompositeValue} if this value is part of a
-     * {@link CompositeValue}, otherwise {@link #ROOT_VALUE_POSITION}.
-     */
-    private final ValuePosition outerPosition;
-
-    public static final int NO_SUBINDEX = -1;
-    public static final ValuePosition ROOT_VALUE_POSITION = null;
-
-    ValuePosition(Values values, int index, int subIndex, ValuePosition outerPosition) {
-        this.values = values;
-        this.index = index;
-        this.subIndex = subIndex;
-        this.outerPosition = outerPosition;
-    }
-
-    /**
-     * @return True if the value denoted by this {@linkplain ValuePosition position} is part of a
-     *         {@link CompositeValue}.
-     */
-    private boolean isCompositePosition() {
-        return outerPosition != ROOT_VALUE_POSITION;
-    }
-
-    /**
-     * @param inst The instruction this {@linkplain ValuePosition position} belongs to.
-     * @return The value denoted by this {@linkplain ValuePosition position}.
-     */
-    public Value get(LIRInstruction inst) {
-        Object obj = inst;
-        if (isCompositePosition()) {
-            obj = outerPosition.get(inst);
-            assert obj instanceof CompositeValue : "The holder of a composite position is not a CompositeValue? " + obj;
-        }
-        if (index < values.getDirectCount()) {
-            return values.getValue(obj, index);
-        }
-        return values.getValueArray(obj, index)[subIndex];
-    }
-
-    /**
-     * Sets the value denoted by this {@linkplain ValuePosition position}.
-     *
-     * @param inst The instruction this {@linkplain ValuePosition position} belongs to.
-     */
-    public void set(LIRInstruction inst, Value value) {
-        Object obj = inst;
-        if (isCompositePosition()) {
-            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
-            CompositeValue newCompValue = compValue.clone();
-            outerPosition.set(inst, newCompValue);
-            obj = newCompValue;
-        }
-        if (index < values.getDirectCount()) {
-            values.setValue(obj, index, value);
-        } else {
-            values.getValueArray(obj, index)[subIndex] = value;
-        }
-    }
-
-    /**
-     * @return The flags associated with the value denoted by this {@linkplain ValuePosition
-     *         position}.
-     */
-    public EnumSet<OperandFlag> getFlags() {
-        return values.getFlags(index);
-    }
-
-    @Override
-    public String toString() {
-        String str = "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
-        if (isCompositePosition()) {
-            return outerPosition.toString() + "[" + str + "]";
-        }
-        return str;
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + index;
-        result = prime * result + subIndex;
-        result = prime * result + ((outerPosition == null) ? 0 : outerPosition.hashCode());
-        result = prime * result + ((values == null) ? 0 : values.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        ValuePosition other = (ValuePosition) obj;
-        if (index != other.index) {
-            return false;
-        }
-        if (subIndex != other.subIndex) {
-            return false;
-        }
-        if (outerPosition == null) {
-            if (other.outerPosition != null) {
-                return false;
-            }
-        } else if (!outerPosition.equals(other.outerPosition)) {
-            return false;
-        }
-        if (values == null) {
-            if (other.values != null) {
-                return false;
-            }
-        } else if (!values.equals(other.values)) {
-            return false;
-        }
-        return true;
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePositionProcedure.java	Thu Apr 16 17:01:53 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2014, 2014, 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;
-
-/**
- * Iterator for iterating over a list of {@linkplain ValuePosition value positions}.
- */
-@FunctionalInterface
-public interface ValuePositionProcedure {
-
-    /**
-     * Iterator method to be overwritten. This version of the iterator does not take additional
-     * parameters to keep the signature short.
-     *
-     * @param instruction The current instruction.
-     * @param position The position of the value that is iterated.
-     */
-    void doValue(LIRInstruction instruction, ValuePosition position);
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Thu Apr 16 17:09:06 2015 +0200
@@ -554,7 +554,9 @@
                             // move target is a stack slot that is always correct, so eliminate
                             // instruction
                             if (Debug.isLogEnabled()) {
-                                Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult()));
+                                }
                             }
                             // null-instructions are deleted by assignRegNum
                             instructions.set(j, null);
@@ -582,7 +584,9 @@
 
                                 insertionBuffer.append(j + 1, getSpillMoveFactory().createMove(toLocation, fromLocation));
 
-                                Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
+                                }
                             }
                             interval = interval.next;
                         }
@@ -612,7 +616,9 @@
             assert temp.spillDefinitionPos() >= temp.from() : "invalid order";
             assert temp.spillDefinitionPos() <= temp.from() + 2 : "only intervals defined once at their start-pos can be optimized";
 
-            Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            if (Debug.isLogEnabled()) {
+                Debug.log("interval %d (from %d to %d) must be stored at %d", temp.operandNumber, temp.from(), temp.to(), temp.spillDefinitionPos());
+            }
 
             prev = temp;
             temp = temp.next;
@@ -695,7 +701,9 @@
                         int operandNum = operandNumber(operand);
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
-                            Debug.log("liveGen for operand %d", operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen for operand %d", operandNum);
+                            }
                         }
                         if (block.getLoop() != null) {
                             intervalInLoop.setBit(operandNum, block.getLoop().getIndex());
@@ -711,7 +719,9 @@
                         int operandNum = operandNumber(operand);
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
-                            Debug.log("liveGen in state for operand %d", operandNum);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("liveGen in state for operand %d", operandNum);
+                            }
                         }
                     }
                 };
@@ -719,7 +729,9 @@
                     if (isVariable(operand)) {
                         int varNum = operandNumber(operand);
                         liveKill.set(varNum);
-                        Debug.log("liveKill for operand %d", varNum);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("liveKill for operand %d", varNum);
+                        }
                         if (block.getLoop() != null) {
                             intervalInLoop.setBit(varNum, block.getLoop().getIndex());
                         }
@@ -754,8 +766,10 @@
                 blockSets.liveIn = new BitSet(liveSize);
                 blockSets.liveOut = new BitSet(liveSize);
 
-                Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
-                Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("liveGen  B%d %s", block.getId(), blockSets.liveGen);
+                    Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill);
+                }
 
             }
         } // end of block iteration
@@ -845,7 +859,9 @@
                             liveIn.andNot(blockSets.liveKill);
                             liveIn.or(blockSets.liveGen);
 
-                            Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("block %d: livein = %s,  liveout = %s", block.getId(), liveIn, blockSets.liveOut);
+                            }
                         }
                     }
                     iterationCount++;
@@ -983,7 +999,9 @@
         // Register use position at even instruction id.
         interval.addUsePos(to & ~1, registerPriority);
 
-        Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
+        if (Debug.isLogEnabled()) {
+            Debug.log("add use: %s, from %d to %d (%s)", interval, from, to, registerPriority.name());
+        }
     }
 
     void addTemp(AllocatableValue operand, int tempPos, RegisterPriority registerPriority, LIRKind kind) {
@@ -1000,7 +1018,9 @@
         interval.addUsePos(tempPos, registerPriority);
         interval.addMaterializationValue(null);
 
-        Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+        if (Debug.isLogEnabled()) {
+            Debug.log("add temp: %s tempPos %d (%s)", interval, tempPos, RegisterPriority.MustHaveRegister.name());
+        }
     }
 
     boolean isProcessed(Value operand) {
@@ -1030,7 +1050,9 @@
             // also add register priority for dead intervals
             interval.addRange(defPos, defPos + 1);
             interval.addUsePos(defPos, registerPriority);
-            Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+            if (Debug.isLogEnabled()) {
+                Debug.log("Warning: def of operand %s at %d occurs without use", operand, defPos);
+            }
         }
 
         changeSpillDefinitionPos(interval, defPos);
@@ -1040,7 +1062,9 @@
         }
         interval.addMaterializationValue(LinearScan.getMaterializedValue(op, operand, interval));
 
-        Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+        if (Debug.isLogEnabled()) {
+            Debug.log("add def: %s defPos %d (%s)", interval, defPos, registerPriority.name());
+        }
     }
 
     /**
@@ -1092,7 +1116,9 @@
                     assert blockForId(op.id()).getPredecessorCount() == 0 : "move from stack must be in first block";
                     assert isVariable(move.getResult()) : "result of move must be a variable";
 
-                    Debug.log("found move from stack slot %s to %s", slot, move.getResult());
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("found move from stack slot %s to %s", slot, move.getResult());
+                    }
                 }
 
                 Interval interval = intervalFor(move.getResult());
@@ -1116,7 +1142,9 @@
                     } else {
                         from.setLocationHint(to);
                     }
-                    Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                    }
 
                     return registerHint;
                 }
@@ -1191,7 +1219,9 @@
                     for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) {
                         assert live.get(operandNum) : "should not stop here otherwise";
                         AllocatableValue operand = intervalFor(operandNum).operand;
-                        Debug.log("live in %d: %s", operandNum, operand);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("live in %d: %s", operandNum, operand);
+                        }
 
                         addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, LIRKind.Illegal);
 
@@ -1220,7 +1250,9 @@
                                         addTemp(r.asValue(), opId, RegisterPriority.None, LIRKind.Illegal);
                                     }
                                 }
-                                Debug.log("operation destroys all caller-save registers");
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("operation destroys all caller-save registers");
+                                }
                             }
 
                             op.visitEachOutput(outputConsumer);
@@ -1413,24 +1445,20 @@
         Interval result = interval.getSplitChildAtOpId(opId, mode, this);
 
         if (result != null) {
-            Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
+            if (Debug.isLogEnabled()) {
+                Debug.log("Split child at pos %d of interval %s is %s", opId, interval, result);
+            }
             return result;
         }
 
         throw new BailoutException("LinearScan: interval is null");
     }
 
-    Interval intervalAtBlockBegin(AbstractBlockBase<?> block, int operandNumber) {
-        return splitChildAtOpId(intervalFor(operandNumber), getFirstLirInstructionId(block), LIRInstruction.OperandMode.DEF);
-    }
-
-    Interval intervalAtBlockEnd(AbstractBlockBase<?> block, int operandNumber) {
-        return splitChildAtOpId(intervalFor(operandNumber), getLastLirInstructionId(block) + 1, LIRInstruction.OperandMode.DEF);
-    }
-
     void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
         assert moveResolver.checkEmpty();
 
+        int toBlockFirstInstructionId = getFirstLirInstructionId(toBlock);
+        int fromBlockLastInstructionId = getLastLirInstructionId(fromBlock) + 1;
         int numOperands = operandSize();
         BitSet liveAtEdge = blockData.get(toBlock).liveIn;
 
@@ -1439,8 +1467,8 @@
             assert operandNum < numOperands : "live information set for not exisiting interval";
             assert blockData.get(fromBlock).liveOut.get(operandNum) && blockData.get(toBlock).liveIn.get(operandNum) : "interval not live at this edge";
 
-            Interval fromInterval = intervalAtBlockEnd(fromBlock, operandNum);
-            Interval toInterval = intervalAtBlockBegin(toBlock, operandNum);
+            Interval fromInterval = splitChildAtOpId(intervalFor(operandNum), fromBlockLastInstructionId, LIRInstruction.OperandMode.DEF);
+            Interval toInterval = splitChildAtOpId(intervalFor(operandNum), toBlockFirstInstructionId, LIRInstruction.OperandMode.DEF);
 
             if (fromInterval != toInterval && !fromInterval.location().equals(toInterval.location())) {
                 // need to insert move instruction
@@ -1451,7 +1479,9 @@
 
     void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
         if (fromBlock.getSuccessorCount() <= 1) {
-            Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
+            }
 
             List<LIRInstruction> instructions = ir.getLIRforBlock(fromBlock);
             LIRInstruction instr = instructions.get(instructions.size() - 1);
@@ -1463,7 +1493,9 @@
             }
 
         } else {
-            Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+            if (Debug.isLogEnabled()) {
+                Debug.log("inserting moves at beginning of toBlock B%d", toBlock.getId());
+            }
 
             if (DetailedAsserts.getValue()) {
                 assert ir.getLIRforBlock(fromBlock).get(0) instanceof StandardOp.LabelOp : "block does not start with a label";
@@ -1508,7 +1540,9 @@
 
                         // prevent optimization of two consecutive blocks
                         if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
-                            Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+                            if (Debug.isLogEnabled()) {
+                                Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId());
+                            }
 
                             blockCompleted.set(block.getLinearScanNumber());
 
@@ -1535,7 +1569,9 @@
                         // check for duplicate edges between the same blocks (can happen with switch
                         // blocks)
                         if (!alreadyResolved.get(toBlock.getLinearScanNumber())) {
-                            Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId());
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId());
+                            }
 
                             alreadyResolved.set(toBlock.getLinearScanNumber());
 
@@ -1841,7 +1877,9 @@
                             // iterate all blocks where the interval has use positions
                             for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
                                 if (dominates(defBlock, splitBlock)) {
-                                    Debug.log("Split interval %s, block %s", splitChild, splitBlock);
+                                    if (Debug.isLogEnabled()) {
+                                        Debug.log("Split interval %s, block %s", splitChild, splitBlock);
+                                    }
                                     if (spillBlock == null) {
                                         spillBlock = splitBlock;
                                     } else {
@@ -1868,14 +1906,18 @@
                         assert firstSpillChild != null;
                         if (!defBlock.equals(spillBlock) && spillBlock.equals(blockForId(firstSpillChild.from()))) {
                             AbstractBlockBase<?> dom = spillBlock.getDominator();
-                            Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
+                            }
                             spillBlock = dom;
                         }
 
                         if (!defBlock.equals(spillBlock)) {
                             assert dominates(defBlock, spillBlock);
                             betterSpillPos.increment();
-                            Debug.log("Better spill position found (Block %s)", spillBlock);
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("Better spill position found (Block %s)", spillBlock);
+                            }
 
                             if (defBlock.probability() <= spillBlock.probability()) {
                                 // better spill block has the same probability -> do nothing
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Thu Apr 16 17:09:06 2015 +0200
@@ -297,7 +297,9 @@
         int optimalSplitPos = -1;
         if (minSplitPos == maxSplitPos) {
             // trivial case, no optimization of split position possible
-            Debug.log("min-pos and max-pos are equal, no optimization possible");
+            if (Debug.isLogEnabled()) {
+                Debug.log("min-pos and max-pos are equal, no optimization possible");
+            }
             optimalSplitPos = minSplitPos;
 
         } else {
@@ -319,7 +321,9 @@
             assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
             if (minBlock == maxBlock) {
                 // split position cannot be moved to block boundary : so split as late as possible
-                Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+                if (Debug.isLogEnabled()) {
+                    Debug.log("cannot move split pos to block boundary because minPos and maxPos are in same block");
+                }
                 optimalSplitPos = maxSplitPos;
 
             } else {
@@ -329,19 +333,25 @@
                     // as mustHaveRegister) with a hole before each definition. When the register is
                     // needed
                     // for the second definition : an earlier reloading is unnecessary.
-                    Debug.log("interval has hole just before maxSplitPos, so splitting at maxSplitPos");
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("interval has hole just before maxSplitPos, so splitting at maxSplitPos");
+                    }
                     optimalSplitPos = maxSplitPos;
 
                 } else {
                     // seach optimal block boundary between minSplitPos and maxSplitPos
-                    Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("moving split pos to optimal block boundary between block B%d and B%d", minBlock.getId(), maxBlock.getId());
+                    }
 
                     if (doLoopOptimization) {
                         // Loop optimization: if a loop-end marker is found between min- and
                         // max-position :
                         // then split before this loop
                         int loopEndPos = interval.nextUsageExact(RegisterPriority.LiveAtLoopEnd, allocator.getLastLirInstructionId(minBlock) + 2);
-                        Debug.log("loop optimization: loop end found at pos %d", loopEndPos);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("loop optimization: loop end found at pos %d", loopEndPos);
+                        }
 
                         assert loopEndPos > minSplitPos : "invalid order";
                         if (loopEndPos < maxSplitPos) {
@@ -354,15 +364,22 @@
                             // of the interval (normally, only mustHaveRegister causes a reloading)
                             AbstractBlockBase<?> loopBlock = allocator.blockForId(loopEndPos);
 
-                            Debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
+                            if (Debug.isLogEnabled()) {
+                                Debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
+                            }
                             assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between";
 
-                            optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, allocator.getLastLirInstructionId(loopBlock) + 2);
-                            if (optimalSplitPos == allocator.getLastLirInstructionId(loopBlock) + 2) {
+                            int maxSpillPos = allocator.getLastLirInstructionId(loopBlock) + 2;
+                            optimalSplitPos = findOptimalSplitPos(minBlock, loopBlock, maxSpillPos);
+                            if (optimalSplitPos == maxSpillPos) {
                                 optimalSplitPos = -1;
-                                Debug.log("loop optimization not necessary");
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("loop optimization not necessary");
+                                }
                             } else {
-                                Debug.log("loop optimization successful");
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("loop optimization successful");
+                                }
                             }
                         }
                     }
@@ -374,7 +391,9 @@
                 }
             }
         }
-        Debug.log("optimal split position: %d", optimalSplitPos);
+        if (Debug.isLogEnabled()) {
+            Debug.log("optimal split position: %d", optimalSplitPos);
+        }
 
         return optimalSplitPos;
     }
@@ -401,7 +420,9 @@
             if (optimalSplitPos == interval.to() && interval.nextUsage(RegisterPriority.MustHaveRegister, minSplitPos) == Integer.MAX_VALUE) {
                 // the split position would be just before the end of the interval
                 // . no split at all necessary
-                Debug.log("no split necessary because optimal split position is at end of interval");
+                if (Debug.isLogEnabled()) {
+                    Debug.log("no split necessary because optimal split position is at end of interval");
+                }
                 return;
             }
 
@@ -414,7 +435,9 @@
                 optimalSplitPos = (optimalSplitPos - 1) | 1;
             }
 
-            Debug.log("splitting at position %d", optimalSplitPos);
+            if (Debug.isLogEnabled()) {
+                Debug.log("splitting at position %d", optimalSplitPos);
+            }
 
             assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary";
             assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary";
@@ -472,7 +495,9 @@
                         if (isRegister(parent.location())) {
                             if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) {
                                 // parent is never used, so kick it out of its assigned register
-                                Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                if (Debug.isLogEnabled()) {
+                                    Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber);
+                                }
                                 allocator.assignSpillSlot(parent);
                                 handleSpillSlot(parent);
                             } else {
@@ -507,7 +532,9 @@
                     allocator.changeSpillState(spilledPart, optimalSplitPos);
 
                     if (!allocator.isBlockBegin(optimalSplitPos)) {
-                        Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber);
+                        }
                         insertMove(optimalSplitPos, interval, spilledPart);
                     }
 
@@ -599,7 +626,9 @@
             Interval locationHint = interval.locationHint(true);
             if (locationHint != null && locationHint.location() != null && isRegister(locationHint.location())) {
                 hint = asRegister(locationHint.location());
-                Debug.log("hint register %d from interval %s", hint.number, locationHint);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("hint register %d from interval %s", hint.number, locationHint);
+                }
             }
             assert interval.location() == null : "register already assigned to interval";
 
@@ -641,7 +670,9 @@
 
             splitPos = usePos[reg.number];
             interval.assignLocation(reg.asValue(interval.kind()));
-            Debug.log("selected register %d", reg.number);
+            if (Debug.isLogEnabled()) {
+                Debug.log("selected register %d", reg.number);
+            }
 
             assert splitPos > 0 : "invalid splitPos";
             if (needSplit) {
@@ -710,7 +741,9 @@
 
             int regUsePos = (reg == null ? 0 : usePos[reg.number]);
             if (regUsePos <= firstUsage) {
-                Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("able to spill current interval. firstUsage(register): %d, usePos: %d", firstUsage, regUsePos);
+                }
 
                 if (firstUsage <= interval.from() + 1) {
                     String description = "cannot spill interval that is used in first instruction (possible reason: no register found) firstUsage=" + firstUsage + ", interval.from()=" +
@@ -729,7 +762,9 @@
 
             int splitPos = blockPos[reg.number];
 
-            Debug.log("decided to use register %d", reg.number);
+            if (Debug.isLogEnabled()) {
+                Debug.log("decided to use register %d", reg.number);
+            }
             assert splitPos > 0 : "invalid splitPos";
             assert needSplit || splitPos > interval.from() : "splitting interval at from";
 
@@ -756,7 +791,9 @@
             if (isOdd(pos)) {
                 // the current instruction is a call that blocks all registers
                 if (pos < allocator.maxOpId() && allocator.hasCall(pos + 1) && interval.to() > pos + 1) {
-                    Debug.log("free register cannot be available because all registers blocked by following call");
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("free register cannot be available because all registers blocked by following call");
+                    }
 
                     // safety check that there is really no register available
                     assert !allocFreeRegister(interval) : "found a register for this interval";
@@ -852,7 +889,9 @@
                 // activating an interval that has a stack slot assigned . split it at first use
                 // position
                 // used for method parameters
-                Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                if (Debug.isLogEnabled()) {
+                    Debug.log("interval has spill slot assigned (method parameter) . split it before first use");
+                }
                 splitStackInterval(interval);
                 result = false;
 
@@ -860,7 +899,9 @@
                 if (interval.location() == null) {
                     // interval has not assigned register . normal allocation
                     // (this is the normal case for most intervals)
-                    Debug.log("normal allocation of register");
+                    if (Debug.isLogEnabled()) {
+                        Debug.log("normal allocation of register");
+                    }
 
                     // assign same spill slot to non-intersecting intervals
                     combineSpilledIntervals(interval);
@@ -884,7 +925,9 @@
                 assert interval.isSplitChild();
                 assert interval.currentSplitChild() != null;
                 assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval";
-                Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber);
+                }
 
                 insertMove(interval.from(), interval.currentSplitChild(), interval);
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu Apr 16 17:09:06 2015 +0200
@@ -54,10 +54,55 @@
 
     @Override
     protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
-        new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
+        new Marker<B>(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
-    private static final class Marker {
+    /**
+     * Ensures that an element is only in the worklist once.
+     *
+     * @param <T>
+     */
+    static class UniqueWorkList<T extends AbstractBlockBase<T>> extends ArrayDeque<T> {
+        private static final long serialVersionUID = 8009554570990975712L;
+        BitSet valid;
+
+        public UniqueWorkList(int size) {
+            this.valid = new BitSet(size);
+        }
+
+        @Override
+        public T poll() {
+            T result = super.poll();
+            if (result != null) {
+                valid.set(result.getId(), false);
+            }
+            return result;
+        }
+
+        @Override
+        public boolean add(T pred) {
+            if (!valid.get(pred.getId())) {
+                valid.set(pred.getId(), true);
+                return super.add(pred);
+            }
+            return false;
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends T> collection) {
+            boolean changed = false;
+            for (T element : collection) {
+                if (!valid.get(element.getId())) {
+                    valid.set(element.getId(), true);
+                    super.add(element);
+                    changed = true;
+                }
+            }
+            return changed;
+        }
+    }
+
+    private static final class Marker<T extends AbstractBlockBase<T>> {
         private final LIR lir;
         private final FrameMap frameMap;
         private final RegisterAttributes[] registerAttributes;
@@ -72,16 +117,17 @@
             liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
         }
 
-        private void build() {
-            Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
+        @SuppressWarnings("unchecked")
+        void build() {
+            UniqueWorkList<T> worklist = new UniqueWorkList<>(lir.getControlFlowGraph().getBlocks().size());
             for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
-                worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
+                worklist.add((T) lir.getControlFlowGraph().getBlocks().get(i));
             }
             for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
                 liveInMap.put(block, frameMap.initReferenceMap(true));
             }
             while (!worklist.isEmpty()) {
-                AbstractBlockBase<?> block = worklist.poll();
+                AbstractBlockBase<T> block = worklist.poll();
                 processBlock(block, worklist);
             }
         }
@@ -101,7 +147,7 @@
             return false;
         }
 
-        private void processBlock(AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) {
+        private void processBlock(AbstractBlockBase<T> block, UniqueWorkList<T> worklist) {
             if (updateOutBlock(block)) {
                 try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
                     BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
@@ -119,14 +165,6 @@
         private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
         private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
 
-        private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
-            if (op.destroysCallerSavedRegisters()) {
-                for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
-                    consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
-                }
-            }
-        }
-
         private final class BlockClosure {
             private final ReferenceMap currentSet;
 
@@ -145,50 +183,57 @@
             private void processInstructionBottomUp(LIRInstruction op) {
                 try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
                     // kills
-                    op.visitEachTemp(this::defConsumer);
-                    op.visitEachOutput(this::defConsumer);
-                    forEachDestroyedCallerSavedRegister(op, this::defConsumer);
+
+                    op.visitEachTemp(defConsumer);
+                    op.visitEachOutput(defConsumer);
+                    if (op.destroysCallerSavedRegisters()) {
+                        for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                            defConsumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
+                        }
+                    }
 
                     // gen - values that are considered alive for this state
-                    op.visitEachAlive(this::useConsumer);
-                    op.visitEachState(this::useConsumer);
+                    op.visitEachAlive(useConsumer);
+                    op.visitEachState(useConsumer);
                     // mark locations
-                    op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
+                    op.forEachState(stateConsumer);
                     // gen
-                    op.visitEachInput(this::useConsumer);
+                    op.visitEachInput(useConsumer);
                 }
             }
 
-            /**
-             * @see InstructionValueConsumer
-             * @param operand
-             * @param mode
-             * @param flags
-             */
-            private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                LIRKind kind = operand.getLIRKind();
-                if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
-                    // no need to insert values and derived reference
-                    Debug.log("set operand: %s", operand);
-                    frameMap.setReference(operand, currentSet);
+            InstructionStateProcedure stateConsumer = new InstructionStateProcedure() {
+                public void doState(LIRInstruction inst, LIRFrameState info) {
+                    markLocation(inst, info, getCurrentSet());
                 }
-            }
+            };
 
-            /**
-             * @see InstructionValueConsumer
-             * @param operand
-             * @param mode
-             * @param flags
-             */
-            private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                if (shouldProcessValue(operand)) {
-                    Debug.log("clear operand: %s", operand);
-                    frameMap.clearReference(operand, currentSet);
-                } else {
-                    assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
-                                    operand, mode);
+            ValueConsumer useConsumer = new ValueConsumer() {
+                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    LIRKind kind = operand.getLIRKind();
+                    if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
+                        // no need to insert values and derived reference
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("set operand: %s", operand);
+                        }
+                        frameMap.setReference(operand, currentSet);
+                    }
                 }
-            }
+            };
+
+            ValueConsumer defConsumer = new ValueConsumer() {
+                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (shouldProcessValue(operand)) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("clear operand: %s", operand);
+                        }
+                        frameMap.clearReference(operand, currentSet);
+                    } else {
+                        assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format(
+                                        "Illegal PlatformKind is only allowed for TEMP mode: %s, %s", operand, mode);
+                    }
+                }
+            };
 
             protected boolean shouldProcessValue(Value operand) {
                 return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Thu Apr 16 17:09:06 2015 +0200
@@ -206,7 +206,9 @@
 
         insertionBuffer.append(insertIdx, allocator.getSpillMoveFactory().createMove(toOpr, fromOpr));
 
-        Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
+        }
     }
 
     private void insertMove(Value fromOpr, Interval toInterval) {
@@ -216,7 +218,9 @@
         AllocatableValue toOpr = toInterval.operand;
         insertionBuffer.append(insertIdx, allocator.getSpillMoveFactory().createMove(toOpr, fromOpr));
 
-        Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
+        if (Debug.isLogEnabled()) {
+            Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
+        }
     }
 
     private void resolveMappings() {
@@ -286,7 +290,9 @@
                 }
                 spillInterval.assignLocation(spillSlot);
 
-                Debug.log("created new Interval for spilling: %s", spillInterval);
+                if (Debug.isLogEnabled()) {
+                    Debug.log("created new Interval for spilling: %s", spillInterval);
+                }
 
                 // insert a move from register to stack and update the mapping
                 insertMove(fromInterval, spillInterval);
@@ -328,7 +334,9 @@
     void addMapping(Interval fromInterval, Interval toInterval) {
 
         if (isIllegal(toInterval.location()) && toInterval.canMaterialize()) {
-            Debug.log("no store to rematerializable interval %s needed", toInterval);
+            if (Debug.isLogEnabled()) {
+                Debug.log("no store to rematerializable interval %s needed", toInterval);
+            }
             return;
         }
         if (isIllegal(fromInterval.location()) && fromInterval.canMaterialize()) {
@@ -337,7 +345,9 @@
             addMapping(rematValue, toInterval);
             return;
         }
-        Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromInterval, toInterval);
+        }
 
         assert !fromInterval.operand.equals(toInterval.operand) : "from and to interval equal: " + fromInterval;
         assert fromInterval.kind().equals(toInterval.kind());
@@ -347,7 +357,9 @@
     }
 
     void addMapping(Value fromOpr, Interval toInterval) {
-        Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+        if (Debug.isLogEnabled()) {
+            Debug.log("add move mapping from %s to %s", fromOpr, toInterval);
+        }
 
         assert isConstant(fromOpr) : "only for constants";
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Apr 16 17:09:06 2015 +0200
@@ -214,8 +214,8 @@
                     // set instruction id to the index in the lir instruction list
                     inst.setId(opId++);
                     inst.visitEachOutput(loadConsumer);
-                    inst.forEachInput(useConsumer);
-                    inst.forEachAlive(useConsumer);
+                    inst.visitEachInput(useConsumer);
+                    inst.visitEachAlive(useConsumer);
 
                 }
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java	Thu Apr 16 17:09:06 2015 +0200
@@ -161,7 +161,11 @@
     }
 
     public void markBlocks() {
-        stream(Flags.USAGE).forEach(block -> setDominatorPath(Flags.SUBTREE, block));
+        for (AbstractBlockBase<?> block : getBlocks()) {
+            if (get(Flags.USAGE, block)) {
+                setDominatorPath(Flags.SUBTREE, block);
+            }
+        }
     }
 
     public boolean isMarked(AbstractBlockBase<?> block) {
@@ -169,7 +173,12 @@
     }
 
     public boolean isLeafBlock(AbstractBlockBase<?> block) {
-        return block.getDominated().stream().noneMatch(this::isMarked);
+        for (AbstractBlockBase<?> dom : block.getDominated()) {
+            if (isMarked(dom)) {
+                return false;
+            }
+        }
+        return true;
     }
 
     public void setSolution(AbstractBlockBase<?> block) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Thu Apr 16 17:09:06 2015 +0200
@@ -172,55 +172,42 @@
         private void processInstructionBottomUp(LIRInstruction op) {
             try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
                 // kills
-                op.visitEachTemp(this::defConsumer);
-                op.visitEachOutput(this::defConsumer);
+                op.visitEachTemp(defConsumer);
+                op.visitEachOutput(defConsumer);
 
                 // gen - values that are considered alive for this state
-                op.visitEachAlive(this::useConsumer);
-                op.visitEachState(this::useConsumer);
+                op.visitEachAlive(useConsumer);
+                op.visitEachState(useConsumer);
                 // mark locations
                 // gen
-                op.visitEachInput(this::useConsumer);
+                op.visitEachInput(useConsumer);
             }
         }
 
-        /**
-         * @see InstructionValueConsumer
-         *
-         * @param inst
-         * @param operand
-         * @param mode
-         * @param flags
-         */
-        private void useConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (isVirtualStackSlot(operand)) {
-                VirtualStackSlot vslot = asVirtualStackSlot(operand);
-                addUse(vslot, inst, flags);
-                usePos.add(inst);
-                Debug.log("set operand: %s", operand);
-                currentSet.set(vslot.getId());
+        InstructionValueConsumer useConsumer = new InstructionValueConsumer() {
+            public void visitValue(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(operand)) {
+                    VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                    addUse(vslot, inst, flags);
+                    usePos.add(inst);
+                    Debug.log("set operand: %s", operand);
+                    currentSet.set(vslot.getId());
+                }
             }
-        }
+        };
 
-        /**
-         *
-         * @see InstructionValueConsumer
-         *
-         * @param inst
-         * @param operand
-         * @param mode
-         * @param flags
-         */
-        private void defConsumer(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (isVirtualStackSlot(operand)) {
-                VirtualStackSlot vslot = asVirtualStackSlot(operand);
-                addDef(vslot, inst);
-                usePos.add(inst);
-                Debug.log("clear operand: %s", operand);
-                currentSet.clear(vslot.getId());
+        InstructionValueConsumer defConsumer = new InstructionValueConsumer() {
+            public void visitValue(LIRInstruction inst, Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(operand)) {
+                    VirtualStackSlot vslot = asVirtualStackSlot(operand);
+                    addDef(vslot, inst);
+                    usePos.add(inst);
+                    Debug.log("clear operand: %s", operand);
+                    currentSet.clear(vslot.getId());
+                }
+
             }
-
-        }
+        };
 
         private void addUse(VirtualStackSlot stackSlot, LIRInstruction inst, EnumSet<OperandFlag> flags) {
             StackInterval interval = getOrCreateInterval(stackSlot);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu Apr 16 17:09:06 2015 +0200
@@ -363,30 +363,26 @@
 
         private void assignStackSlots(Set<LIRInstruction> usePos) {
             for (LIRInstruction op : usePos) {
-                op.forEachInput(this::assignSlot);
-                op.forEachAlive(this::assignSlot);
-                op.forEachState(this::assignSlot);
+                op.forEachInput(assignSlot);
+                op.forEachAlive(assignSlot);
+                op.forEachState(assignSlot);
 
-                op.forEachTemp(this::assignSlot);
-                op.forEachOutput(this::assignSlot);
+                op.forEachTemp(assignSlot);
+                op.forEachOutput(assignSlot);
             }
         }
 
-        /**
-         * @see ValueProcedure
-         * @param value
-         * @param mode
-         * @param flags
-         */
-        private Value assignSlot(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (isVirtualStackSlot(value)) {
-                VirtualStackSlot slot = asVirtualStackSlot(value);
-                StackInterval interval = get(slot);
-                assert interval != null;
-                return interval.location();
+        ValueProcedure assignSlot = new ValueProcedure() {
+            public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (isVirtualStackSlot(value)) {
+                    VirtualStackSlot slot = asVirtualStackSlot(value);
+                    StackInterval interval = get(slot);
+                    assert interval != null;
+                    return interval.location();
+                }
+                return value;
             }
-            return value;
-        }
+        };
 
         // ====================
         //
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Thu Apr 16 17:09:06 2015 +0200
@@ -252,11 +252,12 @@
     public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
         MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE);
         decode(methodScope, null);
-        cleanupGraph(methodScope);
+        cleanupGraph(methodScope, null);
         methodScope.graph.verify();
     }
 
     protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) {
+        Graph.Mark start = methodScope.graph.getMark();
         LoopScope loopScope = new LoopScope(methodScope);
         FixedNode firstNode;
         if (startNode != null) {
@@ -284,9 +285,14 @@
         }
 
         if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
-            cleanupGraph(methodScope);
+            /*
+             * The startNode can get deleted during graph cleanup, so we use its predecessor (if
+             * available) as the starting point for loop detection.
+             */
+            FixedNode detectLoopsStart = startNode.predecessor() != null ? (FixedNode) startNode.predecessor() : startNode;
+            cleanupGraph(methodScope, start);
             Debug.dump(methodScope.graph, "Before loop detection");
-            detectLoops(methodScope.graph, firstNode);
+            detectLoops(methodScope.graph, detectLoopsStart);
         }
     }
 
@@ -1111,18 +1117,21 @@
         }
     }
 
-    protected void cleanupGraph(MethodScope methodScope) {
+    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         assert verifyEdges(methodScope);
 
         Debug.dump(methodScope.graph, "Before removing redundant merges");
-        for (MergeNode mergeNode : methodScope.graph.getNodes(MergeNode.TYPE)) {
-            if (mergeNode.forwardEndCount() == 1) {
-                methodScope.graph.reduceTrivialMerge(mergeNode);
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.forwardEndCount() == 1) {
+                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                }
             }
         }
 
         Debug.dump(methodScope.graph, "Before removing redundant begins");
-        for (Node node : methodScope.graph.getNodes()) {
+        for (Node node : methodScope.graph.getNewNodes(start)) {
             if (node instanceof BeginNode || node instanceof KillingBeginNode) {
                 if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
                     GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
@@ -1132,7 +1141,7 @@
         }
 
         Debug.dump(methodScope.graph, "Before removing unused non-fixed nodes");
-        for (Node node : methodScope.graph.getNodes()) {
+        for (Node node : methodScope.graph.getNewNodes(start)) {
             if (!(node instanceof FixedNode) && node.hasNoUsages()) {
                 GraphUtil.killCFG(node);
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Thu Apr 16 17:09:06 2015 +0200
@@ -35,8 +35,8 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-@NodeInfo(allowedUsageTypes = {InputType.Extension})
-public final class MemoryMapNode extends FloatingNode implements MemoryMap, LIRLowerable {
+@NodeInfo(allowedUsageTypes = {InputType.Extension, InputType.Memory})
+public final class MemoryMapNode extends FloatingNode implements MemoryMap, MemoryNode, LIRLowerable {
 
     public static final NodeClass<MemoryMapNode> TYPE = NodeClass.create(MemoryMapNode.class);
     protected final List<LocationIdentity> locationIdentities;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.output	Thu Apr 16 17:09:06 2015 +0200
@@ -0,0 +1,2 @@
+[deoptimizeWhenCompiled]
+[deoptimizeWhenCompiled]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl	Thu Apr 16 17:09:06 2015 +0200
@@ -0,0 +1,21 @@
+/* 
+ * This tests that simple arithmetic gets inlined.
+ */
+function add(a, b) {
+    deoptimizeWhenCompiled(a == 50); 
+    return a + b;
+}
+
+
+function test() {
+    i = 0;
+    while (i < 100) {
+        i = add(i, 1);
+    }
+    return i;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test, 1 == 2));
+    test();
+}  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Thu Apr 16 17:09:06 2015 +0200
@@ -49,6 +49,7 @@
         SLTestRunner.installBuiltin(SLGenerateDummyNodesBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLCallFunctionsWithBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLIsCompilationConstantBuiltinFactory.getInstance());
+        SLTestRunner.installBuiltin(SLDeoptimizeWhenCompiledBuiltinFactory.getInstance());
 
         /* test specific builtins */
         SLTestRunner.installBuiltin(SLTestTruffleBoundary01BuiltinFactory.getInstance());
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLCallUntilOptimizedBuiltin.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLCallUntilOptimizedBuiltin.java	Thu Apr 16 17:09:06 2015 +0200
@@ -49,7 +49,12 @@
     @Child private IndirectCallNode indirectCall = Truffle.getRuntime().createIndirectCallNode();
 
     @Specialization
-    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function) {
+    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function, @SuppressWarnings("unused") SLNull checkTarget) {
+        return callUntilCompiled(frame, function, false);
+    }
+
+    @Specialization
+    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function, boolean checkTarget) {
         OptimizedCallTarget target = ((OptimizedCallTarget) function.getCallTarget());
         for (int i = 0; i < MAX_CALLS; i++) {
             if (isCompiling(target)) {
@@ -63,7 +68,9 @@
         // call one more in compiled
         indirectCall.call(frame, target, EMPTY_ARGS);
 
-        checkTarget(target);
+        if (checkTarget) {
+            checkTarget(target);
+        }
 
         return function;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLDeoptimizeWhenCompiledBuiltin.java	Thu Apr 16 17:09:06 2015 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 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.truffle.test.builtins;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * Forces a deoptimization as soon as the method runs in compiled code.
+ */
+@NodeInfo(shortName = "deoptimizeWhenCompiled")
+public abstract class SLDeoptimizeWhenCompiledBuiltin extends SLGraalRuntimeBuiltin {
+
+    @Specialization
+    public SLNull deoptimzeWhenCompiled(boolean condition) {
+        if (CompilerDirectives.inCompiledCode()) {
+            if (condition) {
+                printMessage();
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+            }
+        }
+        return SLNull.SINGLETON;
+    }
+
+    @TruffleBoundary
+    private void printMessage() {
+        getContext().getOutput().println("[deoptimizeWhenCompiled]");
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java	Thu Apr 16 17:09:06 2015 +0200
@@ -128,9 +128,11 @@
 
     protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
         protected final PEMethodScope methodScope;
+        protected final Invoke invoke;
 
-        public PENonAppendGraphBuilderContext(PEMethodScope methodScope) {
+        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
             this.methodScope = methodScope;
+            this.invoke = invoke;
         }
 
         @Override
@@ -210,7 +212,7 @@
 
         @Override
         public int bci() {
-            throw unimplemented();
+            return invoke.bci();
         }
 
         @Override
@@ -228,8 +230,8 @@
         protected FixedWithNextNode lastInstr;
         protected ValueNode pushedNode;
 
-        public PEAppendGraphBuilderContext(PEMethodScope methodScope, FixedWithNextNode lastInstr) {
-            super(methodScope);
+        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
+            super(inlineScope, inlineScope.invokeData.invoke);
             this.lastInstr = lastInstr;
         }
 
@@ -319,14 +321,14 @@
         PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin,
                         parameterPlugin, null);
         decode(methodScope, null);
-        cleanupGraph(methodScope);
+        cleanupGraph(methodScope, null);
         methodScope.graph.verify();
     }
 
     @Override
-    protected void cleanupGraph(MethodScope methodScope) {
+    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         GraphBuilderPhase.connectLoopEndToBegin(methodScope.graph);
-        super.cleanupGraph(methodScope);
+        super.cleanupGraph(methodScope, start);
     }
 
     @Override
@@ -378,7 +380,7 @@
         }
 
         if (methodScope.inlineInvokePlugin != null) {
-            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope), callTarget.targetMethod(), invokeData.invoke);
+            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
         }
         return false;
     }
@@ -439,7 +441,7 @@
         }
 
         ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
-        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope);
+        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
         InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType());
         if (inlineInfo == null) {
             return false;
@@ -619,7 +621,7 @@
                 return result;
 
             } else if (methodScope.parameterPlugin != null) {
-                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope);
+                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
                 Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp());
                 if (result != null) {
                     return result;
@@ -657,7 +659,11 @@
             Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
             FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind);
 
-            if (methodScope.caller != null) {
+            /*
+             * When the encoded graph has methods inlining, we can already have a proper caller
+             * state. If not, we set the caller state here.
+             */
+            if (outerState.outerFrameState() == null && methodScope.caller != null) {
                 ensureOuterStateDecoded(methodScope.caller);
                 outerState.setOuterFrameState(methodScope.caller.outerState);
             }
@@ -680,7 +686,7 @@
             registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
             FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
 
-            if (methodScope.caller != null) {
+            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
                 ensureOuterStateDecoded(methodScope.caller);
                 exceptionState.setOuterFrameState(methodScope.caller.outerState);
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Apr 16 17:09:06 2015 +0200
@@ -184,7 +184,9 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
+            if (replacements.hasSubstitution(original, builder.bci())) {
+                return null;
+            }
             assert !builder.parsingReplacement();
 
             if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
@@ -260,7 +262,9 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
+            if (replacements.hasSubstitution(original, builder.bci())) {
+                return null;
+            }
 
             if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) {
                 return null;
@@ -337,7 +341,7 @@
 
         ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget);
 
-        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(parsingInvocationPlugins.getParent());
+        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
         InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements());
         if (PrintTruffleExpansionHistogram.getValue()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Apr 16 17:09:06 2015 +0200
@@ -95,14 +95,9 @@
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
 
         GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-        Plugins graalPlugins = phase.getGraphBuilderConfig().getPlugins();
-        InvocationPlugins invocationPlugins = new InvocationPlugins(graalPlugins.getInvocationPlugins());
-        Plugins plugins = new Plugins(invocationPlugins);
+        // copy all plugins from the host
+        Plugins plugins = new Plugins(phase.getGraphBuilderConfig().getPlugins());
         this.config = GraphBuilderConfiguration.getDefault(plugins).withSkippedExceptionTypes(skippedExceptionTypes);
-        // Since invocationPlugins may include MethodSubstitutionPlugins, we
-        // need to copy the GenericInvocationPlugins so that @NodeIntrinsics
-        // and Word methods in method substitutions are handled correctly.
-        plugins.setGenericInvocationPlugin(graalPlugins.getGenericInvocationPlugin());
 
         this.partialEvaluator = new PartialEvaluator(providers, config, Graal.getRequiredCapability(SnippetReflectionProvider.class));
 
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Thu Apr 16 17:09:06 2015 +0200
@@ -287,4 +287,51 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)})
+    abstract static class TestEvaluatedShortCircuit1 extends Node {
+
+        public abstract Object execute1(VirtualFrame frame, Object value);
+
+        public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB);
+
+        public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b);
+
+        @ShortCircuit("b")
+        public boolean needsB(Object a) {
+            return true;
+        }
+
+        @Specialization
+        int call(Object a, boolean hasB, Object b) {
+            return 42;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)})
+    abstract static class TestEvaluatedShortCircuit2 extends Node {
+
+        public abstract Object execute1(VirtualFrame frame, Object value);
+
+        public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB);
+
+        public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b);
+
+        @ShortCircuit("b")
+        public boolean needsB(Object a) {
+            return true;
+        }
+
+        @Specialization
+        int call(int a, boolean hasB, int b) {
+            return 42;
+        }
+
+        @Specialization
+        int call(Object a, boolean hasB, Object b) {
+            return 42;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java	Thu Apr 16 17:09:06 2015 +0200
@@ -144,18 +144,18 @@
         }
 
         @Specialization(rewriteOn = RuntimeException.class)
-        int s1() {
+        double s1() {
             return 42;
         }
 
         @Specialization
-        int s2() {
+        double s2() {
             return 42;
         }
 
     }
 
-    @ExpectError("Incompatible abstract execute methods found [executeDouble(), executeInt()].%")
+    @ExpectError("Incompatible abstract execute methods found %")
     abstract static class IncompatibleAbstract1 extends Node {
 
         // we don't know how to implement executeDouble
@@ -164,7 +164,7 @@
         abstract int executeInt();
 
         @Specialization
-        int s1() {
+        double s1() {
             return 42;
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Apr 16 17:09:06 2015 +0200
@@ -66,7 +66,9 @@
     private final boolean singleSpecializable;
     private final int varArgsThreshold;
     private final Set<TypeMirror> expectedTypes = new HashSet<>();
+    private final Set<NodeExecutionData> usedExecuteChildMethods = new HashSet<>();
     private boolean nextUsed;
+
     private List<ExecutableTypeData> usedTypes;
     private List<SpecializationData> reachableSpecializations;
 
@@ -210,7 +212,7 @@
         }
 
         for (ExecutableTypeData execType : usedTypes) {
-            if (execType.getMethod() == null) {
+            if (!singleSpecializable && execType.getMethod() == null) {
                 continue;
             }
             clazz.add(createExecutableTypeOverride(usedTypes, execType));
@@ -273,7 +275,7 @@
 
     private Element createUnsupportedMethod() {
         LocalContext locals = LocalContext.load(this);
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported");
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported", varArgsThreshold);
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
@@ -380,6 +382,16 @@
         baseSpecialization.addOptional(createCreatePolymorphic(generated));
         baseSpecialization.addOptional(createGetNext(baseSpecialization));
 
+        for (NodeExecutionData execution : node.getChildExecutions()) {
+            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
+            specializedTypes.add(genericType);
+            for (TypeMirror specializedType : specializedTypes) {
+                if (isExecuteChildShared(execution, specializedType)) {
+                    baseSpecialization.addOptional(createExecuteChildMethod(execution, specializedType));
+                }
+            }
+        }
+
         return node.getUninitializedSpecialization();
     }
 
@@ -418,28 +430,13 @@
             clazz.add(createFastPathExecuteMethod(null, type, usedTypes));
         }
 
-        for (NodeExecutionData execution : node.getChildExecutions()) {
-            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
-            specializedTypes.add(genericType);
-            for (TypeMirror specializedType : specializedTypes) {
-                if (isExecuteChildShared(execution, specializedType)) {
-                    clazz.add(createExecuteChildMethod(execution, specializedType));
-                }
-            }
-        }
-
         return clazz;
     }
 
     private Element createAcceptAndExecute() {
-
-        TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()];
-        Arrays.fill(parameters, genericType);
-
-        ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
-
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
-        CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false);
+        ExecutableTypeData executableElement = createSpecializationNodeSignature(node.getSignatureSize());
+        LocalContext currentLocals = LocalContext.load(this, executableElement, varArgsThreshold);
+        CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false, varArgsThreshold);
 
         executable.getModifiers().add(FINAL);
         CodeTreeBuilder builder = executable.createBuilder();
@@ -451,6 +448,12 @@
         return executable;
     }
 
+    private ExecutableTypeData createSpecializationNodeSignature(int argumentCount) {
+        TypeMirror[] parameters = new TypeMirror[argumentCount];
+        Arrays.fill(parameters, genericType);
+        return new ExecutableTypeData(node, genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
+    }
+
     private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) {
         // always implement the root execute method. they are declared abstract in the base node.
         if (executableType.getDelegatedTo() == null) {
@@ -458,7 +461,7 @@
         }
 
         // specializations with more parameters are just ignored
-        if (executableType.getEvaluatedCount() > node.getSignatureSize()) {
+        if (executableType.getEvaluatedCount() > node.getExecutionCount()) {
             return false;
         }
 
@@ -468,8 +471,9 @@
 
         // the evaluated signature might be compatible to the specialization
         boolean specializationCompatible = true;
-        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
-            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+        List<TypeMirror> signatureParameters = executableType.getSignatureParameters();
+        for (int i = 0; i < signatureParameters.size(); i++) {
+            TypeMirror evaluatedType = signatureParameters.get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType();
 
             if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) {
@@ -489,7 +493,7 @@
         }
 
         // trigger type boxing elimination for unevaluated arguments
-        for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) {
+        for (int i = executableType.getEvaluatedCount(); i < node.getExecutionCount(); i++) {
             NodeExecutionData execution = node.getChildExecutions().get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
             if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) {
@@ -512,8 +516,8 @@
         }
 
         // trigger generation for evaluated assignable type matches other than generic
-        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
-            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+        for (int i = 0; i < signatureParameters.size(); i++) {
+            TypeMirror evaluatedType = signatureParameters.get(i);
             NodeExecutionData execution = node.getChildExecutions().get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
 
@@ -664,12 +668,12 @@
             return null;
         }
 
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
         currentLocals.loadFastPathState(specialization);
 
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical");
         method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other"));
-        currentLocals.addParametersTo(method, FRAME_VALUE);
+        currentLocals.addParametersTo(method, varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         final CodeTreeBuilder builder = method.createBuilder();
 
@@ -729,11 +733,11 @@
             return null;
         }
         TypeMirror specializationNodeType = getType(SpecializationNode.class);
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
 
         CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge");
         executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode"));
-        currentLocals.addParametersTo(executable, FRAME_VALUE);
+        currentLocals.addParametersTo(executable, varArgsThreshold, FRAME_VALUE);
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
 
@@ -802,7 +806,7 @@
     private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) {
         final LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -834,7 +838,7 @@
             locals.removeValue(FRAME_VALUE);
         }
 
-        CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE);
+        CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", varArgsThreshold, FRAME_VALUE);
         if (!frameUsed) {
             boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class)));
         }
@@ -887,7 +891,7 @@
         }
         LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -950,8 +954,8 @@
     }
 
     private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) {
-        LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE);
-        CodeExecutableElement method = createExecuteMethod(null, execType, locals, true);
+        LocalContext locals = LocalContext.load(this, execType, Integer.MAX_VALUE);
+        CodeExecutableElement method = createExecuteMethod(null, execType, locals, true, Integer.MAX_VALUE);
 
         CodeTreeBuilder builder = method.createBuilder();
         if (singleSpecializable) {
@@ -1043,17 +1047,38 @@
                 values.add(createTypeSafeReference(frameLocal, method.getFrameParameter()));
             }
         }
-        for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) {
-            TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex);
-            LocalVariable variable;
-            if (executeWith != null && parameterIndex < executeWith.size()) {
-                variable = currentValues.getValue(executeWith.get(parameterIndex));
+
+        int evaluatedIndex = 0;
+        for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
+            NodeExecutionData parameterExecution;
+            if (executeWith != null && executionIndex < executeWith.size()) {
+                parameterExecution = executeWith.get(executionIndex);
             } else {
-                variable = currentValues.getValue(parameterIndex);
+                parameterExecution = node.getChildExecutions().get(executionIndex);
             }
-            values.add(createTypeSafeReference(variable, targetParameter));
+            if (parameterExecution.isShortCircuit()) {
+                if (evaluatedIndex < method.getEvaluatedCount()) {
+                    TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
+                    LocalVariable shortCircuit = currentValues.getShortCircuit(parameterExecution);
+                    if (shortCircuit != null) {
+                        values.add(createTypeSafeReference(shortCircuit, targetType));
+                    } else {
+                        values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
+                    }
+                    evaluatedIndex++;
+                }
+            }
+            if (evaluatedIndex < method.getEvaluatedCount()) {
+                TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
+                LocalVariable value = currentValues.getValue(parameterExecution);
+                if (value != null) {
+                    values.add(createTypeSafeReference(value, targetType));
+                } else {
+                    values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
+                }
+                evaluatedIndex++;
+            }
         }
-
         return values.toArray(new CodeTree[values.size()]);
     }
 
@@ -1518,8 +1543,11 @@
     }
 
     private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
-        expectedTypes.add(forType);
-        return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree);
+        if (sourceType == null || ElementUtils.needsCastTo(sourceType, forType)) {
+            expectedTypes.add(forType);
+            return TypeSystemCodeGenerator.expect(typeSystem, forType, tree);
+        }
+        return tree;
     }
 
     private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) {
@@ -1554,8 +1582,8 @@
     }
 
     private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) {
-        LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold);
-        CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false);
+        LocalContext currentLocals = LocalContext.load(this, executedType, Integer.MAX_VALUE);
+        CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false, Integer.MAX_VALUE);
         CodeTreeBuilder builder = executable.createBuilder();
         if (specialization == null) {
             if (executedType.getDelegatedTo() == null) {
@@ -1569,28 +1597,17 @@
         return executable;
     }
 
-    private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) {
+    private static final String VARARGS_NAME = "args";
+
+    private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride, int varArgs) {
         TypeMirror returnType = executedType.getReturnType();
-        TypeMirror frame = executedType.getFrameParameter();
-        List<TypeMirror> evaluatedParameters = executedType.getEvaluatedParameters();
 
         if (specialization != null) {
             currentLocals.loadFastPathState(specialization);
         }
 
-        if (frame == null) {
-            currentLocals.removeValue(FRAME_VALUE);
-        } else {
-            currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame));
-        }
-
-        for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) {
-            NodeExecutionData execution = node.getChildExecutions().get(i);
-            currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i)));
-        }
-
         String methodName;
-        if (originalOverride) {
+        if (originalOverride && executedType.getMethod() != null) {
             methodName = executedType.getMethod().getSimpleName().toString();
         } else {
             methodName = executedType.getUniqueName();
@@ -1608,32 +1625,13 @@
                 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE);
             }
 
-            final String varArgsName = "args";
             if (executable.isVarArgs()) {
-                ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName);
+                ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(VARARGS_NAME);
             }
 
-            // rename varargs parameter
-            int signatureIndex = 0;
-            for (TypeMirror parameter : executedType.getEvaluatedParameters()) {
-                LocalVariable var = currentLocals.getValue(signatureIndex);
-                if (var != null) {
-                    int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex));
-                    if (varArgsIndex >= 0) {
-                        var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
-                    } else {
-                        ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName());
-                    }
-                    if (!isObject(parameter)) {
-                        var = var.newType(parameter);
-                    }
-                    currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var);
-                }
-
-                signatureIndex++;
-            }
+            renameOriginalParameters(executedType, executable, currentLocals);
         } else {
-            executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE);
+            executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, varArgs, FRAME_VALUE);
         }
         executable.getThrownTypes().clear();
 
@@ -1644,6 +1642,47 @@
         return executable;
     }
 
+    private void renameOriginalParameters(ExecutableTypeData executedType, CodeExecutableElement executable, LocalContext currentLocals) {
+        // rename varargs parameter
+        int evaluatedIndex = 0;
+        for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
+            NodeExecutionData execution = node.getChildExecutions().get(executionIndex);
+            if (execution.isShortCircuit()) {
+                if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                    TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
+                    LocalVariable shortCircuit = currentLocals.getShortCircuit(execution);
+                    if (shortCircuit != null) {
+                        currentLocals.setShortCircuitValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, shortCircuit));
+                    }
+                    evaluatedIndex++;
+                }
+            }
+            if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
+                LocalVariable value = currentLocals.getValue(execution);
+                if (value != null) {
+                    currentLocals.setValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, value));
+                }
+                evaluatedIndex++;
+            }
+        }
+    }
+
+    private static LocalVariable renameExecutableTypeParameter(CodeExecutableElement method, ExecutableTypeData executedType, int evaluatedIndex, TypeMirror targetType, LocalVariable var) {
+        int parameterIndex = executedType.getParameterIndex(evaluatedIndex);
+        int varArgsIndex = executedType.getVarArgsIndex(parameterIndex);
+        LocalVariable returnVar = var;
+        if (varArgsIndex >= 0) {
+            returnVar = returnVar.accessWith(CodeTreeBuilder.singleString(VARARGS_NAME + "[" + varArgsIndex + "]"));
+        } else {
+            ((CodeVariableElement) method.getParameters().get(parameterIndex)).setName(returnVar.getName());
+        }
+        if (!isObject(targetType)) {
+            returnVar = returnVar.newType(targetType);
+        }
+        return returnVar;
+    }
+
     private boolean needsUnexpectedResultException(ExecutableTypeData executedType) {
         if (!executedType.hasUnexpectedValue(context)) {
             return false;
@@ -1670,8 +1709,9 @@
             delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes);
         }
 
+        int delegateSignatureCount = delegate != null ? delegate.getSignatureParameters().size() : 0;
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) {
+            if (specialization == null && delegate != null && execution.getIndex() >= delegateSignatureCount) {
                 // we just evaluate children for the next delegate
                 continue;
             } else if (specialization != null && delegate != null) {
@@ -1794,15 +1834,21 @@
 
     private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
         LocalVariable shortCircuit = null;
-        SpecializationData resolvedSpecialization = specialization;
-        if (specialization == null) {
-            resolvedSpecialization = node.getGenericSpecialization();
-        }
-
         if (execution.isShortCircuit()) {
-            ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
-            CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
-            shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
+            shortCircuit = currentLocals.getShortCircuit(execution);
+
+            if (shortCircuit == null) {
+                SpecializationData resolvedSpecialization = specialization;
+                if (specialization == null) {
+                    resolvedSpecialization = node.getGenericSpecialization();
+                }
+                ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
+                CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
+                shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
+            } else {
+                CodeTree access = shortCircuit.createReference();
+                shortCircuit = shortCircuit.nextName().accessWith(access);
+            }
         }
         return shortCircuit;
     }
@@ -2016,9 +2062,13 @@
     }
 
     private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) {
-        LocalContext locals = LocalContext.load(this, 0, varArgsThreshold);
-
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE);
+        if (!usedExecuteChildMethods.contains(execution)) {
+            return null;
+        }
+
+        LocalContext locals = LocalContext.load(this, createSpecializationNodeSignature(0), Integer.MAX_VALUE);
+
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), Integer.MAX_VALUE, FRAME_VALUE);
         if (hasChildUnexpectedResult(execution, targetType)) {
             method.getThrownTypes().add(getType(UnexpectedResultException.class));
         }
@@ -2047,6 +2097,10 @@
 
     private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) {
         if (typeSystem.hasImplicitSourceTypes(targetType)) {
+            if (typeEquals(node.getGenericType(execution), targetType)) {
+                return null;
+            }
+
             switch (options.implicitCastOptimization()) {
                 case NONE:
                     return null;
@@ -2185,6 +2239,7 @@
         if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             throw new AssertionError("Execute child not shared with method but called.");
         }
+        usedExecuteChildMethods.add(execution);
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.tree(targetValue.createReference()).string(" = ");
@@ -2594,20 +2649,59 @@
             }
         }
 
-        public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) {
+        public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, int varArgsThreshold, String... optionalArguments) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
-            addParametersTo(method, optionalArguments);
+            addParametersTo(method, varArgsThreshold, optionalArguments);
             return method;
         }
 
-        public static LocalContext load(NodeGenFactory factory, int signatureSize, int varargsThreshold) {
+        public static LocalContext load(NodeGenFactory factory, ExecutableTypeData type, int varargsThreshold) {
             LocalContext context = new LocalContext(factory);
-            context.loadValues(signatureSize, varargsThreshold);
+            context.loadEvaluatedValues(type, varargsThreshold);
             return context;
         }
 
+        private void loadEvaluatedValues(ExecutableTypeData executedType, int varargsThreshold) {
+            TypeMirror frame = executedType.getFrameParameter();
+            if (frame == null) {
+                removeValue(FRAME_VALUE);
+            } else {
+                set(FRAME_VALUE, new LocalVariable(frame, FRAME_VALUE, null, null));
+            }
+            for (NodeFieldData field : factory.node.getFields()) {
+                String fieldName = fieldValueName(field);
+                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
+            }
+            boolean varargs = needsVarargs(false, varargsThreshold);
+            List<TypeMirror> evaluatedParameter = executedType.getEvaluatedParameters();
+            int evaluatedIndex = 0;
+            for (int executionIndex = 0; executionIndex < factory.node.getExecutionCount(); executionIndex++) {
+                NodeExecutionData execution = factory.node.getChildExecutions().get(executionIndex);
+                if (execution.isShortCircuit()) {
+                    if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                        TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
+                        LocalVariable shortCircuit = createShortCircuitValue(execution).newType(evaluatedType);
+                        if (varargs) {
+                            shortCircuit = shortCircuit.accessWith(createReadVarargs(evaluatedIndex));
+                        }
+                        values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
+                        evaluatedIndex++;
+                    }
+                }
+                if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                    TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
+                    LocalVariable value = createValue(execution, evaluatedType);
+                    if (varargs) {
+                        value = value.accessWith(createReadVarargs(evaluatedIndex));
+                    }
+                    values.put(value.getName(), value.makeOriginal());
+                    evaluatedIndex++;
+                }
+            }
+        }
+
         public static LocalContext load(NodeGenFactory factory) {
-            return load(factory, factory.node.getSignatureSize(), factory.varArgsThreshold);
+            return load(factory, factory.createSpecializationNodeSignature(factory.node.getSignatureSize()), factory.varArgsThreshold);
         }
 
         public LocalContext copy() {
@@ -2701,36 +2795,6 @@
             return size >= varArgsThreshold;
         }
 
-        private void loadValues(int evaluatedArguments, int varargsThreshold) {
-            values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null));
-
-            for (NodeFieldData field : factory.node.getFields()) {
-                String fieldName = fieldValueName(field);
-                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
-            }
-
-            boolean varargs = needsVarargs(false, varargsThreshold);
-            for (int i = 0; i < evaluatedArguments; i++) {
-                List<NodeExecutionData> childExecutions = factory.node.getChildExecutions();
-                if (i >= childExecutions.size()) {
-                    break;
-                }
-                NodeExecutionData execution = childExecutions.get(i);
-                if (execution.isShortCircuit()) {
-                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context);
-                    if (varargs) {
-                        shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
-                    }
-                    values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
-                }
-                LocalVariable value = createValue(execution, factory.genericType);
-                if (varargs) {
-                    value = value.accessWith(createReadVarargs(i));
-                }
-                values.put(value.getName(), value.makeOriginal());
-            }
-        }
-
         private static CodeTree createReadVarargs(int i) {
             return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build();
         }
@@ -2766,14 +2830,14 @@
             }
         }
 
-        public void addParametersTo(CodeExecutableElement method, String... optionalNames) {
+        public void addParametersTo(CodeExecutableElement method, int varArgsThreshold, String... optionalNames) {
             for (String var : optionalNames) {
                 LocalVariable local = values.get(var);
                 if (local != null) {
                     method.addParameter(local.createParameter());
                 }
             }
-            if (needsVarargs(true, factory.varArgsThreshold)) {
+            if (needsVarargs(true, varArgsThreshold)) {
                 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_"));
                 method.setVarArgs(true);
             } else {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Apr 16 17:09:06 2015 +0200
@@ -163,21 +163,36 @@
         if (typeEquals(type1, type2)) {
             return type1;
         }
-        TypeElement element1 = fromTypeMirror(type1);
-        TypeElement element2 = fromTypeMirror(type2);
-        if (element1 == null || element2 == null) {
-            if (element1 != null) {
-                return type1;
-            } else if (element2 != null) {
-                return type2;
-            }
+        if (isVoid(type1)) {
+            return type2;
+        } else if (isVoid(type2)) {
+            return type1;
+        }
+        if (isObject(type1)) {
+            return type1;
+        } else if (isObject(type2)) {
+            return type2;
+        }
+
+        if (isPrimitive(type1) || isPrimitive(type2)) {
             return context.getType(Object.class);
         }
 
-        List<TypeElement> element1Types = getDirectSuperTypes(element1);
-        element1Types.add(0, element1);
-        List<TypeElement> element2Types = getDirectSuperTypes(element2);
-        element2Types.add(0, element2);
+        if (isSubtype(type1, type2)) {
+            return type2;
+        } else if (isSubtype(type2, type1)) {
+            return type1;
+        }
+
+        TypeElement element1 = fromTypeMirror(type1);
+        TypeElement element2 = fromTypeMirror(type2);
+
+        if (element1 == null || element2 == null) {
+            return context.getType(Object.class);
+        }
+
+        List<TypeElement> element1Types = getSuperTypes(element1);
+        List<TypeElement> element2Types = getSuperTypes(element2);
 
         for (TypeElement superType1 : element1Types) {
             for (TypeElement superType2 : element2Types) {
@@ -186,6 +201,7 @@
                 }
             }
         }
+
         return context.getType(Object.class);
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java	Thu Apr 16 17:09:06 2015 +0200
@@ -43,6 +43,11 @@
     }
 
     @Override
+    public boolean isAnnotated() {
+        return true;
+    }
+
+    @Override
     public boolean matches(VariableElement variable) {
         if (ElementUtils.findAnnotationMirror(variable.getAnnotationMirrors(), annotationType) != null) {
             return true;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Thu Apr 16 17:09:06 2015 +0200
@@ -35,6 +35,7 @@
 
 public class ExecutableTypeData extends MessageContainer implements Comparable<ExecutableTypeData> {
 
+    private final NodeData node;
     private final ExecutableElement method;
     private final TypeMirror returnType;
     private final TypeMirror frameParameter;
@@ -44,7 +45,8 @@
 
     private String uniqueName;
 
-    public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) {
+    public ExecutableTypeData(NodeData node, TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) {
+        this.node = node;
         this.returnType = returnType;
         this.frameParameter = frameParameter;
         this.evaluatedParameters = evaluatedParameters;
@@ -52,7 +54,8 @@
         this.method = null;
     }
 
-    public ExecutableTypeData(ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) {
+    public ExecutableTypeData(NodeData node, ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) {
+        this.node = node;
         this.method = method;
         this.returnType = method.getReturnType();
         TypeMirror foundFrameParameter = null;
@@ -123,6 +126,21 @@
         return evaluatedParameters;
     }
 
+    public List<TypeMirror> getSignatureParameters() {
+        List<TypeMirror> signaturetypes = new ArrayList<>();
+        int index = 0;
+        for (NodeExecutionData execution : node.getChildExecutions()) {
+            if (execution.isShortCircuit()) {
+                index++;
+            }
+            if (index < getEvaluatedCount()) {
+                signaturetypes.add(getEvaluatedParameters().get(index));
+            }
+            index++;
+        }
+        return signaturetypes;
+    }
+
     public int getVarArgsIndex(int parameterIndex) {
         if (method.isVarArgs()) {
             int index = parameterIndex - (method.getParameters().size() - 1);
@@ -159,7 +177,7 @@
         return evaluatedParameters.size();
     }
 
-    public boolean canDelegateTo(NodeData node, ExecutableTypeData to) {
+    public boolean canDelegateTo(ExecutableTypeData to) {
         ExecutableTypeData from = this;
         if (to.getEvaluatedCount() < from.getEvaluatedCount()) {
             return false;
@@ -189,8 +207,10 @@
             }
         }
 
-        for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) {
-            TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i);
+        List<TypeMirror> fromSignatureParameters = from.getSignatureParameters();
+        List<TypeMirror> toSignatureParameters = to.getSignatureParameters();
+        for (int i = fromSignatureParameters.size(); i < toSignatureParameters.size(); i++) {
+            TypeMirror delegateToParameter = toSignatureParameters.get(i);
             if (i < node.getChildExecutions().size()) {
                 TypeMirror genericType = node.getGenericType(node.getChildExecutions().get(i));
                 if (!isSubtypeBoxed(context, genericType, delegateToParameter)) {
@@ -206,6 +226,14 @@
         ExecutableTypeData o1 = this;
         ProcessorContext context = ProcessorContext.getInstance();
 
+        if (canDelegateTo(o2)) {
+            if (!o2.canDelegateTo(this)) {
+                return 1;
+            }
+        } else if (o2.canDelegateTo(this)) {
+            return -1;
+        }
+
         int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount());
         if (result != 0) {
             return result;
@@ -282,9 +310,22 @@
         }
     }
 
+    public String getName() {
+        if (method != null) {
+            return method.getSimpleName().toString();
+        } else {
+            return getUniqueName();
+        }
+
+    }
+
+    private static String formatType(TypeMirror type) {
+        return type == null ? "null" : ElementUtils.getSimpleName(type);
+    }
+
     @Override
     public String toString() {
-        return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString();
+        return String.format("%s %s(%s,%s)", formatType(getReturnType()), getName(), formatType(getFrameParameter()), getEvaluatedParameters());
     }
 
     public boolean sameParameters(ExecutableTypeData other) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Thu Apr 16 17:09:06 2015 +0200
@@ -134,8 +134,19 @@
         return types;
     }
 
+    public int getExecutionCount() {
+        return getChildExecutions().size();
+    }
+
     public int getSignatureSize() {
-        return getChildExecutions().size();
+        int count = 0;
+        for (NodeExecutionData execution : getChildExecutions()) {
+            if (execution.isShortCircuit()) {
+                count++;
+            }
+            count++;
+        }
+        return count;
     }
 
     public boolean isFrameUsedByAnyGuard() {
@@ -567,20 +578,17 @@
                 if (executable.hasUnexpectedValue(getContext())) {
                     continue;
                 }
-                if (!typeSystem.hasImplicitSourceTypes(executable.getReturnType())) {
-                    types.add(executable.getReturnType());
-                }
+                types.add(executable.getReturnType());
             }
         }
 
         int executionIndex = execution.getIndex();
         if (executionIndex >= 0) {
             for (ExecutableTypeData typeData : getExecutableTypes()) {
-                if (executionIndex < typeData.getEvaluatedCount()) {
-                    TypeMirror genericType = typeData.getEvaluatedParameters().get(executionIndex);
-                    if (!typeSystem.hasImplicitSourceTypes(genericType)) {
-                        types.add(genericType);
-                    }
+                List<TypeMirror> signatureParameters = typeData.getSignatureParameters();
+                if (executionIndex < signatureParameters.size()) {
+                    TypeMirror genericType = signatureParameters.get(executionIndex);
+                    types.add(genericType);
                 }
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Thu Apr 16 17:09:06 2015 +0200
@@ -59,6 +59,10 @@
         this.anyType = anyTypeTemp;
     }
 
+    public boolean isAnnotated() {
+        return false;
+    }
+
     public ParameterSpec(ParameterSpec original, TypeMirror newType) {
         this(original.name, newType);
         this.local = original.local;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Thu Apr 16 17:09:06 2015 +0200
@@ -167,14 +167,6 @@
         return kind == SpecializationKind.POLYMORPHIC;
     }
 
-    public List<Parameter> getDynamicParameters() {
-        List<Parameter> uncachedParameters = new ArrayList<>(getParameters());
-        for (CacheExpression cacheExpression : getCaches()) {
-            uncachedParameters.remove(cacheExpression.getParameter());
-        }
-        return uncachedParameters;
-    }
-
     @Override
     protected List<MessageContainer> findChildContainers() {
         List<MessageContainer> sinks = new ArrayList<>();
@@ -304,7 +296,7 @@
 
     @Override
     public String toString() {
-        return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature());
+        return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getDynamicTypes());
     }
 
     public boolean isFrameUsed() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Thu Apr 16 17:09:06 2015 +0200
@@ -153,6 +153,14 @@
         newParameter.setMethod(this);
     }
 
+    public Iterable<Parameter> getDynamicParameters() {
+        return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
+            public boolean evaluate(Parameter value) {
+                return !value.getSpecification().isLocal() && !value.getSpecification().isAnnotated();
+            }
+        });
+    }
+
     public Iterable<Parameter> getSignatureParameters() {
         return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
             public boolean evaluate(Parameter value) {
@@ -291,8 +299,8 @@
     }
 
     public int compareBySignature(TemplateMethod compareMethod) {
-        List<TypeMirror> signature1 = getSignatureTypes(this);
-        List<TypeMirror> signature2 = getSignatureTypes(compareMethod);
+        List<TypeMirror> signature1 = getDynamicTypes();
+        List<TypeMirror> signature2 = compareMethod.getDynamicTypes();
 
         int result = 0;
         for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) {
@@ -307,9 +315,9 @@
         return result;
     }
 
-    public static List<TypeMirror> getSignatureTypes(TemplateMethod method) {
+    public List<TypeMirror> getDynamicTypes() {
         List<TypeMirror> types = new ArrayList<>();
-        for (Parameter param : method.getSignatureParameters()) {
+        for (Parameter param : getDynamicParameters()) {
             types.add(param.getType());
         }
         return types;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Thu Apr 16 17:09:06 2015 +0200
@@ -134,7 +134,7 @@
             return null;
         }
         for (ImplicitCastData cast : getImplicitCasts()) {
-            if (cast.getSourceType().equals(sourceType) && cast.getTargetType().equals(targetType)) {
+            if (ElementUtils.typeEquals(cast.getSourceType(), sourceType) && ElementUtils.typeEquals(cast.getTargetType(), targetType)) {
                 return cast;
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Thu Apr 16 17:01:53 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Thu Apr 16 17:09:06 2015 +0200
@@ -148,7 +148,7 @@
         node.getFields().addAll(parseFields(lookupTypes, members));
         node.getChildren().addAll(parseChildren(lookupTypes, members));
         node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members));
-        node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false));
+        node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, node.getSignatureSize(), context.getFrameTypes(), false));
 
         initializeExecutableTypes(node);
         initializeImportGuards(node, lookupTypes, members);
@@ -188,8 +188,13 @@
         SpecializationData polymorphic = node.getPolymorphicSpecialization();
         if (polymorphic != null) {
             boolean polymorphicSignatureFound = false;
-            TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null;
-            ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic));
+            List<TypeMirror> dynamicTypes = polymorphic.getDynamicTypes();
+            TypeMirror frame = null;
+            if (polymorphic.getFrame() != null) {
+                frame = dynamicTypes.remove(0);
+            }
+
+            ExecutableTypeData polymorphicType = new ExecutableTypeData(node, polymorphic.getReturnType().getType(), "execute", frame, dynamicTypes);
             for (ExecutableTypeData type : node.getExecutableTypes()) {
                 if (polymorphicType.sameSignature(type)) {
                     polymorphicSignatureFound = true;
@@ -214,9 +219,11 @@
             }
         }
         if (!additionalAbstractRootTypes.isEmpty()) {
-            node.addError("Incompatible abstract execute methods found %s.", rootTypes);
+            node.addError("Incompatible abstract execute methods found %s.", additionalAbstractRootTypes);
         }
 
+        namesUnique(node.getExecutableTypes());
+
     }
 
     private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) {
@@ -235,7 +242,7 @@
     private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) {
         while (executesIterator.hasNext()) {
             ExecutableTypeData other = executesIterator.next();
-            if (other.canDelegateTo(node, parent)) {
+            if (other.canDelegateTo(parent)) {
                 parent.addDelegatedFrom(other);
                 executesIterator.remove();
             }
@@ -574,7 +581,7 @@
         return executions;
     }
 
-    private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
+    private List<ExecutableTypeData> parseExecutableTypeData(NodeData node, List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
         List<ExecutableTypeData> typeData = new ArrayList<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             Set<Modifier> modifiers = method.getModifiers();
@@ -592,7 +599,7 @@
                 continue;
             }
 
-            ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes());
+            ExecutableTypeData executableType = new ExecutableTypeData(node, method, signatureSize, context.getFrameTypes());
 
             if (executableType.getFrameParameter() != null) {
                 boolean supportedType = false;
@@ -610,8 +617,12 @@
             typeData.add(executableType);
         }
 
-        Collections.sort(typeData);
+        namesUnique(typeData);
 
+        return typeData;
+    }
+
+    private static void namesUnique(List<ExecutableTypeData> typeData) {
         List<String> names = new ArrayList<>();
         for (ExecutableTypeData type : typeData) {
             names.add(type.getUniqueName());
@@ -623,8 +634,6 @@
         for (int i = 0; i < typeData.size(); i++) {
             typeData.get(i).setUniqueName(names.get(i));
         }
-
-        return typeData;
     }
 
     private void initializeExecutableTypes(NodeData node) {
@@ -632,9 +641,7 @@
 
         Set<String> inconsistentFrameTypes = new HashSet<>();
         TypeMirror frameType = null;
-        Set<Integer> evaluatedCounts = new HashSet<>();
         for (ExecutableTypeData execute : allExecutes) {
-            evaluatedCounts.add(execute.getEvaluatedCount());
 
             TypeMirror frame = execute.getFrameParameter();
             TypeMirror resolvedFrameType;
@@ -788,7 +795,7 @@
         if (parentNode.getFrameType() != null) {
             frameTypes = Arrays.asList(parentNode.getFrameType());
         }
-        node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true));
+        node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, child.getExecuteWith().size(), frameTypes, true));
         node.setFrameType(parentNode.getFrameType());
         return node;
     }
@@ -1297,26 +1304,11 @@
         }
     }
 
-    private void initializeUninitialized(final NodeData node) {
+    private static void initializeUninitialized(final NodeData node) {
         SpecializationData generic = node.getGenericSpecialization();
         if (generic == null) {
             return;
         }
-        for (Parameter parameter : generic.getReturnTypeAndParameters()) {
-            if (ElementUtils.isObject(parameter.getType())) {
-                continue;
-            }
-            Set<String> types = new HashSet<>();
-            for (SpecializationData specialization : node.getSpecializations()) {
-                Parameter actualParameter = specialization.findParameter(parameter.getLocalName());
-                if (actualParameter != null) {
-                    types.add(ElementUtils.getQualifiedName(actualParameter.getType()));
-                }
-            }
-            if (types.size() > 1) {
-                generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class)));
-            }
-        }
         TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters());
         // should not use messages from generic specialization
         uninializedMethod.getMessages().clear();
@@ -1329,7 +1321,6 @@
         }
 
         SpecializationData generic = node.getGenericSpecialization();
-
         List<VariableElement> types = new ArrayList<>();
 
         Collection<TypeMirror> frameTypes = new HashSet<>();
@@ -1338,6 +1329,10 @@
                 frameTypes.add(specialization.getFrame().getType());
             }
         }
+        if (node.supportsFrame()) {
+            frameTypes.add(node.getFrameType());
+        }
+
         if (!frameTypes.isEmpty()) {
             frameTypes = ElementUtils.uniqueSortedTypes(frameTypes);
             TypeMirror frameType;
@@ -1378,13 +1373,15 @@
 
                 if (usedTypes.size() == 1) {
                     polymorphicType = usedTypes.iterator().next();
+                } else {
+                    polymorphicType = ElementUtils.getCommonSuperType(context, usedTypes);
+                }
 
-                    if (!isReturnParameter && node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) {
-                        polymorphicType = context.getType(Object.class);
-                    }
-                } else {
-                    polymorphicType = context.getType(Object.class);
+                NodeExecutionData execution = genericParameter.getSpecification().getExecution();
+                if (execution != null && !ElementUtils.isSubtypeBoxed(context, polymorphicType, node.getGenericType(execution))) {
+                    throw new AssertionError(String.format("Polymorphic types %s not compatible to generic type %s.", polymorphicType, node.getGenericType(execution)));
                 }
+
             }
             if (isReturnParameter) {
                 returnType = polymorphicType;
@@ -1395,8 +1392,11 @@
         }
 
         SpecializationMethodParser parser = new SpecializationMethodParser(context, node);
+        SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
+        if (polymorphic == null) {
+            throw new AssertionError("Failed to parse polymorphic signature. " + parser.createDefaultMethodSpec(null, null, false, null) + " Types: " + returnType + " - " + types);
+        }
 
-        SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
         polymorphic.setKind(SpecializationKind.POLYMORPHIC);
         node.getSpecializations().add(polymorphic);
     }
--- a/mx/mx_graal.py	Thu Apr 16 17:01:53 2015 +0200
+++ b/mx/mx_graal.py	Thu Apr 16 17:09:06 2015 +0200
@@ -1543,7 +1543,7 @@
 
     with VM('graal', 'product'):
         with Task('BootstrapWithRegisterPressure:product', tasks) as t:
-            if t: 
+            if t:
                 registers = 'o0,o1,o2,o3,f8,f9,d32,d34' if platform.processor() == 'sparc' else 'rbx,r11,r10,r14,xmm3,xmm11,xmm14'
                 vm(['-XX:-TieredCompilation', '-G:RegisterPressure=' + registers, '-esa', '-version'])
 
@@ -2160,7 +2160,7 @@
         'intel/hsdis-amd64.dll' : '6a388372cdd5fe905c1a26ced614334e405d1f30',
         'intel/hsdis-amd64.so' : '844ed9ffed64fe9599638f29a8450c50140e3192',
         'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
-        'sparcv9/hsdis-sparcv9.so': '5f79c312b3dcc55bad551dbb710b11f0048a4ce7',
+        'sparcv9/hsdis-sparcv9.so': '970640a9af0bd63641f9063c11275b371a59ee60',
     }
 
     flavoredLib = flavor + "/" + lib
--- a/mxtool/mx.py	Thu Apr 16 17:01:53 2015 +0200
+++ b/mxtool/mx.py	Thu Apr 16 17:09:06 2015 +0200
@@ -2115,6 +2115,7 @@
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
         self.pack200 = exe_suffix(join(self.jdk, 'bin', 'pack200'))
         self.toolsjar = join(self.jdk, 'lib', 'tools.jar')
+        self._classpaths_initialized = False
         self._bootclasspath = None
         self._extdirs = None
         self._endorseddirs = None
@@ -2158,22 +2159,24 @@
             self.java_args += ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(self.debug_port)]
 
     def _init_classpaths(self):
-        myDir = dirname(__file__)
-        outDir = join(dirname(__file__), '.jdk' + str(self.version))
-        if not exists(outDir):
-            os.makedirs(outDir)
-        javaSource = join(myDir, 'ClasspathDump.java')
-        javaClass = join(outDir, 'ClasspathDump.class')
-        if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
-            subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
-        self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
-        if self.javaCompliance <= JavaCompliance('1.8'):
-            # All 3 system properties accessed by ClasspathDump are expected to exist
-            if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
-                warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
-        self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
-        self._extdirs = _filter_non_existant_paths(self._extdirs)
-        self._endorseddirs = _filter_non_existant_paths(self._endorseddirs)
+        if not self._classpaths_initialized:
+            myDir = dirname(__file__)
+            outDir = join(dirname(__file__), '.jdk' + str(self.version))
+            if not exists(outDir):
+                os.makedirs(outDir)
+            javaSource = join(myDir, 'ClasspathDump.java')
+            javaClass = join(outDir, 'ClasspathDump.class')
+            if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
+                subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
+            self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
+            if self.javaCompliance <= JavaCompliance('1.8'):
+                # All 3 system properties accessed by ClasspathDump are expected to exist
+                if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
+                    warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
+            self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
+            self._extdirs = _filter_non_existant_paths(self._extdirs)
+            self._endorseddirs = _filter_non_existant_paths(self._endorseddirs)
+            self._classpaths_initialized = True
 
     def __repr__(self):
         return "JavaConfig(" + str(self.jdk) + ", " + str(self.debug_port) + ")"
@@ -2205,35 +2208,23 @@
         return self.java_args_pfx + self.java_args + self.java_args_sfx + args
 
     def bootclasspath(self):
-        if self._bootclasspath is None:
-            self._init_classpaths()
+        self._init_classpaths()
         return _separatedCygpathU2W(self._bootclasspath)
 
-    def extdirs(self):
-        if self._extdirs is None:
-            self._init_classpaths()
-        return _separatedCygpathU2W(self._extdirs)
-
-    def endorseddirs(self):
-        if self._endorseddirs is None:
-            self._init_classpaths()
-        return _separatedCygpathU2W(self._endorseddirs)
 
     """
     Add javadoc style options for the library paths of this JDK.
     """
     def javadocLibOptions(self, args):
+        self._init_classpaths()
         if args is None:
             args = []
-        if self.bootclasspath():
+        if self._bootclasspath:
             args.append('-bootclasspath')
-            args.append(self.bootclasspath())
-        if self.endorseddirs():
-            args.append('-endorseddirs')
-            args.append(self.endorseddirs())
-        if self.extdirs():
+            args.append(self._bootclasspath)
+        if self._extdirs:
             args.append('-extdirs')
-            args.append(self.extdirs())
+            args.append(self._extdirs)
         return args
 
     """
@@ -2241,24 +2232,26 @@
     """
     def javacLibOptions(self, args):
         args = self.javadocLibOptions(args)
-        if self.endorseddirs():
+        if self._endorseddirs:
             args.append('-endorseddirs')
-            args.append(self.endorseddirs())
+            args.append(self._endorseddirs)
         return args
 
     def containsJar(self, jar):
-        if self._bootclasspath is None:
-            self._init_classpaths()
-
-        for e in self._bootclasspath.split(os.pathsep):
-            if basename(e) == jar:
-                return True
-        for d in self._extdirs.split(os.pathsep):
-            if len(d) and jar in os.listdir(d):
-                return True
-        for d in self._endorseddirs.split(os.pathsep):
-            if len(d) and jar in os.listdir(d):
-                return True
+        self._init_classpaths()
+
+        if self._bootclasspath:
+            for e in self._bootclasspath.split(os.pathsep):
+                if basename(e) == jar:
+                    return True
+        if self._extdirs:
+            for d in self._extdirs.split(os.pathsep):
+                if len(d) and jar in os.listdir(d):
+                    return True
+        if self._endorseddirs:
+            for d in self._endorseddirs.split(os.pathsep):
+                if len(d) and jar in os.listdir(d):
+                    return True
         return False
 
 def check_get_env(key):
@@ -4873,7 +4866,7 @@
                      '-overview', overviewFile,
                      '-sourcepath', sp,
                      '-source', str(projectJava.javaCompliance)] +
-                     projectJava.javadocLibOptions() +
+                     projectJava.javadocLibOptions([]) +
                      ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/x86/vm/registerMap_x86.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include <runtime/registerMap.hpp>
+#include "vmreg_x86.inline.hpp"
+
+address RegisterMap::pd_location(VMReg reg) const {
+  if (reg->is_XMMRegister()) {
+    int regBase = reg->value() - ConcreteRegisterImpl::max_fpr;
+    if (regBase % 4 == 0) {
+      // Reads of the low and high 16 byte parts should be handled by location itself
+      return NULL;
+    }
+    VMReg baseReg = as_XMMRegister(regBase >> 3)->as_VMReg();
+    intptr_t offset = (reg->value() - baseReg->value()) * 4;
+    if (offset >= 16) {
+      // The high part of YMM registers are saved in a their own area in the frame
+      baseReg = baseReg->next()->next()->next()->next();
+      offset -= 16;
+    }
+    address baseLocation = location(baseReg);
+    if (baseLocation != NULL) {
+      return baseLocation + offset;
+    }
+  }
+  return NULL;
+}
--- a/src/cpu/x86/vm/registerMap_x86.hpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/cpu/x86/vm/registerMap_x86.hpp	Thu Apr 16 17:09:06 2015 +0200
@@ -31,11 +31,7 @@
  private:
   // This is the hook for finding a register in an "well-known" location,
   // such as a register block of a predetermined format.
-  // Since there is none, we just return NULL.
-  // See registerMap_sparc.hpp for an example of grabbing registers
-  // from register save areas of a standard layout.
-   address pd_location(VMReg reg) const {return NULL;}
-
+  address pd_location(VMReg reg) const;
   // no PD state to clear or copy:
   void pd_clear() {}
   void pd_initialize() {}
--- a/src/cpu/x86/vm/register_x86.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/cpu/x86/vm/register_x86.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -64,3 +64,28 @@
   };
   return is_valid() ? names[encoding()] : "xnoreg";
 }
+
+const char* XMMRegisterImpl::sub_word_name(int i) const {
+  const char* names[number_of_registers * 8] = {
+      "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7",
+      "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7",
+      "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7",
+      "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7",
+      "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7",
+      "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7",
+      "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7",
+      "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7",
+#ifdef AMD64
+      "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7",
+      "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7",
+      "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7",
+      "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7",
+      "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7",
+      "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7",
+      "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7",
+      "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7",
+#endif // AMD64
+  };
+  assert(i >= 0 && i < 8, "offset too large");
+  return is_valid() ? names[encoding() * 8 + i] : "xnoreg";
+}
--- a/src/cpu/x86/vm/register_x86.hpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/cpu/x86/vm/register_x86.hpp	Thu Apr 16 17:09:06 2015 +0200
@@ -161,6 +161,7 @@
   int   encoding() const                          { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; }
   bool  is_valid() const                          { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
   const char* name() const;
+  const char* sub_word_name(int offset) const;
 };
 
 
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -70,9 +70,32 @@
   // Capture info about frame layout.  Layout offsets are in jint
   // units because compiler frame slots are jints.
 #define DEF_XMM_OFFS(regnum) xmm ## regnum ## _off = xmm_off + (regnum)*16/BytesPerInt, xmm ## regnum ## H_off
+#define DEF_YMM_HI_OFFS(regnum) ymm_hi ## regnum ## _off = ymm_off + (regnum)*16/BytesPerInt
   enum layout {
     fpu_state_off = frame::arg_reg_save_area_bytes/BytesPerInt, // fxsave save area
-    xmm_off       = fpu_state_off + 160/BytesPerInt,            // offset in fxsave save area
+#if defined(COMPILER2) || defined(GRAAL)
+    ymm_off       = fpu_state_off,            // offset in fxsave save area
+    DEF_YMM_HI_OFFS(0),
+    DEF_YMM_HI_OFFS(1),
+    DEF_YMM_HI_OFFS(2),
+    DEF_YMM_HI_OFFS(3),
+    DEF_YMM_HI_OFFS(4),
+    DEF_YMM_HI_OFFS(5),
+    DEF_YMM_HI_OFFS(6),
+    DEF_YMM_HI_OFFS(7),
+    DEF_YMM_HI_OFFS(8),
+    DEF_YMM_HI_OFFS(9),
+    DEF_YMM_HI_OFFS(10),
+    DEF_YMM_HI_OFFS(11),
+    DEF_YMM_HI_OFFS(12),
+    DEF_YMM_HI_OFFS(13),
+    DEF_YMM_HI_OFFS(14),
+    DEF_YMM_HI_OFFS(15),
+    ymm_hi_save_size = 16 * 16 / BytesPerInt,
+#else
+    ymm_hi_save_size = 0,
+#endif
+    xmm_off       = fpu_state_off + 160/BytesPerInt + ymm_hi_save_size,            // offset in fxsave save area
     DEF_XMM_OFFS(0),
     DEF_XMM_OFFS(1),
     DEF_XMM_OFFS(2),
@@ -89,7 +112,7 @@
     DEF_XMM_OFFS(13),
     DEF_XMM_OFFS(14),
     DEF_XMM_OFFS(15),
-    fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt),
+    fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt) + ymm_hi_save_size,
     fpu_stateH_end,
     r15_off, r15H_off,
     r14_off, r14H_off,
@@ -139,19 +162,6 @@
 };
 
 OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) {
-  int vect_words = 0;
-#ifdef COMPILER2
-  if (save_vectors) {
-    assert(UseAVX > 0, "256bit vectors are supported only with AVX");
-    assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
-    // Save upper half of YMM registes
-    vect_words = 16 * 16 / wordSize;
-    additional_frame_words += vect_words;
-  }
-#else
-  assert(!save_vectors, "vectors are generated only by C2");
-#endif
-
   // Always make the frame size 16-byte aligned
   int frame_size_in_bytes = round_to(additional_frame_words*wordSize +
                                      reg_save_size*BytesPerInt, 16);
@@ -172,26 +182,34 @@
   __ enter();          // rsp becomes 16-byte aligned here
   __ push_CPU_state(); // Push a multiple of 16 bytes
 
-  if (vect_words > 0) {
-    assert(vect_words*wordSize == 256, "");
-    __ subptr(rsp, 256); // Save upper half of YMM registes
-    __ vextractf128h(Address(rsp,  0),xmm0);
-    __ vextractf128h(Address(rsp, 16),xmm1);
-    __ vextractf128h(Address(rsp, 32),xmm2);
-    __ vextractf128h(Address(rsp, 48),xmm3);
-    __ vextractf128h(Address(rsp, 64),xmm4);
-    __ vextractf128h(Address(rsp, 80),xmm5);
-    __ vextractf128h(Address(rsp, 96),xmm6);
-    __ vextractf128h(Address(rsp,112),xmm7);
-    __ vextractf128h(Address(rsp,128),xmm8);
-    __ vextractf128h(Address(rsp,144),xmm9);
-    __ vextractf128h(Address(rsp,160),xmm10);
-    __ vextractf128h(Address(rsp,176),xmm11);
-    __ vextractf128h(Address(rsp,192),xmm12);
-    __ vextractf128h(Address(rsp,208),xmm13);
-    __ vextractf128h(Address(rsp,224),xmm14);
-    __ vextractf128h(Address(rsp,240),xmm15);
+#if defined(COMPILER2) || defined(GRAAL)
+  __ subptr(rsp, 256); // Save upper half of YMM registers
+  if (save_vectors) {
+    assert(UseAVX > 0, "256bit vectors are supported only with AVX");
+#ifdef COMPILER2
+    assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
+#endif
+    // Save upper half of YMM registers
+    __ vextractf128h(Address(rsp, ymm_hi0_off * BytesPerInt),  xmm0);
+    __ vextractf128h(Address(rsp, ymm_hi1_off * BytesPerInt),  xmm1);
+    __ vextractf128h(Address(rsp, ymm_hi2_off * BytesPerInt),  xmm2);
+    __ vextractf128h(Address(rsp, ymm_hi3_off * BytesPerInt),  xmm3);
+    __ vextractf128h(Address(rsp, ymm_hi4_off * BytesPerInt),  xmm4);
+    __ vextractf128h(Address(rsp, ymm_hi5_off * BytesPerInt),  xmm5);
+    __ vextractf128h(Address(rsp, ymm_hi6_off * BytesPerInt),  xmm6);
+    __ vextractf128h(Address(rsp, ymm_hi7_off * BytesPerInt),  xmm7);
+    __ vextractf128h(Address(rsp, ymm_hi8_off * BytesPerInt),  xmm8);
+    __ vextractf128h(Address(rsp, ymm_hi9_off * BytesPerInt),  xmm9);
+    __ vextractf128h(Address(rsp, ymm_hi10_off * BytesPerInt), xmm10);
+    __ vextractf128h(Address(rsp, ymm_hi11_off * BytesPerInt), xmm11);
+    __ vextractf128h(Address(rsp, ymm_hi12_off * BytesPerInt), xmm12);
+    __ vextractf128h(Address(rsp, ymm_hi13_off * BytesPerInt), xmm13);
+    __ vextractf128h(Address(rsp, ymm_hi14_off * BytesPerInt), xmm14);
+    __ vextractf128h(Address(rsp, ymm_hi15_off * BytesPerInt), xmm15);
   }
+#else
+  assert(!save_vectors, "vectors are generated only by C2 and Graal");
+#endif
   if (frame::arg_reg_save_area_bytes != 0) {
     // Allocate argument register save area
     __ subptr(rsp, frame::arg_reg_save_area_bytes);
@@ -240,6 +258,28 @@
   map->set_callee_saved(STACK_OFFSET(xmm14_off), xmm14->as_VMReg());
   map->set_callee_saved(STACK_OFFSET(xmm15_off), xmm15->as_VMReg());
 
+
+#if defined(COMPILER2) || defined(GRAAL)
+  if (save_vectors) {
+    map->set_callee_saved(STACK_OFFSET(ymm_hi0_off ), xmm0->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi1_off ), xmm1->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi2_off ), xmm2->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi3_off ), xmm3->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi4_off ), xmm4->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi5_off ), xmm5->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi6_off ), xmm6->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi7_off ), xmm7->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi8_off ), xmm8->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi9_off ), xmm9->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi10_off), xmm10->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi11_off), xmm11->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi12_off), xmm12->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi13_off), xmm13->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi14_off), xmm14->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi15_off), xmm15->as_VMReg()->next()->next()->next()->next());
+  }
+#endif
+
   // %%% These should all be a waste but we'll keep things as they were for now
   if (true) {
     map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next());
@@ -283,31 +323,33 @@
     // Pop arg register save area
     __ addptr(rsp, frame::arg_reg_save_area_bytes);
   }
-#ifdef COMPILER2
+#if defined(COMPILER2) || defined(GRAAL)
   if (restore_vectors) {
     // Restore upper half of YMM registes.
     assert(UseAVX > 0, "256bit vectors are supported only with AVX");
+#if defined(COMPILER2)
     assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
-    __ vinsertf128h(xmm0, Address(rsp,  0));
-    __ vinsertf128h(xmm1, Address(rsp, 16));
-    __ vinsertf128h(xmm2, Address(rsp, 32));
-    __ vinsertf128h(xmm3, Address(rsp, 48));
-    __ vinsertf128h(xmm4, Address(rsp, 64));
-    __ vinsertf128h(xmm5, Address(rsp, 80));
-    __ vinsertf128h(xmm6, Address(rsp, 96));
-    __ vinsertf128h(xmm7, Address(rsp,112));
-    __ vinsertf128h(xmm8, Address(rsp,128));
-    __ vinsertf128h(xmm9, Address(rsp,144));
-    __ vinsertf128h(xmm10, Address(rsp,160));
-    __ vinsertf128h(xmm11, Address(rsp,176));
-    __ vinsertf128h(xmm12, Address(rsp,192));
-    __ vinsertf128h(xmm13, Address(rsp,208));
-    __ vinsertf128h(xmm14, Address(rsp,224));
-    __ vinsertf128h(xmm15, Address(rsp,240));
-    __ addptr(rsp, 256);
+#endif
+    __ vinsertf128h(xmm0,  Address(rsp, ymm_hi0_off * BytesPerInt));
+    __ vinsertf128h(xmm1,  Address(rsp, ymm_hi1_off * BytesPerInt));
+    __ vinsertf128h(xmm2,  Address(rsp, ymm_hi2_off * BytesPerInt));
+    __ vinsertf128h(xmm3,  Address(rsp, ymm_hi3_off * BytesPerInt));
+    __ vinsertf128h(xmm4,  Address(rsp, ymm_hi4_off * BytesPerInt));
+    __ vinsertf128h(xmm5,  Address(rsp, ymm_hi5_off * BytesPerInt));
+    __ vinsertf128h(xmm6,  Address(rsp, ymm_hi6_off * BytesPerInt));
+    __ vinsertf128h(xmm7,  Address(rsp, ymm_hi7_off * BytesPerInt));
+    __ vinsertf128h(xmm8,  Address(rsp, ymm_hi8_off * BytesPerInt));
+    __ vinsertf128h(xmm9,  Address(rsp, ymm_hi9_off * BytesPerInt));
+    __ vinsertf128h(xmm10, Address(rsp, ymm_hi10_off * BytesPerInt));
+    __ vinsertf128h(xmm11, Address(rsp, ymm_hi11_off * BytesPerInt));
+    __ vinsertf128h(xmm12, Address(rsp, ymm_hi12_off * BytesPerInt));
+    __ vinsertf128h(xmm13, Address(rsp, ymm_hi13_off * BytesPerInt));
+    __ vinsertf128h(xmm14, Address(rsp, ymm_hi14_off * BytesPerInt));
+    __ vinsertf128h(xmm15, Address(rsp, ymm_hi15_off * BytesPerInt));
   }
+  __ addptr(rsp, 256);
 #else
-  assert(!restore_vectors, "vectors are generated only by C2");
+  assert(!restore_vectors, "vectors are generated only by C2 and Graal");
 #endif
   // Recover CPU state
   __ pop_CPU_state();
--- a/src/cpu/x86/vm/vmreg_x86.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/cpu/x86/vm/vmreg_x86.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -48,8 +48,9 @@
 
   XMMRegister xreg = ::as_XMMRegister(0);
   for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
-    for (int j = 0 ; j < 8 ; j++) {
-      regName[i++] = xreg->name();
+    regName[i++] = xreg->name();
+    for (int j = 1 ; j < 8 ; j++) {
+      regName[i++] = xreg->sub_word_name(j);
     }
     xreg = xreg->successor();
   }
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Apr 16 17:09:06 2015 +0200
@@ -208,6 +208,7 @@
   GRAAL_ONLY(do_klass(HotSpotCompiledRuntimeStub_klass,      com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,          Graal)) \
   GRAAL_ONLY(do_klass(HotSpotForeignCallLinkageImpl_klass,   com_oracle_graal_hotspot_HotSpotForeignCallLinkageImpl,       Graal)) \
   GRAAL_ONLY(do_klass(HotSpotReferenceMap_klass,             com_oracle_graal_hotspot_HotSpotReferenceMap,                 Graal)) \
+  GRAAL_ONLY(do_klass(HotSpotOopMap_klass,                   com_oracle_graal_hotspot_HotSpotReferenceMap_HotSpotOopMap,   Graal)) \
   GRAAL_ONLY(do_klass(HotSpotInstalledCode_klass,            com_oracle_graal_hotspot_meta_HotSpotInstalledCode,           Graal)) \
   GRAAL_ONLY(do_klass(HotSpotNmethod_klass,                  com_oracle_graal_hotspot_meta_HotSpotNmethod,                 Graal)) \
   GRAAL_ONLY(do_klass(HotSpotResolvedJavaMethodImpl_klass,   com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethodImpl,  Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu Apr 16 17:09:06 2015 +0200
@@ -310,6 +310,7 @@
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotCompiledRuntimeStub,      "com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub"))           \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotForeignCallLinkageImpl,   "com/oracle/graal/hotspot/HotSpotForeignCallLinkageImpl"))        \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotReferenceMap,             "com/oracle/graal/hotspot/HotSpotReferenceMap"))                  \
+  GRAAL_ONLY(template(com_oracle_graal_hotspot_HotSpotReferenceMap_HotSpotOopMap, "com/oracle/graal/hotspot/HotSpotReferenceMap$HotSpotOopMap"))  \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_bridge_CompilerToVMImpl,         "com/oracle/graal/hotspot/bridge/CompilerToVMImpl"))              \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotInstalledCode,       "com/oracle/graal/hotspot/meta/HotSpotInstalledCode"))            \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotNmethod,             "com/oracle/graal/hotspot/meta/HotSpotNmethod"))                  \
--- a/src/share/vm/compiler/oopMap.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/compiler/oopMap.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -388,68 +388,71 @@
       do {
         omv = oms.current();
         oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
-        if ( loc != NULL ) {
-          oop *base_loc    = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
-          oop *derived_loc = loc;
-          oop val = *base_loc;
-          if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
-            // Ignore NULL oops and decoded NULL narrow oops which
-            // equal to Universe::narrow_oop_base when a narrow oop
-            // implicit null check is used in compiled code.
-            // The narrow_oop_base could be NULL or be the address
-            // of the page below heap depending on compressed oops mode.
-          } else
-            derived_oop_fn(base_loc, derived_loc);
+        guarantee(loc != NULL, "missing saved register");
+        oop *base_loc    = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
+        oop *derived_loc = loc;
+        oop val = *base_loc;
+        if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
+          // Ignore NULL oops and decoded NULL narrow oops which
+          // equal to Universe::narrow_oop_base when a narrow oop
+          // implicit null check is used in compiled code.
+          // The narrow_oop_base could be NULL or be the address
+          // of the page below heap depending on compressed oops mode.
+        } else {
+          derived_oop_fn(base_loc, derived_loc);
         }
         oms.next();
       }  while (!oms.is_done());
     }
   }
 
-  // We want coop, value and oop oop_types
+  // We want narrowoop and oop oop_types
   int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value;
   {
     for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {
       omv = oms.current();
       oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
-      if ( loc != NULL ) {
-        if ( omv.type() == OopMapValue::oop_value ) {
-          oop val = *loc;
-          if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
-            // Ignore NULL oops and decoded NULL narrow oops which
-            // equal to Universe::narrow_oop_base when a narrow oop
-            // implicit null check is used in compiled code.
-            // The narrow_oop_base could be NULL or be the address
-            // of the page below heap depending on compressed oops mode.
-            continue;
-          }
+      // It should be an error if no location can be found for a
+      // register mentioned as contained an oop of some kind.  Maybe
+      // this was allowed previously because value_value items might
+      // be missing?
+      guarantee(loc != NULL, "missing saved register");
+      if ( omv.type() == OopMapValue::oop_value ) {
+        oop val = *loc;
+        if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
+          // Ignore NULL oops and decoded NULL narrow oops which
+          // equal to Universe::narrow_oop_base when a narrow oop
+          // implicit null check is used in compiled code.
+          // The narrow_oop_base could be NULL or be the address
+          // of the page below heap depending on compressed oops mode.
+          continue;
+        }
 #ifdef ASSERT
-          if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
-             !Universe::heap()->is_in_or_null(*loc)) {
-            tty->print_cr("# Found non oop pointer.  Dumping state at failure");
-            // try to dump out some helpful debugging information
-            trace_codeblob_maps(fr, reg_map);
-            omv.print();
-            tty->print_cr("register r");
-            omv.reg()->print();
-            tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
-            // do the real assert.
-            assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
-          }
+        if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
+            !Universe::heap()->is_in_or_null(*loc)) {
+          tty->print_cr("# Found non oop pointer.  Dumping state at failure");
+          // try to dump out some helpful debugging information
+          trace_codeblob_maps(fr, reg_map);
+          omv.print();
+          tty->print_cr("register r");
+          omv.reg()->print();
+          tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
+          // do the real assert.
+          assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
+        }
 #endif // ASSERT
-          oop_fn->do_oop(loc);
-        } else if ( omv.type() == OopMapValue::narrowoop_value ) {
-          narrowOop *nl = (narrowOop*)loc;
+        oop_fn->do_oop(loc);
+      } else if ( omv.type() == OopMapValue::narrowoop_value ) {
+        narrowOop *nl = (narrowOop*)loc;
 #ifndef VM_LITTLE_ENDIAN
-          if (!omv.reg()->is_stack()) {
-            // compressed oops in registers only take up 4 bytes of an
-            // 8 byte register but they are in the wrong part of the
-            // word so adjust loc to point at the right place.
-            nl = (narrowOop*)((address)nl + 4);
-          }
+        if (!omv.reg()->is_stack()) {
+          // compressed oops in registers only take up 4 bytes of an
+          // 8 byte register but they are in the wrong part of the
+          // word so adjust loc to point at the right place.
+          nl = (narrowOop*)((address)nl + 4);
+        }
 #endif
-          oop_fn->do_oop(nl);
-        }
+        oop_fn->do_oop(nl);
       }
     }
   }
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -71,35 +71,39 @@
 
 const int MapWordBits = 64;
 
-static bool is_bit_set(typeArrayOop words, int i) {
+static int entry_value(typeArrayOop words, int i) {
   jint words_idx = i / MapWordBits;
   assert(words_idx >= 0 && words_idx < words->length(), "unexpected index");
   jlong word = words->long_at(words_idx);
-  return (word & (1LL << (i % MapWordBits))) != 0;
+  return (word >> (i % MapWordBits)) & 15LL;
 }
 
-static int bitset_size(oop bitset) {
-  typeArrayOop arr = BitSet::words(bitset);
+static int fixedmap_size(oop bitset) {
+  typeArrayOop arr = HotSpotOopMap::words(bitset);
   return arr->length() * MapWordBits;
 }
 
 static void set_vmreg_oops(OopMap* map, VMReg reg, typeArrayOop words, int idx) {
-  bool is_oop = is_bit_set(words, 3 * idx);
-  if (is_oop) {
-    bool narrow1 = is_bit_set(words, 3 * idx + 1);
-    bool narrow2 = is_bit_set(words, 3 * idx + 2);
-    if (narrow1 || narrow2) {
-      if (narrow1) {
-        map->set_narrowoop(reg);
-      }
-      if (narrow2) {
-        map->set_narrowoop(reg->next());
-      }
-    } else {
+  int value = entry_value(words, 4 * idx);
+  switch (value) {
+    case 10:
       map->set_oop(reg);
-    }
-  } else {
-    map->set_value(reg);
+      break;
+    case 5:
+      map->set_narrowoop(reg);
+      map->set_narrowoop(reg->next());
+      break;
+    case 1:
+      map->set_narrowoop(reg);
+      break;
+    case 4:
+      map->set_narrowoop(reg->next());
+      break;
+    case 0:
+      break;
+    default:
+      assert(false, err_msg("unexpected bit pattern at %d = 0x%x", idx, value));
+      ShouldNotReachHere();
   }
 }
 
@@ -112,30 +116,30 @@
   oop callee_save_info = (oop) DebugInfo::calleeSaveInfo(debug_info);
 
   if (register_map != NULL) {
-    typeArrayOop words = BitSet::words(register_map);
+    typeArrayOop words = HotSpotOopMap::words(register_map);
+    int mapIdx = 0;
     for (jint i = 0; i < RegisterImpl::number_of_registers; i++) {
-      set_vmreg_oops(map, as_Register(i)->as_VMReg(), words, i);
+      set_vmreg_oops(map, as_Register(i)->as_VMReg(), words, mapIdx);
+      mapIdx++;
     }
 #ifdef TARGET_ARCH_x86
     for (jint i = 0; i < XMMRegisterImpl::number_of_registers; i++) {
       VMReg reg = as_XMMRegister(i)->as_VMReg();
-      int idx = RegisterImpl::number_of_registers + 4 * i;
       for (jint j = 0; j < 4; j++) {
-        set_vmreg_oops(map, reg->next(2 * j), words, idx + j);
+        set_vmreg_oops(map, reg->next(2 * j), words, mapIdx++);
       }
     }
 #endif
 #ifdef TARGET_ARCH_sparc
     for (jint i = 0; i < FloatRegisterImpl::number_of_registers; i++) {
       VMReg reg = as_FloatRegister(i)->as_VMReg();
-      int idx = RegisterImpl::number_of_registers + i;
-      set_vmreg_oops(map, reg, words, idx);
+      set_vmreg_oops(map, reg, words, mapIdx++);
     }
 #endif
   }
 
-  typeArrayOop words = BitSet::words(frame_map);
-  int size = bitset_size(frame_map) / 3;
+  typeArrayOop words = HotSpotOopMap::words(frame_map);
+  int size = fixedmap_size(frame_map) / 4;
   for (jint i = 0; i < size; i++) {
     // HotSpot stack slots are 4 bytes
     VMReg reg = VMRegImpl::stack2reg(i * VMRegImpl::slots_per_word);
@@ -161,7 +165,6 @@
 #endif
     }
   }
-
   return map;
 }
 
--- a/src/share/vm/graal/graalEnv.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/graal/graalEnv.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -546,6 +546,12 @@
         }
       } else {
         nm->set_has_unsafe_access(has_unsafe_access);
+#ifdef TARGET_ARCH_x86
+        // It might be preferable to set this only for methods which
+        // use vector instructions but we currently don't track this
+        // and it probably wouldn't make much difference.
+        nm->set_has_wide_vectors(UseAVX >= 2);
+#endif
 
         // Record successful registration.
         // (Put nm into the task handle *before* publishing to the Java heap.)
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Thu Apr 16 17:09:06 2015 +0200
@@ -162,15 +162,15 @@
     objArrayOop_field(DebugInfo, virtualObjectMapping, "[Lcom/oracle/graal/api/meta/Value;")                                                                   \
   end_class                                                                                                                                                    \
   start_class(HotSpotReferenceMap)                                                                                                                             \
-    oop_field(HotSpotReferenceMap, registerRefMap, "Ljava/util/BitSet;")                                                                                       \
-    oop_field(HotSpotReferenceMap, frameRefMap, "Ljava/util/BitSet;")                                                                                          \
+    oop_field(HotSpotReferenceMap, registerRefMap, "Lcom/oracle/graal/hotspot/HotSpotReferenceMap$HotSpotOopMap;")                                             \
+    oop_field(HotSpotReferenceMap, frameRefMap, "Lcom/oracle/graal/hotspot/HotSpotReferenceMap$HotSpotOopMap;")                                                \
   end_class                                                                                                                                                    \
   start_class(RegisterSaveLayout)                                                                                                                              \
     objArrayOop_field(RegisterSaveLayout, registers, "[Lcom/oracle/graal/api/code/Register;")                                                                  \
     typeArrayOop_field(RegisterSaveLayout, slots, "[I")                                                                                                        \
   end_class                                                                                                                                                    \
-  start_class(BitSet)                                                                                                                                          \
-    typeArrayOop_field(BitSet, words, "[J")                                                                                                                    \
+  start_class(HotSpotOopMap)                                                                                                                                   \
+    typeArrayOop_field(HotSpotOopMap, words, "[J")                                                                                                             \
   end_class                                                                                                                                                    \
   start_class(BytecodeFrame)                                                                                                                                   \
     objArrayOop_field(BytecodeFrame, values, "[Lcom/oracle/graal/api/meta/Value;")                                                                             \
--- a/src/share/vm/runtime/sharedRuntime.cpp	Thu Apr 16 17:01:53 2015 +0200
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Thu Apr 16 17:09:06 2015 +0200
@@ -111,9 +111,14 @@
   _resolve_virtual_call_blob           = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),       "resolve_virtual_call");
   _resolve_static_call_blob            = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),        "resolve_static_call");
 
+#if defined(COMPILER2) || defined(GRAAL)
+  // Vectors are generated only by C2 and Graal.
 #ifdef COMPILER2
-  // Vectors are generated only by C2.
-  if (is_wide_vector(MaxVectorSize)) {
+  bool support_wide = is_wide_vector(MaxVectorSize) || IS_GRAAL_DEFINED;
+#else
+  bool support_wide = true;
+#endif
+  if (support_wide) {
     _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP);
   }
 #endif // COMPILER2