Mercurial > hg > truffle
diff graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java @ 5858:911315a3e642
Factor out common infrastructure from NodeClass and LIRInstructionClass
author | Christian Wimmer <christian.wimmer@oracle.com> |
---|---|
date | Wed, 18 Jul 2012 13:49:51 -0700 |
parents | 3b8bc07f8d17 |
children | 5d7d9a6953bd |
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Jul 18 10:50:57 2012 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Wed Jul 18 13:49:51 2012 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2012, 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 @@ -21,66 +21,46 @@ * questions. */ package com.oracle.graal.graph; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; +import java.lang.reflect.*; import java.util.*; -import java.util.Map.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.Map.Entry; import com.oracle.graal.graph.Graph.DuplicationReplacement; -import com.oracle.graal.graph.Node.*; +import com.oracle.graal.graph.Node.Verbosity; + +public class NodeClass extends FieldIntrospection { + + public static final NodeClass get(Class<?> c) { + NodeClass clazz = (NodeClass) allClasses.get(c); + if (clazz != null) { + return clazz; + } -import sun.misc.Unsafe; + // We can have a race of multiple threads creating the LIRInstructionClass at the same time. + // However, only one will be put into the map, and this is the one returned by all threads. + clazz = new NodeClass(c); + NodeClass oldClazz = (NodeClass) allClasses.putIfAbsent(c, clazz); + if (oldClazz != null) { + return oldClazz; + } else { + return clazz; + } + } -public class NodeClass { public static final int NOT_ITERABLE = -1; - /** - * Interface used by {@link NodeClass#rescanAllFieldOffsets(CalcOffset)} to determine the offset (in bytes) of a field. - */ - public interface CalcOffset { - long getOffset(Field field); - } - - private static final Class< ? > NODE_CLASS = Node.class; - private static final Class< ? > INPUT_LIST_CLASS = NodeInputList.class; - private static final Class< ? > SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; - - private static final Unsafe unsafe = getUnsafe(); + private static final Class<?> NODE_CLASS = Node.class; + private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class; + private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; - private static Unsafe getUnsafe() { - try { - // this will only fail if graal is not part of the boot class path - return Unsafe.getUnsafe(); - } catch (SecurityException e) { - // nothing to do - } - try { - Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafeInstance.setAccessible(true); - return (Unsafe) theUnsafeInstance.get(Unsafe.class); - } catch (Exception e) { - // currently we rely on being able to use Unsafe... - throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e); - } - } - - private static final Map<Class< ? >, NodeClass> nodeClasses = new ConcurrentHashMap<>(); private static int nextIterableId = 0; - private final Class< ? > clazz; private final int directInputCount; private final long[] inputOffsets; - private final Class<?>[] inputTypes; - private final String[] inputNames; private final int directSuccessorCount; private final long[] successorOffsets; - private final Class<?>[] successorTypes; - private final String[] successorNames; - private final long[] dataOffsets; private final Class<?>[] dataTypes; - private final String[] dataNames; private final boolean canGVN; private final int startGVNNumber; private final String shortName; @@ -88,16 +68,10 @@ private final int iterableId; private final boolean hasOutgoingEdges; - static class DefaultCalcOffset implements CalcOffset { - @Override - public long getOffset(Field field) { - return unsafe.objectFieldOffset(field); - } - } - public NodeClass(Class< ? > clazz) { + public NodeClass(Class<?> clazz) { + super(clazz); assert NODE_CLASS.isAssignableFrom(clazz); - this.clazz = clazz; FieldScanner scanner = new FieldScanner(new DefaultCalcOffset()); scanner.scan(clazz); @@ -106,16 +80,15 @@ inputOffsets = sortedLongCopy(scanner.inputOffsets, scanner.inputListOffsets); directSuccessorCount = scanner.successorOffsets.size(); successorOffsets = sortedLongCopy(scanner.successorOffsets, scanner.successorListOffsets); - dataOffsets = new long[scanner.dataOffsets.size()]; - for (int i = 0; i < scanner.dataOffsets.size(); ++i) { - dataOffsets[i] = scanner.dataOffsets.get(i); + + dataOffsets = sortedLongCopy(scanner.dataOffsets); + dataTypes = new Class[dataOffsets.length]; + for (int i = 0; i < dataOffsets.length; i++) { + dataTypes[i] = scanner.fieldTypes.get(dataOffsets[i]); } - dataTypes = scanner.dataTypes.toArray(new Class[0]); - dataNames = scanner.dataNames.toArray(new String[0]); - inputTypes = arrayUsingSortedOffsets(scanner.inputTypesMap, inputOffsets, new Class<?>[inputOffsets.length]); - inputNames = arrayUsingSortedOffsets(scanner.inputNamesMap, inputOffsets, new String[inputOffsets.length]); - successorTypes = arrayUsingSortedOffsets(scanner.successorTypesMap, successorOffsets, new Class<?>[successorOffsets.length]); - successorNames = arrayUsingSortedOffsets(scanner.successorNamesMap, successorOffsets, new String[successorOffsets.length]); + + fieldNames = scanner.fieldNames; + fieldTypes = scanner.fieldTypes; canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz); startGVNNumber = clazz.hashCode(); @@ -150,52 +123,26 @@ this.hasOutgoingEdges = this.inputOffsets.length > 0 || this.successorOffsets.length > 0; } - public static void rescanAllFieldOffsets(CalcOffset calc) { - for (NodeClass nodeClass : nodeClasses.values()) { - nodeClass.rescanFieldOffsets(calc); - } - } - - private void rescanFieldOffsets(CalcOffset calc) { + @Override + protected void rescanFieldOffsets(CalcOffset calc) { FieldScanner scanner = new FieldScanner(calc); scanner.scan(clazz); assert directInputCount == scanner.inputOffsets.size(); copyInto(inputOffsets, sortedLongCopy(scanner.inputOffsets, scanner.inputListOffsets)); assert directSuccessorCount == scanner.successorOffsets.size(); copyInto(successorOffsets, sortedLongCopy(scanner.successorOffsets, scanner.successorListOffsets)); - assert dataOffsets.length == scanner.dataOffsets.size(); - for (int i = 0; i < scanner.dataOffsets.size(); ++i) { - dataOffsets[i] = scanner.dataOffsets.get(i); + copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets)); + + for (int i = 0; i < dataOffsets.length; i++) { + dataTypes[i] = scanner.fieldTypes.get(dataOffsets[i]); } - copyInto(dataTypes, scanner.dataTypes); - copyInto(dataNames, scanner.dataNames); - copyInto(inputTypes, arrayUsingSortedOffsets(scanner.inputTypesMap, this.inputOffsets, new Class<?>[this.inputOffsets.length])); - copyInto(inputNames, arrayUsingSortedOffsets(scanner.inputNamesMap, this.inputOffsets, new String[this.inputOffsets.length])); - copyInto(successorTypes, arrayUsingSortedOffsets(scanner.successorTypesMap, this.successorOffsets, new Class<?>[this.successorOffsets.length])); - copyInto(successorNames, arrayUsingSortedOffsets(scanner.successorNamesMap, this.successorOffsets, new String[this.successorNames.length])); + fieldNames.clear(); + fieldNames.putAll(scanner.fieldNames); + fieldTypes.clear(); + fieldTypes.putAll(scanner.fieldTypes); } - private static void copyInto(long[] dest, long[] src) { - assert dest.length == src.length; - for (int i = 0; i < dest.length; i++) { - dest[i] = src[i]; - } - } - - private 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]; - } - } - - private 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); - } - } public boolean hasOutgoingEdges() { return hasOutgoingEdges; @@ -213,107 +160,49 @@ return canGVN; } - private static synchronized NodeClass getSynchronized(Class< ? > c) { - NodeClass clazz = nodeClasses.get(c); - if (clazz == null) { - clazz = new NodeClass(c); - nodeClasses.put(c, clazz); - } - return clazz; - } - - public static final NodeClass get(Class< ? > c) { - NodeClass clazz = nodeClasses.get(c); - return clazz == null ? getSynchronized(c) : clazz; - } - public static int cacheSize() { return nextIterableId; } - private static class FieldScanner { + protected static class FieldScanner extends BaseFieldScanner { public final ArrayList<Long> inputOffsets = new ArrayList<>(); public final ArrayList<Long> inputListOffsets = new ArrayList<>(); - public final Map<Long, Class< ? >> inputTypesMap = new HashMap<>(); - public final Map<Long, String> inputNamesMap = new HashMap<>(); public final ArrayList<Long> successorOffsets = new ArrayList<>(); public final ArrayList<Long> successorListOffsets = new ArrayList<>(); - public final Map<Long, Class< ? >> successorTypesMap = new HashMap<>(); - public final Map<Long, String> successorNamesMap = new HashMap<>(); - public final ArrayList<Long> dataOffsets = new ArrayList<>(); - public final ArrayList<Class< ? >> dataTypes = new ArrayList<>(); - public final ArrayList<String> dataNames = new ArrayList<>(); - public final CalcOffset calc; - public FieldScanner(CalcOffset calc) { - this.calc = calc; + protected FieldScanner(CalcOffset calc) { + super(calc); } - public void scan(Class< ? > clazz) { - Class< ? > currentClazz = clazz; - do { - for (Field field : currentClazz.getDeclaredFields()) { - if (!Modifier.isStatic(field.getModifiers())) { - Class< ? > type = field.getType(); - long offset = calc.getOffset(field); - String name = field.getName(); - if (field.isAnnotationPresent(Node.Input.class)) { - assert !field.isAnnotationPresent(Node.Successor.class) : "field cannot be both input and successor"; - if (INPUT_LIST_CLASS.isAssignableFrom(type)) { - inputListOffsets.add(offset); - } else { - assert NODE_CLASS.isAssignableFrom(type) : "invalid input type: " + type; - inputOffsets.add(offset); - inputTypesMap.put(offset, type); - } - if (field.getAnnotation(Node.Input.class).notDataflow()) { - inputNamesMap.put(offset, name + "#NDF"); - } else { - inputNamesMap.put(offset, name); - } - } else if (field.isAnnotationPresent(Node.Successor.class)) { - if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { - successorListOffsets.add(offset); - } else { - assert NODE_CLASS.isAssignableFrom(type) : "invalid successor type: " + type; - successorOffsets.add(offset); - successorTypesMap.put(offset, type); - } - successorNamesMap.put(offset, name); - } else { - assert !NODE_CLASS.isAssignableFrom(type) || name.equals("Null") : "suspicious node field: " + field; - assert !INPUT_LIST_CLASS.isAssignableFrom(type) : "suspicious node input list field: " + field; - assert !SUCCESSOR_LIST_CLASS.isAssignableFrom(type) : "suspicious node successor list field: " + field; - dataOffsets.add(offset); - dataTypes.add(type); - dataNames.add(name); - } - } + @Override + protected void scanField(Field field, Class<?> type, long offset) { + if (field.isAnnotationPresent(Node.Input.class)) { + assert !field.isAnnotationPresent(Node.Successor.class) : "field cannot be both input and successor"; + if (INPUT_LIST_CLASS.isAssignableFrom(type)) { + inputListOffsets.add(offset); + } else { + assert NODE_CLASS.isAssignableFrom(type) : "invalid input type: " + type; + inputOffsets.add(offset); + } + if (field.getAnnotation(Node.Input.class).notDataflow()) { + fieldNames.put(offset, field.getName() + "#NDF"); } - currentClazz = currentClazz.getSuperclass(); - } while (currentClazz != Node.class); + } else if (field.isAnnotationPresent(Node.Successor.class)) { + if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { + successorListOffsets.add(offset); + } else { + assert NODE_CLASS.isAssignableFrom(type) : "invalid successor type: " + type; + successorOffsets.add(offset); + } + } else { + assert !NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null") : "suspicious node field: " + field; + assert !INPUT_LIST_CLASS.isAssignableFrom(type) : "suspicious node input list field: " + field; + assert !SUCCESSOR_LIST_CLASS.isAssignableFrom(type) : "suspicious node successor list field: " + field; + dataOffsets.add(offset); + } } } - private 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; - } - - private 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; - } @Override public String toString() { @@ -561,7 +450,7 @@ */ public void getDebugProperties(Node node, Map<Object, Object> properties) { for (int i = 0; i < dataOffsets.length; ++i) { - Class<?> type = dataTypes[i]; + Class<?> type = fieldTypes.get(dataOffsets[i]); Object value = null; if (type.isPrimitive()) { if (type == Integer.TYPE) { @@ -580,7 +469,7 @@ } else { value = unsafe.getObject(node, dataOffsets[i]); } - properties.put(dataNames[i], value); + properties.put(fieldNames.get(dataOffsets[i]), value); } } @@ -654,14 +543,14 @@ } public String getName(Position pos) { - return pos.input ? inputNames[pos.index] : successorNames[pos.index]; + return fieldNames.get(pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]); } private void set(Node node, Position pos, Node x) { long offset = pos.input ? inputOffsets[pos.index] : successorOffsets[pos.index]; if (pos.subIndex == NOT_ITERABLE) { Node old = getNode(node, offset); - assert x == null || (pos.input ? inputTypes : successorTypes)[pos.index].isAssignableFrom(x.getClass()) : this + ".set(node, pos, " + x + ") while type is " + (pos.input ? inputTypes : successorTypes)[pos.index]; + assert x == null || fieldTypes.get((pos.input ? inputOffsets : successorOffsets)[pos.index]).isAssignableFrom(x.getClass()) : this + ".set(node, pos, " + x + ")"; putNode(node, offset, x); if (pos.input) { node.updateUsages(old, x); @@ -717,7 +606,7 @@ while (index < directInputCount) { Node input = getNode(node, inputOffsets[index]); if (input == old) { - assert other == null || inputTypes[index].isAssignableFrom(other.getClass()); // : "Can not assign " + other.getClass() + " to " + inputTypes[index] + " in " + node; + assert other == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(other.getClass()); // : "Can not assign " + other.getClass() + " to " + inputTypes[index] + " in " + node; putNode(node, inputOffsets[index], other); return true; } @@ -739,7 +628,7 @@ while (index < directSuccessorCount) { Node successor = getNode(node, successorOffsets[index]); if (successor == old) { - assert other == null || successorTypes[index].isAssignableFrom(other.getClass()); // : successorTypes[index] + " is not compatible with " + other.getClass(); + assert other == null || fieldTypes.get(successorOffsets[index]).isAssignableFrom(other.getClass()); // : successorTypes[index] + " is not compatible with " + other.getClass(); putNode(node, successorOffsets[index], other); return true; } @@ -970,7 +859,7 @@ Node replacement = replacements.replacement(input); if (replacement != input) { replacementsMap.put(input, replacement); - assert replacement == null || node.getNodeClass().inputTypes[pos.index] == null || node.getNodeClass().inputTypes[pos.index].isAssignableFrom(replacement.getClass()); + assert isAssignable(node.getNodeClass().fieldTypes.get(node.getNodeClass().inputOffsets[pos.index]), replacement); target = replacement; } else if (input.graph() == graph) { // patch to the outer world target = input; @@ -998,7 +887,7 @@ Node replacement = replacements.replacement(succ); if (replacement != succ) { replacementsMap.put(succ, replacement); - assert replacement == null || node.getNodeClass().successorTypes[pos.index] == null || node.getNodeClass().successorTypes[pos.index].isAssignableFrom(replacement.getClass()); + assert isAssignable(node.getNodeClass().fieldTypes.get(node.getNodeClass().successorOffsets[pos.index]), replacement); target = replacement; } } @@ -1008,4 +897,8 @@ } return newNodes; } + + private static boolean isAssignable(Class<?> fieldType, Node replacement) { + return replacement == null || !NODE_CLASS.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(replacement.getClass()); + } }