changeset 18261:d66c79acfeac

refactored Fields class to make it usable for implementing custom serialization
author Doug Simon <doug.simon@oracle.com>
date Wed, 05 Nov 2014 17:32:21 +0100
parents 0f23e16288c5
children f7d45e2426d4
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.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.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
diffstat 8 files changed, 188 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Wed Nov 05 17:32:21 2014 +0100
@@ -22,28 +22,10 @@
  */
 package com.oracle.graal.compiler.common;
 
-import java.lang.reflect.*;
-import java.util.*;
 import java.util.concurrent.*;
 
 public abstract class FieldIntrospection extends UnsafeAccess {
 
-    /**
-     * Interface used to determine the offset (in bytes) of a field.
-     */
-    public interface CalcOffset {
-
-        long getOffset(Field field);
-    }
-
-    public static class DefaultCalcOffset implements CalcOffset {
-
-        @Override
-        public long getOffset(Field field) {
-            return unsafe.objectFieldOffset(field);
-        }
-    }
-
     protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
 
     private final Class<?> clazz;
@@ -67,65 +49,4 @@
     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;
-
-        /**
-         * 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, boolean includeSuperclasses) {
-            Class<?> currentClazz = clazz;
-            do {
-                for (Field field : currentClazz.getDeclaredFields()) {
-                    if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
-                        continue;
-                    }
-                    long offset = calc.getOffset(field);
-                    scanField(field, offset);
-                }
-                currentClazz = currentClazz.getSuperclass();
-            } while (includeSuperclasses && currentClazz.getSuperclass() != Object.class);
-        }
-
-        protected abstract void scanField(Field field, long offset);
-    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Wed Nov 05 17:32:21 2014 +0100
@@ -28,8 +28,6 @@
 
 import sun.misc.*;
 
-import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
-
 /**
  * Describes fields in a class, primarily for access via {@link Unsafe}.
  */
@@ -50,13 +48,19 @@
      */
     private final Class<?>[] types;
 
-    public Fields(ArrayList<? extends FieldInfo> fields) {
+    public static Fields forClass(Class<?> clazz, Class<?> endClazz, boolean includeTransient, FieldsScanner.CalcOffset calcOffset) {
+        FieldsScanner scanner = new FieldsScanner(calcOffset == null ? new FieldsScanner.DefaultCalcOffset() : calcOffset);
+        scanner.scan(clazz, endClazz, includeTransient);
+        return new Fields(scanner.data);
+    }
+
+    public Fields(ArrayList<? extends FieldsScanner.FieldInfo> fields) {
         Collections.sort(fields);
         this.offsets = new long[fields.size()];
         this.names = new String[offsets.length];
         this.types = new Class[offsets.length];
         int index = 0;
-        for (FieldInfo f : fields) {
+        for (FieldsScanner.FieldInfo f : fields) {
             offsets[index] = f.offset;
             names[index] = f.name;
             types[index] = f.type;
@@ -71,19 +75,40 @@
         return offsets.length;
     }
 
-    public static void translateInto(Fields fields, ArrayList<FieldInfo> infos) {
+    public static void translateInto(Fields fields, ArrayList<FieldsScanner.FieldInfo> infos) {
         for (int index = 0; index < fields.getCount(); index++) {
-            infos.add(new FieldInfo(fields.offsets[index], fields.names[index], fields.types[index]));
+            infos.add(new FieldsScanner.FieldInfo(fields.offsets[index], fields.names[index], fields.types[index]));
         }
     }
 
     /**
-     * Copies fields from {@code from} to {@code to}. The objects must be of the exact same type.
+     * Function enabling an object field value to be replaced with another value when being copied
+     * within {@link Fields#copy(Object, Object, ObjectTransformer)}.
+     */
+    @FunctionalInterface
+    public interface ObjectTransformer {
+        Object apply(int index, Object from);
+    }
+
+    /**
+     * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
      *
-     * @param from the object from which the fields should be copied.
-     * @param to the object to which the fields should be copied.
+     * @param from the object from which the fields should be copied
+     * @param to the object to which the fields should be copied
      */
     public void copy(Object from, Object to) {
+        copy(from, to, null);
+    }
+
+    /**
+     * Copies fields from {@code from} to {@code to}, both of which must be of the same type.
+     *
+     * @param from the object from which the fields should be copied
+     * @param to the object to which the fields should be copied
+     * @param trans function to applied to object field values as they are copied. If {@code null},
+     *            the value is copied unchanged.
+     */
+    public void copy(Object from, Object to, ObjectTransformer trans) {
         assert from.getClass() == to.getClass();
         for (int index = 0; index < offsets.length; index++) {
             long offset = offsets[index];
@@ -109,7 +134,8 @@
                     assert false : "unhandled property type: " + type;
                 }
             } else {
-                unsafe.putObject(to, offset, unsafe.getObject(from, offset));
+                Object obj = unsafe.getObject(from, offset);
+                unsafe.putObject(to, offset, trans == null ? obj : trans.apply(index, obj));
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java	Wed Nov 05 17:32:21 2014 +0100
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import sun.misc.*;
+
+/**
+ * Scans the fields in a class hierarchy.
+ */
+public class FieldsScanner {
+
+    /**
+     * Determines the offset (in bytes) of a field.
+     */
+    public interface CalcOffset {
+
+        long getOffset(Field field);
+    }
+
+    /**
+     * Determines the offset (in bytes) of a field using {@link Unsafe#objectFieldOffset(Field)}.
+     */
+    public static class DefaultCalcOffset implements CalcOffset {
+
+        @Override
+        public long getOffset(Field field) {
+            return unsafe.objectFieldOffset(field);
+        }
+    }
+
+    /**
+     * Describes a field in a class during {@linkplain FieldsScanner 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();
+        }
+    }
+
+    private final FieldsScanner.CalcOffset calc;
+
+    /**
+     * Fields not belonging to a more specific category defined by scanner subclasses are added to
+     * this list.
+     */
+    public final ArrayList<FieldsScanner.FieldInfo> data = new ArrayList<>();
+
+    public FieldsScanner(FieldsScanner.CalcOffset calc) {
+        this.calc = calc;
+    }
+
+    /**
+     * Scans the fields in a class hierarchy.
+     *
+     * @param clazz the class at which to start scanning
+     * @param endClazz scanning stops when this class is encountered (i.e. {@code endClazz} is not
+     *            scanned)
+     */
+    public void scan(Class<?> clazz, Class<?> endClazz, boolean includeTransient) {
+        Class<?> currentClazz = clazz;
+        while (currentClazz != endClazz) {
+            for (Field field : currentClazz.getDeclaredFields()) {
+                if (Modifier.isStatic(field.getModifiers())) {
+                    continue;
+                }
+                if (!includeTransient && Modifier.isTransient(field.getModifiers())) {
+                    continue;
+                }
+                long offset = calc.getOffset(field);
+                scanField(field, offset);
+            }
+            currentClazz = currentClazz.getSuperclass();
+        }
+    }
+
+    protected void scanField(Field field, long offset) {
+        data.add(new FieldsScanner.FieldInfo(offset, field.getName(), field.getType()));
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Wed Nov 05 17:32:21 2014 +0100
@@ -28,7 +28,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.compiler.common.FieldIntrospection.FieldInfo;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.NodeClass.EdgeInfo;
 
@@ -49,7 +48,7 @@
     private final int directCount;
     private final Type type;
 
-    public Edges(Type type, int directCount, ArrayList<? extends FieldInfo> edges) {
+    public Edges(Type type, int directCount, ArrayList<? extends FieldsScanner.FieldInfo> edges) {
         super(edges);
         this.type = type;
         this.directCount = directCount;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Nov 05 17:32:21 2014 +0100
@@ -136,10 +136,10 @@
     private final boolean isLeafNode;
 
     public NodeClass(Class<?> clazz, NodeClass superNodeClass) {
-        this(clazz, superNodeClass, new DefaultCalcOffset(), null, 0);
+        this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0);
     }
 
-    public NodeClass(Class<?> clazz, NodeClass superNodeClass, CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
+    public NodeClass(Class<?> clazz, NodeClass superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         this.superNodeClass = superNodeClass;
         assert NODE_CLASS.isAssignableFrom(clazz);
@@ -151,9 +151,9 @@
 
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
-        FieldScanner fs = new FieldScanner(calcOffset, superNodeClass);
+        NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass);
         try (TimerCloseable t = Init_FieldScanning.start()) {
-            fs.scan(clazz, false);
+            fs.scan(clazz, clazz.getSuperclass(), false);
         }
 
         try (TimerCloseable t1 = Init_Edges.start()) {
@@ -266,7 +266,7 @@
     /**
      * Describes a field representing an input or successor edge in a node.
      */
-    protected static class EdgeInfo extends FieldInfo {
+    protected static class EdgeInfo extends FieldsScanner.FieldInfo {
 
         public EdgeInfo(long offset, String name, Class<?> type) {
             super(offset, name, type);
@@ -276,7 +276,7 @@
          * Sorts non-list edges before list edges.
          */
         @Override
-        public int compareTo(FieldInfo o) {
+        public int compareTo(FieldsScanner.FieldInfo o) {
             if (NodeList.class.isAssignableFrom(o.type)) {
                 if (!NodeList.class.isAssignableFrom(type)) {
                     return -1;
@@ -309,14 +309,14 @@
         }
     }
 
-    protected static class FieldScanner extends BaseFieldScanner {
+    protected static class NodeFieldsScanner extends FieldsScanner {
 
         public final ArrayList<InputInfo> inputs = new ArrayList<>();
         public final ArrayList<EdgeInfo> successors = new ArrayList<>();
         int directInputs;
         int directSuccessors;
 
-        protected FieldScanner(CalcOffset calc, NodeClass superNodeClass) {
+        protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass superNodeClass) {
             super(calc);
             if (superNodeClass != null) {
                 translateInto(superNodeClass.inputs, inputs);
@@ -372,7 +372,7 @@
                     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);
-                    data.add(new FieldInfo(offset, field.getName(), type));
+                    super.scanField(field, offset);
                 }
             }
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Wed Nov 05 17:32:21 2014 +0100
@@ -58,22 +58,22 @@
     }
 
     public CompositeValueClass(Class<? extends CompositeValue> clazz) {
-        this(clazz, new DefaultCalcOffset());
+        this(clazz, new FieldsScanner.DefaultCalcOffset());
     }
 
-    public CompositeValueClass(Class<? extends CompositeValue> clazz, CalcOffset calcOffset) {
+    public CompositeValueClass(Class<? extends CompositeValue> clazz, FieldsScanner.CalcOffset calcOffset) {
         super(clazz);
 
-        ValueFieldScanner vfs = new ValueFieldScanner(calcOffset);
-        vfs.scan(clazz, true);
+        CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(calcOffset);
+        vfs.scan(clazz, CompositeValue.class, false);
 
         values = new Values(vfs.valueAnnotations.get(CompositeValue.Component.class));
         data = new Fields(vfs.data);
     }
 
-    private static class ValueFieldScanner extends FieldScanner {
+    private static class CompositeValueFieldsScanner extends LIRFieldsScanner {
 
-        public ValueFieldScanner(CalcOffset calc) {
+        public CompositeValueFieldsScanner(FieldsScanner.CalcOffset calc) {
             super(calc);
             valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Wed Nov 05 17:32:21 2014 +0100
@@ -63,14 +63,14 @@
     private int opcodeIndex;
 
     private LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
-        this(clazz, new DefaultCalcOffset());
+        this(clazz, new FieldsScanner.DefaultCalcOffset());
     }
 
-    public LIRInstructionClass(Class<? extends LIRInstruction> clazz, CalcOffset calcOffset) {
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz, FieldsScanner.CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        InstructionFieldScanner ifs = new InstructionFieldScanner(calcOffset);
+        LIRInstructionFieldsScanner ifs = new LIRInstructionFieldsScanner(calcOffset);
         ifs.scan(clazz);
 
         uses = new Values(ifs.valueAnnotations.get(LIRInstruction.Use.class));
@@ -89,16 +89,16 @@
         }
     }
 
-    private static class InstructionFieldScanner extends FieldScanner {
+    private static class LIRInstructionFieldsScanner extends LIRFieldsScanner {
 
         private String opcodeConstant;
 
         /**
          * Field (if any) annotated by {@link Opcode}.
          */
-        private FieldInfo opcodeField;
+        private FieldsScanner.FieldInfo opcodeField;
 
-        public InstructionFieldScanner(CalcOffset calc) {
+        public LIRInstructionFieldsScanner(FieldsScanner.CalcOffset calc) {
             super(calc);
 
             valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
@@ -134,7 +134,7 @@
             }
             opcodeField = null;
 
-            super.scan(clazz, true);
+            super.scan(clazz, LIRInstructionBase.class, false);
 
             if (opcodeConstant == null && opcodeField == null) {
                 opcodeConstant = clazz.getSimpleName();
@@ -150,7 +150,7 @@
             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;
-                states.add(new FieldInfo(offset, field.getName(), type));
+                states.add(new FieldsScanner.FieldInfo(offset, field.getName(), type));
             } else {
                 super.scanField(field, offset);
             }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Wed Nov 05 17:07:30 2014 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Wed Nov 05 17:32:21 2014 +0100
@@ -96,7 +96,7 @@
      */
     protected Values values;
 
-    protected static class ValueFieldInfo extends FieldInfo {
+    protected static class ValueFieldInfo extends FieldsScanner.FieldInfo {
 
         final EnumSet<OperandFlag> flags;
 
@@ -110,7 +110,7 @@
          * Sorts non-array fields before array fields.
          */
         @Override
-        public int compareTo(FieldInfo o) {
+        public int compareTo(FieldsScanner.FieldInfo o) {
             if (VALUE_ARRAY_CLASS.isAssignableFrom(o.type)) {
                 if (!VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
                     return -1;
@@ -138,12 +138,12 @@
         public final ArrayList<ValueFieldInfo> values = new ArrayList<>();
     }
 
-    protected abstract static class FieldScanner extends BaseFieldScanner {
+    protected abstract static class LIRFieldsScanner extends FieldsScanner {
 
         public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
-        public final ArrayList<FieldInfo> states = new ArrayList<>();
+        public final ArrayList<FieldsScanner.FieldInfo> states = new ArrayList<>();
 
-        public FieldScanner(CalcOffset calc) {
+        public LIRFieldsScanner(FieldsScanner.CalcOffset calc) {
             super(calc);
             valueAnnotations = new HashMap<>();
         }
@@ -182,7 +182,7 @@
             } 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;
-                data.add(new FieldInfo(offset, field.getName(), type));
+                super.scanField(field, offset);
             }
         }