changeset 17244:aef31f60e970

converted all FieldIntrospection subclass to use Fields
author Doug Simon <doug.simon@oracle.com>
date Sat, 27 Sep 2014 18:16:18 +0200
parents 5b00a1e62a5e
children 86d9e456ef98
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java
diffstat 11 files changed, 512 insertions(+), 510 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Sat Sep 27 18:16:18 2014 +0200
@@ -47,9 +47,11 @@
     protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
 
     private final Class<?> clazz;
-    protected long[] dataOffsets;
-    protected Map<Long, String> fieldNames;
-    protected Map<Long, Class<?>> fieldTypes;
+
+    /**
+     * The set of fields in {@link #clazz} that do long belong to a more specific category.
+     */
+    protected Fields data;
 
     public FieldIntrospection(Class<?> clazz) {
         this.clazz = clazz;
@@ -59,20 +61,57 @@
         return clazz;
     }
 
+    /**
+     * Gets the fields in {@link #getClazz()} that do long belong to specific category.
+     */
+    public Fields getData() {
+        return data;
+    }
+
+    /**
+     * Describes a field in a class during scanning.
+     */
+    public static class FieldInfo implements Comparable<FieldInfo> {
+        public final long offset;
+        public final String name;
+        public final Class<?> type;
+
+        public FieldInfo(long offset, String name, Class<?> type) {
+            this.offset = offset;
+            this.name = name;
+            this.type = type;
+        }
+
+        /**
+         * Sorts fields in ascending order by their {@link #offset}s.
+         */
+        public int compareTo(FieldInfo o) {
+            return offset < o.offset ? -1 : (offset > o.offset ? 1 : 0);
+        }
+
+        @Override
+        public String toString() {
+            return "[" + offset + "]" + name + ":" + type.getSimpleName();
+        }
+    }
+
     public abstract static class BaseFieldScanner {
 
         private final CalcOffset calc;
 
-        /** The offsets of fields that are not specially handled by subclasses. */
-        public final ArrayList<Long> dataOffsets = new ArrayList<>();
-
-        public final Map<Long, String> fieldNames = new HashMap<>();
-        public final Map<Long, Class<?>> fieldTypes = new HashMap<>();
+        /**
+         * Fields not belonging to a more specific category defined by scanner subclasses are added
+         * to this list.
+         */
+        public final ArrayList<FieldInfo> data = new ArrayList<>();
 
         protected BaseFieldScanner(CalcOffset calc) {
             this.calc = calc;
         }
 
+        /**
+         * Scans the fields in a class hierarchy.
+         */
         public void scan(Class<?> clazz) {
             Class<?> currentClazz = clazz;
             do {
@@ -80,69 +119,13 @@
                     if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
                         continue;
                     }
-                    Class<?> type = field.getType();
                     long offset = calc.getOffset(field);
-
-                    // scanField() may overwrite the name with a customized name.
-                    fieldNames.put(offset, field.getName());
-                    fieldTypes.put(offset, type);
-
-                    scanField(field, type, offset);
+                    scanField(field, offset);
                 }
                 currentClazz = currentClazz.getSuperclass();
             } while (currentClazz.getSuperclass() != Object.class);
         }
 
