# HG changeset patch # User Andreas Woess # Date 1406039563 -7200 # Node ID 8be5c68a779defd78459bdfaeafe466a8cbe8ba3 # Parent a7d9b88ecd686b1fbf507ceca630fd9aba4c8487 Truffle: revert to previous iterator implementation, add test case diff -r a7d9b88ecd68 -r 8be5c68a779d graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Tue Jul 22 15:06:15 2014 +0200 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildrenNodesTest.java Tue Jul 22 16:32:43 2014 +0200 @@ -95,4 +95,50 @@ return 21; } } + + @Test + public void testMultipleChildrenFields() { + TruffleRuntime runtime = Truffle.getRuntime(); + TestChildNode firstChild = new TestChildNode(); + TestChildNode secondChild = new TestChildNode(); + TestChildNode thirdChild = new TestChildNode(); + TestChildNode forthChild = new TestChildNode(); + TestRootNode rootNode = new TestRoot2Node(new TestChildNode[]{firstChild, secondChild}, new TestChildNode[]{thirdChild, forthChild}); + CallTarget target = runtime.createCallTarget(rootNode); + Assert.assertEquals(rootNode, firstChild.getParent()); + Assert.assertEquals(rootNode, secondChild.getParent()); + Assert.assertEquals(rootNode, thirdChild.getParent()); + Assert.assertEquals(rootNode, forthChild.getParent()); + Iterator iterator = rootNode.getChildren().iterator(); + Assert.assertEquals(firstChild, iterator.next()); + Assert.assertEquals(secondChild, iterator.next()); + Assert.assertEquals(thirdChild, iterator.next()); + Assert.assertEquals(forthChild, iterator.next()); + Assert.assertFalse(iterator.hasNext()); + Object result = target.call(); + Assert.assertEquals(2 * 42, result); + } + + class TestRoot2Node extends TestRootNode { + @Children private final TestChildNode[] children1; + @Children private final TestChildNode[] children2; + + public TestRoot2Node(TestChildNode[] children1, TestChildNode[] children2) { + super(new TestChildNode[0]); + this.children1 = children1; + this.children2 = children2; + } + + @Override + public Object execute(VirtualFrame frame) { + int sum = 0; + for (int i = 0; i < children1.length; ++i) { + sum += children1[i].execute(); + } + for (int i = 0; i < children2.length; ++i) { + sum += children2[i].execute(); + } + return sum; + } + } } diff -r a7d9b88ecd68 -r 8be5c68a779d graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Tue Jul 22 15:06:15 2014 +0200 +++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java Tue Jul 22 16:32:43 2014 +0200 @@ -252,53 +252,58 @@ private final class NodeIterator implements Iterator { private final Node node; - private int fieldIndex; - private int arrayIndex; + private final int childrenCount; + private int index; protected NodeIterator(Node node) { this.node = node; + this.index = 0; + this.childrenCount = childrenCount(); + } + + private int childrenCount() { + int nodeCount = childOffsets.length; + for (long fieldOffset : childrenOffsets) { + Node[] children = ((Node[]) unsafe.getObject(node, fieldOffset)); + if (children != null) { + nodeCount += children.length; + } + } + return nodeCount; + } + + private Node nodeAt(int idx) { + int nodeCount = childOffsets.length; + if (idx < nodeCount) { + return (Node) unsafe.getObject(node, childOffsets[idx]); + } else { + for (long fieldOffset : childrenOffsets) { + Node[] nodeArray = (Node[]) unsafe.getObject(node, fieldOffset); + if (idx < nodeCount + nodeArray.length) { + return nodeArray[idx - nodeCount]; + } + nodeCount += nodeArray.length; + } + } + return null; } private void forward() { - if (fieldIndex < childOffsets.length) { - fieldIndex++; - } else if (fieldIndex < childOffsets.length + childrenOffsets.length) { - if (arrayIndex + 1 < currentChildrenArrayLength()) { - arrayIndex++; - } else { - arrayIndex = 0; - do { - fieldIndex++; - } while (fieldIndex < childOffsets.length + childrenOffsets.length && currentChildrenArrayLength() == 0); - } + if (index < childrenCount) { + index++; } } public boolean hasNext() { - return fieldIndex < childOffsets.length || (fieldIndex < childOffsets.length + childrenOffsets.length && arrayIndex < currentChildrenArrayLength()); - } - - private Node[] currentChildrenArray() { - assert fieldIndex >= childOffsets.length && fieldIndex < childOffsets.length + childrenOffsets.length; - return (Node[]) unsafe.getObject(node, childrenOffsets[fieldIndex - childOffsets.length]); - } - - private int currentChildrenArrayLength() { - Node[] childrenArray = currentChildrenArray(); - return childrenArray != null ? childrenArray.length : 0; + return index < childrenCount; } public Node next() { - Node next; - if (fieldIndex < childOffsets.length) { - next = (Node) unsafe.getObject(node, childOffsets[fieldIndex]); - } else if (fieldIndex < childOffsets.length + childrenOffsets.length) { - next = currentChildrenArray()[arrayIndex]; - } else { - throw new NoSuchElementException(); + try { + return nodeAt(index); + } finally { + forward(); } - forward(); - return next; } public void remove() {