# HG changeset patch # User Stefan Anzinger # Date 1411663348 25200 # Node ID 7d8bb35e67c8737cb4a27231a8c63715eddc4d6f # Parent 7a99826863d9800def6cbce3f517248bc613511d# Parent 26d07b31c4a867c3b39113bece86ea1816ad63fc Merge diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java Thu Sep 25 09:42:28 2014 -0700 @@ -707,6 +707,8 @@ StructuredGraph graph = new StructuredGraph(javaMethod); graphBuilderSuite.apply(graph, new HighTierContext(providers, null, null, graphBuilderSuite, OptimisticOptimizations.ALL)); return graph; + } catch (Throwable e) { + throw Debug.handle(e); } } diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java --- /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 09:42:28 2014 -0700 @@ -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 stail; + + @Input NodeInputList 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()); + } +} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodeRefIteratorTest.java Thu Sep 25 09:41:55 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 stail; - - @Input NodeInputList 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()); - } -} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Thu Sep 25 09:42:28 2014 -0700 @@ -970,6 +970,8 @@ } } } + } catch (Throwable e) { + throw Debug.handle(e); } } diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java Thu Sep 25 09:42:28 2014 -0700 @@ -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) { diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Thu Sep 25 09:42:28 2014 -0700 @@ -217,9 +217,26 @@ * * * @param name the name of the new scope + * @param contextObjects an array of object to be appended to the {@linkplain #context() + * current} debug context + * @throws Throwable used to enforce a catch block. * @return the scope entered by this method which will be exited when its {@link Scope#close()} * method is called */ + public static Scope scope(Object name, Object[] contextObjects) throws Throwable { + if (ENABLED) { + return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, contextObjects); + } else { + return null; + } + } + + /** + * Similar to {@link #scope(Object, Object[])} but without context objects. Therefore the catch + * block can be omitted. + * + * @see #scope(Object, Object[]) + */ public static Scope scope(Object name) { if (ENABLED) { return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null); @@ -229,23 +246,10 @@ } /** - * @see #scope(Object) - * @param contextObjects an array of object to be appended to the {@linkplain #context() - * current} debug context - */ - public static Scope scope(Object name, Object[] contextObjects) { - if (ENABLED) { - return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, contextObjects); - } else { - return null; - } - } - - /** - * @see #scope(Object) + * @see #scope(Object, Object[]) * @param context an object to be appended to the {@linkplain #context() current} debug context */ - public static Scope scope(Object name, Object context) { + public static Scope scope(Object name, Object context) throws Throwable { if (ENABLED) { return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context); } else { @@ -254,13 +258,13 @@ } /** - * @see #scope(Object) + * @see #scope(Object, Object[]) * @param context1 first object to be appended to the {@linkplain #context() current} debug * context * @param context2 second object to be appended to the {@linkplain #context() current} debug * context */ - public static Scope scope(Object name, Object context1, Object context2) { + public static Scope scope(Object name, Object context1, Object context2) throws Throwable { if (ENABLED) { return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2); } else { @@ -269,7 +273,7 @@ } /** - * @see #scope(Object) + * @see #scope(Object, Object[]) * @param context1 first object to be appended to the {@linkplain #context() current} debug * context * @param context2 second object to be appended to the {@linkplain #context() current} debug @@ -277,7 +281,7 @@ * @param context3 third object to be appended to the {@linkplain #context() current} debug * context */ - public static Scope scope(Object name, Object context1, Object context2, Object context3) { + public static Scope scope(Object name, Object context1, Object context2, Object context3) throws Throwable { if (ENABLED) { return DebugScope.getInstance().scope(convertFormatArg(name).toString(), null, context1, context2, context3); } else { @@ -305,7 +309,7 @@ * @return the scope entered by this method which will be exited when its {@link Scope#close()} * method is called */ - public static Scope sandbox(CharSequence name, DebugConfig config, Object... context) { + public static Scope sandbox(CharSequence name, DebugConfig config, Object... context) throws Throwable { if (ENABLED) { DebugConfig sandboxConfig = config == null ? silentConfig() : config; return DebugScope.getInstance().scope(name, sandboxConfig, context); @@ -314,7 +318,7 @@ } } - public static Scope forceLog() { + public static Scope forceLog() throws Throwable { ArrayList context = new ArrayList<>(); for (Object obj : context()) { context.add(obj); @@ -346,7 +350,7 @@ * pattern recommended by {@link #scope(Object)} and * {@link #sandbox(CharSequence, DebugConfig, Object...)} is used * - * @see #scope(Object) + * @see #scope(Object, Object[]) * @see #sandbox(CharSequence, DebugConfig, Object...) */ public static RuntimeException handle(Throwable exception) { diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java --- /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 09:42:28 2014 -0700 @@ -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 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 names, Map> types) { + this.nodeClass = (Class) 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 getNodeList(Node node, long offset) { + return (NodeList) 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 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 list = getNodeList(node, index); + int size = list.initialSize; + NodeList 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 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 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 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 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 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]); + } + } +} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionCollection.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionCollection.java Thu Sep 25 09:41:55 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 implements Collection { - - 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 iterator() { - return new FirstLevelPositionIterator(nodeFields, allNodeRefFields - nodeFields, isInputs); - } -} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionIterator.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/FirstLevelPositionIterator.java Thu Sep 25 09:41:55 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 { - - 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; - } -} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Thu Sep 25 09:42:28 2014 -0700 @@ -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; } } diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/InputEdges.java --- /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 09:42:28 2014 -0700 @@ -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 names, Map> types, Map inputTypes, Set 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); + } +} diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Sep 25 09:42:28 2014 -0700 @@ -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("}"); diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Thu Sep 25 09:41:55 2014 -0700 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Thu Sep 25 09:42:28 2014 -0700 @@ -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 @@ * *
      *     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 getNodeList(Node node, long offset) {
-        return (NodeList) 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 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 list = getNodeList(node, inputOffsets[index]);
-            assert list != null : getClazz();
-            putNodeList(node, inputOffsets[index], updateInputListCopy(list, node, duplicationReplacement));
+        while (index < edges.getCount()) {
+            NodeList 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 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 updateInputListCopy(NodeList list, Node node, InplaceUpdateClosure duplicationReplacement) {
-        int size = list.size();
-        NodeInputList result = new NodeInputList<>(node, size);
+    private static NodeList updateEdgeListCopy(Node node, NodeList list, InplaceUpdateClosure duplicationReplacement, Edges.Type type) {
+        NodeList 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 updateSuccListCopy(NodeList list, Node node, InplaceUpdateClosure duplicationReplacement) {
-        int size = list.size();
-        NodeSuccessorList 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 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 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 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 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 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 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 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 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 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 list = getNodeList(node, successorOffsets[index]);
-            if (list.contains(other)) {
-                return true;
-            }
-            index++;
-        }
-        return false;
-    }
-
-    public Collection getFirstLevelInputPositions() {
-        return new AbstractCollection() {
-            @Override
-            public Iterator iterator() {
-                return new Iterator() {
-                    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 getFirstLevelSuccessorPositions() {
-        return new AbstractCollection() {
-            @Override
-            public Iterator iterator() {
-                return new Iterator() {
-                    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 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 addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable 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 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 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 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() {
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClassIterable.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClassIterable.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClassIterable.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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 {
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeInputList.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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 extends NodeList {
 
-    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 elements) {
-        super(elements);
+        super(self, elements);
         assert self.usages().isEmpty();
-        this.self = self;
     }
 
     public NodeInputList(Node self, Collection 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 other) {
-        self.incModCount();
-        super.copy(other);
-    }
-
-    @Override
-    public void setAll(NodeList values) {
-        self.incModCount();
-        super.setAll(values);
+    public Type getEdgesType() {
+        return Inputs;
     }
 }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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 elements) {
+    protected NodeList(Node self, List elements) {
+        this.self = self;
         if (elements == null || elements.isEmpty()) {
             this.size = 0;
             this.nodes = EMPTY_NODE_ARRAY;
@@ -77,7 +82,8 @@
         }
     }
 
-    protected NodeList(Collection elements) {
+    protected NodeList(Node self, Collection 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 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 values) {
+        self.incModCount();
         incModCount();
         for (int i = 0; i < size(); i++) {
             update((T) nodes[i], null);
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeSuccessorList.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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 extends NodeList {
 
-    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 other) {
-        self.incModCount();
-        super.copy(other);
-    }
-
-    @Override
-    public void setAll(NodeList values) {
-        self.incModCount();
-        super.setAll(values);
+    public Type getEdgesType() {
+        return Successors;
     }
 }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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;
-    }
 }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/SuccessorEdges.java
--- /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 09:42:28 2014 -0700
@@ -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 names, Map> types) {
+        super(nodeClass, Successors, directCount, offsets, names, types);
+    }
+
+    @Override
+    protected void update(Node node, Node oldValue, Node newValue) {
+        node.updatePredecessor(oldValue, newValue);
+    }
+}
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Sep 25 09:42:28 2014 -0700
@@ -167,6 +167,8 @@
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
             installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null, null);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
         }
         return installedCode;
     }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Sep 25 09:42:28 2014 -0700
@@ -64,12 +64,12 @@
     private BlockMap> blockMap;
     private BlockMap insertionBuffers;
 
-    private static DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]");
-    private static DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]");
-    private static DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]");
-    private static DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
-    private static DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
-    private static DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]");
+    private static final DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]");
+    private static final DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]");
+    private static final DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]");
+    private static final DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
+    private static final DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
+    private static final DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]");
 
     private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) {
         this.lir = lir;
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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);
             }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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);
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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();
             }
         }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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:
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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);
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Sep 25 09:42:28 2014 -0700
@@ -399,6 +399,8 @@
             throw new GraalInternalError(e).addContext(calleeInfo.toString());
         } catch (GraalInternalError e) {
             throw e.addContext(calleeInfo.toString());
+        } catch (Throwable e) {
+            throw Debug.handle(e);
         }
     }
 
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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 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 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 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 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);
                 }
             }
         }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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);
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Thu Sep 25 09:42:28 2014 -0700
@@ -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++;
             }
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java
--- /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 09:42:28 2014 -0700
@@ -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);
+    }
+
+}
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Thu Sep 25 09:41:55 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);
-    }
-
-}
diff -r 7a99826863d9 -r 7d8bb35e67c8 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Sep 25 09:41:55 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Sep 25 09:42:28 2014 -0700
@@ -130,6 +130,8 @@
                 CodeCacheProvider codeCache = providers.getCodeCache();
                 try (Scope s = Debug.scope("CodeInstall", codeCache, method)) {
                     codeCache.setDefaultMethod(method, compResult);
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
                 }
             }
         }