# HG changeset patch # User Doug Simon # Date 1415205141 -3600 # Node ID d66c79acfeace3036ef85f6f6500667cf24d1af7 # Parent 0f23e16288c5f3827611067844eeaf35dd79d102 refactored Fields class to make it usable for implementing custom serialization diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java --- 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, 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 { - 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 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); - } } diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java --- 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 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 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 infos) { + public static void translateInto(Fields fields, ArrayList 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)); } } } diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldsScanner.java --- /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 { + 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 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())); + } +} diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java --- 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 edges) { + public Edges(Type type, int directCount, ArrayList edges) { super(edges); this.type = type; this.directCount = directCount; diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- 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 inputs = new ArrayList<>(); public final ArrayList 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); } } } diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java --- 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 clazz) { - this(clazz, new DefaultCalcOffset()); + this(clazz, new FieldsScanner.DefaultCalcOffset()); } - public CompositeValueClass(Class clazz, CalcOffset calcOffset) { + public CompositeValueClass(Class 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()); } diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java --- 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 clazz) { - this(clazz, new DefaultCalcOffset()); + this(clazz, new FieldsScanner.DefaultCalcOffset()); } - public LIRInstructionClass(Class clazz, CalcOffset calcOffset) { + public LIRInstructionClass(Class 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); } diff -r 0f23e16288c5 -r d66c79acfeac graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java --- 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 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 values = new ArrayList<>(); } - protected abstract static class FieldScanner extends BaseFieldScanner { + protected abstract static class LIRFieldsScanner extends FieldsScanner { public final Map, OperandModeAnnotation> valueAnnotations; - public final ArrayList states = new ArrayList<>(); + public final ArrayList 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); } }