-        protected abstract void scanField(Field field, Class<?> type, long offset);
-    }
-
-    protected static void copyInto(long[] dest, long[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, T[] src) {
-        assert dest.length == src.length;
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src[i];
-        }
-    }
-
-    protected static <T> void copyInto(T[] dest, List<T> src) {
-        assert dest.length == src.size();
-        for (int i = 0; i < dest.length; i++) {
-            dest[i] = src.get(i);
-        }
-    }
-
-    protected static <T> T[] arrayUsingSortedOffsets(Map<Long, T> map, long[] sortedOffsets, T[] result) {
-        for (int i = 0; i < sortedOffsets.length; i++) {
-            result[i] = map.get(sortedOffsets[i]);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1) {
-        Collections.sort(list1);
-        long[] result = new long[list1.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        return result;
-    }
-
-    protected static long[] sortedLongCopy(ArrayList<Long> list1, ArrayList<Long> list2) {
-        Collections.sort(list1);
-        Collections.sort(list2);
-        long[] result = new long[list1.size() + list2.size()];
-        for (int i = 0; i < list1.size(); i++) {
-            result[i] = list1.get(i);
-        }
-        for (int i = 0; i < list2.size(); i++) {
-            result[list1.size() + i] = list2.get(i);
-        }
-        return result;
+        protected abstract void scanField(Field field, long offset);
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Sat Sep 27 18:16:18 2014 +0200
@@ -28,25 +28,39 @@
 
 import sun.misc.*;
 
+import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
+
 /**
  * Describes fields in a class, primarily for access via {@link Unsafe}.
  */
 public class Fields {
 
-    protected final Class<?> clazz;
+    /**
+     * Offsets used with {@link Unsafe} to access the fields.
+     */
     protected final long[] offsets;
+
+    /**
+     * The names of the fields.
+     */
     private final String[] names;
+
+    /**
+     * The types of the fields.
+     */
     private final Class<?>[] types;
 
-    public Fields(Class<?> clazz, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        this.clazz = clazz;
-        this.offsets = offsets;
-
+    public Fields(ArrayList<? extends FieldInfo> fields) {
+        Collections.sort(fields);
+        this.offsets = new long[fields.size()];
         this.names = new String[offsets.length];
         this.types = new Class[offsets.length];
-        for (int i = 0; i < offsets.length; i++) {
-            this.names[i] = names.get(offsets[i]);
-            this.types[i] = types.get(offsets[i]);
+        int index = 0;
+        for (FieldInfo f : fields) {
+            offsets[index] = f.offset;
+            names[index] = f.name;
+            types[index] = f.type;
+            index++;
         }
     }
 
@@ -126,44 +140,46 @@
      * @param index the index of the field to check
      * @param value a value that will be assigned to the field
      */
-    private boolean checkAssignableFrom(int index, Object value) {
-        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", clazz.getSimpleName(), getName(index),
-                        getType(index).getSimpleName(), value.getClass().getSimpleName());
+    private boolean checkAssignableFrom(Object object, int index, Object value) {
+        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("Field %s.%s of type %s is not assignable from %s", object.getClass().getSimpleName(),
+                        getName(index), getType(index).getSimpleName(), value.getClass().getSimpleName());
         return true;
     }
 
     public void set(Object object, int index, Object value) {
-        long dataOffset = offsets[index];
+        long offset = offsets[index];
         Class<?> type = types[index];
         if (type.isPrimitive()) {
             if (type == Integer.TYPE) {
-                unsafe.putInt(object, dataOffset, (Integer) value);
+                unsafe.putInt(object, offset, (Integer) value);
             } else if (type == Long.TYPE) {
-                unsafe.putLong(object, dataOffset, (Long) value);
+                unsafe.putLong(object, offset, (Long) value);
             } else if (type == Boolean.TYPE) {
-                unsafe.putBoolean(object, dataOffset, (Boolean) value);
+                unsafe.putBoolean(object, offset, (Boolean) value);
             } else if (type == Float.TYPE) {
-                unsafe.putFloat(object, dataOffset, (Float) value);
+                unsafe.putFloat(object, offset, (Float) value);
             } else if (type == Double.TYPE) {
-                unsafe.putDouble(object, dataOffset, (Double) value);
+                unsafe.putDouble(object, offset, (Double) value);
             } else if (type == Short.TYPE) {
-                unsafe.putShort(object, dataOffset, (Short) value);
+                unsafe.putShort(object, offset, (Short) value);
             } else if (type == Character.TYPE) {
-                unsafe.putChar(object, dataOffset, (Character) value);
+                unsafe.putChar(object, offset, (Character) value);
             } else if (type == Byte.TYPE) {
-                unsafe.putByte(object, dataOffset, (Byte) value);
+                unsafe.putByte(object, offset, (Byte) value);
             } else {
                 assert false : "unhandled property type: " + type;
             }
         } else {
-            assert checkAssignableFrom(index, value);
-            unsafe.putObject(object, dataOffset, value);
+            assert checkAssignableFrom(object, index, value);
+            unsafe.putObject(object, offset, value);
         }
     }
 
     @Override
     public String toString() {
-        return clazz.getSimpleName();
+        StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('[');
+        appendFields(sb);
+        return sb.append(']').toString();
     }
 
     public void appendFields(StringBuilder sb) {
@@ -216,4 +232,9 @@
         assert !types[i].isPrimitive();
         return unsafe.getObject(object, offsets[i]);
     }
+
+    public void putObject(Object object, int i, Object value) {
+        assert checkAssignableFrom(object, i, value);
+        unsafe.putObject(object, offsets[i], value);
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Sat Sep 27 18:16:18 2014 +0200
@@ -29,6 +29,7 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.FieldIntrospection.*;
 
 /**
  * Describes {@link Node} fields representing the set of inputs for the node or the set of the
@@ -47,8 +48,8 @@
     private final int directCount;
     private final Type type;
 
-    public Edges(Class<?> nodeClass, Type type, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        super(nodeClass, offsets, names, types);
+    public Edges(Type type, int directCount, ArrayList<? extends FieldInfo> fields) {
+        super(fields);
         this.type = type;
         this.directCount = directCount;
     }
@@ -134,7 +135,7 @@
      * @param toNode the node to which the edges should be copied.
      */
     public void copy(Node fromNode, Node toNode) {
-        assert fromNode.getNodeClass().getClazz() == clazz && toNode.getNodeClass().getClazz() == clazz;
+        assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz();
         int index = 0;
         while (index < getDirectCount()) {
             initializeNode(toNode, index, getNode(fromNode, index));
@@ -169,7 +170,7 @@
         }
         while (index < getCount()) {
             NodeList<Node> list = getNodeList(node, index);
-            assert list != null : clazz;
+            assert list != null : this;
             if (list.replaceFirst(key, replacement)) {
                 return true;
             }
@@ -235,7 +236,7 @@
      * Determines if the edges of two given nodes are the same.
      */
     public boolean areEqualIn(Node node, Node other) {
-        assert node.getNodeClass().getClazz() == clazz && other.getNodeClass().getClazz() == clazz;
+        assert node.getNodeClass().getClazz() == other.getNodeClass().getClazz();
         int index = 0;
         while (index < directCount) {
             if (getNode(other, index) != getNode(node, index)) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Sat Sep 27 18:16:18 2014 +0200
@@ -26,6 +26,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.NodeClass.InputFieldInfo;
 import com.oracle.graal.nodeinfo.*;
 
 public final class InputEdges extends Edges {
@@ -33,14 +34,14 @@
     private final InputType[] inputTypes;
     private final boolean[] isOptional;
 
-    public InputEdges(Class<?> nodeClass, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types, Map<Long, InputType> inputTypes, Set<Long> isOptional) {
-        super(nodeClass, Inputs, directCount, offsets, names, types);
+    public InputEdges(int directCount, ArrayList<InputFieldInfo> fields) {
+        super(Inputs, directCount, fields);
 
-        this.inputTypes = new InputType[offsets.length];
-        this.isOptional = new boolean[offsets.length];
-        for (int i = 0; i < offsets.length; i++) {
-            this.inputTypes[i] = inputTypes.get(offsets[i]);
-            this.isOptional[i] = isOptional.contains(offsets[i]);
+        this.inputTypes = new InputType[fields.size()];
+        this.isOptional = new boolean[fields.size()];
+        for (int i = 0; i < fields.size(); i++) {
+            this.inputTypes[i] = fields.get(i).inputType;
+            this.isOptional[i] = fields.get(i).optional;
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sat Sep 27 18:16:18 2014 +0200
@@ -885,7 +885,7 @@
      */
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
         NodeClass nodeClass = getNodeClass();
-        Fields properties = nodeClass.getProperties();
+        Fields properties = nodeClass.getData();
         for (int i = 0; i < properties.getCount(); i++) {
             map.put(properties.getName(i), properties.get(this, i));
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sat Sep 27 18:16:18 2014 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Edges.Type;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
 import com.oracle.graal.graph.Node.Input;
 import com.oracle.graal.graph.Node.Successor;
@@ -111,7 +112,6 @@
 
     private final Edges inputs;
     private final Edges successors;
-    private final Fields properties;
 
     private final boolean canGVN;
     private final int startGVNNumber;
@@ -146,13 +146,6 @@
         this(clazz, new DefaultCalcOffset(), null, 0);
     }
 
-    private static long[] sortedOffsets(ArrayList<Long> list1, ArrayList<Long> list2) {
-        if (list1.isEmpty() && list2.isEmpty()) {
-            return new long[0];
-        }
-        return sortedLongCopy(list1, list2);
-    }
-
     public NodeClass(Class<?> clazz, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
@@ -170,16 +163,14 @@
         }
 
         try (TimerCloseable t1 = Init_Edges.start()) {
-            successors = new SuccessorEdges(clazz, fs.successorOffsets.size(), sortedOffsets(fs.successorOffsets, fs.successorListOffsets), fs.fieldNames, fs.fieldTypes);
-            inputs = new InputEdges(clazz, fs.inputOffsets.size(), sortedOffsets(fs.inputOffsets, fs.inputListOffsets), fs.fieldNames, fs.fieldTypes, fs.types, fs.optionalInputs);
+            successors = new SuccessorEdges(fs.directSuccessors, fs.successors);
+            inputs = new InputEdges(fs.directInputs, fs.inputs);
         }
         try (TimerCloseable t1 = Init_Data.start()) {
-            properties = new Fields(clazz, sortedLongCopy(fs.dataOffsets), fs.fieldNames, fs.fieldTypes);
+            data = new Fields(fs.data);
         }
 
         isLeafNode = inputs.getCount() + successors.getCount() == 0;
-        fieldNames = fs.fieldNames;
-        fieldTypes = fs.fieldTypes;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
         startGVNNumber = clazz.hashCode();
@@ -336,21 +327,66 @@
         return allowedUsageTypes;
     }
 
+    /**
+     * Describes a field representing an input or successor edge in a node.
+     */
+    protected static class EdgeFieldInfo extends FieldInfo {
+
+        public EdgeFieldInfo(long offset, String name, Class<?> type) {
+            super(offset, name, type);
+        }
+
+        /**
+         * Sorts non-list edges before list edges.
+         */
+        @Override
+        public int compareTo(FieldInfo o) {
+            if (NodeList.class.isAssignableFrom(o.type)) {
+                if (!NodeList.class.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (NodeList.class.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+    }
+
+    /**
+     * Describes a field representing an {@linkplain Type#Inputs input} edge in a node.
+     */
+    protected static class InputFieldInfo extends EdgeFieldInfo {
+        final InputType inputType;
+        final boolean optional;
+
+        public InputFieldInfo(long offset, String name, Class<?> type, InputType inputType, boolean optional) {
+            super(offset, name, type);
+            this.inputType = inputType;
+            this.optional = optional;
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}";
+        }
+    }
+
     protected static class FieldScanner extends BaseFieldScanner {
 
-        public final ArrayList<Long> inputOffsets = new ArrayList<>();
-        public final ArrayList<Long> inputListOffsets = new ArrayList<>();
-        public final ArrayList<Long> successorOffsets = new ArrayList<>();
-        public final ArrayList<Long> successorListOffsets = new ArrayList<>();
-        public final HashMap<Long, InputType> types = new HashMap<>();
-        public final HashSet<Long> optionalInputs = new HashSet<>();
+        public final ArrayList<InputFieldInfo> inputs = new ArrayList<>();
+        public final ArrayList<FieldInfo> successors = new ArrayList<>();
+        int directInputs;
+        int directSuccessors;
 
         protected FieldScanner(CalcOffset calc) {
             super(calc);
         }
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
             if (field.isAnnotationPresent(Node.Input.class) || field.isAnnotationPresent(Node.OptionalInput.class)) {
                 assert !field.isAnnotationPresent(Node.Successor.class) : "field cannot be both input and successor";
                 assert field.isAnnotationPresent(Node.Input.class) ^ field.isAnnotationPresent(Node.OptionalInput.class) : "inputs can either be optional or non-optional";
@@ -359,37 +395,35 @@
                     // written (via Unsafe) in clearInputs()
                     GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "NodeInputList input field %s should not be final", field);
                     GraalInternalError.guarantee(!Modifier.isPublic(field.getModifiers()), "NodeInputList input field %s should not be public", field);
-                    inputListOffsets.add(offset);
                 } else {
                     GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
                     GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "Node input field %s should not be final", field);
-                    inputOffsets.add(offset);
+                    directInputs++;
                 }
+                InputType inputType;
                 if (field.isAnnotationPresent(Node.Input.class)) {
-                    types.put(offset, field.getAnnotation(Node.Input.class).value());
+                    inputType = field.getAnnotation(Node.Input.class).value();
                 } else {
-                    types.put(offset, field.getAnnotation(Node.OptionalInput.class).value());
+                    inputType = field.getAnnotation(Node.OptionalInput.class).value();
                 }
-                if (field.isAnnotationPresent(Node.OptionalInput.class)) {
-                    optionalInputs.add(offset);
-                }
+                inputs.add(new InputFieldInfo(offset, field.getName(), type, inputType, field.isAnnotationPresent(Node.OptionalInput.class)));
             } else if (field.isAnnotationPresent(Node.Successor.class)) {
                 if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) {
                     // NodeSuccessorList fields should not be final since they are
                     // written (via Unsafe) in clearSuccessors()
                     GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "NodeSuccessorList successor field % should not be final", field);
                     GraalInternalError.guarantee(!Modifier.isPublic(field.getModifiers()), "NodeSuccessorList successor field %s should not be public", field);
-                    successorListOffsets.add(offset);
                 } else {
                     GraalInternalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type);
                     GraalInternalError.guarantee(!Modifier.isFinal(field.getModifiers()), "Node successor field %s should not be final", field);
-                    successorOffsets.add(offset);
+                    directSuccessors++;
                 }
+                successors.add(new FieldInfo(offset, field.getName(), type));
             } else {
                 GraalInternalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field);
                 GraalInternalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field);
                 GraalInternalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field);
-                dataOffsets.add(offset);
+                data.add(new FieldInfo(offset, field.getName(), type));
             }
         }
     }
@@ -402,7 +436,7 @@
         str.append("] [");
         successors.appendFields(str);
         str.append("] [");
-        properties.appendFields(str);
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
@@ -437,41 +471,41 @@
         int number = 0;
         if (canGVN) {
             number = startGVNNumber;
-            for (int i = 0; i < properties.getCount(); ++i) {
-                Class<?> type = properties.getType(i);
+            for (int i = 0; i < data.getCount(); ++i) {
+                Class<?> type = data.getType(i);
                 if (type.isPrimitive()) {
                     if (type == Integer.TYPE) {
-                        int intValue = properties.getInt(n, i);
+                        int intValue = data.getInt(n, i);
                         number += intValue;
                     } else if (type == Long.TYPE) {
-                        long longValue = properties.getLong(n, i);
+                        long longValue = data.getLong(n, i);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Boolean.TYPE) {
-                        boolean booleanValue = properties.getBoolean(n, i);
+                        boolean booleanValue = data.getBoolean(n, i);
                         if (booleanValue) {
                             number += 7;
                         }
                     } else if (type == Float.TYPE) {
-                        float floatValue = properties.getFloat(n, i);
+                        float floatValue = data.getFloat(n, i);
                         number += Float.floatToRawIntBits(floatValue);
                     } else if (type == Double.TYPE) {
-                        double doubleValue = properties.getDouble(n, i);
+                        double doubleValue = data.getDouble(n, i);
                         long longValue = Double.doubleToRawLongBits(doubleValue);
                         number += longValue ^ (longValue >>> 32);
                     } else if (type == Short.TYPE) {
-                        short shortValue = properties.getShort(n, i);
+                        short shortValue = data.getShort(n, i);
                         number += shortValue;
                     } else if (type == Character.TYPE) {
-                        char charValue = properties.getChar(n, i);
+                        char charValue = data.getChar(n, i);
                         number += charValue;
                     } else if (type == Byte.TYPE) {
-                        byte byteValue = properties.getByte(n, i);
+                        byte byteValue = data.getByte(n, i);
                         number += byteValue;
                     } else {
                         assert false : "unhandled property type: " + type;
                     }
                 } else {
-                    Object o = properties.getObject(n, i);
+                    Object o = data.getObject(n, i);
                     number += deepHashCode0(o);
                 }
                 number *= 13;
@@ -511,54 +545,54 @@
         if (a.getClass() != b.getClass()) {
             return a == b;
         }
-        for (int i = 0; i < properties.getCount(); ++i) {
-            Class<?> type = properties.getType(i);
+        for (int i = 0; i < data.getCount(); ++i) {
+            Class<?> type = data.getType(i);
             if (type.isPrimitive()) {
                 if (type == Integer.TYPE) {
-                    int aInt = properties.getInt(a, i);
-                    int bInt = properties.getInt(b, i);
+                    int aInt = data.getInt(a, i);
+                    int bInt = data.getInt(b, i);
                     if (aInt != bInt) {
                         return false;
                     }
                 } else if (type == Boolean.TYPE) {
-                    boolean aBoolean = properties.getBoolean(a, i);
-                    boolean bBoolean = properties.getBoolean(b, i);
+                    boolean aBoolean = data.getBoolean(a, i);
+                    boolean bBoolean = data.getBoolean(b, i);
                     if (aBoolean != bBoolean) {
                         return false;
                     }
                 } else if (type == Long.TYPE) {
-                    long aLong = properties.getLong(a, i);
-                    long bLong = properties.getLong(b, i);
+                    long aLong = data.getLong(a, i);
+                    long bLong = data.getLong(b, i);
                     if (aLong != bLong) {
                         return false;
                     }
                 } else if (type == Float.TYPE) {
-                    float aFloat = properties.getFloat(a, i);
-                    float bFloat = properties.getFloat(b, i);
+                    float aFloat = data.getFloat(a, i);
+                    float bFloat = data.getFloat(b, i);
                     if (aFloat != bFloat) {
                         return false;
                     }
                 } else if (type == Double.TYPE) {
-                    double aDouble = properties.getDouble(a, i);
-                    double bDouble = properties.getDouble(b, i);
+                    double aDouble = data.getDouble(a, i);
+                    double bDouble = data.getDouble(b, i);
                     if (aDouble != bDouble) {
                         return false;
                     }
                 } else if (type == Short.TYPE) {
-                    short aShort = properties.getShort(a, i);
-                    short bShort = properties.getShort(b, i);
+                    short aShort = data.getShort(a, i);
+                    short bShort = data.getShort(b, i);
                     if (aShort != bShort) {
                         return false;
                     }
                 } else if (type == Character.TYPE) {
-                    char aChar = properties.getChar(a, i);
-                    char bChar = properties.getChar(b, i);
+                    char aChar = data.getChar(a, i);
+                    char bChar = data.getChar(b, i);
                     if (aChar != bChar) {
                         return false;
                     }
                 } else if (type == Byte.TYPE) {
-                    byte aByte = properties.getByte(a, i);
-                    byte bByte = properties.getByte(b, i);
+                    byte aByte = data.getByte(a, i);
+                    byte bByte = data.getByte(b, i);
                     if (aByte != bByte) {
                         return false;
                     }
@@ -566,8 +600,8 @@
                     assert false : "unhandled type: " + type;
                 }
             } else {
-                Object objectA = properties.getObject(a, i);
-                Object objectB = properties.getObject(b, i);
+                Object objectA = data.getObject(a, i);
+                Object objectB = data.getObject(b, i);
                 if (objectA != objectB) {
                     if (objectA != null && objectB != null) {
                         if (!deepEquals0(objectA, objectB)) {
@@ -596,13 +630,6 @@
         return toEdges.isSame(fromEdges, pos.getIndex());
     }
 
-    /**
-     * Gets the non-edge properties defined by this node class.
-     */
-    public Fields getProperties() {
-        return properties;
-    }
-
     static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
         int index = 0;
         while (index < edges.getDirectCount()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java	Sat Sep 27 18:16:18 2014 +0200
@@ -26,10 +26,12 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
+
 public final class SuccessorEdges extends Edges {
 
-    public SuccessorEdges(Class<?> nodeClass, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
-        super(nodeClass, Successors, directCount, offsets, names, types);
+    public SuccessorEdges(int directCount, ArrayList<FieldInfo> fields) {
+        super(Successors, directCount, fields);
     }
 
     @Override
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Sat Sep 27 18:16:18 2014 +0200
@@ -57,37 +57,24 @@
         }
     }
 
-    private final int directComponentCount;
-    private final long[] componentOffsets;
-    private final EnumSet<OperandFlag>[] componentFlags;
-
     public CompositeValueClass(Class<? extends CompositeValue> clazz) {
         this(clazz, new DefaultCalcOffset());
     }
 
-    @SuppressWarnings("unchecked")
     public CompositeValueClass(Class<? extends CompositeValue> clazz, CalcOffset calcOffset) {
         super(clazz);
 
-        ValueFieldScanner scanner = new ValueFieldScanner(calcOffset);
-        scanner.scan(clazz);
+        ValueFieldScanner vfs = new ValueFieldScanner(calcOffset);
+        vfs.scan(clazz);
 
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
-        directComponentCount = mode.scalarOffsets.size();
-        componentOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        componentFlags = arrayUsingSortedOffsets(mode.flags, componentOffsets, new EnumSet[componentOffsets.length]);
-
-        dataOffsets = sortedLongCopy(scanner.dataOffsets);
-
-        fieldNames = scanner.fieldNames;
-        fieldTypes = scanner.fieldTypes;
+        values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
+        data = new Fields(vfs.data);
     }
 
     private static class ValueFieldScanner extends FieldScanner {
 
         public ValueFieldScanner(CalcOffset calc) {
             super(calc);
-
             valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
         }
 
@@ -111,57 +98,53 @@
     @Override
     public String toString() {
         StringBuilder str = new StringBuilder();
-        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" component[");
-        for (int i = 0; i < componentOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
-        }
+        str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" components[");
+        values.appendFields(str);
         str.append("] data[");
-        for (int i = 0; i < dataOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
-        }
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
 
     final CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, OperandMode mode, InstructionValueProcedureBase proc) {
-        return forEachComponent(inst, obj, directComponentCount, componentOffsets, mode, componentFlags, 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, directComponentCount, componentOffsets, mode, componentFlags, proc, outerPosition);
+        forEach(inst, obj, values, mode, proc, outerPosition);
     }
 
     public String toString(CompositeValue obj) {
         StringBuilder result = new StringBuilder();
 
-        appendValues(result, obj, "", "", "{", "}", new String[]{""}, componentOffsets);
+        appendValues(result, obj, "", "", "{", "}", new String[]{""}, values);
 
-        for (int i = 0; i < dataOffsets.length; i++) {
-            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+        for (int i = 0; i < data.getCount(); i++) {
+            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
         }
 
         return result.toString();
     }
 
     Value getValue(CompositeValue obj, ValuePosition pos) {
-        return getValueForPosition(obj, componentOffsets, directComponentCount, pos);
+        return getValueForPosition(obj, values, pos);
     }
 
     CompositeValue createUpdatedValue(CompositeValue compValue, ValuePosition pos, Value value) {
         CompositeValue newCompValue = compValue.clone();
-        setValueForPosition(newCompValue, componentOffsets, directComponentCount, pos, value);
+        setValueForPosition(newCompValue, values, pos, value);
         return newCompValue;
     }
 
     EnumSet<OperandFlag> getFlags(ValuePosition pos) {
-        return componentFlags[pos.getIndex()];
+        return values.getFlags(pos.getIndex());
     }
 
     void copyValueArrays(CompositeValue compositeValue) {
-        for (int i = directComponentCount; i < componentOffsets.length; i++) {
-            Value[] valueArray = getValueArray(compositeValue, componentOffsets[i]);
+        for (int i = values.getDirectCount(); i < values.getCount(); i++) {
+            Value[] valueArray = values.getValueArray(compositeValue, i);
             Value[] newValueArray = Arrays.copyOf(valueArray, valueArray.length);
-            setValueArray(compositeValue, componentOffsets[i], newValueArray);
+            values.setValueArray(compositeValue, i, newValueArray);
         }
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Sat Sep 27 18:16:18 2014 +0200
@@ -53,70 +53,50 @@
     private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
     private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
 
-    private final int directUseCount;
-    private final long[] useOffsets;
-    private final EnumSet<OperandFlag>[] useFlags;
-    private final int directAliveCount;
-    private final long[] aliveOffsets;
-    private final EnumSet<OperandFlag>[] aliveFlags;
-    private final int directTempCount;
-    private final long[] tempOffsets;
-    private final EnumSet<OperandFlag>[] tempFlags;
-    private final int directDefCount;
-    private final long[] defOffsets;
-    private final EnumSet<OperandFlag>[] defFlags;
-
-    private final long[] stateOffsets;
+    private final Values uses;
+    private final Values alives;
+    private final Values temps;
+    private final Values defs;
+    private final Fields states;
 
     private String opcodeConstant;
-    private long opcodeOffset;
+    private int opcodeIndex;
 
     private LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
         this(clazz, new DefaultCalcOffset());
     }
 
-    @SuppressWarnings("unchecked")
     public LIRInstructionClass(Class<? extends LIRInstruction> clazz, CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        InstructionFieldScanner scanner = new InstructionFieldScanner(calcOffset);
-        scanner.scan(clazz);
+        InstructionFieldScanner ifs = new InstructionFieldScanner(calcOffset);
+        ifs.scan(clazz);
 
-        OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
-        directUseCount = mode.scalarOffsets.size();
-        useOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        useFlags = arrayUsingSortedOffsets(mode.flags, useOffsets, new EnumSet[useOffsets.length]);
-
-        mode = scanner.valueAnnotations.get(LIRInstruction.Alive.class);
-        directAliveCount = mode.scalarOffsets.size();
-        aliveOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        aliveFlags = arrayUsingSortedOffsets(mode.flags, aliveOffsets, new EnumSet[aliveOffsets.length]);
+        uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class));
+        alives = new Values(ifs.valueAnnotations.get(LIRInstruction.Alive.class));
+        temps = new Values(ifs.valueAnnotations.get(LIRInstruction.Temp.class));
+        defs = new Values(ifs.valueAnnotations.get(LIRInstruction.Def.class));
 
-        mode = scanner.valueAnnotations.get(LIRInstruction.Temp.class);
-        directTempCount = mode.scalarOffsets.size();
-        tempOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        tempFlags = arrayUsingSortedOffsets(mode.flags, tempOffsets, new EnumSet[tempOffsets.length]);
+        states = new Fields(ifs.states);
+        data = new Fields(ifs.data);
 
-        mode = scanner.valueAnnotations.get(LIRInstruction.Def.class);
-        directDefCount = mode.scalarOffsets.size();
-        defOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
-        defFlags = arrayUsingSortedOffsets(mode.flags, defOffsets, new EnumSet[defOffsets.length]);
-
-        stateOffsets = sortedLongCopy(scanner.stateOffsets);
-        dataOffsets = sortedLongCopy(scanner.dataOffsets);
-
-        fieldNames = scanner.fieldNames;
-        fieldTypes = scanner.fieldTypes;
-
-        opcodeConstant = scanner.opcodeConstant;
-        opcodeOffset = scanner.opcodeOffset;
+        opcodeConstant = ifs.opcodeConstant;
+        if (ifs.opcodeField == null) {
+            opcodeIndex = -1;
+        } else {
+            opcodeIndex = ifs.data.indexOf(ifs.opcodeField);
+        }
     }
 
     private static class InstructionFieldScanner extends FieldScanner {
 
         private String opcodeConstant;
-        private long opcodeOffset;
+
+        /**
+         * Field (if any) annotated by {@link Opcode}.
+         */
+        private FieldInfo opcodeField;
 
         public InstructionFieldScanner(CalcOffset calc) {
             super(calc);
@@ -153,11 +133,11 @@
             if (clazz.getAnnotation(Opcode.class) != null) {
                 opcodeConstant = clazz.getAnnotation(Opcode.class).value();
             }
-            opcodeOffset = -1;
+            opcodeField = null;
 
             super.scan(clazz);
 
-            if (opcodeConstant == null && opcodeOffset == -1) {
+            if (opcodeConstant == null && opcodeField == null) {
                 opcodeConstant = clazz.getSimpleName();
                 if (opcodeConstant.endsWith("Op")) {
                     opcodeConstant = opcodeConstant.substring(0, opcodeConstant.length() - 2);
@@ -166,18 +146,20 @@
         }
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
             if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
-                stateOffsets.add(offset);
+                states.add(new FieldInfo(offset, field.getName(), type));
             } else {
-                super.scanField(field, type, offset);
+                super.scanField(field, offset);
             }
 
             if (field.getAnnotation(Opcode.class) != null) {
-                assert opcodeConstant == null && opcodeOffset == -1 : "Can have only one Opcode definition: " + field.getType();
-                opcodeOffset = offset;
+                assert opcodeConstant == null && opcodeField == null : "Can have only one Opcode definition: " + type;
+                assert data.get(data.size() - 1).offset == offset;
+                opcodeField = data.get(data.size() - 1);
             }
         }
     }
@@ -186,97 +168,33 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(getClass().getSimpleName()).append(" ").append(getClazz().getSimpleName()).append(" use[");
-        for (int i = 0; i < useOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(useOffsets[i]);
-        }
+        uses.appendFields(str);
         str.append("] alive[");
-        for (int i = 0; i < aliveOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(aliveOffsets[i]);
-        }
+        alives.appendFields(str);
         str.append("] temp[");
-        for (int i = 0; i < tempOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(tempOffsets[i]);
-        }
+        temps.appendFields(str);
         str.append("] def[");
-        for (int i = 0; i < defOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(defOffsets[i]);
-        }
+        defs.appendFields(str);
         str.append("] state[");
-        for (int i = 0; i < stateOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(stateOffsets[i]);
-        }
+        states.appendFields(str);
         str.append("] data[");
-        for (int i = 0; i < dataOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
-        }
+        data.appendFields(str);
         str.append("]");
         return str.toString();
     }
 
-    Value getValue(LIRInstruction obj, ValuePosition pos) {
-        long[] offsets;
-        int directCount;
-        switch (pos.getMode()) {
-            case USE:
-                directCount = directUseCount;
-                offsets = useOffsets;
-                break;
-            case ALIVE:
-                directCount = directAliveCount;
-                offsets = aliveOffsets;
-                break;
-            case TEMP:
-                directCount = directTempCount;
-                offsets = tempOffsets;
-                break;
-            case DEF:
-                directCount = directDefCount;
-                offsets = defOffsets;
-                break;
-            default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
-        }
-        return getValueForPosition(obj, offsets, directCount, pos);
-    }
-
-    void setValue(LIRInstruction obj, ValuePosition pos, Value value) {
-        long[] offsets;
-        int directCount;
-        switch (pos.getMode()) {
+    Values getValues(OperandMode mode) {
+        switch (mode) {
             case USE:
-                directCount = directUseCount;
-                offsets = useOffsets;
-                break;
+                return uses;
             case ALIVE:
-                directCount = directAliveCount;
-                offsets = aliveOffsets;
-                break;
+                return alives;
             case TEMP:
-                directCount = directTempCount;
-                offsets = tempOffsets;
-                break;
+                return temps;
             case DEF:
-                directCount = directDefCount;
-                offsets = defOffsets;
-                break;
+                return defs;
             default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
-        }
-        setValueForPosition(obj, offsets, directCount, pos, value);
-    }
-
-    EnumSet<OperandFlag> getFlags(ValuePosition pos) {
-        switch (pos.getMode()) {
-            case USE:
-                return useFlags[pos.getIndex()];
-            case ALIVE:
-                return aliveFlags[pos.getIndex()];
-            case TEMP:
-                return tempFlags[pos.getIndex()];
-            case DEF:
-                return defFlags[pos.getIndex()];
-            default:
-                throw GraalInternalError.shouldNotReachHere("unkown OperandMode: " + pos.getMode());
+                throw GraalInternalError.shouldNotReachHere("unknown OperandMode: " + mode);
         }
     }
 
@@ -284,17 +202,17 @@
         if (opcodeConstant != null) {
             return opcodeConstant;
         }
-        assert opcodeOffset != -1;
-        return unsafe.getObject(obj, opcodeOffset).toString();
+        assert opcodeIndex != -1;
+        return data.getObject(obj, opcodeIndex).toString();
     }
 
     final boolean hasOperands() {
-        return useOffsets.length > 0 || aliveOffsets.length > 0 || tempOffsets.length > 0 || defOffsets.length > 0;
+        return uses.getCount() > 0 || alives.getCount() > 0 || temps.getCount() > 0 || defs.getCount() > 0;
     }
 
     final boolean hasState(LIRInstruction obj) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            if (getState(obj, stateOffsets[i]) != null) {
+        for (int i = 0; i < states.getCount(); i++) {
+            if (states.getObject(obj, i) != null) {
                 return true;
             }
         }
@@ -302,40 +220,40 @@
     }
 
     final void forEachUse(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+        forEach(obj, obj, uses, OperandMode.USE, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
     final void forEachAlive(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+        forEach(obj, obj, alives, OperandMode.ALIVE, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
     final void forEachTemp(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+        forEach(obj, obj, temps, OperandMode.TEMP, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
     final void forEachDef(LIRInstruction obj, ValuePositionProcedure proc) {
-        forEach(obj, obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc, ValuePosition.ROOT_VALUE_POSITION);
+        forEach(obj, obj, defs, OperandMode.DEF, proc, ValuePosition.ROOT_VALUE_POSITION);
     }
 
     final void forEachUse(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directUseCount, useOffsets, OperandMode.USE, useFlags, proc);
+        forEach(obj, uses, OperandMode.USE, proc);
     }
 
     final void forEachAlive(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directAliveCount, aliveOffsets, OperandMode.ALIVE, aliveFlags, proc);
+        forEach(obj, alives, OperandMode.ALIVE, proc);
     }
 
     final void forEachTemp(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directTempCount, tempOffsets, OperandMode.TEMP, tempFlags, proc);
+        forEach(obj, temps, OperandMode.TEMP, proc);
     }
 
     final void forEachDef(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        forEach(obj, directDefCount, defOffsets, OperandMode.DEF, defFlags, proc);
+        forEach(obj, defs, OperandMode.DEF, proc);
     }
 
     final void forEachState(LIRInstruction obj, InstructionValueProcedureBase proc) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
                 state.forEachState(obj, proc);
             }
@@ -343,8 +261,8 @@
     }
 
     final void forEachState(LIRInstruction obj, InstructionStateProcedure proc) {
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
                 proc.doState(obj, state);
             }
@@ -352,27 +270,24 @@
     }
 
     final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, InstructionValueProcedure proc) {
-        int hintDirectCount = 0;
-        long[] hintOffsets = null;
+        Values hints;
         if (mode == OperandMode.USE) {
-            hintDirectCount = directDefCount;
-            hintOffsets = defOffsets;
+            hints = defs;
         } else if (mode == OperandMode.DEF) {
-            hintDirectCount = directUseCount;
-            hintOffsets = useOffsets;
+            hints = uses;
         } else {
             return null;
         }
 
-        for (int i = 0; i < hintOffsets.length; i++) {
-            if (i < hintDirectCount) {
-                Value hintValue = getValue(obj, hintOffsets[i]);
+        for (int i = 0; i < hints.getCount(); i++) {
+            if (i < hints.getDirectCount()) {
+                Value hintValue = hints.getValue(obj, i);
                 Value result = proc.processValue(obj, hintValue, null, null);
                 if (result != null) {
                     return result;
                 }
             } else {
-                Value[] hintValues = getValueArray(obj, hintOffsets[i]);
+                Value[] hintValues = hints.getValueArray(obj, i);
                 for (int j = 0; j < hintValues.length; j++) {
                     Value hintValue = hintValues[j];
                     Value result = proc.processValue(obj, hintValue, null, null);
@@ -385,29 +300,25 @@
         return null;
     }
 
-    private static LIRFrameState getState(LIRInstruction obj, long offset) {
-        return (LIRFrameState) unsafe.getObject(obj, offset);
-    }
-
     String toString(LIRInstruction obj) {
         StringBuilder result = new StringBuilder();
 
-        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defOffsets);
-        result.append(getOpcode(obj).toUpperCase());
-        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, useOffsets, aliveOffsets);
-        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, tempOffsets);
+        appendValues(result, obj, "", " = ", "(", ")", new String[]{""}, defs);
+        result.append(String.valueOf(getOpcode(obj)).toUpperCase());
+        appendValues(result, obj, " ", "", "(", ")", new String[]{"", "~"}, uses, alives);
+        appendValues(result, obj, " ", "", "{", "}", new String[]{""}, temps);
 
-        for (int i = 0; i < dataOffsets.length; i++) {
-            if (dataOffsets[i] == opcodeOffset) {
+        for (int i = 0; i < data.getCount(); i++) {
+            if (i == opcodeIndex) {
                 continue;
             }
-            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+            result.append(" ").append(data.getName(i)).append(": ").append(getFieldString(obj, i, data));
         }
 
-        for (int i = 0; i < stateOffsets.length; i++) {
-            LIRFrameState state = getState(obj, stateOffsets[i]);
+        for (int i = 0; i < states.getCount(); i++) {
+            LIRFrameState state = (LIRFrameState) states.getObject(obj, i);
             if (state != null) {
-                result.append(" ").append(fieldNames.get(stateOffsets[i])).append(" [bci:");
+                result.append(" ").append(states.getName(i)).append(" [bci:");
                 String sep = "";
                 for (BytecodeFrame cur = state.topFrame; cur != null; cur = cur.caller()) {
                     result.append(sep).append(cur.getBCI());
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Sat Sep 27 18:16:18 2014 +0200
@@ -48,21 +48,117 @@
         super(clazz);
     }
 
+    protected static class Values extends Fields {
+        private final int directCount;
+        private final OperandMode mode;
+        private final EnumSet<OperandFlag>[] flags;
+
+        public Values(OperandModeAnnotation mode) {
+            this(mode.directCount, null, mode.values);
+        }
+
+        @SuppressWarnings("unchecked")
+        public Values(int directCount, OperandMode mode, ArrayList<ValueFieldInfo> fields) {
+            super(fields);
+            this.mode = mode;
+            this.directCount = directCount;
+            flags = new EnumSet[fields.size()];
+            for (int i = 0; i < fields.size(); i++) {
+                flags[i] = fields.get(i).flags;
+            }
+        }
+
+        public int getDirectCount() {
+            return directCount;
+        }
+
+        public OperandMode getMode() {
+            return mode;
+        }
+
+        public EnumSet<OperandFlag> getFlags(int i) {
+            return flags[i];
+        }
+
+        protected Value getValue(Object obj, int index) {
+            return (Value) getObject(obj, index);
+        }
+
+        protected void setValue(Object obj, int index, Value value) {
+            putObject(obj, index, value);
+        }
+
+        protected Value[] getValueArray(Object obj, int index) {
+            return (Value[]) getObject(obj, index);
+        }
+
+        protected void setValueArray(Object obj, int index, Value[] valueArray) {
+            putObject(obj, index, valueArray);
+        }
+
+        @Override
+        public String toString() {
+            if (mode != null) {
+                return super.toString() + ":" + mode;
+            }
+            return super.toString();
+        }
+    }
+
+    /**
+     * The component values in an {@link LIRInstruction} or {@link CompositeValue}.
+     */
+    protected Values values;
+
+    protected static class ValueFieldInfo extends FieldInfo {
+
+        final EnumSet<OperandFlag> flags;
+
+        public ValueFieldInfo(long offset, String name, Class<?> type, EnumSet<OperandFlag> flags) {
+            super(offset, name, type);
+            assert VALUE_ARRAY_CLASS.isAssignableFrom(type) || VALUE_CLASS.isAssignableFrom(type);
+            this.flags = flags;
+        }
+
+        /**
+         * Sorts non-array fields before array fields.
+         */
+        @Override
+        public int compareTo(FieldInfo o) {
+            if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) {
+                if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return -1;
+                }
+            } else {
+                if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                    return 1;
+                }
+            }
+            return super.compareTo(o);
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + flags;
+        }
+    }
+
     protected static class OperandModeAnnotation {
 
-        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
-        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
-        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
+        /**
+         * Number of non-array fields in {@link #values}.
+         */
+        public int directCount;
+        public final ArrayList<ValueFieldInfo> values = new ArrayList<>();
     }
 
     protected abstract static class FieldScanner extends BaseFieldScanner {
 
         public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
-        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+        public final ArrayList<FieldInfo> states = new ArrayList<>();
 
         public FieldScanner(CalcOffset calc) {
             super(calc);
-
             valueAnnotations = new HashMap<>();
         }
 
@@ -81,26 +177,26 @@
         protected abstract EnumSet<OperandFlag> getFlags(Field field);
 
         @Override
-        protected void scanField(Field field, Class<?> type, long offset) {
+        protected void scanField(Field field, long offset) {
+            Class<?> type = field.getType();
             if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
                 assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.scalarOffsets.add(offset);
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type, flags);
-                annotation.flags.put(offset, getFlags(field));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
+                annotation.directCount++;
             } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
                 OperandModeAnnotation annotation = getOperandModeAnnotation(field);
                 assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.arrayOffsets.add(offset);
                 EnumSet<OperandFlag> flags = getFlags(field);
                 assert verifyFlags(field, type.getComponentType(), flags);
-                annotation.flags.put(offset, getFlags(field));
+                annotation.values.add(new ValueFieldInfo(offset, field.getName(), type, flags));
             } else {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
-                dataOffsets.add(offset);
+                data.add(new FieldInfo(offset, field.getName(), type));
             }
         }
 
@@ -118,74 +214,73 @@
         }
     }
 
-    protected static void forEach(LIRInstruction inst, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, InstructionValueProcedureBase proc) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+    protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedureBase proc) {
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
-            if (i < directCount) {
-                Value value = getValue(inst, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(inst, i);
                 Value newValue;
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
                     newValue = composite.forEachComponent(inst, mode, proc);
                 } else {
-                    newValue = proc.processValue(inst, value, mode, flags[i]);
+                    newValue = proc.processValue(inst, value, mode, values.getFlags(i));
                 }
                 if (!value.identityEquals(newValue)) {
-                    setValue(inst, offsets[i], newValue);
+                    values.setValue(inst, i, newValue);
                 }
             } else {
-                Value[] values = getValueArray(inst, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                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);
                     } else {
-                        newValue = proc.processValue(inst, value, mode, flags[i]);
+                        newValue = proc.processValue(inst, value, mode, values.getFlags(i));
                     }
                     if (!value.identityEquals(newValue)) {
-                        values[j] = newValue;
+                        valueArray[j] = newValue;
                     }
                 }
             }
         }
     }
 
-    protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags,
-                    InstructionValueProcedureBase proc) {
+    protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, Values values, OperandMode mode, InstructionValueProcedureBase proc) {
         CompositeValue newCompValue = null;
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+        for (int i = 0; i < values.getCount(); i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
-            if (i < directCount) {
-                Value value = getValue(obj, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(obj, i);
                 Value newValue;
                 if (value instanceof CompositeValue) {
                     CompositeValue composite = (CompositeValue) value;
                     newValue = composite.forEachComponent(inst, mode, proc);
                 } else {
-                    newValue = proc.processValue(inst, value, mode, flags[i]);
+                    newValue = proc.processValue(inst, value, mode, values.getFlags(i));
                 }
                 if (!value.identityEquals(newValue)) {
                     // lazy initialize
                     if (newCompValue == null) {
                         newCompValue = obj.clone();
                     }
-                    setValue(newCompValue, offsets[i], newValue);
+                    values.setValue(newCompValue, i, newValue);
                 }
             } else {
-                Value[] values = getValueArray(obj, offsets[i]);
+                Value[] valueArray = values.getValueArray(obj, i);
                 Value[] newValues = null;
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                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);
                     } else {
-                        newValue = proc.processValue(inst, value, mode, flags[i]);
+                        newValue = proc.processValue(inst, value, mode, values.getFlags(i));
                     }
                     if (!value.identityEquals(newValue)) {
                         // lazy initialize
@@ -193,7 +288,7 @@
                             if (newCompValue == null) {
                                 newCompValue = obj.clone();
                             }
-                            newValues = getValueArray(newCompValue, offsets[i]);
+                            newValues = values.getValueArray(newCompValue, i);
                         }
                         newValues[j] = newValue;
                     }
@@ -203,18 +298,17 @@
         return newCompValue != null ? newCompValue : obj;
     }
 
-    protected static void forEach(LIRInstruction inst, Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValuePositionProcedure proc,
-                    ValuePosition outerPosition) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+    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 < directCount) {
-                Value value = getValue(obj, offsets[i]);
+            if (i < values.getDirectCount()) {
+                Value value = values.getValue(obj, i);
                 doForValue(inst, mode, proc, outerPosition, i, ValuePosition.NO_SUBINDEX, value);
             } else {
-                Value[] values = getValueArray(obj, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
+                Value[] valueArray = values.getValueArray(obj, i);
+                for (int j = 0; j < valueArray.length; j++) {
+                    Value value = valueArray[j];
                     doForValue(inst, mode, proc, outerPosition, i, j, value);
                 }
             }
@@ -222,7 +316,8 @@
     }
 
     private static void doForValue(LIRInstruction inst, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition, int index, int subIndex, Value value) {
-        ValuePosition position = new ValuePosition(mode, index, subIndex, outerPosition);
+        Values values = inst.getLIRInstructionClass().getValues(mode);
+        ValuePosition position = new ValuePosition(values, index, subIndex, outerPosition);
         if (value instanceof CompositeValue) {
             CompositeValue composite = (CompositeValue) value;
             composite.forEachComponent(inst, mode, proc, position);
@@ -231,41 +326,25 @@
         }
     }
 
-    protected static Value getValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos) {
-        if (pos.getIndex() < directCount) {
-            return getValue(obj, offsets[pos.getIndex()]);
+    protected static Value getValueForPosition(Object obj, Values values, ValuePosition pos) {
+        if (pos.getIndex() < values.getDirectCount()) {
+            return values.getValue(obj, pos.getIndex());
         }
-        return getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()];
+        return values.getValueArray(obj, pos.getIndex())[pos.getSubIndex()];
     }
 
-    protected static void setValueForPosition(Object obj, long[] offsets, int directCount, ValuePosition pos, Value value) {
-        if (pos.getIndex() < directCount) {
-            setValue(obj, offsets[pos.getIndex()], value);
+    protected static void setValueForPosition(Object obj, Values values, ValuePosition pos, Value value) {
+        if (pos.getIndex() < values.getDirectCount()) {
+            values.setValue(obj, pos.getIndex(), value);
         } else {
-            getValueArray(obj, offsets[pos.getIndex()])[pos.getSubIndex()] = value;
+            values.getValueArray(obj, pos.getIndex())[pos.getSubIndex()] = value;
         }
     }
 
-    protected static Value getValue(Object obj, long offset) {
-        return (Value) unsafe.getObject(obj, offset);
-    }
-
-    protected static void setValue(Object obj, long offset, Value value) {
-        unsafe.putObject(obj, offset, value);
-    }
-
-    protected static Value[] getValueArray(Object obj, long offset) {
-        return (Value[]) unsafe.getObject(obj, offset);
-    }
-
-    protected static void setValueArray(Object obj, long offset, Value[] valueArray) {
-        unsafe.putObject(obj, offset, valueArray);
-    }
-
-    protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
+    protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, Fields... fieldsList) {
         int total = 0;
-        for (long[] offsets : moffsets) {
-            total += offsets.length;
+        for (Fields fields : fieldsList) {
+            total += fields.getCount();
         }
         if (total == 0) {
             return;
@@ -276,16 +355,15 @@
             result.append(startMultiple);
         }
         String sep = "";
-        for (int i = 0; i < moffsets.length; i++) {
-            long[] offsets = moffsets[i];
+        int i = 0;
+        for (Fields fields : fieldsList) {
 
-            for (int j = 0; j < offsets.length; j++) {
-                result.append(sep).append(prefix[i]);
-                long offset = offsets[j];
+            for (int j = 0; j < fields.getCount(); j++) {
+                result.append(sep).append(prefix[i++]);
                 if (total > 1) {
-                    result.append(fieldNames.get(offset)).append(": ");
+                    result.append(fields.getName(j)).append(": ");
                 }
-                result.append(getFieldString(obj, offset));
+                result.append(getFieldString(obj, j, fields));
                 sep = ", ";
             }
         }
@@ -295,38 +373,25 @@
         result.append(end);
     }
 
-    protected String getFieldString(Object obj, long offset) {
-        Class<?> type = fieldTypes.get(offset);
-        if (type == int.class) {
-            return String.valueOf(unsafe.getInt(obj, offset));
-        } else if (type == long.class) {
-            return String.valueOf(unsafe.getLong(obj, offset));
-        } else if (type == boolean.class) {
-            return String.valueOf(unsafe.getBoolean(obj, offset));
-        } else if (type == float.class) {
-            return String.valueOf(unsafe.getFloat(obj, offset));
-        } else if (type == double.class) {
-            return String.valueOf(unsafe.getDouble(obj, offset));
-        } else if (type == byte.class) {
-            return String.valueOf(unsafe.getByte(obj, offset));
-        } else if (!type.isPrimitive()) {
-            Object value = unsafe.getObject(obj, offset);
-            if (!type.isArray()) {
-                return String.valueOf(value);
-            } else if (type == int[].class) {
-                return Arrays.toString((int[]) value);
-            } else if (type == double[].class) {
-                return Arrays.toString((double[]) value);
-            } else if (type == byte[].class) {
-                byte[] byteValue = (byte[]) value;
-                if (isPrintableAsciiString(byteValue)) {
-                    return toString(byteValue);
-                } else {
-                    return Arrays.toString(byteValue);
-                }
-            } else if (!type.getComponentType().isPrimitive()) {
-                return Arrays.toString((Object[]) value);
+    protected 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()) {
+            return String.valueOf(value);
+        }
+        if (type == int[].class) {
+            return Arrays.toString((int[]) value);
+        } else if (type == double[].class) {
+            return Arrays.toString((double[]) value);
+        } else if (type == byte[].class) {
+            byte[] byteValue = (byte[]) value;
+            if (isPrintableAsciiString(byteValue)) {
+                return toString(byteValue);
+            } else {
+                return Arrays.toString(byteValue);
             }
+        } else if (!type.getComponentType().isPrimitive()) {
+            return Arrays.toString((Object[]) value);
         }
         assert false : "unhandled field type: " + type;
         return "";
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Fri Sep 26 18:59:08 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ValuePosition.java	Sat Sep 27 18:16:18 2014 +0200
@@ -25,14 +25,15 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.lir.LIRInstruction.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRIntrospection.Values;
 
 /**
  * Describes an operand slot for a {@link LIRInstructionClass}.
  */
 public final class ValuePosition {
 
-    private final OperandMode mode;
+    private final Values values;
     private final int index;
     private final int subIndex;
     private final ValuePosition outerPosition;
@@ -40,8 +41,8 @@
     public static final int NO_SUBINDEX = -1;
     public static final ValuePosition ROOT_VALUE_POSITION = null;
 
-    public ValuePosition(OperandMode mode, int index, int subIndex, ValuePosition outerPosition) {
-        this.mode = mode;
+    public ValuePosition(Values values, int index, int subIndex, ValuePosition outerPosition) {
+        this.values = values;
         this.index = index;
         this.subIndex = subIndex;
         this.outerPosition = outerPosition;
@@ -51,20 +52,12 @@
         return outerPosition != ROOT_VALUE_POSITION;
     }
 
-    public Value get(LIRInstruction inst) {
+    public Value get(Object inst) {
         if (isCompositePosition()) {
             CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
             return compValue.getValueClass().getValue(compValue, this);
         }
-        return inst.getLIRInstructionClass().getValue(inst, this);
-    }
-
-    public EnumSet<OperandFlag> getFlags(LIRInstruction inst) {
-        if (isCompositePosition()) {
-            CompositeValue compValue = (CompositeValue) outerPosition.get(inst);
-            return compValue.getValueClass().getFlags(this);
-        }
-        return inst.getLIRInstructionClass().getFlags(this);
+        return getValue(inst);
     }
 
     public void set(LIRInstruction inst, Value value) {
@@ -73,7 +66,7 @@
             CompositeValue newCompValue = compValue.getValueClass().createUpdatedValue(compValue, this, value);
             outerPosition.set(inst, newCompValue);
         } else {
-            inst.getLIRInstructionClass().setValue(inst, this, value);
+            setValue(inst, value);
         }
     }
 
@@ -85,8 +78,23 @@
         return index;
     }
 
-    public OperandMode getMode() {
-        return mode;
+    public EnumSet<OperandFlag> getFlags() {
+        return values.getFlags(index);
+    }
+
+    public Value getValue(Object obj) {
+        if (index < values.getDirectCount()) {
+            return values.getValue(obj, index);
+        }
+        return values.getValueArray(obj, index)[subIndex];
+    }
+
+    public void setValue(Object obj, Value value) {
+        if (index < values.getDirectCount()) {
+            values.setValue(obj, index, value);
+        } else {
+            values.getValueArray(obj, index)[subIndex] = value;
+        }
     }
 
     public ValuePosition getSuperPosition() {
@@ -96,9 +104,9 @@
     @Override
     public String toString() {
         if (outerPosition == ROOT_VALUE_POSITION) {
-            return mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
+            return values.getMode() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")";
         }
-        return outerPosition.toString() + "[" + mode.toString() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")]";
+        return outerPosition.toString() + "[" + values.getMode() + "(" + index + (subIndex < 0 ? "" : "/" + subIndex) + ")]";
     }
 
     @Override
@@ -106,7 +114,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + index;
-        result = prime * result + ((mode == null) ? 0 : mode.hashCode());
+        result = prime * result + ((values.getMode() == null) ? 0 : values.getMode().hashCode());
         result = prime * result + subIndex;
         result = prime * result + ((outerPosition == null) ? 0 : outerPosition.hashCode());
         return result;
@@ -127,7 +135,7 @@
         if (index != other.index) {
             return false;
         }
-        if (mode != other.mode) {
+        if (values.getMode() != other.values.getMode()) {
             return false;
         }
         if (subIndex != other.subIndex) {