changeset 20981:92fc95e8667d

Add more efficient implementation of HotSpotReferenceMap
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 15 Apr 2015 10:09:13 -0700
parents abc059cb0acf
children 23d6b95bd687
files graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java src/share/vm/classfile/systemDictionary.hpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/graal/graalCodeInstaller.cpp src/share/vm/graal/graalJavaAccess.hpp
diffstat 7 files changed, 460 insertions(+), 243 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Tue Apr 14 11:37:24 2015 -0700
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ReferenceMap.java	Wed Apr 15 10:09:13 2015 -0700
@@ -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.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Tue Apr 14 11:37:24 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReferenceMap.java	Wed Apr 15 10:09:13 2015 -0700
@@ -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	Tue Apr 14 11:37:24 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotTargetDescription.java	Wed Apr 15 10:09:13 2015 -0700
@@ -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/src/share/vm/classfile/systemDictionary.hpp	Tue Apr 14 11:37:24 2015 -0700
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Apr 15 10:09:13 2015 -0700
@@ -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	Tue Apr 14 11:37:24 2015 -0700
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Apr 15 10:09:13 2015 -0700
@@ -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/graal/graalCodeInstaller.cpp	Tue Apr 14 11:37:24 2015 -0700
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Wed Apr 15 10:09:13 2015 -0700
@@ -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/graalJavaAccess.hpp	Tue Apr 14 11:37:24 2015 -0700
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Wed Apr 15 10:09:13 2015 -0700
@@ -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;")                                                                             \