Mercurial > hg > truffle
diff graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java @ 11528:8f500c7a510a
inlined NodeUsageList into Node (GRAAL-452)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Thu, 05 Sep 2013 00:44:36 +0200 |
parents | dede53632f3e |
children | 331f7590b741 |
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Wed Sep 04 10:47:37 2013 -0400 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Thu Sep 05 00:44:36 2013 +0200 @@ -121,7 +121,17 @@ // therefore points to the next Node of the same type. Node typeCacheNext; - private NodeUsagesList usages; + private static final int INLINE_USAGE_COUNT = 2; + private static final Node[] NO_NODES = {}; + + /** + * Head of usage list. The elements of the usage list in order are {@link #usage0}, + * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list. + */ + private Node usage0; + private Node usage1; + private Node[] extraUsages = NO_NODES; + private Node predecessor; public Node() { @@ -157,8 +167,184 @@ return getNodeClass().getSuccessorIterable(this); } + class NodeUsageIterator implements Iterator<Node> { + + private final int expectedModCount = usageModCount(); + int index = -1; + Node current; + + private void advance() { + assert index == -1 || current != null; + current = null; + index++; + if (index == 0) { + current = usage0; + } else if (index == 1) { + current = usage1; + } else { + if (index - INLINE_USAGE_COUNT < extraUsages.length) { + current = extraUsages[index - INLINE_USAGE_COUNT]; + } + } + } + + public NodeUsageIterator() { + advance(); + } + + public boolean hasNext() { + assert expectedModCount == usageModCount(); + return current != null; + } + + public Node next() { + assert expectedModCount == usageModCount(); + Node result = current; + if (result == null) { + throw new NoSuchElementException(); + } + advance(); + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + class NodeUsageIterable extends AbstractNodeIterable<Node> { + + public NodeUsageIterator iterator() { + return new NodeUsageIterator(); + } + + @Override + public boolean isEmpty() { + return usage0 == null; + } + + @Override + public boolean isNotEmpty() { + return usage0 != null; + } + + @Override + public int count() { + if (usage0 == null) { + return 0; + } + if (usage1 == null) { + return 1; + } + int count = 2; + for (int i = 0; i < extraUsages.length && extraUsages[i] != null; i++) { + count++; + } + return count; + } + } + + /** + * Gets the list of nodes that use this node (e.g., as an input). + */ public final NodeIterable<Node> usages() { - return usages; + return new NodeUsageIterable(); + } + + /** + * Adds a given node to this node's {@linkplain #usages() usages}. + * + * @param node the node to add + */ + private void addUsage(Node node) { + incUsageModCount(); + if (usage0 == null) { + usage0 = node; + } else if (usage1 == null) { + usage1 = node; + } else { + int length = extraUsages.length; + int start = extraUsages.length >> 1; + if (start < length && extraUsages[start] == null) { + start = 0; + } + for (int i = start; i < length; i++) { + if (extraUsages[i] == null) { + extraUsages[i] = node; + return; + } + } + extraUsages = Arrays.copyOf(extraUsages, length * 2 + 1); + extraUsages[length] = node; + } + } + + private Node removeFirstExtraUsage() { + Node res = null; + if (extraUsages.length > 0) { + res = extraUsages[0]; + for (int i = 1; i < extraUsages.length; ++i) { + Node n = extraUsages[i]; + extraUsages[i - 1] = n; + if (n == null) { + break; + } + } + extraUsages[extraUsages.length - 1] = null; + } + return res; + } + + /** + * Removes a given node from this node's {@linkplain #usages() usages}. + * + * @param node the node to remove + * @return whether or not {@code usage} was in the usage list + */ + private boolean removeUsage(Node node) { + // It is critical that this method maintains the invariant that + // the usage list has no null element preceding a non-null element + incUsageModCount(); + if (usage0 == null) { + return false; + } + if (usage0 == node) { + usage0 = usage1; + if (usage1 != null) { + usage1 = removeFirstExtraUsage(); + } + return true; + } + if (usage1 == null) { + return false; + } + if (usage1 == node) { + usage1 = removeFirstExtraUsage(); + return true; + } + int length = extraUsages.length; + for (int i = 0; i < length; i++) { + if (extraUsages[i] == node) { + for (int j = i + 1; j < length; j++) { + Node toMove = extraUsages[j]; + extraUsages[j - 1] = toMove; + if (toMove == null) { + break; + } + } + extraUsages[length - 1] = null; + + return true; + } + } + return false; + } + + private void clearUsages() { + incUsageModCount(); + usage0 = null; + usage1 = null; + extraUsages = NO_NODES; } public final Node predecessor() { @@ -178,6 +364,19 @@ } } + final int usageModCount() { + if (MODIFICATION_COUNTS_ENABLED && graph != null) { + return graph.usageModCount(this); + } + return 0; + } + + final void incUsageModCount() { + if (MODIFICATION_COUNTS_ENABLED && graph != null) { + graph.incUsageModCount(this); + } + } + public boolean isDeleted() { return id <= DELETED_ID_START; } @@ -191,7 +390,6 @@ * newInput: removes this node from oldInput's usages and adds this node to newInput's usages. */ protected void updateUsages(Node oldInput, Node newInput) { - assert assertTrue(usages != null, "usages == null while adding %s to %s", newInput, this); if (oldInput != newInput) { if (oldInput != null) { boolean result = removeThisFromUsages(oldInput); @@ -202,8 +400,7 @@ if (inputChanged != null) { inputChanged.nodeChanged(this); } - assert newInput.usages != null : "not yet added? " + newInput; - newInput.usages.add(this); + newInput.addUsage(this); } else if (oldInput != null && oldInput.usages().isEmpty()) { NodeChangedListener nodeChangedListener = graph.usagesDroppedZero; if (nodeChangedListener != null) { @@ -219,7 +416,6 @@ * this node to newSuccessor's predecessors. */ protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) { - assert assertTrue(usages != null, "usages == null while adding %s to %s", newSuccessor, this); if (oldSuccessor != newSuccessor) { if (oldSuccessor != null) { assert assertTrue(oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s", oldSuccessor, oldSuccessor.predecessor); @@ -236,7 +432,6 @@ assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id); this.graph = newGraph; newGraph.register(this); - usages = new NodeUsagesList(); for (Node input : inputs()) { updateUsages(null, input); } @@ -259,7 +454,7 @@ public void replaceAtUsages(Node other) { assert checkReplaceWith(other); - for (Node usage : usages) { + for (Node usage : usages()) { boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); assert assertTrue(result, "not found in inputs, usage: %s", usage); if (other != null) { @@ -267,10 +462,10 @@ if (inputChanged != null) { inputChanged.nodeChanged(usage); } - other.usages.add(usage); + other.addUsage(usage); } } - usages.clear(); + clearUsages(); } public void replaceAtPredecessor(Node other) { @@ -320,11 +515,7 @@ } private boolean removeThisFromUsages(Node n) { - if (n.usages.remove(this)) { - return true; - } else { - return false; - } + return n.removeUsage(this); } public void clearSuccessors() { @@ -338,7 +529,7 @@ } private boolean checkDeletion() { - assertTrue(usages.isEmpty(), "cannot delete node %s because of usages: %s", this, usages); + assertTrue(usages().isEmpty(), "cannot delete node %s because of usages: %s", this, usages()); assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor); return true; } @@ -361,7 +552,7 @@ NodeClass clazz = getNodeClass(); clazz.copyInputs(this, newNode); for (Node input : inputs()) { - input.usages.add(newNode); + input.addUsage(newNode); } return newNode; } @@ -379,7 +570,9 @@ newNode.typeCacheNext = null; newNode.id = INITIAL_ID; into.register(newNode); - newNode.usages = new NodeUsagesList(); + newNode.usage0 = null; + newNode.usage1 = null; + newNode.extraUsages = NO_NODES; newNode.predecessor = null; return newNode; } @@ -581,10 +774,10 @@ } if (precision > 0) { - if (this.usages.count() > 0) { + if (!usages().isEmpty()) { formatter.format(" usages={"); int z = 0; - for (Node usage : this.usages) { + for (Node usage : usages()) { if (z != 0) { formatter.format(", "); }