changeset 17210:ef64e2682bb6

added Edges class to consolidate code operating on set of input or successor edges and to better isolate magic used to access edges
author Doug Simon <doug.simon@oracle.com>
date Thu, 25 Sep 2014 10:27:17 +0200
parents 1b6172cb270e
children 1ac6b4879443 f4b939d433a4
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionCollection.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionIterator.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.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/NodeClassIterable.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java
diffstat 26 files changed, 1114 insertions(+), 1509 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Thu Sep 25 10:27:17 2014 +0200
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2012, 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
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
+public class NodePosIteratorTest extends GraalCompilerTest {
+
+    @NodeInfo
+    static class TestNode extends Node {
+        @Successor Node s1;
+        @Successor Node s2;
+        @Successor NodeSuccessorList<Node> stail;
+
+        @Input NodeInputList<ValueNode> itail;
+        @Input ConstantNode i1;
+        @Input FloatingNode i2;
+
+        public static TestNode create() {
+            return USE_GENERATED_NODES ? new NodePosIteratorTest_TestNodeGen() : new TestNode();
+        }
+    }
+
+    @Test
+    public void testInputs() {
+        TestNode n = TestNode.create();
+
+        ConstantNode i1 = ConstantNode.forInt(1);
+        ConstantNode i2 = ConstantNode.forDouble(1.0d);
+        ConstantNode i3 = ConstantNode.forInt(4);
+        ConstantNode i4 = ConstantNode.forInt(14);
+        n.itail = new NodeInputList<>(n, new ValueNode[]{i3, i4});
+        n.i1 = i1;
+        n.i2 = i2;
+
+        NodeClassIterable inputs = n.inputs();
+
+        NodePosIterator iterator = inputs.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = inputs.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals("ConstantNode:i1", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals("FloatingNode:i2", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals("NodeInputList:itail[0]", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals("NodeInputList:itail[1]", iterator.nextPosition().toString());
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = inputs.iterator();
+        n.i1 = i4;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        n.i2 = i1;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i3);
+        n.itail.initialize(1, i4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = inputs.iterator();
+        n.i1 = null;
+        n.i2 = i2;
+        n.itail.initialize(0, null);
+        n.itail.initialize(1, i4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = inputs.withNullIterator();
+        n.i1 = null;
+        n.i2 = null;
+        n.itail.initialize(0, i3);
+        n.itail.initialize(1, null);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), i3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+    }
+
+    @Test
+    public void testSuccessors() {
+        TestNode n = TestNode.create();
+        EndNode s1 = EndNode.create();
+        EndNode s2 = EndNode.create();
+        EndNode s3 = EndNode.create();
+        EndNode s4 = EndNode.create();
+        n.s1 = s1;
+        n.s2 = s2;
+        n.stail = new NodeSuccessorList<>(n, new Node[]{s3, s4});
+
+        NodeClassIterable successors = n.successors();
+        NodePosIterator iterator = successors.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = successors.iterator();
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(Node.class.getSimpleName() + ":s1", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(Node.class.getSimpleName() + ":s2", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[0]", iterator.nextPosition().toString());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(NodeSuccessorList.class.getSimpleName() + ":stail[1]", iterator.nextPosition().toString());
+        Assert.assertFalse(iterator.hasNext());
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = successors.iterator();
+        n.s1 = s4;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        n.s2 = s1;
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s1);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s3);
+        n.stail.initialize(1, s4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = successors.iterator();
+        n.s1 = null;
+        n.s2 = s2;
+        n.stail.initialize(0, null);
+        n.stail.initialize(1, s4);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s2);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s4);
+        Assert.assertFalse(iterator.hasNext());
+
+        iterator = successors.withNullIterator();
+        n.s1 = null;
+        n.s2 = null;
+        n.stail.initialize(0, s3);
+        n.stail.initialize(1, null);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertEquals(iterator.next(), s3);
+        Assert.assertTrue(iterator.hasNext());
+        Assert.assertNull(iterator.next());
+        Assert.assertFalse(iterator.hasNext());
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java	Wed Sep 24 17:17:27 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,219 +0,0 @@
-/*
- * Copyright (c) 2012, 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
- * 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.test;
-
-import org.junit.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-public class NodeRefIteratorTest extends GraalCompilerTest {
-
-    @NodeInfo
-    static class TestNode extends Node {
-        @Successor Node s1;
-        @Successor Node s2;
-        @Successor NodeSuccessorList<Node> stail;
-
-        @Input NodeInputList<ValueNode> itail;
-        @Input ValueNode i1;
-        @Input ValueNode i2;
-
-        public static TestNode create() {
-            return USE_GENERATED_NODES ? new NodeRefIteratorTest_TestNodeGen() : new TestNode();
-        }
-    }
-
-    @Test
-    public void testInputs() {
-        TestNode n = TestNode.create();
-
-        ConstantNode i1 = ConstantNode.forInt(1);
-        ConstantNode i2 = ConstantNode.forDouble(1.0d);
-        ConstantNode i3 = ConstantNode.forInt(4);
-        ConstantNode i4 = ConstantNode.forInt(14);
-        n.itail = new NodeInputList<>(n, new ValueNode[]{i3, i4});
-        n.i1 = i1;
-        n.i2 = i2;
-
-        NodeClassIterable inputs = n.inputs();
-
-        NodePosIterator iterator = inputs.iterator();
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i1);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i2);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i3);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i4);
-        Assert.assertFalse(iterator.hasNext());
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = inputs.iterator();
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "input 0/-1");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "input 1/-1");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "input 2/0");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "input 2/1");
-        Assert.assertFalse(iterator.hasNext());
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = inputs.iterator();
-        n.i1 = i4;
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i4);
-        n.i2 = i1;
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i1);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i3);
-        n.itail.initialize(1, i4);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i4);
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = inputs.iterator();
-        n.i1 = null;
-        n.i2 = i2;
-        n.itail.initialize(0, null);
-        n.itail.initialize(1, i4);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i2);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i4);
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = inputs.withNullIterator();
-        n.i1 = null;
-        n.i2 = null;
-        n.itail.initialize(0, i3);
-        n.itail.initialize(1, null);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), i3);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertFalse(iterator.hasNext());
-    }
-
-    @Test
-    public void testSuccessors() {
-        TestNode n = TestNode.create();
-        EndNode s1 = EndNode.create();
-        EndNode s2 = EndNode.create();
-        EndNode s3 = EndNode.create();
-        EndNode s4 = EndNode.create();
-        n.s1 = s1;
-        n.s2 = s2;
-        n.stail = new NodeSuccessorList<>(n, new Node[]{s3, s4});
-
-        NodeClassIterable successors = n.successors();
-        NodePosIterator iterator = successors.iterator();
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s1);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s2);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s3);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s4);
-        Assert.assertFalse(iterator.hasNext());
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = successors.iterator();
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "successor 0/-1");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "successor 1/-1");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "successor 2/0");
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.nextPosition().toString(), "successor 2/1");
-        Assert.assertFalse(iterator.hasNext());
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = successors.iterator();
-        n.s1 = s4;
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s4);
-        n.s2 = s1;
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s1);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s3);
-        n.stail.initialize(1, s4);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s4);
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = successors.iterator();
-        n.s1 = null;
-        n.s2 = s2;
-        n.stail.initialize(0, null);
-        n.stail.initialize(1, s4);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s2);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s4);
-        Assert.assertFalse(iterator.hasNext());
-
-        iterator = successors.withNullIterator();
-        n.s1 = null;
-        n.s2 = null;
-        n.stail.initialize(0, s3);
-        n.stail.initialize(1, null);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertEquals(iterator.next(), s3);
-        Assert.assertTrue(iterator.hasNext());
-        Assert.assertNull(iterator.next());
-        Assert.assertFalse(iterator.hasNext());
-    }
-}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Thu Sep 25 10:27:17 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.match;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
+import static com.oracle.graal.graph.Edges.Type.*;
 
 import java.util.*;
 import java.util.Map.Entry;
@@ -65,11 +66,10 @@
         Position[] result = new Position[names.length];
         NodeClass nodeClass = lookup.get(theClass);
         for (int i = 0; i < names.length; i++) {
-            for (Position position : nodeClass.getFirstLevelInputPositions()) {
-                String name = nodeClass.getName(position);
-                if (name.equals(names[i])) {
-                    result[i] = position;
-                    break;
+            Edges edges = nodeClass.getEdges(Inputs);
+            for (int e = 0; e < edges.getDirectCount(); e++) {
+                if (names[i].equals(edges.getName(e))) {
+                    result[i] = new Position(edges, e, Node.NOT_ITERABLE);
                 }
             }
             if (result[i] == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Thu Sep 25 10:27:17 2014 +0200
@@ -0,0 +1,487 @@
+/*
+ * 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.graph;
+
+import static com.oracle.graal.compiler.common.UnsafeAccess.*;
+import static com.oracle.graal.graph.Graph.*;
+import static com.oracle.graal.graph.Node.*;
+
+import java.util.*;
+
+/**
+ * Describes {@link Node} fields representing the set of inputs for the node or the set of the
+ * node's successors.
+ */
+public abstract class Edges {
+
+    /**
+     * Constants denoting whether a set of edges are inputs or successors.
+     */
+    public enum Type {
+        Inputs,
+        Successors;
+    }
+
+    private final Class<? extends Node> nodeClass;
+    private final int directCount;
+    private final long[] offsets;
+    private final String[] names;
+    private final Class<?>[] types;
+    private final Type type;
+
+    @SuppressWarnings("unchecked")
+    public Edges(Class<?> nodeClass, Type type, int directCount, long[] offsets, Map<Long, String> names, Map<Long, Class<?>> types) {
+        this.nodeClass = (Class<? extends Node>) nodeClass;
+        this.type = type;
+        this.directCount = directCount;
+        this.offsets = offsets;
+
+        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]);
+        }
+    }
+
+    /**
+     * Gets the number of edges represented by this object.
+     */
+    public int getCount() {
+        return offsets.length;
+    }
+
+    /**
+     * Get the number of direct edges represented by this object. A direct edge goes directly to
+     * another {@link Node}. An indirect edge goes via a {@link NodeList}.
+     */
+    public int getDirectCount() {
+        return directCount;
+    }
+
+    private static Node getNode(Node node, long offset) {
+        return (Node) unsafe.getObject(node, offset);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static NodeList<Node> getNodeList(Node node, long offset) {
+        return (NodeList<Node>) unsafe.getObject(node, offset);
+    }
+
+    private static void putNode(Node node, long offset, Node value) {
+        unsafe.putObject(node, offset, value);
+    }
+
+    private static void putNodeList(Node node, long offset, NodeList<?> value) {
+        unsafe.putObject(node, offset, value);
+    }
+
+    /**
+     * Gets the {@link Node} at the end point of a {@linkplain #getDirectCount() direct} edge.
+     *
+     * @param node one end point of the edge
+     * @param index the index of a non-list the edge (must be less than {@link #getDirectCount()})
+     * @return the Node at the other edge of the requested edge
+     */
+    public Node getNode(Node node, int index) {
+        assert index >= 0 && index < directCount;
+        return getNode(node, offsets[index]);
+    }
+
+    /**
+     * Gets the {@link NodeList} at the end point of a {@linkplain #getDirectCount() direct} edge.
+     *
+     * @param node one end point of the edge
+     * @param index the index of a non-list the edge (must be equal to or greater than
+     *            {@link #getDirectCount()})
+     * @return the {@link NodeList} at the other edge of the requested edge
+     */
+    public NodeList<Node> getNodeList(Node node, int index) {
+        assert index >= directCount && index < offsets.length;
+        return getNodeList(node, offsets[index]);
+    }
+
+    /**
+     * Clear edges in a given node. This is accomplished by setting {@linkplain #getDirectCount()
+     * direct} edges to null and replacing the lists containing indirect edges with new lists. The
+     * latter is important so that this method can be used to clear the edges of cloned nodes.
+     *
+     * @param node the node whose edges are to be cleared
+     */
+    public void clear(Node node) {
+        int index = 0;
+        while (index < getDirectCount()) {
+            initializeNode(node, index++, null);
+        }
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(node, index);
+            int size = list.initialSize;
+            NodeList<Node> newList = type == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+
+            // replacing with a new list object is the expected behavior!
+            initializeList(node, index, newList);
+            index++;
+        }
+    }
+
+    /**
+     * Copies edges from {@code fromNode} to {@code toNode}. The nodes are expected to be of the
+     * exact same type.
+     *
+     * @param fromNode the node from which the edges should be copied.
+     * @param toNode the node to which the edges should be copied.
+     */
+    public void copy(Node fromNode, Node toNode) {
+        assert fromNode.getNodeClass().getClazz() == nodeClass && toNode.getNodeClass().getClazz() == nodeClass;
+        int index = 0;
+        while (index < getDirectCount()) {
+            initializeNode(toNode, index, getNode(fromNode, index));
+            index++;
+        }
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(toNode, index);
+            list.copy(getNodeList(fromNode, index));
+            index++;
+        }
+    }
+
+    /**
+     * Searches for the first edge in a given node matching {@code key} and if found, replaces it
+     * with {@code replacement}.
+     *
+     * @param node the node whose edges are to be searched
+     * @param key the edge to search for
+     * @param replacement the replacement for {@code key}
+     * @return true if a replacement was made
+     */
+    public boolean replaceFirst(Node node, Node key, Node replacement) {
+        int index = 0;
+        while (index < getDirectCount()) {
+            Node edge = getNode(node, index);
+            if (edge == key) {
+                assert replacement == null || getType(index).isAssignableFrom(replacement.getClass()) : "Can not assign " + replacement.getClass() + " to " + getType(index) + " in " + node;
+                initializeNode(node, index, replacement);
+                return true;
+            }
+            index++;
+        }
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(node, index);
+            assert list != null : nodeClass;
+            if (list.replaceFirst(key, replacement)) {
+                return true;
+            }
+            index++;
+        }
+        return false;
+    }
+
+    public boolean isSameEdge(Edges other, int index) {
+        return offsets[index] == other.offsets[index];
+    }
+
+    /**
+     * Gets the name of an edge.
+     *
+     * @param index index of an edge
+     */
+    public String getName(int index) {
+        return names[index];
+    }
+
+    /**
+     * Gets the type of the field storing the end point of an edge.
+     *
+     * @param index index of an edge
+     */
+    public Class<?> getType(int index) {
+        return types[index];
+    }
+
+    private boolean checkAssignable(int index, Node value) {
+        assert value == null || getType(index).isAssignableFrom(value.getClass()) : String.format("%s.%s of type %s is not assignable from %s", nodeClass.getSimpleName(), getName(index),
+                        getType(index).getSimpleName(), value.getClass().getSimpleName());
+        return true;
+    }
+
+    public void initializeNode(Node node, int index, Node value) {
+        assert checkAssignable(index, value);
+        putNode(node, offsets[index], value);
+    }
+
+    public void initializeList(Node node, int index, NodeList<Node> value) {
+        assert index >= directCount;
+        putNodeList(node, offsets[index], value);
+    }
+
+    public void setNode(Node node, int index, Node value) {
+        assert index < directCount;
+        long offset = offsets[index];
+        Node old = getNode(node, offset);
+        assert checkAssignable(index, value);
+        putNode(node, offset, value);
+        update(node, old, value);
+    }
+
+    protected abstract void update(Node node, Node oldValue, Node newValue);
+
+    public boolean contains(Node node, Node value) {
+        for (int i = 0; i < directCount; i++) {
+            if (getNode(node, i) == value) {
+                return true;
+            }
+        }
+        for (int i = directCount; i < getCount(); i++) {
+            if (getNodeList(node, i).contains(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determines if the edges of two given nodes are the same.
+     */
+    public boolean areEqualIn(Node node, Node other) {
+        assert node.getNodeClass().getClazz() == nodeClass && other.getNodeClass().getClazz() == nodeClass;
+        int index = 0;
+        while (index < directCount) {
+            if (getNode(other, index) != getNode(node, index)) {
+                return false;
+            }
+            index++;
+        }
+        while (index < getCount()) {
+            NodeList<Node> list = getNodeList(other, index);
+            if (!list.equals(getNodeList(node, index))) {
+                return false;
+            }
+            index++;
+        }
+        return true;
+    }
+
+    /**
+     * An iterator that will iterate over edges.
+     *
+     * An iterator of this type will not return null values, unless edges are modified concurrently.
+     * Concurrent modifications are detected by an assertion on a best-effort basis.
+     */
+    private static class EdgesIterator implements NodePosIterator {
+        protected final Node node;
+        protected final Edges edges;
+        protected int index;
+        protected int subIndex;
+        NodeList<Node> list;
+        protected boolean needsForward;
+        protected Node nextElement;
+
+        /**
+         * Creates an iterator that will iterate over some given edges in a given node.
+         */
+        EdgesIterator(Node node, Edges edges) {
+            this.node = node;
+            this.edges = edges;
+            index = NOT_ITERABLE;
+            subIndex = 0;
+            needsForward = true;
+        }
+
+        void forward() {
+            needsForward = false;
+            if (index < edges.getDirectCount()) {
+                index++;
+                while (index < edges.getDirectCount()) {
+                    nextElement = edges.getNode(node, index);
+                    if (nextElement != null) {
+                        return;
+                    }
+                    index++;
+                }
+            } else {
+                subIndex++;
+            }
+            while (index < edges.getCount()) {
+                if (subIndex == 0) {
+                    list = edges.getNodeList(node, index);
+                }
+                while (subIndex < list.size()) {
+                    nextElement = list.get(subIndex);
+                    if (nextElement != null) {
+                        return;
+                    }
+                    subIndex++;
+                }
+                subIndex = 0;
+                index++;
+            }
+        }
+
+        private Node nextElement() {
+            if (needsForward) {
+                forward();
+            }
+            needsForward = true;
+            if (index < edges.getCount()) {
+                return nextElement;
+            }
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (needsForward) {
+                forward();
+            }
+            return index < edges.getCount();
+        }
+
+        @Override
+        public Node next() {
+            return nextElement();
+        }
+
+        public Position nextPosition() {
+            if (needsForward) {
+                forward();
+            }
+            needsForward = true;
+            if (index < edges.getDirectCount()) {
+                return new Position(edges, index, NOT_ITERABLE);
+            } else {
+                return new Position(edges, index, subIndex);
+            }
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static class AllEdgesIterator extends EdgesIterator {
+        AllEdgesIterator(Node node, Edges edges) {
+            super(node, edges);
+        }
+
+        @Override
+        void forward() {
+            needsForward = false;
+            if (index < edges.getDirectCount()) {
+                index++;
+                if (index < edges.getDirectCount()) {
+                    nextElement = edges.getNode(node, index);
+                    return;
+                }
+            } else {
+                subIndex++;
+            }
+            while (index < edges.getCount()) {
+                if (subIndex == 0) {
+                    list = edges.getNodeList(node, index);
+                }
+                if (subIndex < list.size()) {
+                    nextElement = list.get(subIndex);
+                    return;
+                }
+                subIndex = 0;
+                index++;
+            }
+        }
+    }
+
+    private static final class EdgesWithModCountIterator extends EdgesIterator {
+        private final int modCount;
+
+        private EdgesWithModCountIterator(Node node, Edges edges) {
+            super(node, edges);
+            assert MODIFICATION_COUNTS_ENABLED;
+            this.modCount = node.modCount();
+        }
+
+        @Override
+        public boolean hasNext() {
+            try {
+                return super.hasNext();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+
+        @Override
+        public Node next() {
+            try {
+                return super.next();
+            } finally {
+                assert modCount == node.modCount() : "must not be modified";
+            }
+        }
+
+        @Override
+        public Position nextPosition() {
+            try {
+                return super.nextPosition();
+            } finally {
+                assert modCount == node.modCount();
+            }
+        }
+    }
+
+    public NodeClassIterable getIterable(final Node node) {
+        return new NodeClassIterable() {
+
+            @Override
+            public EdgesIterator iterator() {
+                if (MODIFICATION_COUNTS_ENABLED) {
+                    return new EdgesWithModCountIterator(node, Edges.this);
+                } else {
+                    return new EdgesIterator(node, Edges.this);
+                }
+            }
+
+            public EdgesIterator withNullIterator() {
+                return new AllEdgesIterator(node, Edges.this);
+            }
+
+            @Override
+            public boolean contains(Node other) {
+                return Edges.this.contains(node, other);
+            }
+        };
+    }
+
+    public Type type() {
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return nodeClass.getSimpleName() + ":" + type;
+    }
+
+    void appendOffsets(StringBuilder sb) {
+        for (int i = 0; i < offsets.length; i++) {
+            sb.append(i == 0 ? "" : ", ").append(offsets[i]);
+        }
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionCollection.java	Wed Sep 24 17:17:27 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * 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.graph;
-
-import static com.oracle.graal.graph.Node.*;
-
-import java.util.*;
-
-import com.oracle.graal.graph.Node.Input;
-import com.oracle.graal.graph.Node.Successor;
-
-/**
- * A collection of the positions of the {@link Node} and {@link NodeList} fields in a node.
- */
-public final class FirstLevelPositionCollection extends AbstractCollection<Position> implements Collection<Position> {
-
-    public static final FirstLevelPositionCollection Empty = new FirstLevelPositionCollection(0, 0, false);
-
-    /**
-     * The total number of {@link Node} and {@link NodeList} fields.
-     */
-    protected final int allNodeRefFields;
-
-    /**
-     * The number of {@link Node} fields.
-     */
-    protected final int nodeFields;
-
-    /**
-     * Specifies if this iterator iterates over {@linkplain Input inputs} or {@linkplain Successor
-     * successors}.
-     */
-    private final boolean isInputs;
-
-    /**
-     * Creates a collection of the positions of the {@link Node} and {@link NodeList} fields in a
-     * node.
-     */
-    public FirstLevelPositionCollection(int nodeFields, int nodeListFields, boolean isInputs) {
-        this.allNodeRefFields = nodeListFields + nodeFields;
-        this.nodeFields = nodeFields;
-        this.isInputs = isInputs;
-    }
-
-    @Override
-    public int size() {
-        return allNodeRefFields;
-    }
-
-    @Override
-    public Iterator<Position> iterator() {
-        return new FirstLevelPositionIterator(nodeFields, allNodeRefFields - nodeFields, isInputs);
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionIterator.java	Wed Sep 24 17:17:27 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * 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.graph;
-
-import static com.oracle.graal.graph.Node.*;
-
-import java.util.*;
-
-import com.oracle.graal.graph.Node.Input;
-import com.oracle.graal.graph.Node.Successor;
-
-/**
- * An iterator over the {@link Node} and {@link NodeList} fields in a node.
- */
-public class FirstLevelPositionIterator implements Iterator<Position> {
-
-    public static final FirstLevelPositionIterator Empty = new FirstLevelPositionIterator(0, 0, false);
-
-    /**
-     * The total number of {@link Node} and {@link NodeList} fields.
-     */
-    protected final int allNodeRefFields;
-
-    /**
-     * The number of {@link Node} fields.
-     */
-    protected final int nodeFields;
-
-    /**
-     * Specifies if this iterator iterates over {@linkplain Input inputs} or {@linkplain Successor
-     * successors}.
-     */
-    private final boolean isInputs;
-
-    /**
-     * Current field iteration index.
-     */
-    protected int index;
-
-    /**
-     * Creates an iterator over the {@link Node} and {@link NodeList} fields in a node.
-     *
-     * @param nodeFields the number of {@link Node} fields in the class hierarchy of the node being
-     *            iterated
-     * @param nodeListFields the number of {@link NodeList} fields in the class hierarchy of the
-     *            node being iterated
-     */
-    protected FirstLevelPositionIterator(int nodeFields, int nodeListFields, boolean isInputs) {
-        this.allNodeRefFields = nodeListFields + nodeFields;
-        this.nodeFields = nodeFields;
-        this.isInputs = isInputs;
-        index = Node.NOT_ITERABLE;
-    }
-
-    @Override
-    public void remove() {
-        throw new UnsupportedOperationException();
-    }
-
-    public Position next() {
-        Position pos = new Position(isInputs, index, index >= nodeFields ? NODE_LIST : NOT_ITERABLE);
-        index++;
-        return pos;
-    }
-
-    public boolean hasNext() {
-        return index < allNodeRefFields;
-    }
-
-    public int size() {
-        return allNodeRefFields;
-    }
-}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.graph;
 
+import static com.oracle.graal.graph.Edges.Type.*;
 import static com.oracle.graal.graph.Node.*;
 
 import java.util.*;
@@ -497,7 +498,8 @@
             }
             if (minCountNode != null) {
                 for (Node usage : minCountNode.usages()) {
-                    if (usage != node && nodeClass == usage.getNodeClass() && nodeClass.valueEqual(node, usage) && nodeClass.edgesEqual(node, usage)) {
+                    if (usage != node && nodeClass == usage.getNodeClass() && nodeClass.valueEqual(node, usage) && nodeClass.getEdges(Inputs).areEqualIn(node, usage) &&
+                                    nodeClass.getEdges(Successors).areEqualIn(node, usage)) {
                         return usage;
                     }
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java	Thu Sep 25 10:27:17 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.graph;
+
+import static com.oracle.graal.graph.Edges.Type.*;
+
+import java.util.*;
+
+import com.oracle.graal.nodeinfo.*;
+
+public final class InputEdges extends Edges {
+
+    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);
+
+        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]);
+        }
+    }
+
+    public InputType getInputType(int index) {
+        return inputTypes[index];
+    }
+
+    public boolean isOptional(int index) {
+        return isOptional[index];
+    }
+
+    @Override
+    protected void update(Node node, Node oldValue, Node newValue) {
+        node.updateUsages(oldValue, newValue);
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.graph;
 
+import static com.oracle.graal.graph.Edges.Type.*;
 import static com.oracle.graal.graph.Graph.*;
 
 import java.lang.annotation.*;
@@ -196,7 +197,7 @@
      * @return an {@link NodeClassIterable iterable} for all non-null input edges.
      */
     public NodeClassIterable inputs() {
-        return getNodeClass().getInputIterable(this);
+        return getNodeClass().getEdges(Inputs).getIterable(this);
     }
 
     /**
@@ -206,7 +207,7 @@
      * @return an {@link NodeClassIterable iterable} for all non-null successor edges.
      */
     public NodeClassIterable successors() {
-        return getNodeClass().getSuccessorIterable(this);
+        return getNodeClass().getEdges(Successors).getIterable(this);
     }
 
     /**
@@ -545,7 +546,7 @@
     public void replaceAtUsages(Node other) {
         assert checkReplaceWith(other);
         for (Node usage : usages()) {
-            boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+            boolean result = usage.getNodeClass().getEdges(Inputs).replaceFirst(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
                 maybeNotifyInputChanged(usage);
@@ -565,7 +566,7 @@
                 if (removeStart < 0) {
                     removeStart = it.index - 1;
                 }
-                boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
+                boolean result = usage.getNodeClass().getEdges(Inputs).replaceFirst(usage, this, other);
                 assert assertTrue(result, "not found in inputs, usage: %s", usage);
                 if (other != null) {
                     maybeNotifyInputChanged(usage);
@@ -593,7 +594,7 @@
             NodePosIterator iter = usage.inputs().iterator();
             while (iter.hasNext()) {
                 Position pos = iter.nextPosition();
-                if (pos.getInputType(usage) == type && pos.get(usage) == this) {
+                if (pos.getInputType() == type && pos.get(usage) == this) {
                     pos.set(usage, other);
                 }
             }
@@ -623,7 +624,7 @@
     public void replaceAtPredecessor(Node other) {
         assert checkReplaceWith(other);
         if (predecessor != null) {
-            boolean result = predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other);
+            boolean result = predecessor.getNodeClass().getEdges(Successors).replaceFirst(predecessor, this, other);
             assert assertTrue(result, "not found in successors, predecessor: %s", predecessor);
             predecessor.updatePredecessor(this, other);
         }
@@ -640,13 +641,13 @@
     }
 
     public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) {
-        if (getNodeClass().replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) {
+        if (getNodeClass().getEdges(Successors).replaceFirst(this, oldSuccessor, newSuccessor)) {
             updatePredecessor(oldSuccessor, newSuccessor);
         }
     }
 
     public void replaceFirstInput(Node oldInput, Node newInput) {
-        if (getNodeClass().replaceFirstInput(this, oldInput, newInput)) {
+        if (getNodeClass().getEdges(Inputs).replaceFirst(this, oldInput, newInput)) {
             updateUsages(oldInput, newInput);
         }
     }
@@ -664,7 +665,7 @@
         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
 
         unregisterInputs();
-        getNodeClass().clearInputs(this);
+        getNodeClass().getEdges(Inputs).clear(this);
     }
 
     private boolean removeThisFromUsages(Node n) {
@@ -682,7 +683,7 @@
         assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
 
         unregisterSuccessors();
-        getNodeClass().clearSuccessors(this);
+        getNodeClass().getEdges(Successors).clear(this);
     }
 
     private boolean checkDeletion() {
@@ -711,7 +712,7 @@
     public final Node copyWithInputs(boolean addToGraph) {
         Node newNode = clone(addToGraph ? graph : null);
         NodeClass clazz = getNodeClass();
-        clazz.copyInputs(this, newNode);
+        clazz.getEdges(Inputs).copy(this, newNode);
         if (addToGraph) {
             for (Node input : inputs()) {
                 input.addUsage(newNode);
@@ -751,8 +752,8 @@
             throw new GraalGraphInternalError(e).addContext(this);
         }
         if (clearInputsAndSuccessors) {
-            nodeClass.clearInputs(newNode);
-            nodeClass.clearSuccessors(newNode);
+            nodeClass.getEdges(Inputs).clear(newNode);
+            nodeClass.getEdges(Successors).clear(newNode);
         }
         newNode.graph = into;
         newNode.typeCacheNext = null;
@@ -798,15 +799,15 @@
             NodePosIterator iterator = usage.inputs().iterator();
             while (iterator.hasNext()) {
                 Position pos = iterator.nextPosition();
-                if (pos.get(usage) == this && pos.getInputType(usage) != InputType.Unchecked) {
-                    assert isAllowedUsageType(pos.getInputType(usage)) : "invalid input of type " + pos.getInputType(usage) + " from " + usage + " to " + this + " (" + pos.getInputName(usage) + ")";
+                if (pos.get(usage) == this && pos.getInputType() != InputType.Unchecked) {
+                    assert isAllowedUsageType(pos.getInputType()) : "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")";
                 }
             }
         }
         NodePosIterator iterator = inputs().withNullIterator();
         while (iterator.hasNext()) {
             Position pos = iterator.nextPosition();
-            assert pos.isInputOptional(this) || pos.get(this) != null : "non-optional input " + pos.getInputName(this) + " cannot be null in " + this + " (fix nullness or use @OptionalInput)";
+            assert pos.isInputOptional() || pos.get(this) != null : "non-optional input " + pos.getName() + " cannot be null in " + this + " (fix nullness or use @OptionalInput)";
         }
         if (predecessor != null) {
             assertFalse(predecessor.isDeleted(), "predecessor %s must never be deleted", predecessor);
@@ -943,7 +944,6 @@
 
         boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY);
         int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0);
-        NodeClass nodeClass = getNodeClass();
         if (width > 0) {
             if (this.predecessor != null) {
                 formatter.format(" pred={");
@@ -954,10 +954,10 @@
             NodePosIterator inputIter = inputs().iterator();
             while (inputIter.hasNext()) {
                 Position position = inputIter.nextPosition();
-                Node input = nodeClass.get(this, position);
+                Node input = position.get(this);
                 if (input != null) {
                     formatter.format(" ");
-                    formatter.format(nodeClass.getName(position));
+                    formatter.format(position.getName());
                     formatter.format("={");
                     input.formatTo(formatter, neighborsFlags, width - 1, 0);
                     formatter.format("}");
@@ -982,10 +982,10 @@
             NodePosIterator succIter = successors().iterator();
             while (succIter.hasNext()) {
                 Position position = succIter.nextPosition();
-                Node successor = nodeClass.get(this, position);
+                Node successor = position.get(this);
                 if (successor != null) {
                     formatter.format(" ");
-                    formatter.format(nodeClass.getName(position));
+                    formatter.format(position.getName());
                     formatter.format("={");
                     successor.formatTo(formatter, neighborsFlags, 0, precision - 1);
                     formatter.format("}");
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.graph;
 
-import static com.oracle.graal.graph.Graph.*;
 import static com.oracle.graal.graph.Node.*;
 import static com.oracle.graal.graph.util.CollectionsAccess.*;
 import static java.lang.reflect.Modifier.*;
@@ -54,7 +53,8 @@
     // Timers for creation of a NodeClass instance
     private static final DebugTimer Init = Debug.timer("NodeClass.Init");
     private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning");
-    private static final DebugTimer Init_Offsets = Debug.timer("NodeClass.Init.Offsets");
+    private static final DebugTimer Init_Edges = Debug.timer("NodeClass.Init.Edges");
+    private static final DebugTimer Init_Data = Debug.timer("NodeClass.Init.Data");
     private static final DebugTimer Init_Naming = Debug.timer("NodeClass.Init.Naming");
     private static final DebugTimer Init_AllowedUsages = Debug.timer("NodeClass.Init.AllowedUsages");
     private static final DebugTimer Init_IterableIds = Debug.timer("NodeClass.Init.IterableIds");
@@ -109,12 +109,9 @@
 
     private static int nextIterableId = 0;
 
-    private final int directInputCount;
-    private final long[] inputOffsets;
-    private final InputType[] inputTypes;
-    private final boolean[] inputOptional;
-    private final int directSuccessorCount;
-    private final long[] successorOffsets;
+    private final Edges inputs;
+    private final Edges successors;
+
     private final Class<?>[] dataTypes;
     private final boolean canGVN;
     private final int startGVNNumber;
@@ -167,37 +164,26 @@
 
         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 
-        FieldScanner scanner = new FieldScanner(calcOffset);
+        FieldScanner fs = new FieldScanner(calcOffset);
         try (TimerCloseable t = Init_FieldScanning.start()) {
-            scanner.scan(clazz);
+            fs.scan(clazz);
         }
 
-        try (TimerCloseable t1 = Init_Offsets.start()) {
-            directInputCount = scanner.inputOffsets.size();
-
-            isLeafNode = scanner.inputOffsets.isEmpty() && scanner.inputListOffsets.isEmpty() && scanner.successorOffsets.isEmpty() && scanner.successorListOffsets.isEmpty();
-
-            inputOffsets = sortedOffsets(scanner.inputOffsets, scanner.inputListOffsets);
-
-            inputTypes = new InputType[inputOffsets.length];
-            inputOptional = new boolean[inputOffsets.length];
-            for (int i = 0; i < inputOffsets.length; i++) {
-                inputTypes[i] = scanner.types.get(inputOffsets[i]);
-                assert inputTypes[i] != null;
-                inputOptional[i] = scanner.optionalInputs.contains(inputOffsets[i]);
-            }
-            directSuccessorCount = scanner.successorOffsets.size();
-            successorOffsets = sortedOffsets(scanner.successorOffsets, scanner.successorListOffsets);
-
-            dataOffsets = sortedLongCopy(scanner.dataOffsets);
+        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);
+        }
+        try (TimerCloseable t1 = Init_Data.start()) {
+            dataOffsets = sortedLongCopy(fs.dataOffsets);
             dataTypes = new Class[dataOffsets.length];
             for (int i = 0; i < dataOffsets.length; i++) {
-                dataTypes[i] = scanner.fieldTypes.get(dataOffsets[i]);
+                dataTypes[i] = fs.fieldTypes.get(dataOffsets[i]);
             }
         }
 
-        fieldNames = scanner.fieldNames;
-        fieldTypes = scanner.fieldTypes;
+        isLeafNode = inputs.getCount() + successors.getCount() == 0;
+        fieldNames = fs.fieldNames;
+        fieldTypes = fs.fieldTypes;
 
         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
         startGVNNumber = clazz.hashCode();
@@ -297,22 +283,7 @@
 
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
-        FieldScanner scanner = new FieldScanner(calc);
-        scanner.scan(getClazz());
-        assert directInputCount == scanner.inputOffsets.size();
-        copyInto(inputOffsets, sortedLongCopy(scanner.inputOffsets, scanner.inputListOffsets));
-        assert directSuccessorCount == scanner.successorOffsets.size();
-        copyInto(successorOffsets, sortedLongCopy(scanner.successorOffsets, scanner.successorListOffsets));
-        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
-
-        for (int i = 0; i < dataOffsets.length; i++) {
-            dataTypes[i] = scanner.fieldTypes.get(dataOffsets[i]);
-        }
-
-        fieldNames.clear();
-        fieldNames.putAll(scanner.fieldNames);
-        fieldTypes.clear();
-        fieldTypes.putAll(scanner.fieldTypes);
+        throw new UnsupportedOperationException();
     }
 
     /**
@@ -322,7 +293,7 @@
      *
      * <pre>
      *     if (node.getNodeClass().is(BeginNode.class)) { ... }
-     * 
+     *
      *     // Due to generated Node classes, the test below
      *     // is *not* the same as the test above:
      *     if (node.getClass() == BeginNode.class) { ... }
@@ -436,13 +407,9 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append("NodeClass ").append(getClazz().getSimpleName()).append(" [");
-        for (int i = 0; i < inputOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(inputOffsets[i]);
-        }
+        inputs.appendOffsets(str);
         str.append("] [");
-        for (int i = 0; i < successorOffsets.length; i++) {
-            str.append(i == 0 ? "" : ", ").append(successorOffsets[i]);
-        }
+        successors.appendOffsets(str);
         str.append("] [");
         for (int i = 0; i < dataOffsets.length; i++) {
             str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
@@ -451,313 +418,6 @@
         return str.toString();
     }
 
-    private static Node getNode(Node node, long offset) {
-        return (Node) unsafe.getObject(node, offset);
-    }
-
-    @SuppressWarnings("unchecked")
-    private static NodeList<Node> getNodeList(Node node, long offset) {
-        return (NodeList<Node>) unsafe.getObject(node, offset);
-    }
-
-    private static void putNode(Node node, long offset, Node value) {
-        unsafe.putObject(node, offset, value);
-    }
-
-    private static void putNodeList(Node node, long offset, NodeList<?> value) {
-        unsafe.putObject(node, offset, value);
-    }
-
-    /**
-     * An iterator that will iterate over the fields given in {@link #getOffsets()}. The first
-     * {@link #getDirectCount()} offsets are treated as fields of type {@link Node}, while the rest
-     * of the fields are treated as {@link NodeList}s. All elements of these NodeLists will be
-     * visited by the iterator as well. This iterator can be used to iterate over the inputs or
-     * successors of a node.
-     *
-     * An iterator of this type will not return null values, unless the field values are modified
-     * concurrently. Concurrent modifications are detected by an assertion on a best-effort basis.
-     */
-    public abstract static class NodeClassIterator implements NodePosIterator {
-        protected final Node node;
-        protected int index;
-        protected int subIndex;
-        NodeList<Node> list;
-        protected boolean needsForward;
-        protected Node nextElement;
-
-        /**
-         * Creates an iterator that will iterate over fields in the given node.
-         *
-         * @param node the node which contains the fields.
-         */
-        NodeClassIterator(Node node) {
-            this.node = node;
-            index = NOT_ITERABLE;
-            subIndex = 0;
-            needsForward = true;
-        }
-
-        void forward() {
-            needsForward = false;
-            if (index < getDirectCount()) {
-                index++;
-                while (index < getDirectCount()) {
-                    nextElement = getNode(node, getOffsets()[index]);
-                    if (nextElement != null) {
-                        return;
-                    }
-                    index++;
-                }
-            } else {
-                subIndex++;
-            }
-            while (index < getOffsets().length) {
-                if (subIndex == 0) {
-                    list = getNodeList(node, getOffsets()[index]);
-                }
-                while (subIndex < list.size()) {
-                    nextElement = list.get(subIndex);
-                    if (nextElement != null) {
-                        return;
-                    }
-                    subIndex++;
-                }
-                subIndex = 0;
-                index++;
-            }
-        }
-
-        private Node nextElement() {
-            if (needsForward) {
-                forward();
-            }
-            needsForward = true;
-            if (index < getOffsets().length) {
-                return nextElement;
-            }
-            throw new NoSuchElementException();
-        }
-
-        @Override
-        public boolean hasNext() {
-            if (needsForward) {
-                forward();
-            }
-            return index < getOffsets().length;
-        }
-
-        @Override
-        public Node next() {
-            return nextElement();
-        }
-
-        public Position nextPosition() {
-            if (needsForward) {
-                forward();
-            }
-            needsForward = true;
-            if (index < getDirectCount()) {
-                return new Position(getOffsets() == getNodeClass().inputOffsets, index, NOT_ITERABLE);
-            } else {
-                return new Position(getOffsets() == getNodeClass().inputOffsets, index, subIndex);
-            }
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-
-        protected abstract int getDirectCount();
-
-        protected abstract long[] getOffsets();
-
-        protected abstract NodeClass getNodeClass();
-    }
-
-    private class NodeClassInputsIterator extends NodeClassIterator {
-
-        NodeClassInputsIterator(Node node) {
-            super(node);
-            assert NodeClass.this == node.getNodeClass();
-        }
-
-        @Override
-        protected int getDirectCount() {
-            return directInputCount;
-        }
-
-        @Override
-        protected long[] getOffsets() {
-            return inputOffsets;
-        }
-
-        @Override
-        protected NodeClass getNodeClass() {
-            return NodeClass.this;
-        }
-    }
-
-    private class NodeClassAllInputsIterator extends NodeClassInputsIterator {
-        NodeClassAllInputsIterator(Node node) {
-            super(node);
-        }
-
-        @Override
-        void forward() {
-            needsForward = false;
-            if (index < getDirectCount()) {
-                index++;
-                if (index < getDirectCount()) {
-                    nextElement = getNode(node, getOffsets()[index]);
-                    return;
-                }
-            } else {
-                subIndex++;
-            }
-            while (index < getOffsets().length) {
-                if (subIndex == 0) {
-                    list = getNodeList(node, getOffsets()[index]);
-                }
-                if (subIndex < list.size()) {
-                    nextElement = list.get(subIndex);
-                    return;
-                }
-                subIndex = 0;
-                index++;
-            }
-        }
-    }
-
-    private class NodeClassAllSuccessorsIterator extends NodeClassSuccessorsIterator {
-        NodeClassAllSuccessorsIterator(Node node) {
-            super(node);
-        }
-
-        @Override
-        void forward() {
-            needsForward = false;
-            if (index < getDirectCount()) {
-                index++;
-                if (index < getDirectCount()) {
-                    nextElement = getNode(node, getOffsets()[index]);
-                    return;
-                }
-            } else {
-                subIndex++;
-            }
-            while (index < getOffsets().length) {
-                if (subIndex == 0) {
-                    list = getNodeList(node, getOffsets()[index]);
-                }
-                if (subIndex < list.size()) {
-                    nextElement = list.get(subIndex);
-                    return;
-                }
-                subIndex = 0;
-                index++;
-            }
-        }
-    }
-
-    private final class NodeClassInputsWithModCountIterator extends NodeClassInputsIterator {
-        private final int modCount;
-
-        private NodeClassInputsWithModCountIterator(Node node) {
-            super(node);
-            assert MODIFICATION_COUNTS_ENABLED;
-            this.modCount = node.modCount();
-        }
-
-        @Override
-        public boolean hasNext() {
-            try {
-                return super.hasNext();
-            } finally {
-                assert modCount == node.modCount() : "must not be modified";
-            }
-        }
-
-        @Override
-        public Node next() {
-            try {
-                return super.next();
-            } finally {
-                assert modCount == node.modCount() : "must not be modified";
-            }
-        }
-
-        @Override
-        public Position nextPosition() {
-            try {
-                return super.nextPosition();
-            } finally {
-                assert modCount == node.modCount();
-            }
-        }
-    }
-
-    private class NodeClassSuccessorsIterator extends NodeClassIterator {
-
-        NodeClassSuccessorsIterator(Node node) {
-            super(node);
-            assert NodeClass.this == node.getNodeClass();
-        }
-
-        @Override
-        protected int getDirectCount() {
-            return directSuccessorCount;
-        }
-
-        @Override
-        protected long[] getOffsets() {
-            return successorOffsets;
-        }
-
-        @Override
-        protected NodeClass getNodeClass() {
-            return NodeClass.this;
-        }
-    }
-
-    private final class NodeClassSuccessorsWithModCountIterator extends NodeClassSuccessorsIterator {
-        private final int modCount;
-
-        private NodeClassSuccessorsWithModCountIterator(Node node) {
-            super(node);
-            assert MODIFICATION_COUNTS_ENABLED;
-            this.modCount = node.modCount();
-        }
-
-        @Override
-        public boolean hasNext() {
-            try {
-                return super.hasNext();
-            } finally {
-                assert modCount == node.modCount() : "must not be modified";
-            }
-        }
-
-        @Override
-        public Node next() {
-            try {
-                return super.next();
-            } finally {
-                assert modCount == node.modCount() : "must not be modified";
-            }
-        }
-
-        @Override
-        public Position nextPosition() {
-            try {
-                return super.nextPosition();
-            } finally {
-                assert modCount == node.modCount();
-            }
-        }
-    }
-
     private static int deepHashCode0(Object o) {
         if (o instanceof Object[]) {
             return Arrays.deepHashCode((Object[]) o);
@@ -933,48 +593,18 @@
         return true;
     }
 
-    public boolean isValid(Position pos, NodeClass from) {
+    public boolean isValid(Position pos, NodeClass from, Edges fromEdges) {
         if (this == from) {
             return true;
         }
-        long[] offsets = pos.isInput() ? inputOffsets : successorOffsets;
-        if (pos.getIndex() >= offsets.length) {
-            return false;
-        }
-        long[] fromOffsets = pos.isInput() ? from.inputOffsets : from.successorOffsets;
-        if (pos.getIndex() >= fromOffsets.length) {
+        Edges toEdges = getEdges(fromEdges.type());
+        if (pos.getIndex() >= toEdges.getCount()) {
             return false;
         }
-        return offsets[pos.getIndex()] == fromOffsets[pos.getIndex()];
-    }
-
-    public Node get(Node node, Position pos) {
-        long offset = pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()];
-        if (pos.getSubIndex() == NOT_ITERABLE) {
-            return getNode(node, offset);
-        } else {
-            return getNodeList(node, offset).get(pos.getSubIndex());
+        if (pos.getIndex() >= fromEdges.getCount()) {
+            return false;
         }
-    }
-
-    public InputType getInputType(Position pos) {
-        assert pos.isInput();
-        return inputTypes[pos.getIndex()];
-    }
-
-    public boolean isInputOptional(Position pos) {
-        assert pos.isInput();
-        return inputOptional[pos.getIndex()];
-    }
-
-    public NodeList<?> getNodeList(Node node, Position pos) {
-        long offset = pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()];
-        assert pos.getSubIndex() == Node.NODE_LIST;
-        return getNodeList(node, offset);
-    }
-
-    public String getName(Position pos) {
-        return fieldNames.get(pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()]);
+        return toEdges.isSameEdge(fromEdges, pos.getIndex());
     }
 
     public String getPropertyName(int pos) {
@@ -1044,446 +674,54 @@
         }
     }
 
-    void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
+    static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
         int index = 0;
-        while (index < directInputCount) {
-            Node input = getNode(node, inputOffsets[index]);
-            if (input != null) {
-                Node newInput = duplicationReplacement.replacement(input, true);
-                node.updateUsages(null, newInput);
-                assert newInput == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(newInput.getClass()) : "Can not assign " + newInput.getClass() + " to " +
-                                fieldTypes.get(inputOffsets[index]) + " in " + node;
-                putNode(node, inputOffsets[index], newInput);
-            }
-            index++;
-        }
-
-        if (index < inputOffsets.length) {
-            updateInputLists(node, duplicationReplacement, index);
-        }
-
-        index = 0;
-        while (index < directSuccessorCount) {
-            Node successor = getNode(node, successorOffsets[index]);
-            if (successor != null) {
-                Node newSucc = duplicationReplacement.replacement(successor, false);
-                node.updatePredecessor(null, newSucc);
-                assert newSucc == null || fieldTypes.get(successorOffsets[index]).isAssignableFrom(newSucc.getClass()) : fieldTypes.get(successorOffsets[index]) + " is not compatible with " +
-                                newSucc.getClass();
-                putNode(node, successorOffsets[index], newSucc);
+        while (index < edges.getDirectCount()) {
+            Node edge = edges.getNode(node, index);
+            if (edge != null) {
+                Node newEdge = duplicationReplacement.replacement(edge, edges.type());
+                if (edges.type() == Edges.Type.Inputs) {
+                    node.updateUsages(null, newEdge);
+                } else {
+                    node.updatePredecessor(null, newEdge);
+                }
+                assert newEdge == null || edges.getType(index).isAssignableFrom(newEdge.getClass()) : "Can not assign " + newEdge.getClass() + " to " + edges.getType(index) + " in " + node;
+                edges.initializeNode(node, index, newEdge);
             }
             index++;
         }
 
-        if (index < successorOffsets.length) {
-            updateSuccLists(node, duplicationReplacement, index);
-        }
-    }
-
-    private void updateInputLists(Node node, InplaceUpdateClosure duplicationReplacement, int startIndex) {
-        int index = startIndex;
-        while (index < inputOffsets.length) {
-            NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : getClazz();
-            putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement));
+        while (index < edges.getCount()) {
+            NodeList<Node> list = edges.getNodeList(node, index);
+            assert list != null : edges;
+            edges.initializeList(node, index, updateEdgeListCopy(node, list, duplicationReplacement, edges.type()));
             index++;
         }
     }
 
-    private void updateSuccLists(Node node, InplaceUpdateClosure duplicationReplacement, int startIndex) {
-        int index = startIndex;
-        while (index < successorOffsets.length) {
-            NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : getClazz();
-            putNodeList(node, successorOffsets[index], updateSuccListCopy(list, node, duplicationReplacement));
-            index++;
-        }
+    void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
+        updateEdgesInPlace(node, duplicationReplacement, inputs);
+        updateEdgesInPlace(node, duplicationReplacement, successors);
     }
 
-    private static NodeInputList<Node> updateInputListCopy(NodeList<Node> list, Node node, InplaceUpdateClosure duplicationReplacement) {
-        int size = list.size();
-        NodeInputList<Node> result = new NodeInputList<>(node, size);
+    private static NodeList<Node> updateEdgeListCopy(Node node, NodeList<Node> list, InplaceUpdateClosure duplicationReplacement, Edges.Type type) {
+        NodeList<Node> result = type == Edges.Type.Inputs ? new NodeInputList<>(node, list.size()) : new NodeSuccessorList<>(node, list.size());
+
         for (int i = 0; i < list.count(); ++i) {
             Node oldNode = list.get(i);
             if (oldNode != null) {
-                Node newNode = duplicationReplacement.replacement(oldNode, true);
-                result.set(i, newNode);
-            }
-        }
-        return result;
-    }
-
-    private static NodeSuccessorList<Node> updateSuccListCopy(NodeList<Node> list, Node node, InplaceUpdateClosure duplicationReplacement) {
-        int size = list.size();
-        NodeSuccessorList<Node> result = new NodeSuccessorList<>(node, size);
-        for (int i = 0; i < list.count(); ++i) {
-            Node oldNode = list.get(i);
-            if (oldNode != null) {
-                Node newNode = duplicationReplacement.replacement(oldNode, false);
+                Node newNode = duplicationReplacement.replacement(oldNode, type);
                 result.set(i, newNode);
             }
         }
         return result;
     }
 
-    public void set(Node node, Position pos, Node x) {
-        long offset = pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()];
-        if (pos.getSubIndex() == NOT_ITERABLE) {
-            Node old = getNode(node, offset);
-            assert x == null || fieldTypes.get((pos.isInput() ? inputOffsets : successorOffsets)[pos.getIndex()]).isAssignableFrom(x.getClass()) : this + ".set(node, pos, " + x + ")";
-            putNode(node, offset, x);
-            if (pos.isInput()) {
-                node.updateUsages(old, x);
-            } else {
-                node.updatePredecessor(old, x);
-            }
-        } else {
-            NodeList<Node> list = getNodeList(node, offset);
-            if (pos.getSubIndex() < list.size()) {
-                list.set(pos.getSubIndex(), x);
-            } else {
-                while (list.size() < pos.getSubIndex()) {
-                    list.add(null);
-                }
-                list.add(x);
-            }
-        }
-    }
-
-    public void initializePosition(Node node, Position pos, Node x) {
-        long offset = pos.isInput() ? inputOffsets[pos.getIndex()] : successorOffsets[pos.getIndex()];
-        if (pos.getSubIndex() == NOT_ITERABLE) {
-            assert x == null || fieldTypes.get((pos.isInput() ? inputOffsets : successorOffsets)[pos.getIndex()]).isAssignableFrom(x.getClass()) : this + ".set(node, pos, " + x + ")";
-            putNode(node, offset, x);
-        } else {
-            NodeList<Node> list = getNodeList(node, offset);
-            while (list.size() <= pos.getSubIndex()) {
-                list.add(null);
-            }
-            list.initialize(pos.getSubIndex(), x);
-        }
-    }
-
-    public NodeClassIterable getInputIterable(final Node node) {
-        assert getClazz().isInstance(node);
-        return new NodeClassIterable() {
-
-            @Override
-            public NodeClassIterator iterator() {
-                if (MODIFICATION_COUNTS_ENABLED) {
-                    return new NodeClassInputsWithModCountIterator(node);
-                } else {
-                    return new NodeClassInputsIterator(node);
-                }
-            }
-
-            public NodeClassIterator withNullIterator() {
-                return new NodeClassAllInputsIterator(node);
-            }
-
-            @Override
-            public boolean contains(Node other) {
-                return inputContains(node, other);
-            }
-        };
-    }
-
-    public NodeClassIterable getSuccessorIterable(final Node node) {
-        assert getClazz().isInstance(node);
-        return new NodeClassIterable() {
-
-            @Override
-            public NodeClassIterator iterator() {
-                if (MODIFICATION_COUNTS_ENABLED) {
-                    return new NodeClassSuccessorsWithModCountIterator(node);
-                } else {
-                    return new NodeClassSuccessorsIterator(node);
-                }
-            }
-
-            public NodeClassIterator withNullIterator() {
-                return new NodeClassAllSuccessorsIterator(node);
-            }
-
-            @Override
-            public boolean contains(Node other) {
-                return successorContains(node, other);
-            }
-        };
-    }
-
-    public boolean replaceFirstInput(Node node, Node old, Node other) {
-        int index = 0;
-        while (index < directInputCount) {
-            Node input = getNode(node, inputOffsets[index]);
-            if (input == old) {
-                assert other == null || fieldTypes.get(inputOffsets[index]).isAssignableFrom(other.getClass()) : "Can not assign " + other.getClass() + " to " + fieldTypes.get(inputOffsets[index]) +
-                                " in " + node;
-                putNode(node, inputOffsets[index], other);
-                return true;
-            }
-            index++;
-        }
-        while (index < inputOffsets.length) {
-            NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            assert list != null : getClazz();
-            if (list.replaceFirst(old, other)) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
-    public boolean replaceFirstSuccessor(Node node, Node old, Node other) {
-        int index = 0;
-        while (index < directSuccessorCount) {
-            Node successor = getNode(node, successorOffsets[index]);
-            if (successor == old) {
-                assert other == null || fieldTypes.get(successorOffsets[index]).isAssignableFrom(other.getClass()) : fieldTypes.get(successorOffsets[index]) + " is not compatible with " +
-                                other.getClass();
-                putNode(node, successorOffsets[index], other);
-                return true;
-            }
-            index++;
-        }
-        while (index < successorOffsets.length) {
-            NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            assert list != null : getClazz() + " " + successorOffsets[index] + " " + node;
-            if (list.replaceFirst(old, other)) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
     /**
-     * Clear all inputs in the given node. This is accomplished by setting input fields to null and
-     * replacing input lists with new lists. (which is important so that this method can be used to
-     * clear the inputs of cloned nodes.)
-     *
-     * @param node the node to be cleared
-     */
-    public void clearInputs(Node node) {
-        int index = 0;
-        while (index < directInputCount) {
-            putNode(node, inputOffsets[index++], null);
-        }
-        while (index < inputOffsets.length) {
-            long curOffset = inputOffsets[index++];
-            int size = (getNodeList(node, curOffset)).initialSize;
-            // replacing with a new list object is the expected behavior!
-            putNodeList(node, curOffset, new NodeInputList<>(node, size));
-        }
-    }
-
-    /**
-     * Clear all successors in the given node. This is accomplished by setting successor fields to
-     * null and replacing successor lists with new lists. (which is important so that this method
-     * can be used to clear the successors of cloned nodes.)
-     *
-     * @param node the node to be cleared
-     */
-    public void clearSuccessors(Node node) {
-        int index = 0;
-        while (index < directSuccessorCount) {
-            putNode(node, successorOffsets[index++], null);
-        }
-        while (index < successorOffsets.length) {
-            long curOffset = successorOffsets[index++];
-            int size = getNodeList(node, curOffset).initialSize;
-            // replacing with a new list object is the expected behavior!
-            putNodeList(node, curOffset, new NodeSuccessorList<>(node, size));
-        }
-    }
-
-    /**
-     * Copies the inputs from node to newNode. The nodes are expected to be of the exact same
-     * NodeClass type.
-     *
-     * @param node the node from which the inputs should be copied.
-     * @param newNode the node to which the inputs should be copied.
+     * Gets the input or successor edges defined by this node class.
      */
-    public void copyInputs(Node node, Node newNode) {
-        assert node.getNodeClass() == this && newNode.getNodeClass() == this;
-
-        int index = 0;
-        while (index < directInputCount) {
-            putNode(newNode, inputOffsets[index], getNode(node, inputOffsets[index]));
-            index++;
-        }
-        while (index < inputOffsets.length) {
-            NodeList<Node> list = getNodeList(newNode, inputOffsets[index]);
-            list.copy(getNodeList(node, inputOffsets[index]));
-            index++;
-        }
-    }
-
-    /**
-     * Copies the successors from node to newNode. The nodes are expected to be of the exact same
-     * NodeClass type.
-     *
-     * @param node the node from which the successors should be copied.
-     * @param newNode the node to which the successors should be copied.
-     */
-    public void copySuccessors(Node node, Node newNode) {
-        assert node.getNodeClass() == this && newNode.getNodeClass() == this;
-
-        int index = 0;
-        while (index < directSuccessorCount) {
-            putNode(newNode, successorOffsets[index], getNode(node, successorOffsets[index]));
-            index++;
-        }
-        while (index < successorOffsets.length) {
-            NodeList<Node> list = getNodeList(newNode, successorOffsets[index]);
-            list.copy(getNodeList(node, successorOffsets[index]));
-            index++;
-        }
-    }
-
-    public boolean edgesEqual(Node node, Node other) {
-        return inputsEqual(node, other) && successorsEqual(node, other);
-    }
-
-    public boolean inputsEqual(Node node, Node other) {
-        assert node.getNodeClass() == this && other.getNodeClass() == this;
-        int index = 0;
-        while (index < directInputCount) {
-            if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
-                return false;
-            }
-            index++;
-        }
-        while (index < inputOffsets.length) {
-            NodeList<Node> list = getNodeList(other, inputOffsets[index]);
-            if (!list.equals(getNodeList(node, inputOffsets[index]))) {
-                return false;
-            }
-            index++;
-        }
-        return true;
-    }
-
-    public boolean successorsEqual(Node node, Node other) {
-        assert node.getNodeClass() == this && other.getNodeClass() == this;
-        int index = 0;
-        while (index < directSuccessorCount) {
-            if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
-                return false;
-            }
-            index++;
-        }
-        while (index < successorOffsets.length) {
-            NodeList<Node> list = getNodeList(other, successorOffsets[index]);
-            if (!list.equals(getNodeList(node, successorOffsets[index]))) {
-                return false;
-            }
-            index++;
-        }
-        return true;
-    }
-
-    public boolean inputContains(Node node, Node other) {
-        assert node.getNodeClass() == this;
-
-        int index = 0;
-        while (index < directInputCount) {
-            if (getNode(node, inputOffsets[index]) == other) {
-                return true;
-            }
-            index++;
-        }
-        while (index < inputOffsets.length) {
-            NodeList<Node> list = getNodeList(node, inputOffsets[index]);
-            if (list.contains(other)) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
-    public boolean successorContains(Node node, Node other) {
-        assert node.getNodeClass() == this;
-
-        int index = 0;
-        while (index < directSuccessorCount) {
-            if (getNode(node, successorOffsets[index]) == other) {
-                return true;
-            }
-            index++;
-        }
-        while (index < successorOffsets.length) {
-            NodeList<Node> list = getNodeList(node, successorOffsets[index]);
-            if (list.contains(other)) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
-    public Collection<Position> getFirstLevelInputPositions() {
-        return new AbstractCollection<Position>() {
-            @Override
-            public Iterator<Position> iterator() {
-                return new Iterator<Position>() {
-                    int i = 0;
-
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public Position next() {
-                        Position pos = new Position(true, i, i >= directInputCount ? Node.NODE_LIST : Node.NOT_ITERABLE);
-                        i++;
-                        return pos;
-                    }
-
-                    public boolean hasNext() {
-                        return i < inputOffsets.length;
-                    }
-                };
-            }
-
-            @Override
-            public int size() {
-                return inputOffsets.length;
-            }
-        };
-    }
-
-    public Collection<Position> getFirstLevelSuccessorPositions() {
-        return new AbstractCollection<Position>() {
-            @Override
-            public Iterator<Position> iterator() {
-                return new Iterator<Position>() {
-                    int i = 0;
-
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-
-                    public Position next() {
-                        Position pos = new Position(false, i, i >= directSuccessorCount ? Node.NODE_LIST : Node.NOT_ITERABLE);
-                        i++;
-                        return pos;
-                    }
-
-                    public boolean hasNext() {
-                        return i < successorOffsets.length;
-                    }
-                };
-            }
-
-            @Override
-            public int size() {
-                return successorOffsets.length;
-            }
-        };
+    public Edges getEdges(Edges.Type type) {
+        return type == Edges.Type.Inputs ? inputs : successors;
     }
 
     public Collection<Integer> getPropertyPositions() {
@@ -1522,14 +760,15 @@
      */
     public void initRawNode(Node node) {
         node.init();
-        for (int inputPos = directInputCount; inputPos < inputOffsets.length; inputPos++) {
-            if (getNodeList(node, inputOffsets[inputPos]) == null) {
-                putNodeList(node, inputOffsets[inputPos], new NodeInputList<>(node));
-            }
-        }
-        for (int successorPos = directSuccessorCount; successorPos < successorOffsets.length; successorPos++) {
-            if (getNodeList(node, successorOffsets[successorPos]) == null) {
-                putNodeList(node, successorOffsets[successorPos], new NodeSuccessorList<>(node));
+        initNullEdgeLists(node, Edges.Type.Inputs);
+        initNullEdgeLists(node, Edges.Type.Successors);
+    }
+
+    private void initNullEdgeLists(Node node, Edges.Type type) {
+        Edges edges = getEdges(type);
+        for (int inputPos = edges.getDirectCount(); inputPos < edges.getCount(); inputPos++) {
+            if (edges.getNodeList(node, inputPos) == null) {
+                edges.initializeList(node, inputPos, type == Edges.Type.Inputs ? new NodeInputList<>(node) : new NodeSuccessorList<>(node));
             }
         }
     }
@@ -1548,7 +787,7 @@
 
     interface InplaceUpdateClosure {
 
-        Node replacement(Node node, boolean isInput);
+        Node replacement(Node node, Edges.Type type);
     }
 
     static Map<Node, Node> addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable<Node> nodes, final DuplicationReplacement replacements) {
@@ -1565,7 +804,7 @@
 
         InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() {
 
-            public Node replacement(Node node, boolean isInput) {
+            public Node replacement(Node node, Edges.Type type) {
                 Node target = newNodes.get(node);
                 if (target == null) {
                     Node replacement = node;
@@ -1574,7 +813,7 @@
                     }
                     if (replacement != node) {
                         target = replacement;
-                    } else if (node.graph() == graph && isInput) {
+                    } else if (node.graph() == graph && type == Edges.Type.Inputs) {
                         // patch to the outer world
                         target = node;
                     }
@@ -1588,12 +827,11 @@
         // re-wire inputs
         for (Node oldNode : nodes) {
             Node node = newNodes.get(oldNode);
-            NodeClass oldNodeClass = oldNode.getNodeClass();
             NodeClass nodeClass = node.getNodeClass();
             if (replacements == null || replacements.replacement(oldNode) == oldNode) {
                 nodeClass.updateInputSuccInPlace(node, replacementClosure);
             } else {
-                transferValuesDifferentNodeClass(graph, replacements, newNodes, oldNode, node, oldNodeClass, nodeClass);
+                transferEdgesDifferentNodeClass(graph, replacements, newNodes, oldNode, node);
             }
         }
 
@@ -1621,50 +859,36 @@
         }
     }
 
-    private static void transferValuesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node, NodeClass oldNodeClass,
-                    NodeClass nodeClass) {
-        for (NodePosIterator iter = oldNode.inputs().iterator(); iter.hasNext();) {
-            Position pos = iter.nextPosition();
-            if (!nodeClass.isValid(pos, oldNodeClass)) {
+    private static void transferEdgesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node) {
+        transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Inputs);
+        transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Successors);
+    }
+
+    private static void transferEdges(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node, Edges.Type type) {
+        NodeClass nodeClass = node.getNodeClass();
+        NodeClass oldNodeClass = oldNode.getNodeClass();
+        Edges oldEdges = oldNodeClass.getEdges(type);
+        for (NodePosIterator oldIter = oldEdges.getIterable(oldNode).iterator(); oldIter.hasNext();) {
+            Position pos = oldIter.nextPosition();
+            if (!nodeClass.isValid(pos, oldNodeClass, oldEdges)) {
                 continue;
             }
-            Node input = oldNodeClass.get(oldNode, pos);
-            Node target = newNodes.get(input);
+            Node oldEdge = pos.get(oldNode);
+            Node target = newNodes.get(oldEdge);
             if (target == null) {
-                Node replacement = input;
+                Node replacement = oldEdge;
                 if (replacements != null) {
-                    replacement = replacements.replacement(input);
+                    replacement = replacements.replacement(oldEdge);
                 }
-                if (replacement != input) {
-                    assert isAssignable(nodeClass.fieldTypes.get(nodeClass.inputOffsets[pos.getIndex()]), replacement);
+                if (replacement != oldEdge) {
                     target = replacement;
-                } else if (input.graph() == graph) { // patch to the outer world
-                    target = input;
+                } else if (type == Edges.Type.Inputs && oldEdge.graph() == graph) {
+                    // patch to the outer world
+                    target = oldEdge;
                 }
             }
-            nodeClass.set(node, pos, target);
+            pos.set(node, target);
         }
-
-        for (NodePosIterator iter = oldNode.successors().iterator(); iter.hasNext();) {
-            Position pos = iter.nextPosition();
-            if (!nodeClass.isValid(pos, oldNodeClass)) {
-                continue;
-            }
-            Node succ = oldNodeClass.get(oldNode, pos);
-            Node target = newNodes.get(succ);
-            if (target == null) {
-                Node replacement = replacements.replacement(succ);
-                if (replacement != succ) {
-                    assert isAssignable(nodeClass.fieldTypes.get(node.getNodeClass().successorOffsets[pos.getIndex()]), replacement);
-                    target = replacement;
-                }
-            }
-            nodeClass.set(node, pos, target);
-        }
-    }
-
-    private static boolean isAssignable(Class<?> fieldType, Node replacement) {
-        return replacement == null || !NODE_CLASS.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(replacement.getClass());
     }
 
     public boolean isLeafNode() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClassIterable.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClassIterable.java	Thu Sep 25 10:27:17 2014 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.graph.iterators.*;
 
 /**
- * The iterator returned by this iterable can be used to access {@link Position Positions} during
+ * The iterator returned by this iterable can be used to access {@link Position positions} during
  * iteration using {@link NodePosIterator#nextPosition()}.
  */
 public interface NodeClassIterable extends NodeIterable<Node> {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,37 +22,35 @@
  */
 package com.oracle.graal.graph;
 
+import static com.oracle.graal.graph.Edges.Type.*;
+
 import java.util.*;
 
+import com.oracle.graal.graph.Edges.*;
+
 public final class NodeInputList<T extends Node> extends NodeList<T> {
 
-    private final Node self;
-
     public NodeInputList(Node self, int initialSize) {
-        super(initialSize);
-        this.self = self;
+        super(self, initialSize);
     }
 
     public NodeInputList(Node self) {
-        this.self = self;
+        super(self);
     }
 
     public NodeInputList(Node self, T[] elements) {
-        super(elements);
+        super(self, elements);
         assert self.usages().isEmpty();
-        this.self = self;
     }
 
     public NodeInputList(Node self, List<? extends T> elements) {
-        super(elements);
+        super(self, elements);
         assert self.usages().isEmpty();
-        this.self = self;
     }
 
     public NodeInputList(Node self, Collection<? extends NodeInterface> elements) {
-        super(elements);
+        super(self, elements);
         assert self.usages().isEmpty();
-        this.self = self;
     }
 
     @Override
@@ -61,39 +59,7 @@
     }
 
     @Override
-    public boolean add(Node node) {
-        assert node == null || !node.isDeleted();
-        self.incModCount();
-        return super.add(node);
-    }
-
-    @Override
-    public T remove(int index) {
-        self.incModCount();
-        return super.remove(index);
-    }
-
-    @Override
-    public boolean remove(Object node) {
-        self.incModCount();
-        return super.remove(node);
-    }
-
-    @Override
-    public void clear() {
-        self.incModCount();
-        super.clear();
-    }
-
-    @Override
-    void copy(NodeList<? extends Node> other) {
-        self.incModCount();
-        super.copy(other);
-    }
-
-    @Override
-    public void setAll(NodeList<T> values) {
-        self.incModCount();
-        super.setAll(values);
+    public Type getEdgesType() {
+        return Inputs;
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Sep 25 10:27:17 2014 +0200
@@ -30,22 +30,26 @@
 
     protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
 
+    protected final Node self;
     protected Node[] nodes;
     private int size;
     protected final int initialSize;
 
-    protected NodeList() {
+    protected NodeList(Node self) {
+        this.self = self;
         this.nodes = EMPTY_NODE_ARRAY;
         this.initialSize = 0;
     }
 
-    protected NodeList(int initialSize) {
+    protected NodeList(Node self, int initialSize) {
+        this.self = self;
         this.size = initialSize;
         this.initialSize = initialSize;
         this.nodes = new Node[initialSize];
     }
 
-    protected NodeList(T[] elements) {
+    protected NodeList(Node self, T[] elements) {
+        this.self = self;
         if (elements == null || elements.length == 0) {
             this.size = 0;
             this.nodes = EMPTY_NODE_ARRAY;
@@ -61,7 +65,8 @@
         }
     }
 
-    protected NodeList(List<? extends T> elements) {
+    protected NodeList(Node self, List<? extends T> elements) {
+        this.self = self;
         if (elements == null || elements.isEmpty()) {
             this.size = 0;
             this.nodes = EMPTY_NODE_ARRAY;
@@ -77,7 +82,8 @@
         }
     }
 
-    protected NodeList(Collection<? extends NodeInterface> elements) {
+    protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
+        this.self = self;
         if (elements == null || elements.isEmpty()) {
             this.size = 0;
             this.nodes = EMPTY_NODE_ARRAY;
@@ -95,8 +101,14 @@
         }
     }
 
+    public boolean isList() {
+        return true;
+    }
+
     protected abstract void update(T oldNode, T newNode);
 
+    public abstract Edges.Type getEdgesType();
+
     @Override
     public final int size() {
         return size;
@@ -124,6 +136,8 @@
     @SuppressWarnings("unchecked")
     @Override
     public boolean add(Node node) {
+        assert node == null || !node.isDeleted();
+        self.incModCount();
         incModCount();
         if (size == nodes.length) {
             nodes = Arrays.copyOf(nodes, nodes.length * 2 + 1);
@@ -162,6 +176,7 @@
     }
 
     void copy(NodeList<? extends Node> other) {
+        self.incModCount();
         incModCount();
         nodes = Arrays.copyOf(other.nodes, other.size);
         size = other.size;
@@ -182,6 +197,7 @@
     @SuppressWarnings("unchecked")
     @Override
     public void clear() {
+        self.incModCount();
         incModCount();
         for (int i = 0; i < size; i++) {
             update((T) nodes[i], null);
@@ -193,6 +209,7 @@
     @Override
     @SuppressWarnings("unchecked")
     public boolean remove(Object node) {
+        self.incModCount();
         int i = 0;
         incModCount();
         while (i < size && nodes[i] != node) {
@@ -216,6 +233,7 @@
     @Override
     @SuppressWarnings("unchecked")
     public T remove(int index) {
+        self.incModCount();
         T oldValue = (T) nodes[index];
         int i = index + 1;
         incModCount();
@@ -290,6 +308,7 @@
 
     @SuppressWarnings("unchecked")
     public void setAll(NodeList<T> values) {
+        self.incModCount();
         incModCount();
         for (int i = 0; i < size(); i++) {
             update((T) nodes[i], null);
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,23 +22,23 @@
  */
 package com.oracle.graal.graph;
 
+import static com.oracle.graal.graph.Edges.Type.*;
+
+import com.oracle.graal.graph.Edges.*;
+
 public final class NodeSuccessorList<T extends Node> extends NodeList<T> {
 
-    private final Node self;
-
     public NodeSuccessorList(Node self, int initialSize) {
-        super(initialSize);
-        this.self = self;
+        super(self, initialSize);
     }
 
     protected NodeSuccessorList(Node self) {
-        this.self = self;
+        super(self);
     }
 
     public NodeSuccessorList(Node self, T[] elements) {
-        super(elements);
+        super(self, elements);
         assert self.usages().isEmpty();
-        this.self = self;
     }
 
     @Override
@@ -47,38 +47,7 @@
     }
 
     @Override
-    public boolean add(Node node) {
-        self.incModCount();
-        return super.add(node);
-    }
-
-    @Override
-    public T remove(int index) {
-        self.incModCount();
-        return super.remove(index);
-    }
-
-    @Override
-    public boolean remove(Object node) {
-        self.incModCount();
-        return super.remove(node);
-    }
-
-    @Override
-    public void clear() {
-        self.incModCount();
-        super.clear();
-    }
-
-    @Override
-    void copy(NodeList<? extends Node> other) {
-        self.incModCount();
-        super.copy(other);
-    }
-
-    @Override
-    public void setAll(NodeList<T> values) {
-        self.incModCount();
-        super.setAll(values);
+    public Type getEdgesType() {
+        return Successors;
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,21 +22,17 @@
  */
 package com.oracle.graal.graph;
 
-import com.oracle.graal.graph.Node.Input;
-import com.oracle.graal.graph.Node.OptionalInput;
 import com.oracle.graal.nodeinfo.*;
 
 /**
  * Describes an edge slot for a {@link NodeClass}.
- *
- * @see NodeClass#getName(Position)
  */
 public final class Position {
 
     /**
-     * Specifies if this position denotes an {@link Input} or {@link OptionalInput} field.
+     * The edges in which this position lies.
      */
-    private final boolean input;
+    private final Edges edges;
 
     /**
      * Index of the {@link Node} or {@link NodeList} field denoted by this position.
@@ -49,39 +45,55 @@
      */
     private final int subIndex;
 
-    public Position(boolean input, int index, int subIndex) {
-        this.input = input;
+    public Position(Edges edges, int index, int subIndex) {
+        this.edges = edges;
         this.index = index;
         this.subIndex = subIndex;
     }
 
     public Node get(Node node) {
-        return node.getNodeClass().get(node, this);
-    }
-
-    public InputType getInputType(Node node) {
-        return node.getNodeClass().getInputType(this);
+        if (index < edges.getDirectCount()) {
+            return edges.getNode(node, index);
+        } else {
+            return edges.getNodeList(node, index).get(subIndex);
+        }
     }
 
-    public String getInputName(Node node) {
-        return node.getNodeClass().getName(this);
+    public InputType getInputType() {
+        return ((InputEdges) edges).getInputType(index);
     }
 
-    public boolean isInputOptional(Node node) {
-        return node.getNodeClass().isInputOptional(this);
+    public String getName() {
+        return edges.getName(index);
+    }
+
+    public boolean isInputOptional() {
+        return ((InputEdges) edges).isOptional(index);
     }
 
     public void set(Node node, Node value) {
-        node.getNodeClass().set(node, this, value);
+        if (index < edges.getDirectCount()) {
+            edges.setNode(node, index, value);
+        } else {
+            edges.getNodeList(node, index).set(subIndex, value);
+        }
     }
 
     public void initialize(Node node, Node value) {
-        node.getNodeClass().initializePosition(node, this, value);
+        if (index < edges.getDirectCount()) {
+            edges.initializeNode(node, index, value);
+        } else {
+            edges.getNodeList(node, index).initialize(subIndex, value);
+        }
     }
 
     @Override
     public String toString() {
-        return (input ? "input " : "successor ") + index + "/" + subIndex;
+        String res = edges.getType(index).getSimpleName() + ":" + edges.getName(index);
+        if (subIndex != Node.NOT_ITERABLE) {
+            res += "[" + subIndex + "]";
+        }
+        return res;
     }
 
     @Override
@@ -89,7 +101,7 @@
         final int prime = 31;
         int result = 1;
         result = prime * result + index;
-        result = prime * result + (input ? 1231 : 1237);
+        result = prime * result + edges.hashCode();
         result = prime * result + subIndex;
         return result;
     }
@@ -109,7 +121,7 @@
         if (index != other.index) {
             return false;
         }
-        if (input != other.input) {
+        if (edges != other.edges) {
             return false;
         }
         if (subIndex != other.subIndex) {
@@ -132,12 +144,4 @@
     public int getIndex() {
         return index;
     }
-
-    /**
-     * Returns true if this position denotes an {@link Input} or {@link OptionalInput} field, false
-     * otherwise.
-     */
-    public boolean isInput() {
-        return input;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java	Thu Sep 25 10:27:17 2014 +0200
@@ -0,0 +1,39 @@
+/*
+ * 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.graph;
+
+import static com.oracle.graal.graph.Edges.Type.*;
+
+import java.util.*;
+
+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);
+    }
+
+    @Override
+    protected void update(Node node, Node oldValue, Node newValue) {
+        node.updatePredecessor(oldValue, newValue);
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Thu Sep 25 10:27:17 2014 +0200
@@ -89,22 +89,21 @@
         assert successors.hasNext();
         // original loop is used as first successor
         Position firstPosition = successors.nextPosition();
-        NodeClass controlSplitClass = firstNode.getNodeClass();
         BeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
-        controlSplitClass.set(newControlSplit, firstPosition, originalLoopBegin);
+        firstPosition.set(newControlSplit, originalLoopBegin);
 
         while (successors.hasNext()) {
             Position position = successors.nextPosition();
             // create a new loop duplicate and connect it.
             LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
             BeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
-            controlSplitClass.set(newControlSplit, position, newBegin);
+            position.set(newControlSplit, newBegin);
 
             // For each cloned ControlSplitNode, simplify the proper path
             for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
                 ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
                 if (duplicatedControlSplit.isAlive()) {
-                    BeginNode survivingSuccessor = (BeginNode) controlSplitClass.get(duplicatedControlSplit, position);
+                    BeginNode survivingSuccessor = (BeginNode) position.get(duplicatedControlSplit);
                     survivingSuccessor.replaceAtUsages(InputType.Guard, newBegin);
                     graph.removeSplitPropagate(duplicatedControlSplit, survivingSuccessor);
                 }
@@ -113,7 +112,7 @@
         // original loop is simplified last to avoid deleting controlSplitNode too early
         for (ControlSplitNode controlSplitNode : controlSplitNodeSet) {
             if (controlSplitNode.isAlive()) {
-                BeginNode survivingSuccessor = (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition);
+                BeginNode survivingSuccessor = (BeginNode) firstPosition.get(controlSplitNode);
                 survivingSuccessor.replaceAtUsages(InputType.Guard, originalLoopBegin);
                 graph.removeSplitPropagate(controlSplitNode, survivingSuccessor);
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import static com.oracle.graal.graph.Edges.Type.*;
+
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -226,7 +228,7 @@
                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
                 NodeClass nodeClass = trueNext.getNodeClass();
                 if (trueNext.getClass() == falseNext.getClass()) {
-                    if (nodeClass.inputsEqual(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
+                    if (nodeClass.getEdges(Inputs).areEqualIn(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
                         falseNext.replaceAtUsages(trueNext);
                         graph().removeFixed(falseNext);
                         GraphUtil.unlinkFixedNode(trueNext);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu Sep 25 10:27:17 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import static com.oracle.graal.graph.Edges.Type.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -97,7 +99,7 @@
 
         if (next() instanceof IntegerDivNode) {
             NodeClass nodeClass = getNodeClass();
-            if (next().getClass() == this.getClass() && nodeClass.inputsEqual(this, next()) && nodeClass.valueEqual(this, next())) {
+            if (next().getClass() == this.getClass() && nodeClass.getEdges(Inputs).areEqualIn(this, next()) && nodeClass.valueEqual(this, next())) {
                 return next();
             }
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Thu Sep 25 10:27:17 2014 +0200
@@ -500,7 +500,7 @@
                     while (iter.hasNext()) {
                         Position pos = iter.nextPosition();
                         if (pos.get(usage) == duplicated) {
-                            switch (pos.getInputType(usage)) {
+                            switch (pos.getInputType()) {
                                 case Extension:
                                 case Condition:
                                 case State:
@@ -549,7 +549,7 @@
                 Position pos = iter.nextPosition();
                 Node input = pos.get(duplicated);
                 if (input != null && !duplicatedNodes.contains(input)) {
-                    switch (pos.getInputType(duplicated)) {
+                    switch (pos.getInputType()) {
                         case Extension:
                         case Condition:
                         case State:
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Thu Sep 25 10:27:17 2014 +0200
@@ -95,11 +95,11 @@
         } else {
             /*
              * Not comparable, two cases:
-             * 
+             *
              * Example 1: 'a' standing for j.l.Number and 'b' for j.l.String We return null for lack
              * of a value representing NullType, the right answer. Same goes when both arguments are
              * non-comparable interfaces.
-             * 
+             *
              * Example 2: 'a' standing for sun/nio/ch/DirectBuffer (an interface) and b for
              * java/nio/Buffer (an abstract class). The class always takes precedence.
              */
@@ -232,7 +232,7 @@
         NodePosIterator iter = n.inputs().iterator();
         while (iter.hasNext()) {
             Position pos = iter.nextPosition();
-            InputType inputType = pos.getInputType(n);
+            InputType inputType = pos.getInputType();
             boolean isReducibleInput = (inputType == InputType.Value || inputType == InputType.Condition);
             if (isReducibleInput) {
                 ValueNode i = (ValueNode) pos.get(n);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Thu Sep 25 10:27:17 2014 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.printer;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.Edges.Type.*;
 
 import java.io.*;
 import java.nio.*;
@@ -297,19 +298,8 @@
             writeByte(POOL_NODE_CLASS);
             writeString(nodeClass.getJavaClass().getSimpleName());
             writeString(nodeClass.getNameTemplate());
-            Collection<Position> directInputPositions = nodeClass.getFirstLevelInputPositions();
-            writeShort((char) directInputPositions.size());
-            for (Position pos : directInputPositions) {
-                writeByte(pos.getSubIndex() == Node.NOT_ITERABLE ? 0 : 1);
-                writePoolObject(nodeClass.getName(pos));
-                writePoolObject(nodeClass.getInputType(pos));
-            }
-            Collection<Position> directSuccessorPositions = nodeClass.getFirstLevelSuccessorPositions();
-            writeShort((char) directSuccessorPositions.size());
-            for (Position pos : directSuccessorPositions) {
-                writeByte(pos.getSubIndex() == Node.NOT_ITERABLE ? 0 : 1);
-                writePoolObject(nodeClass.getName(pos));
-            }
+            writeEdgesInfo(nodeClass, Inputs);
+            writeEdgesInfo(nodeClass, Successors);
         } else if (object instanceof ResolvedJavaMethod) {
             writeByte(POOL_METHOD);
             ResolvedJavaMethod method = ((ResolvedJavaMethod) object);
@@ -340,6 +330,18 @@
         }
     }
 
+    private void writeEdgesInfo(NodeClass nodeClass, Edges.Type type) throws IOException {
+        Edges edges = nodeClass.getEdges(type);
+        writeShort((char) edges.getCount());
+        for (int i = 0; i < edges.getCount(); i++) {
+            writeByte(i < edges.getDirectCount() ? 0 : 1);
+            writePoolObject(edges.getName(i));
+            if (type == Inputs) {
+                writePoolObject(((InputEdges) edges).getInputType(i));
+            }
+        }
+    }
+
     private void writePropertyObject(Object obj) throws IOException {
         if (obj instanceof Integer) {
             writeByte(PROPERTY_INT);
@@ -429,32 +431,29 @@
                 writePoolObject(key);
                 writePropertyObject(entry.getValue());
             }
-            // inputs
-            writeEdges(node, nodeClass.getFirstLevelInputPositions());
-            // successors
-            writeEdges(node, nodeClass.getFirstLevelSuccessorPositions());
+            writeEdges(node, Inputs);
+            writeEdges(node, Successors);
 
             props.clear();
         }
     }
 
-    private void writeEdges(Node node, Collection<Position> positions) throws IOException {
+    private void writeEdges(Node node, Edges.Type type) throws IOException {
         NodeClass nodeClass = node.getNodeClass();
-        for (Position pos : positions) {
-            if (pos.getSubIndex() == Node.NOT_ITERABLE) {
-                Node edge = nodeClass.get(node, pos);
-                writeNodeRef(edge);
+        Edges edges = nodeClass.getEdges(type);
+        for (int i = 0; i < edges.getDirectCount(); i++) {
+            writeNodeRef(edges.getNode(node, i));
+        }
+        for (int i = edges.getDirectCount(); i < edges.getCount(); i++) {
+            NodeList<Node> list = edges.getNodeList(node, i);
+            if (list == null) {
+                writeShort((char) 0);
             } else {
-                NodeList<?> list = nodeClass.getNodeList(node, pos);
-                if (list == null) {
-                    writeShort((char) 0);
-                } else {
-                    int listSize = list.count();
-                    assert listSize == ((char) listSize);
-                    writeShort((char) listSize);
-                    for (Node edge : list) {
-                        writeNodeRef(edge);
-                    }
+                int listSize = list.count();
+                assert listSize == ((char) listSize);
+                writeShort((char) listSize);
+                for (Node edge : list) {
+                    writeNodeRef(edge);
                 }
             }
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Sep 25 10:27:17 2014 +0200
@@ -370,7 +370,7 @@
         int lastIndex = -1;
         while (iter.hasNext()) {
             Position pos = iter.nextPosition();
-            if (hideSuffix != null && node.getNodeClass().getName(pos).endsWith(hideSuffix)) {
+            if (hideSuffix != null && pos.getName().endsWith(hideSuffix)) {
                 continue;
             }
 
@@ -378,10 +378,10 @@
                 if (lastIndex != -1) {
                     out.print(suffix);
                 }
-                out.print(prefix).print(node.getNodeClass().getName(pos)).print(": ");
+                out.print(prefix).print(pos.getName()).print(": ");
                 lastIndex = pos.getIndex();
             }
-            out.print(nodeToString(node.getNodeClass().get(node, pos))).print(" ");
+            out.print(nodeToString(pos.get(node))).print(" ");
         }
         if (lastIndex != -1) {
             out.print(suffix);
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Wed Sep 24 17:17:27 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Thu Sep 25 10:27:17 2014 +0200
@@ -215,9 +215,9 @@
             NodePosIterator succIter = node.successors().iterator();
             while (succIter.hasNext()) {
                 Position position = succIter.nextPosition();
-                Node successor = node.getNodeClass().get(node, position);
+                Node successor = position.get(node);
                 if (successor != null) {
-                    edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, node.getNodeClass().getName(position)));
+                    edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, position.getName()));
                 }
                 fromIndex++;
             }
@@ -227,9 +227,9 @@
             NodePosIterator inputIter = node.inputs().iterator();
             while (inputIter.hasNext()) {
                 Position position = inputIter.nextPosition();
-                Node input = node.getNodeClass().get(node, position);
+                Node input = position.get(node);
                 if (input != null) {
-                    edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, node.getNodeClass().getName(position)));
+                    edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, position.getName()));
                 }
                 toIndex++;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Thu Sep 25 10:27:17 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011, 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.replacements;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Substitutions for improving the performance of some critical methods in {@link Edges}. These
+ * substitutions improve the performance by forcing the relevant methods to be inlined
+ * (intrinsification being a special form of inlining) and removing a checked cast. The latter
+ * cannot be done directly in Java code as {@link PiNode} is not available to the project containing
+ * {@link Edges}.
+ */
+@ClassSubstitution(Edges.class)
+public class EdgesSubstitutions {
+
+    @MethodSubstitution
+    private static Node getNode(Node node, long offset) {
+        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class);
+    }
+
+    @MethodSubstitution
+    private static NodeList<?> getNodeList(Node node, long offset) {
+        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class);
+    }
+
+    @MethodSubstitution
+    private static void putNode(Node node, long offset, Node value) {
+        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
+    }
+
+    @MethodSubstitution
+    private static void putNodeList(Node node, long offset, NodeList<?> value) {
+        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
+    }
+
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Wed Sep 24 17:17:27 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2011, 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.replacements;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-
-/**
- * Substitutions for improving the performance of some critical methods in {@link NodeClass}
- * methods. These substitutions improve the performance by forcing the relevant methods to be
- * inlined (intrinsification being a special form of inlining) and removing a checked cast. The
- * latter cannot be done directly in Java code as {@link PiNode} is not available to the project
- * containing {@link NodeClass}.
- */
-@ClassSubstitution(NodeClass.class)
-public class NodeClassSubstitutions {
-
-    @MethodSubstitution
-    private static Node getNode(Node node, long offset) {
-        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class);
-    }
-
-    @MethodSubstitution
-    private static NodeList<?> getNodeList(Node node, long offset) {
-        return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class);
-    }
-
-    @MethodSubstitution
-    private static void putNode(Node node, long offset, Node value) {
-        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution
-    private static void putNodeList(Node node, long offset, NodeList<?> value) {
-        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-}