changeset 17329:1e7e354e407f

use Unsafe.allocateInstance in Node.clone(Graph into, boolean clearInputsAndSuccessors) to avoid initializing fields twice
author Doug Simon <doug.simon@oracle.com>
date Fri, 03 Oct 2014 15:16:02 +0200
parents c9bb0da795d4
children 106f78219955
files 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/Node.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java
diffstat 4 files changed, 92 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Oct 03 14:19:58 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/Fields.java	Fri Oct 03 15:16:02 2014 +0200
@@ -78,6 +78,43 @@
     }
 
     /**
+     * Copies fields from {@code from} to {@code to}. The objects must be of the exact same type.
+     *
+     * @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) {
+        assert from.getClass() == to.getClass();
+        for (int index = 0; index < offsets.length; index++) {
+            long offset = offsets[index];
+            Class<?> type = types[index];
+            if (type.isPrimitive()) {
+                if (type == Integer.TYPE) {
+                    unsafe.putInt(to, offset, unsafe.getInt(from, offset));
+                } else if (type == Long.TYPE) {
+                    unsafe.putLong(to, offset, unsafe.getLong(from, offset));
+                } else if (type == Boolean.TYPE) {
+                    unsafe.putBoolean(to, offset, unsafe.getBoolean(from, offset));
+                } else if (type == Float.TYPE) {
+                    unsafe.putFloat(to, offset, unsafe.getFloat(from, offset));
+                } else if (type == Double.TYPE) {
+                    unsafe.putDouble(to, offset, unsafe.getDouble(from, offset));
+                } else if (type == Short.TYPE) {
+                    unsafe.putShort(to, offset, unsafe.getShort(from, offset));
+                } else if (type == Character.TYPE) {
+                    unsafe.putChar(to, offset, unsafe.getChar(from, offset));
+                } else if (type == Byte.TYPE) {
+                    unsafe.putByte(to, offset, unsafe.getByte(from, offset));
+                } else {
+                    assert false : "unhandled property type: " + type;
+                }
+            } else {
+                unsafe.putObject(to, offset, unsafe.getObject(from, offset));
+            }
+        }
+    }
+
+    /**
      * Gets the value of a field for a given object.
      *
      * @param object the object whose field is to be read
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Oct 03 14:19:58 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Fri Oct 03 15:16:02 2014 +0200
@@ -135,6 +135,24 @@
     }
 
     /**
+     * Initializes the list edges in a given node based on the size of the list edges in a prototype
+     * node.
+     *
+     * @param node the node whose list edges are to be initialized
+     * @param prototype the node whose list edge sizes are used when creating new edge lists
+     */
+    public void initializeLists(Node node, Node prototype) {
+        int index = getDirectCount();
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(prototype, index);
+            int size = list.initialSize;
+            NodeList<Node> newList = type == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+            initializeList(node, index, newList);
+            index++;
+        }
+    }
+
+    /**
      * Copies edges from {@code fromNode} to {@code toNode}. The nodes are expected to be of the
      * exact same type.
      *
@@ -150,7 +168,13 @@
         }
         while (index < getCount()) {
             NodeList<Node> list = getNodeList(toNode, index);
-            list.copy(getNodeList(fromNode, index));
+            if (list == null) {
+                NodeList<Node> fromList = getNodeList(fromNode, index);
+                list = type == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList);
+                initializeList(toNode, index, list);
+            } else {
+                list.copy(getNodeList(fromNode, index));
+            }
             index++;
         }
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Oct 03 14:19:58 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Oct 03 15:16:02 2014 +0200
@@ -58,6 +58,7 @@
 public abstract class Node implements Cloneable, Formattable {
 
     public final static boolean USE_GENERATED_NODES = Boolean.parseBoolean(System.getProperty("graal.useGeneratedNodes", "true"));
+    public final static boolean USE_UNSAFE_CLONE = Boolean.parseBoolean(System.getProperty("graal.useUnsafeClone", "true"));
 
     static final int DELETED_ID_START = -1000000000;
     static final int INITIAL_ID = -1;
@@ -756,24 +757,36 @@
 
         Node newNode = null;
         try {
-            newNode = (Node) this.clone();
-        } catch (CloneNotSupportedException e) {
+            if (USE_UNSAFE_CLONE) {
+                newNode = (Node) UnsafeAccess.unsafe.allocateInstance(getClass());
+                nodeClass.getData().copy(this, newNode);
+                if (clearInputsAndSuccessors) {
+                    nodeClass.getEdges(Inputs).initializeLists(newNode, this);
+                    nodeClass.getEdges(Successors).initializeLists(newNode, this);
+                } else {
+                    nodeClass.getEdges(Inputs).copy(this, newNode);
+                    nodeClass.getEdges(Successors).copy(this, newNode);
+                }
+            } else {
+                newNode = (Node) this.clone();
+                if (clearInputsAndSuccessors) {
+                    nodeClass.getEdges(Inputs).clear(newNode);
+                    nodeClass.getEdges(Successors).clear(newNode);
+                }
+                newNode.typeCacheNext = null;
+                newNode.usage0 = null;
+                newNode.usage1 = null;
+                newNode.predecessor = null;
+            }
+        } catch (Exception e) {
             throw new GraalGraphInternalError(e).addContext(this);
         }
-        if (clearInputsAndSuccessors) {
-            nodeClass.getEdges(Inputs).clear(newNode);
-            nodeClass.getEdges(Successors).clear(newNode);
-        }
         newNode.graph = into;
-        newNode.typeCacheNext = null;
         newNode.id = INITIAL_ID;
         if (into != null) {
             into.register(newNode);
         }
-        newNode.usage0 = null;
-        newNode.usage1 = null;
         newNode.extraUsages = NO_NODES;
-        newNode.predecessor = null;
 
         if (into != null && nodeClass.valueNumberable() && nodeClass.isLeafNode()) {
             into.putNodeIntoCache(newNode);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Fri Oct 03 14:19:58 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Fri Oct 03 15:16:02 2014 +0200
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.graph.Edges.Type.*;
 
+import java.util.*;
+
 import com.oracle.graal.graph.Edges.*;
 
 public final class NodeSuccessorList<T extends Node> extends NodeList<T> {
@@ -41,6 +43,11 @@
         assert self.usages().isEmpty();
     }
 
+    public NodeSuccessorList(Node self, List<? extends T> elements) {
+        super(self, elements);
+        assert self.usages().isEmpty();
+    }
+
     @Override
     protected void update(T oldNode, T newNode) {
         self.updatePredecessor(oldNode, newNode);