changeset 15969:5d0fbc245e55

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 28 May 2014 21:17:16 +0200
parents 42eaa579e134 (current diff) 9d7b2134c4ce (diff)
children af95e5727fdc
files
diffstat 41 files changed, 545 insertions(+), 491 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Wed May 28 21:17:16 2014 +0200
@@ -86,7 +86,7 @@
             Class<?> currentClazz = clazz;
             do {
                 for (Field field : currentClazz.getDeclaredFields()) {
-                    if (Modifier.isStatic(field.getModifiers())) {
+                    if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) {
                         continue;
                     }
                     Class<?> type = field.getType();
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Wed May 28 21:17:16 2014 +0200
@@ -208,6 +208,9 @@
         if (!(otherStamp instanceof IntegerStamp)) {
             return StampFactory.illegal(Kind.Illegal);
         }
+        if (equals(otherStamp)) {
+            return this;
+        }
         IntegerStamp other = (IntegerStamp) otherStamp;
         return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
     }
--- a/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.debug.test/src/com/oracle/graal/debug/test/DebugHistogramTest.java	Wed May 28 21:17:16 2014 +0200
@@ -111,7 +111,7 @@
         DebugHistogram histogram = Debug.createHistogram("TestHistogram");
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         histogram.add("MyCustomValue");
-        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10).print(histogram);
+        new DebugHistogramAsciiPrinter(new PrintStream(outputStream), Integer.MAX_VALUE, 10, 10, 1).print(histogram);
         String[] lines = outputStream.toString().split("\n");
         Assert.assertEquals(4, lines.length);
         Assert.assertEquals("TestHistogram has 1 unique elements and 1 total elements:", lines[0]);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugHistogram.java	Wed May 28 21:17:16 2014 +0200
@@ -40,16 +40,18 @@
      */
     void add(Object value);
 
+    void add(Object value, long count);
+
     /**
      * A value and a frequency. The ordering imposed by {@link #compareTo(CountedValue)} places
      * values with higher frequencies first.
      */
     public class CountedValue implements Comparable<CountedValue> {
 
-        private int count;
+        private long count;
         private final Object value;
 
-        public CountedValue(int count, Object value) {
+        public CountedValue(long count, Object value) {
             this.count = count;
             this.value = value;
         }
@@ -72,11 +74,11 @@
             count++;
         }
 
-        public void add(int n) {
+        public void add(long n) {
             count += n;
         }
 
-        public int getCount() {
+        public long getCount() {
             return count;
         }
 
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramAsciiPrinter.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramAsciiPrinter.java	Wed May 28 21:17:16 2014 +0200
@@ -37,14 +37,16 @@
     public static final int NumberSize = 10;
     public static final int DefaultNameSize = 50;
     public static final int DefaultBarSize = 100;
+    public static final int DefaultScale = 1;
 
-    private PrintStream os;
-    private int limit;
-    private int nameSize;
-    private int barSize;
+    private final PrintStream os;
+    private final int limit;
+    private final int nameSize;
+    private final int barSize;
+    private final int scale;
 
     public DebugHistogramAsciiPrinter(PrintStream os) {
-        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize);
+        this(os, Integer.MAX_VALUE, DefaultNameSize, DefaultBarSize, DefaultScale);
     }
 
     /**
@@ -52,12 +54,14 @@
      * @param limit limits printing to the {@code limit} most frequent values
      * @param nameSize the width of the value names column
      * @param barSize the width of the value frequency column
+     * @param scale a factor by which every result is divided
      */
-    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize) {
+    public DebugHistogramAsciiPrinter(PrintStream os, int limit, int nameSize, int barSize, int scale) {
         this.os = os;
         this.limit = limit;
         this.nameSize = nameSize;
         this.barSize = barSize;
+        this.scale = scale;
     }
 
     public void print(DebugHistogram histogram) {
@@ -68,21 +72,18 @@
         }
 
         // Sum up the total number of elements.
-        int total = 0;
-        for (CountedValue cv : list) {
-            total += cv.getCount();
-        }
+        long total = list.stream().mapToLong(CountedValue::getCount).sum();
 
         // Print header.
-        os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total);
+        os.printf("%s has %d unique elements and %d total elements:%n", histogram.getName(), list.size(), total / scale);
 
-        int max = list.get(0).getCount();
+        long max = list.get(0).getCount() / scale;
         final int lineSize = nameSize + NumberSize + barSize + 10;
         printLine(os, '-', lineSize);
         String formatString = "| %-" + nameSize + "s | %-" + NumberSize + "d | %-" + barSize + "s |\n";
         for (int i = 0; i < list.size() && i < limit; ++i) {
             CountedValue cv = list.get(i);
-            int value = cv.getCount();
+            long value = cv.getCount() / scale;
             char[] bar = new char[(int) (((double) value / (double) max) * barSize)];
             Arrays.fill(bar, '=');
             String objectString = String.valueOf(cv.getValue());
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugHistogramImpl.java	Wed May 28 21:17:16 2014 +0200
@@ -44,6 +44,15 @@
         }
     }
 
+    public void add(Object value, long count) {
+        CountedValue cv = map.get(value);
+        if (cv == null) {
+            map.put(value, new CountedValue(count, value));
+        } else {
+            cv.add(count);
+        }
+    }
+
     @Override
     public String getName() {
         return name;
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Wed May 28 21:17:16 2014 +0200
@@ -121,17 +121,4 @@
         map.setAndGrow(newNode, 1);
         assertEquals((Integer) 1, map.get(newNode));
     }
-
-    @Test(expected = AssertionError.class)
-    public void testNewSetAndGrowMultiple() {
-        TestNode newNode = graph.add(new TestNode());
-        map.setAndGrow(newNode, 1);
-        assertEquals((Integer) 1, map.get(newNode));
-        /*
-         * Failing here is not required, but if this behavior changes, usages of getAndGrow and
-         * setAndGrow need to be checked for compatibility.
-         */
-        TestNode newNode2 = graph.add(new TestNode());
-        map.get(newNode2);
-    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed May 28 21:17:16 2014 +0200
@@ -740,11 +740,7 @@
     }
 
     public NodeBitMap createNodeBitMap() {
-        return createNodeBitMap(false);
-    }
-
-    public NodeBitMap createNodeBitMap(boolean autoGrow) {
-        return new NodeBitMap(this, autoGrow);
+        return new NodeBitMap(this);
     }
 
     public <T> NodeMap<T> createNodeMap() {
@@ -756,11 +752,11 @@
     }
 
     public NodeWorkList createNodeWorkList() {
-        return new NodeWorkList(this);
+        return new NodeWorkList.SingletonNodeWorkList(this);
     }
 
-    public NodeWorkList createNodeWorkList(boolean fill, int iterationLimitPerNode) {
-        return new NodeWorkList(this, fill, iterationLimitPerNode);
+    public NodeWorkList createIterativeNodeWorkList(boolean fill, int iterationLimitPerNode) {
+        return new NodeWorkList.IterativeNodeWorkList(this, fill, iterationLimitPerNode);
     }
 
     void register(Node node) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Wed May 28 21:17:16 2014 +0200
@@ -27,92 +27,109 @@
 import com.oracle.graal.graph.iterators.*;
 
 public final class NodeBitMap implements NodeIterable<Node> {
+    private static final int SHIFT = 6;
 
-    private final boolean autoGrow;
-    private final BitSet bitMap;
+    private long[] bits;
     private int nodeCount;
     private final NodeIdAccessor nodeIdAccessor;
 
     public NodeBitMap(Graph graph) {
-        this(graph, false);
+        nodeCount = graph.nodeIdCount();
+        bits = new long[sizeForNodeCount(nodeCount)];
+        this.nodeIdAccessor = new NodeIdAccessor(graph);
     }
 
-    public NodeBitMap(Graph graph, boolean autoGrow) {
-        this(graph, autoGrow, graph.nodeIdCount(), new BitSet(graph.nodeIdCount()));
+    private static int sizeForNodeCount(int nodeCount) {
+        return (nodeCount + Long.SIZE - 1) >> SHIFT;
     }
 
-    private NodeBitMap(Graph graph, boolean autoGrow, int nodeCount, BitSet bits) {
-        this.nodeIdAccessor = new NodeIdAccessor(graph);
-        this.autoGrow = autoGrow;
-        this.nodeCount = nodeCount;
-        bitMap = bits;
+    private NodeBitMap(NodeBitMap other) {
+        this.bits = other.bits.clone();
+        this.nodeCount = other.nodeCount;
+        this.nodeIdAccessor = other.nodeIdAccessor;
     }
 
     public Graph graph() {
         return nodeIdAccessor.getGraph();
     }
 
-    public void setUnion(NodeBitMap other) {
-        bitMap.or(other.bitMap);
-    }
-
-    public void negate() {
-        grow();
-        bitMap.flip(0, nodeCount);
-    }
-
-    public boolean isNotNewMarked(Node node) {
-        return !isNew(node) && isMarked(node);
-    }
-
-    public boolean isNotNewNotMarked(Node node) {
-        return !isNew(node) && !isMarked(node);
-    }
-
-    public boolean isMarked(Node node) {
-        return bitMap.get(nodeIdAccessor.getNodeId(node));
-    }
-
     public boolean isNew(Node node) {
         return nodeIdAccessor.getNodeId(node) >= nodeCount;
     }
 
+    public boolean isMarked(Node node) {
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        return (bits[id >> SHIFT] & (1L << id)) != 0;
+    }
+
+    public boolean isMarkedAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        return (bits[id >> SHIFT] & (1L << id)) != 0;
+    }
+
     public void mark(Node node) {
-        if (autoGrow && isNew(node)) {
-            grow();
-        }
-        assert check(node);
-        bitMap.set(nodeIdAccessor.getNodeId(node));
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        bits[id >> SHIFT] |= (1L << id);
+    }
+
+    public void markAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        bits[id >> SHIFT] |= (1L << id);
     }
 
     public void clear(Node node) {
-        if (autoGrow && isNew(node)) {
-            return;
+        assert check(node, false);
+        int id = nodeIdAccessor.getNodeId(node);
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    public void clearAndGrow(Node node) {
+        assert check(node, true);
+        int id = nodeIdAccessor.getNodeId(node);
+        checkGrow(id);
+        bits[id >> SHIFT] &= ~(1L << id);
+    }
+
+    private void checkGrow(int id) {
+        if (id >= nodeCount) {
+            if ((id >> SHIFT) >= bits.length) {
+                grow();
+            } else {
+                nodeCount = id + 1;
+            }
         }
-        assert check(node);
-        bitMap.clear(nodeIdAccessor.getNodeId(node));
     }
 
     public void clearAll() {
-        bitMap.clear();
+        Arrays.fill(bits, 0);
     }
 
     public void intersect(NodeBitMap other) {
         assert graph() == other.graph();
-        bitMap.and(other.bitMap);
-    }
-
-    public void grow(Node node) {
-        nodeCount = Math.max(nodeCount, nodeIdAccessor.getNodeId(node) + 1);
+        int commonLength = Math.min(bits.length, other.bits.length);
+        for (int i = commonLength; i < bits.length; i++) {
+            bits[i] = 0;
+        }
+        for (int i = 0; i < commonLength; i++) {
+            bits[i] &= other.bits[i];
+        }
     }
 
-    public void grow() {
+    private void grow() {
         nodeCount = Math.max(nodeCount, graph().nodeIdCount());
+        int newLength = Math.max((bits.length * 3 / 2) + 1, sizeForNodeCount(nodeCount));
+        bits = Arrays.copyOf(bits, newLength);
     }
 
-    private boolean check(Node node) {
+    private boolean check(Node node, boolean grow) {
         assert node.graph() == graph() : "this node is not part of the graph";
-        assert !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
+        assert grow || !isNew(node) : "node was added to the graph after creating the node bitmap: " + node;
         assert node.isAlive() : "node is deleted!";
         return true;
     }
@@ -175,12 +192,8 @@
         return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator());
     }
 
-    public int cardinality() {
-        return bitMap.cardinality();
-    }
-
     public NodeBitMap copy() {
-        return new NodeBitMap(graph(), autoGrow, nodeCount, (BitSet) bitMap.clone());
+        return new NodeBitMap(this);
     }
 
     @Override
@@ -190,7 +203,11 @@
 
     @Override
     public int count() {
-        return bitMap.cardinality();
+        int count = 0;
+        for (long l : bits) {
+            count += Long.bitCount(l);
+        }
+        return count;
     }
 
     @Override
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Wed May 28 21:17:16 2014 +0200
@@ -28,6 +28,8 @@
 
 public class NodeMap<T> extends NodeIdAccessor {
 
+    private static final int MIN_REALLOC_SIZE = 16;
+
     protected Object[] values;
 
     public NodeMap(Graph graph) {
@@ -54,7 +56,7 @@
 
     private void checkAndGrow(Node node) {
         if (isNew(node)) {
-            this.values = Arrays.copyOf(values, graph.nodeIdCount());
+            this.values = Arrays.copyOf(values, Math.max(MIN_REALLOC_SIZE, graph.nodeIdCount() * 3 / 2));
         }
         assert check(node);
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Wed May 28 21:17:16 2014 +0200
@@ -24,23 +24,11 @@
 
 import java.util.*;
 
-public class NodeWorkList implements Iterable<Node> {
+public abstract class NodeWorkList implements Iterable<Node> {
 
-    private final NodeBitMap visited;
-    private final NodeBitMap inQueue;
-    private final Queue<Node> worklist;
-    private int iterationLimit = Integer.MAX_VALUE;
-    private Node firstNoChange;
-    private Node lastPull;
-    private Node lastChain;
+    protected final Queue<Node> worklist;
 
-    public NodeWorkList(Graph graph) {
-        this(graph, false, -1);
-    }
-
-    public NodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
-        visited = graph.createNodeBitMap();
-        inQueue = graph.createNodeBitMap();
+    private NodeWorkList(Graph graph, boolean fill) {
         if (fill) {
             ArrayDeque<Node> deque = new ArrayDeque<>(graph.getNodeCount());
             for (Node node : graph.getNodes()) {
@@ -50,9 +38,6 @@
         } else {
             worklist = new ArrayDeque<>();
         }
-        if (iterationLimitPerNode > 0) {
-            iterationLimit = iterationLimitPerNode * graph.getNodeCount();
-        }
     }
 
     public void addAll(Iterable<? extends Node> nodes) {
@@ -63,111 +48,13 @@
         }
     }
 
-    public void add(Node node) {
-        if (node != null) {
-            if (visited.isNew(node)) {
-                visited.grow(node);
-                inQueue.grow(node);
-            }
-            if (!visited.isMarked(node)) {
-                addAgain(node);
-            }
-        }
-    }
+    public abstract void add(Node node);
 
-    public void addAgain(Node node) {
-        if (visited.isNew(node)) {
-            visited.grow(node);
-            inQueue.grow(node);
-        }
-        if (node != null && !inQueue.isMarked(node)) {
-            if (lastPull == node) {
-                if (firstNoChange == null) {
-                    firstNoChange = node;
-                    lastChain = node;
-                } else if (node == firstNoChange) {
-                    throw new InfiniteWorkException("ReAdded " + node);
-                } else {
-                    lastChain = node;
-                }
-            } else {
-                firstNoChange = null;
-            }
-            visited.mark(node);
-            inQueue.mark(node);
-            worklist.add(node);
-        }
-    }
-
-    public void clearVisited() {
-        visited.clearAll();
-    }
-
-    public void replaced(Node newNode, Node oldNode) {
-        this.replaced(newNode, oldNode, false);
-    }
+    private abstract class QueueConsumingIterator implements Iterator<Node> {
 
-    public void replaced(Node newNode, Node oldNode, boolean add) {
-        worklist.remove(oldNode);
-        if (newNode == null) {
-            return;
-        }
-        if (add) {
-            this.add(newNode);
-        }
-        for (Node n : newNode.usages()) {
-            addAgain(n);
-        }
-    }
-
-    public boolean isMarked(Node node) {
-        return visited.isMarked(node);
-    }
-
-    public boolean isNew(Node node) {
-        return visited.isNew(node);
-    }
-
-    public boolean isEmpty() {
-        return worklist.isEmpty();
-    }
-
-    public boolean isInQueue(Node node) {
-        return !inQueue.isNew(node) && inQueue.isMarked(node);
-    }
-
-    private class QueueConsumingIterator implements Iterator<Node> {
-
-        private final Queue<Node> queue;
-
-        public QueueConsumingIterator(Queue<Node> queue) {
-            this.queue = queue;
-        }
-
-        @Override
-        public boolean hasNext() {
-            dropDeleted();
-            return iterationLimit > 0 && !queue.isEmpty();
-        }
-
-        @Override
-        public Node next() {
-            if (iterationLimit-- <= 0) {
-                throw new NoSuchElementException();
-            }
-            dropDeleted();
-            Node node = queue.remove();
-            if (lastPull != lastChain) {
-                firstNoChange = null;
-            }
-            lastPull = node;
-            inQueue.clear(node);
-            return node;
-        }
-
-        private void dropDeleted() {
-            while (!queue.isEmpty() && queue.peek().isDeleted()) {
-                queue.remove();
+        protected void dropDeleted() {
+            while (!worklist.isEmpty() && worklist.peek().isDeleted()) {
+                worklist.remove();
             }
         }
 
@@ -177,74 +64,142 @@
         }
     }
 
-    @Override
-    public Iterator<Node> iterator() {
-        return new QueueConsumingIterator(worklist);
-    }
-
-    private static class UnmarkedNodeIterator implements Iterator<Node> {
+    public static final class IterativeNodeWorkList extends NodeWorkList {
 
-        private final NodeBitMap visited;
-        private Iterator<Node> nodes;
-        private Node nextNode;
-
-        public UnmarkedNodeIterator(NodeBitMap visited, Iterator<Node> nodes) {
-            this.visited = visited;
-            this.nodes = nodes;
-            forward();
-        }
+        private static final int EXPLICIT_BITMAP_THRESHOLD = 10;
+        protected NodeBitMap inQueue;
 
-        private void forward() {
-            do {
-                if (!nodes.hasNext()) {
-                    nextNode = null;
-                    return;
-                }
-                nextNode = nodes.next();
-            } while (visited.isMarked(nextNode));
-        }
+        private int iterationLimit = Integer.MAX_VALUE;
+        private Node firstNoChange;
+        private Node lastPull;
+        private Node lastChain;
 
-        @Override
-        public boolean hasNext() {
-            return nextNode != null;
-        }
-
-        @Override
-        public Node next() {
-            try {
-                return nextNode;
-            } finally {
-                forward();
+        public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) {
+            super(graph, fill);
+            if (iterationLimitPerNode > 0) {
+                iterationLimit = iterationLimitPerNode * graph.getNodeCount();
             }
         }
 
         @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return iterationLimit > 0 && !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    if (iterationLimit-- <= 0) {
+                        throw new NoSuchElementException();
+                    }
+                    dropDeleted();
+                    Node node = worklist.remove();
+                    assert updateInfiniteWork(node);
+                    if (inQueue != null) {
+                        inQueue.clearAndGrow(node);
+                    }
+                    return node;
+                }
+
+                private boolean updateInfiniteWork(Node node) {
+                    if (lastPull != lastChain) {
+                        firstNoChange = null;
+                    }
+                    lastPull = node;
+                    return true;
+                }
+            };
         }
 
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (inQueue != null) {
+                    if (inQueue.isMarkedAndGrow(node)) {
+                        return;
+                    }
+                } else {
+                    if (worklist.size() > EXPLICIT_BITMAP_THRESHOLD) {
+                        inflateToBitMap(node.graph());
+                    } else {
+                        for (Node queuedNode : worklist) {
+                            if (queuedNode == node) {
+                                return;
+                            }
+                        }
+                    }
+                }
+                assert checkInfiniteWork(node) : "Readded " + node;
+                if (inQueue != null) {
+                    inQueue.markAndGrow(node);
+                }
+                worklist.add(node);
+            }
+        }
+
+        private boolean checkInfiniteWork(Node node) {
+            if (lastPull == node) {
+                if (firstNoChange == null) {
+                    firstNoChange = node;
+                    lastChain = node;
+                } else if (node == firstNoChange) {
+                    return false;
+                } else {
+                    lastChain = node;
+                }
+            } else {
+                firstNoChange = null;
+            }
+            return true;
+        }
+
+        private void inflateToBitMap(Graph graph) {
+            assert inQueue == null;
+            inQueue = graph.createNodeBitMap();
+            for (Node queuedNode : worklist) {
+                if (queuedNode.isAlive()) {
+                    inQueue.mark(queuedNode);
+                }
+            }
+        }
     }
 
-    public Iterable<Node> unmarkedNodes() {
-        return new Iterable<Node>() {
+    public static final class SingletonNodeWorkList extends NodeWorkList {
+        protected final NodeBitMap visited;
 
-            @Override
-            public Iterator<Node> iterator() {
-                return new UnmarkedNodeIterator(visited, visited.graph().getNodes().iterator());
-            }
-        };
-    }
-
-    public static class InfiniteWorkException extends RuntimeException {
-
-        private static final long serialVersionUID = -5319329402219396658L;
-
-        public InfiniteWorkException() {
-            super();
+        public SingletonNodeWorkList(Graph graph) {
+            super(graph, false);
+            visited = graph.createNodeBitMap();
         }
 
-        public InfiniteWorkException(String message) {
-            super(message);
+        @Override
+        public void add(Node node) {
+            if (node != null) {
+                if (!visited.isMarkedAndGrow(node)) {
+                    visited.mark(node);
+                    worklist.add(node);
+                }
+            }
+        }
+
+        @Override
+        public Iterator<Node> iterator() {
+            return new QueueConsumingIterator() {
+                @Override
+                public boolean hasNext() {
+                    dropDeleted();
+                    return !worklist.isEmpty();
+                }
+
+                @Override
+                public Node next() {
+                    dropDeleted();
+                    return worklist.remove();
+                }
+            };
         }
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Wed May 28 21:17:16 2014 +0200
@@ -50,7 +50,7 @@
             return true;
         }
         if (visited == null) {
-            visited = n.graph().createNodeBitMap(true);
+            visited = n.graph().createNodeBitMap();
         }
         boolean accept = !visited.isMarked(n);
         visited.mark(n);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Wed May 28 21:17:16 2014 +0200
@@ -23,15 +23,18 @@
 package com.oracle.graal.hotspot.test;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+
 import java.lang.ref.*;
 import java.lang.reflect.*;
 
 import com.oracle.graal.phases.common.inlining.policy.InlineEverythingPolicy;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -160,7 +163,7 @@
     }
 
     public static Object test5Snippet() throws Exception {
-        return UnsafeLoadNode.load(wr, useCompressedOops() ? 12 : 16, Kind.Object, LocationIdentity.ANY_LOCATION);
+        return UnsafeAccess.unsafe.getObject(wr, useCompressedOops() ? 12L : 16L);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed May 28 21:17:16 2014 +0200
@@ -216,23 +216,29 @@
             // Canonicalization may attempt to process an unsafe read before
             // processing a guard (e.g. a null check or a type check) for this read
             // so we need to check the object being read
-            if (object != null && isInObject(object)) {
+            if (object != null) {
                 if (isFinal()) {
-                    Constant value = readValue(receiver);
-                    if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
-                        return value;
+                    if (isInObject(object)) {
+                        Constant value = readValue(receiver);
+                        if (assumeNonStaticFinalFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
+                            return value;
+                        }
                     }
                 } else if (isStable()) {
-                    Constant value = readValue(receiver);
-                    if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
-                        return value;
+                    if (isInObject(object)) {
+                        Constant value = readValue(receiver);
+                        if (assumeDefaultStableFieldsAsFinal(object.getClass()) || !value.isDefaultForKind()) {
+                            return value;
+                        }
                     }
                 } else {
                     Class<?> clazz = object.getClass();
                     if (StableOptionValue.class.isAssignableFrom(clazz)) {
-                        assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
-                        StableOptionValue<?> option = (StableOptionValue<?>) object;
-                        return HotSpotObjectConstant.forObject(option.getValue());
+                        if (isInObject(object)) {
+                            assert getName().equals("value") : "Unexpected field in " + StableOptionValue.class.getName() + " hierarchy:" + this;
+                            StableOptionValue<?> option = (StableOptionValue<?>) object;
+                            return HotSpotObjectConstant.forObject(option.getValue());
+                        }
                     }
                 }
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Wed May 28 21:17:16 2014 +0200
@@ -66,7 +66,7 @@
     }
 
     public boolean contains(Node n) {
-        return nodes().contains(n);
+        return nodes().isMarkedAndGrow(n);
     }
 
     @SuppressWarnings("unchecked")
@@ -96,7 +96,7 @@
         return original;
     }
 
-    public abstract NodeIterable<Node> nodes();
+    public abstract NodeBitMap nodes();
 
     public StructuredGraph graph() {
         LoopEx l;
@@ -155,7 +155,7 @@
     }
 
     protected static NodeBitMap computeNodes(Graph graph, Iterable<BeginNode> blocks, Iterable<LoopExitNode> earlyExits) {
-        final NodeBitMap nodes = graph.createNodeBitMap(true);
+        final NodeBitMap nodes = graph.createNodeBitMap();
         for (BeginNode b : blocks) {
             if (b.isDeleted()) {
                 continue;
@@ -187,7 +187,7 @@
             }
         }
 
-        final NodeBitMap notloopNodes = graph.createNodeBitMap(true);
+        final NodeBitMap notloopNodes = graph.createNodeBitMap();
         for (BeginNode b : blocks) {
             if (b.isDeleted()) {
                 continue;
@@ -336,8 +336,8 @@
                  *
                  * We now update the original fragment's nodes accordingly:
                  */
-                state.applyToVirtual(node -> original.nodes.clear(node));
-                exitState.applyToVirtual(node -> original.nodes.mark(node));
+                state.applyToVirtual(node -> original.nodes.clearAndGrow(node));
+                exitState.applyToVirtual(node -> original.nodes.markAndGrow(node));
             }
             FrameState finalExitState = exitState;
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Wed May 28 21:17:16 2014 +0200
@@ -102,7 +102,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
+    public NodeBitMap nodes() {
         if (nodes == null) {
             LoopFragmentWhole whole = loop().whole();
             whole.nodes(); // init nodes bitmap in whole
@@ -203,10 +203,10 @@
         for (LoopExitNode exit : exits()) {
             FrameState exitState = exit.stateAfter();
             if (exitState != null) {
-                exitState.applyToVirtual(v -> usagesToPatch.mark(v));
+                exitState.applyToVirtual(v -> usagesToPatch.markAndGrow(v));
             }
             for (ProxyNode proxy : exit.proxies()) {
-                usagesToPatch.mark(proxy);
+                usagesToPatch.markAndGrow(proxy);
             }
         }
 
@@ -232,7 +232,7 @@
             newPhis.add(newPhi);
             for (Node usage : phi.usages().snapshot()) {
                 // patch only usages that should use the new phi ie usages that were peeled
-                if (usagesToPatch.isMarked(usage)) {
+                if (usagesToPatch.isMarkedAndGrow(usage)) {
                     usage.replaceFirstInput(phi, newPhi);
                 }
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideBefore.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideBefore.java	Wed May 28 21:17:16 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.loop;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 
 public class LoopFragmentInsideBefore extends LoopFragmentInside {
@@ -51,8 +50,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
-        // TODO Auto-generated method stub
+    public NodeBitMap nodes() {
         return null;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideFrom.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInsideFrom.java	Wed May 28 21:17:16 2014 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.loop;
 
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 
 public class LoopFragmentInsideFrom extends LoopFragmentInside {
@@ -51,8 +50,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
-        // TODO Auto-generated method stub
+    public NodeBitMap nodes() {
         return null;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java	Wed May 28 21:17:16 2014 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 
@@ -55,7 +54,7 @@
     }
 
     @Override
-    public NodeIterable<Node> nodes() {
+    public NodeBitMap nodes() {
         if (nodes == null) {
             Loop<Block> lirLoop = loop().lirLoop();
             nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.getBlocks()), LoopFragment.toHirExits(lirLoop.getExits()));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Wed May 28 21:17:16 2014 +0200
@@ -72,7 +72,7 @@
         for (Node successor : controlSplit.successors()) {
             BeginNode branch = (BeginNode) successor;
             // this may count twice because of fall-through in switches
-            inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality();
+            inBranchTotal += loop.nodesInLoopFrom(branch, postDom).count();
             double probability = controlSplit.probability(branch);
             if (probability > maxProbability) {
                 maxProbability = probability;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed May 28 21:17:16 2014 +0200
@@ -149,65 +149,27 @@
             LogicNegationNode negation = (LogicNegationNode) condition();
             IfNode newIfNode = graph().add(new IfNode(negation.getInput(), falseSucc, trueSucc, 1 - trueSuccessorProbability));
             predecessor().replaceFirstSuccessor(this, newIfNode);
-            this.safeDelete();
+            GraphUtil.killWithUnusedFloatingInputs(this);
             return;
         }
-        if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
-            // push similar nodes upwards through the if, thereby deduplicating them
-            do {
-                BeginNode trueSucc = trueSuccessor();
-                BeginNode falseSucc = falseSuccessor();
-                if (trueSucc.getClass() == BeginNode.class && falseSucc.getClass() == BeginNode.class && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
-                    FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
-                    FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
-                    NodeClass nodeClass = trueNext.getNodeClass();
-                    if (trueNext.getClass() == falseNext.getClass()) {
-                        if (nodeClass.inputsEqual(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
-                            falseNext.replaceAtUsages(trueNext);
-                            graph().removeFixed(falseNext);
-                            FixedNode next = trueNext.next();
-                            trueNext.setNext(null);
-                            trueNext.replaceAtPredecessor(next);
-                            graph().addBeforeFixed(this, trueNext);
-                            for (Node usage : trueNext.usages().snapshot()) {
-                                if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
-                                    Node newNode = graph().findDuplicate(usage);
-                                    if (newNode != null) {
-                                        usage.replaceAtUsages(newNode);
-                                        usage.safeDelete();
-                                    }
-                                }
-                                if (usage.isAlive()) {
-                                    tool.addToWorkList(usage);
-                                }
-                            }
-                            continue;
-                        }
-                    }
-                }
-            } while (false);
-        }
-
-        if (checkForUnsignedCompare(tool)) {
-            return;
-        }
-
         if (condition() instanceof LogicConstantNode) {
             LogicConstantNode c = (LogicConstantNode) condition();
             if (c.getValue()) {
                 tool.deleteBranch(falseSuccessor());
                 tool.addToWorkList(trueSuccessor());
                 graph().removeSplit(this, trueSuccessor());
-                return;
             } else {
                 tool.deleteBranch(trueSuccessor());
                 tool.addToWorkList(falseSuccessor());
                 graph().removeSplit(this, falseSuccessor());
-                return;
             }
-        } else if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+            return;
+        }
+        if (trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
 
-            if (removeOrMaterializeIf(tool)) {
+            pushNodesThroughIf(tool);
+
+            if (checkForUnsignedCompare(tool) || removeOrMaterializeIf(tool)) {
                 return;
             }
         }
@@ -248,6 +210,43 @@
         }
     }
 
+    private void pushNodesThroughIf(SimplifierTool tool) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
+        // push similar nodes upwards through the if, thereby deduplicating them
+        do {
+            BeginNode trueSucc = trueSuccessor();
+            BeginNode falseSucc = falseSuccessor();
+            if (trueSucc.getClass() == BeginNode.class && falseSucc.getClass() == BeginNode.class && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
+                FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
+                FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
+                NodeClass nodeClass = trueNext.getNodeClass();
+                if (trueNext.getClass() == falseNext.getClass()) {
+                    if (nodeClass.inputsEqual(trueNext, falseNext) && nodeClass.valueEqual(trueNext, falseNext)) {
+                        falseNext.replaceAtUsages(trueNext);
+                        graph().removeFixed(falseNext);
+                        FixedNode next = trueNext.next();
+                        trueNext.setNext(null);
+                        trueNext.replaceAtPredecessor(next);
+                        graph().addBeforeFixed(this, trueNext);
+                        for (Node usage : trueNext.usages().snapshot()) {
+                            if (usage.getNodeClass().valueNumberable() && !usage.getNodeClass().isLeafNode()) {
+                                Node newNode = graph().findDuplicate(usage);
+                                if (newNode != null) {
+                                    usage.replaceAtUsages(newNode);
+                                    usage.safeDelete();
+                                }
+                            }
+                            if (usage.isAlive()) {
+                                tool.addToWorkList(usage);
+                            }
+                        }
+                        continue;
+                    }
+                }
+            }
+        } while (false);
+    }
+
     /**
      * Recognize a couple patterns that can be merged into an unsigned compare.
      *
@@ -255,7 +254,8 @@
      * @return true if a replacement was done.
      */
     private boolean checkForUnsignedCompare(SimplifierTool tool) {
-        if (condition() instanceof IntegerLessThanNode && trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty()) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
+        if (condition() instanceof IntegerLessThanNode) {
             IntegerLessThanNode lessThan = (IntegerLessThanNode) condition();
             Constant y = lessThan.y().stamp().asConstant();
             if (y != null && y.asLong() == 0 && falseSuccessor().next() instanceof IfNode) {
@@ -478,6 +478,7 @@
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeOrMaterializeIf(SimplifierTool tool) {
+        assert trueSuccessor().usages().isEmpty() && falseSuccessor().usages().isEmpty();
         if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
@@ -621,6 +622,11 @@
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeIntermediateMaterialization(SimplifierTool tool) {
+        if (!(predecessor() instanceof MergeNode) || predecessor() instanceof LoopBeginNode) {
+            return false;
+        }
+        MergeNode merge = (MergeNode) predecessor();
+
         if (!(condition() instanceof CompareNode)) {
             return false;
         }
@@ -630,16 +636,6 @@
             return false;
         }
 
-        if (!(predecessor() instanceof MergeNode)) {
-            return false;
-        }
-
-        if (predecessor() instanceof LoopBeginNode) {
-            return false;
-        }
-
-        MergeNode merge = (MergeNode) predecessor();
-
         // Only consider merges with a single usage that is both a phi and an operand of the
         // comparison
         NodeIterable<Node> mergeUsages = merge.usages();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed May 28 21:17:16 2014 +0200
@@ -26,6 +26,8 @@
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -62,6 +64,17 @@
      */
     public abstract boolean unorderedIsTrue();
 
+    protected static final DebugHistogram histogram = Debug.createHistogram("histo");
+
+    static {
+        Runtime.getRuntime().addShutdownHook(new Thread() {
+            @Override
+            public void run() {
+                new DebugHistogramAsciiPrinter(System.out).print(histogram);
+            }
+        });
+    }
+
     private LogicNode optimizeConditional(Constant constant, ConditionalNode conditionalNode, ConstantReflectionProvider constantReflection, Condition cond) {
         Constant trueConstant = conditionalNode.trueValue().asConstant();
         Constant falseConstant = conditionalNode.falseValue().asConstant();
@@ -105,38 +118,42 @@
             return result;
         }
         if (x().isConstant()) {
-            if (y() instanceof ConditionalNode) {
-                return optimizeConditional(x().asConstant(), (ConditionalNode) y(), tool.getConstantReflection(), condition().mirror());
-            } else if (y() instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(x().asConstant(), (NormalizeCompareNode) y(), true);
+            if ((result = canonicalizeSymmetricConstant(tool, x().asConstant(), y(), true)) != this) {
+                return result;
             }
         } else if (y().isConstant()) {
-            if (x() instanceof ConditionalNode) {
-                return optimizeConditional(y().asConstant(), (ConditionalNode) x(), tool.getConstantReflection(), condition());
-            } else if (x() instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false);
+            if ((result = canonicalizeSymmetricConstant(tool, y().asConstant(), x(), false)) != this) {
+                return result;
             }
-        }
-        if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
+        } else if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
             ConvertNode convertX = (ConvertNode) x();
             ConvertNode convertY = (ConvertNode) y();
             if (convertX.preservesOrder(condition()) && convertY.preservesOrder(condition()) && convertX.getInput().stamp().isCompatible(convertY.getInput().stamp())) {
-                setX(convertX.getInput());
-                setY(convertY.getInput());
+                return graph().unique(duplicateModified(convertX.getInput(), convertY.getInput()));
             }
-        } else if (x() instanceof ConvertNode && y().isConstant()) {
-            ConvertNode convertX = (ConvertNode) x();
-            ConstantNode newY = canonicalConvertConstant(tool, convertX, y().asConstant());
-            if (newY != null) {
-                setX(convertX.getInput());
-                setY(newY);
+
+        }
+        return this;
+    }
+
+    protected abstract CompareNode duplicateModified(ValueNode newX, ValueNode newY);
+
+    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (nonConstant instanceof BinaryNode) {
+            if (nonConstant instanceof ConditionalNode) {
+                return optimizeConditional(constant, (ConditionalNode) nonConstant, tool.getConstantReflection(), mirrored ? condition().mirror() : condition());
+            } else if (nonConstant instanceof NormalizeCompareNode) {
+                return optimizeNormalizeCmp(constant, (NormalizeCompareNode) nonConstant, mirrored);
             }
-        } else if (y() instanceof ConvertNode && x().isConstant()) {
-            ConvertNode convertY = (ConvertNode) y();
-            ConstantNode newX = canonicalConvertConstant(tool, convertY, x().asConstant());
-            if (newX != null) {
-                setX(newX);
-                setY(convertY.getInput());
+        } else if (nonConstant instanceof ConvertNode) {
+            ConvertNode convert = (ConvertNode) nonConstant;
+            ConstantNode newConstant = canonicalConvertConstant(tool, convert, constant);
+            if (newConstant != null) {
+                if (mirrored) {
+                    return graph().unique(duplicateModified(newConstant, convert.getInput()));
+                } else {
+                    return graph().unique(duplicateModified(convert.getInput(), newConstant));
+                }
             }
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed May 28 21:17:16 2014 +0200
@@ -68,4 +68,9 @@
         }
         return super.evaluate(constantReflection, forX, forY);
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new FloatEqualsNode(newX, newY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed May 28 21:17:16 2014 +0200
@@ -67,4 +67,9 @@
         }
         return super.evaluate(constantReflection, forX, forY);
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new FloatLessThanNode(newX, newY, unorderedIsTrue);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Wed May 28 21:17:16 2014 +0200
@@ -86,4 +86,9 @@
         }
         return this;
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerBelowThanNode(newX, newY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed May 28 21:17:16 2014 +0200
@@ -23,7 +23,7 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -72,6 +72,11 @@
     }
 
     @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerEqualsNode(newX, newY);
+    }
+
+    @Override
     public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
         if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
             return TriState.TRUE;
@@ -82,62 +87,51 @@
     }
 
     @Override
-    public Node canonical(CanonicalizerTool tool) {
-        Node result = super.canonical(tool);
-        if (result != this) {
-            return result;
-        }
-
-        result = canonicalizeSymmetric(x(), y());
-        if (result != this) {
-            return result;
-        }
-
-        return canonicalizeSymmetric(y(), x());
-    }
-
-    private ValueNode canonicalizeSymmetric(ValueNode x, ValueNode y) {
-        if (y.isConstant() && y.asConstant().asLong() == 0) {
-            if (x instanceof AndNode) {
-                return graph().unique(new IntegerTestNode(((AndNode) x).x(), ((AndNode) x).y()));
-            } else if (x instanceof LeftShiftNode) {
-                LeftShiftNode shift = (LeftShiftNode) x;
-                if (shift.y().isConstant()) {
-                    int mask = shift.getShiftAmountMask();
-                    int amount = shift.y().asConstant().asInt() & mask;
-                    if (shift.x().getKind() == Kind.Int) {
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 >>> amount, graph())));
-                    } else {
-                        assert shift.x().getKind() == Kind.Long;
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+    protected Node canonicalizeSymmetricConstant(CanonicalizerTool tool, Constant constant, ValueNode nonConstant, boolean mirrored) {
+        if (constant.asLong() == 0) {
+            if (nonConstant instanceof AndNode) {
+                AndNode andNode = (AndNode) nonConstant;
+                return graph().unique(new IntegerTestNode(andNode.x(), andNode.y()));
+            } else if (nonConstant instanceof ShiftNode) {
+                if (nonConstant instanceof LeftShiftNode) {
+                    LeftShiftNode shift = (LeftShiftNode) nonConstant;
+                    if (shift.y().isConstant()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.y().asConstant().asInt() & mask;
+                        if (shift.x().getKind() == Kind.Int) {
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 >>> amount, graph())));
+                        } else {
+                            assert shift.x().getKind() == Kind.Long;
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L >>> amount, graph())));
+                        }
                     }
-                }
-            } else if (x instanceof RightShiftNode) {
-                RightShiftNode shift = (RightShiftNode) x;
-                if (shift.y().isConstant() && ((IntegerStamp) shift.x().stamp()).isPositive()) {
-                    int mask = shift.getShiftAmountMask();
-                    int amount = shift.y().asConstant().asInt() & mask;
-                    if (shift.x().getKind() == Kind.Int) {
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
-                    } else {
-                        assert shift.x().getKind() == Kind.Long;
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                } else if (nonConstant instanceof RightShiftNode) {
+                    RightShiftNode shift = (RightShiftNode) nonConstant;
+                    if (shift.y().isConstant() && ((IntegerStamp) shift.x().stamp()).isPositive()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.y().asConstant().asInt() & mask;
+                        if (shift.x().getKind() == Kind.Int) {
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                        } else {
+                            assert shift.x().getKind() == Kind.Long;
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                        }
                     }
-                }
-            } else if (x instanceof UnsignedRightShiftNode) {
-                UnsignedRightShiftNode shift = (UnsignedRightShiftNode) x;
-                if (shift.y().isConstant()) {
-                    int mask = shift.getShiftAmountMask();
-                    int amount = shift.y().asConstant().asInt() & mask;
-                    if (shift.x().getKind() == Kind.Int) {
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
-                    } else {
-                        assert shift.x().getKind() == Kind.Long;
-                        return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                } else if (nonConstant instanceof UnsignedRightShiftNode) {
+                    UnsignedRightShiftNode shift = (UnsignedRightShiftNode) nonConstant;
+                    if (shift.y().isConstant()) {
+                        int mask = shift.getShiftAmountMask();
+                        int amount = shift.y().asConstant().asInt() & mask;
+                        if (shift.x().getKind() == Kind.Int) {
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forInt(-1 << amount, graph())));
+                        } else {
+                            assert shift.x().getKind() == Kind.Long;
+                            return graph().unique(new IntegerTestNode(shift.x(), ConstantNode.forLong(-1L << amount, graph())));
+                        }
                     }
                 }
             }
         }
-        return this;
+        return super.canonicalizeSymmetricConstant(tool, constant, nonConstant, mirrored);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed May 28 21:17:16 2014 +0200
@@ -101,4 +101,9 @@
         }
         return this;
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new IntegerLessThanNode(newX, newY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed May 28 21:17:16 2014 +0200
@@ -119,7 +119,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 * 
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
@@ -138,4 +138,9 @@
             }
         }
     }
+
+    @Override
+    protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) {
+        return new ObjectEqualsNode(newX, newY);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Wed May 28 21:17:16 2014 +0200
@@ -42,6 +42,8 @@
     private ResolvedJavaMethod targetMethod;
     private InvokeKind invokeKind;
 
+    private transient Stamp lastCanonicalizedReceiverStamp;
+
     /**
      * @param arguments
      */
@@ -138,12 +140,17 @@
             }
 
             // check if the type of the receiver can narrow the result
-            ValueNode receiver = receiver();
-            ResolvedJavaType type = StampTool.typeOrNull(receiver);
+            Stamp receiverStamp = receiver().stamp();
+            if (receiverStamp.equals(lastCanonicalizedReceiverStamp)) {
+                return this;
+            }
+            lastCanonicalizedReceiverStamp = receiverStamp;
+
+            ResolvedJavaType type = StampTool.typeOrNull(receiverStamp);
             if (type != null && (invoke().stateAfter() != null || invoke().stateDuring() != null)) {
                 // either the holder class is exact, or the receiver object has an exact type
                 ResolvedJavaMethod resolvedMethod = type.resolveMethod(targetMethod, invoke().getContextType());
-                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver))) {
+                if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiverStamp))) {
                     invokeKind = InvokeKind.Special;
                     targetMethod = resolvedMethod;
                     return this;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed May 28 21:17:16 2014 +0200
@@ -137,9 +137,9 @@
         protected void run(StructuredGraph graph) {
             boolean wholeGraph = newNodesMark == null || newNodesMark.isStart();
             if (initWorkingSet == null) {
-                workList = graph.createNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE);
+                workList = graph.createIterativeNodeWorkList(wholeGraph, MAX_ITERATION_PER_NODE);
             } else {
-                workList = graph.createNodeWorkList(false, MAX_ITERATION_PER_NODE);
+                workList = graph.createIterativeNodeWorkList(false, MAX_ITERATION_PER_NODE);
                 workList.addAll(initWorkingSet);
             }
             if (!wholeGraph) {
@@ -154,7 +154,7 @@
 
                 @Override
                 public void nodeChanged(Node node) {
-                    workList.addAgain(node);
+                    workList.add(node);
                 }
             };
             graph.trackInputChange(nodeChangedListener);
@@ -336,7 +336,7 @@
                 if (node.inferStamp()) {
                     METRIC_STAMP_CHANGED.increment();
                     for (Node usage : node.usages()) {
-                        workList.addAgain(usage);
+                        workList.add(usage);
                     }
                     return true;
                 }
@@ -373,7 +373,7 @@
 
             @Override
             public void addToWorkList(Node node) {
-                workList.addAgain(node);
+                workList.add(node);
             }
 
             @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Wed May 28 21:17:16 2014 +0200
@@ -145,8 +145,7 @@
             } else {
                 GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, Constant.NULL_OBJECT));
                 if (OptEliminateGuards.getValue()) {
-                    activeGuards.grow();
-                    activeGuards.mark(newGuard);
+                    activeGuards.markAndGrow(newGuard);
                 }
                 return newGuard;
             }
@@ -283,7 +282,7 @@
 
             if (parentAnchor == null && OptEliminateGuards.getValue()) {
                 for (GuardNode guard : anchor.asNode().usages().filter(GuardNode.class)) {
-                    if (activeGuards.contains(guard)) {
+                    if (activeGuards.isMarkedAndGrow(guard)) {
                         activeGuards.clear(guard);
                     }
                 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -22,13 +22,13 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.FixedWithNextNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
-
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
@@ -51,18 +51,33 @@
         return invoke;
     }
 
-    protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+    protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+        Collection<Node> parameterUsages = new ArrayList<>();
         if (inlineable instanceof InlineableGraph) {
             StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
-            InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
+            Map<Node, Node> duplicateMap = InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
+            getInlinedParameterUsages(parameterUsages, calleeGraph, duplicateMap);
         } else {
             assert inlineable instanceof InlineableMacroNode;
 
             Class<? extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
-            InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
+            FixedWithNextNode macroNode = InliningUtil.inlineMacroNode(invoke, concrete, macroNodeClass);
+            parameterUsages.add(macroNode);
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
         assumptions.recordMethodContents(concrete);
+        return parameterUsages;
+    }
+
+    public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
+        for (ParameterNode parameter : calleeGraph.getNodes(ParameterNode.class)) {
+            for (Node usage : parameter.usages()) {
+                Node node = duplicateMap.get(usage);
+                if (node != null && node.isAlive()) {
+                    parameterUsages.add(node);
+                }
+            }
+        }
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.MetaAccessProvider;
 import com.oracle.graal.api.meta.MetaUtil;
@@ -30,6 +32,7 @@
 import com.oracle.graal.phases.common.inlining.InliningUtil;
 import com.oracle.graal.phases.util.Providers;
 import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 
 /**
@@ -46,9 +49,9 @@
     }
 
     @Override
-    public void inline(Providers providers, Assumptions assumptions) {
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
         assumptions.record(takenAssumption);
-        super.inline(providers, assumptions);
+        return super.inline(providers, assumptions);
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -22,10 +22,13 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.MetaAccessProvider;
 import com.oracle.graal.api.meta.MetaUtil;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
 import com.oracle.graal.phases.util.Providers;
@@ -51,8 +54,8 @@
     }
 
     @Override
-    public void inline(Providers providers, Assumptions assumptions) {
-        inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+        return inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.MetaAccessProvider;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.Invoke;
 import com.oracle.graal.nodes.StructuredGraph;
 import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
@@ -68,8 +71,10 @@
      * Performs the inlining described by this object and returns the node that represents the
      * return value of the inlined method (or null for void methods and methods that have no
      * non-exceptional exit).
+     * 
+     * @return a collection of nodes that need to be canonicalized after the inlining
      */
-    void inline(Providers providers, Assumptions assumptions);
+    Collection<Node> inline(Providers providers, Assumptions assumptions);
 
     /**
      * Try to make the call static bindable to avoid interface and virtual method calls.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -132,11 +132,11 @@
     }
 
     @Override
-    public void inline(Providers providers, Assumptions assumptions) {
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
         if (hasSingleMethod()) {
-            inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
+            return inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
         } else {
-            inlineMultipleMethods(graph(), providers, assumptions);
+            return inlineMultipleMethods(graph(), providers, assumptions);
         }
     }
 
@@ -157,7 +157,7 @@
         return notRecordedTypeProbability > 0;
     }
 
-    private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
+    private Collection<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
         int numberOfMethods = concretes.size();
         FixedNode continuation = invoke.next();
 
@@ -222,6 +222,8 @@
 
         ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
 
+        Collection<Node> parameterUsages = new ArrayList<>();
+
         // do the actual inlining for every invoke
         for (int i = 0; i < numberOfMethods; i++) {
             BeginNode node = successors[i];
@@ -239,7 +241,7 @@
             GuardedValueNode anchoredReceiver = InliningUtil.createAnchoredReceiver(graph, node, commonType, receiver, exact);
             invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
 
-            inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
+            parameterUsages.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
 
             replacementNodes.add(anchoredReceiver);
         }
@@ -272,6 +274,7 @@
                 TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
             }
         }
+        return parameterUsages;
     }
 
     private int getTypeCount(int concreteMethodIndex) {
@@ -307,7 +310,7 @@
         return result;
     }
 
-    private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
+    private Collection<Node> inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
         assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
         BeginNode calleeEntryNode = graph.add(new BeginNode());
@@ -318,7 +321,7 @@
 
         calleeEntryNode.setNext(invoke.asNode());
 
-        inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
+        return inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
     }
 
     private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Wed May 28 21:17:16 2014 +0200
@@ -22,9 +22,12 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.Assumptions;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.Condition;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.CompareNode;
 import com.oracle.graal.nodes.extended.LoadHubNode;
@@ -87,9 +90,9 @@
     }
 
     @Override
-    public void inline(Providers providers, Assumptions assumptions) {
+    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
         createGuard(graph(), providers.getMetaAccess());
-        inline(invoke, concrete, inlineableElement, assumptions, false);
+        return inline(invoke, concrete, inlineableElement, assumptions, false);
     }
 
     @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Wed May 28 21:17:16 2014 +0200
@@ -22,11 +22,13 @@
  */
 package com.oracle.graal.phases.common.inlining.info.elem;
 
+import java.util.*;
+
 import com.oracle.graal.api.meta.Constant;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
 import com.oracle.graal.compiler.common.type.Stamp;
 import com.oracle.graal.debug.Debug;
-import com.oracle.graal.graph.NodeInputList;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.DeadCodeEliminationPhase;
@@ -71,31 +73,34 @@
 
             boolean callerHasMoreInformationAboutArguments = false;
             NodeInputList<ValueNode> args = invoke.callTarget().arguments();
+            ArrayList<Node> parameterUsages = new ArrayList<>();
             for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
                 ValueNode arg = args.get(param.index());
                 if (arg.isConstant()) {
                     Constant constant = arg.asConstant();
                     newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
                     callerHasMoreInformationAboutArguments = true;
+                    param.usages().snapshotTo(parameterUsages);
                 } else {
                     Stamp joinedStamp = param.stamp().join(arg.stamp());
                     if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
                         param.setStamp(joinedStamp);
                         callerHasMoreInformationAboutArguments = true;
+                        param.usages().snapshotTo(parameterUsages);
                     }
                 }
             }
 
-            if (!callerHasMoreInformationAboutArguments) {
+            if (callerHasMoreInformationAboutArguments) {
+                if (OptCanonicalizer.getValue()) {
+                    canonicalizer.applyIncremental(newGraph, context, parameterUsages);
+                }
+            } else {
                 // TODO (chaeubl): if args are not more concrete, inlining should be avoided
                 // in most cases or we could at least use the previous graph size + invoke
                 // probability to check the inlining
             }
 
-            if (OptCanonicalizer.getValue()) {
-                canonicalizer.apply(newGraph, context);
-            }
-
             return newGraph;
         } catch (Throwable e) {
             throw Debug.handle(e);
@@ -117,12 +122,10 @@
      * profiling info is mature, the resulting graph is cached.
      */
     private static StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context, CanonicalizerPhase canonicalizer) {
-        final boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
-
         if (context.getGraphBuilderSuite() != null) {
             context.getGraphBuilderSuite().apply(newGraph, context);
         }
-        assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
+        assert newGraph.start().next() != null : "graph needs to be populated the GraphBuilderSuite";
 
         new DeadCodeEliminationPhase().apply(newGraph);
 
@@ -130,7 +133,7 @@
             canonicalizer.apply(newGraph, context);
         }
 
-        if (hasMatureProfilingInfo && context.getGraphCache() != null) {
+        if (context.getGraphCache() != null) {
             context.getGraphCache().put(newGraph.method(), newGraph.copy());
         }
         return newGraph;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed May 28 21:17:16 2014 +0200
@@ -47,9 +47,7 @@
 import com.oracle.graal.phases.tiers.HighTierContext;
 import com.oracle.graal.phases.util.Providers;
 
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
 import java.util.function.ToDoubleFunction;
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
@@ -340,19 +338,21 @@
 
     private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
         StructuredGraph callerGraph = callerCallsiteHolder.graph();
-        Graph.Mark markBeforeInlining = callerGraph.getMark();
         InlineInfo calleeInfo = calleeInvocation.callee();
         try {
             try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
-                List<Node> invokeUsages = calleeInfo.invoke().asNode().usages().snapshot();
-                calleeInfo.inline(new Providers(context), callerAssumptions);
+                Set<Node> canonicalizedNodes = new HashSet<>();
+                calleeInfo.invoke().asNode().usages().snapshotTo(canonicalizedNodes);
+                Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context), callerAssumptions);
+                canonicalizedNodes.addAll(parameterUsages);
                 callerAssumptions.record(calleeInvocation.assumptions());
                 metricInliningRuns.increment();
                 Debug.dump(callerGraph, "after %s", calleeInfo);
 
                 if (OptCanonicalizer.getValue()) {
                     Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
-                    canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
+
+                    canonicalizer.applyIncremental(callerGraph, context, canonicalizedNodes);
 
                     // process invokes that are possibly created during canonicalization
                     for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed May 28 21:17:16 2014 +0200
@@ -34,7 +34,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
-import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.graph.spi.*;
@@ -49,6 +48,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
@@ -210,11 +210,10 @@
                             try (Indent indent = Debug.logAndIndent("inline graph %s", methodCallTargetNode.targetMethod())) {
 
                                 int nodeCountBefore = graph.getNodeCount();
-                                Mark mark = graph.getMark();
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.preExpand(methodCallTargetNode, inlineGraph);
                                 }
-                                List<Node> invokeUsages = methodCallTargetNode.invoke().asNode().usages().snapshot();
+                                List<Node> canonicalizedNodes = methodCallTargetNode.invoke().asNode().usages().snapshot();
                                 Map<Node, Node> inlined = InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, false);
                                 if (TraceTruffleExpansion.getValue()) {
                                     expansionLogger.postExpand(inlined);
@@ -223,7 +222,8 @@
                                     int nodeCountAfter = graph.getNodeCount();
                                     Debug.dump(graph, "After inlining %s %+d (%d)", methodCallTargetNode.targetMethod().toString(), nodeCountAfter - nodeCountBefore, nodeCountAfter);
                                 }
-                                canonicalizer.applyIncremental(graph, phaseContext, invokeUsages, mark);
+                                AbstractInlineInfo.getInlinedParameterUsages(canonicalizedNodes, inlineGraph, inlined);
+                                canonicalizer.applyIncremental(graph, phaseContext, canonicalizedNodes);
 
                                 changed = true;
                             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed May 28 17:41:59 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Wed May 28 21:17:16 2014 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
@@ -102,6 +103,10 @@
     public static final DebugTimer CompilationTime = Debug.timer("CompilationTime");
     public static final DebugTimer CodeInstallationTime = Debug.timer("CodeInstallation");
 
+    public static final DebugMemUseTracker PartialEvaluationMemUse = Debug.memUseTracker("TrufflePartialEvaluationMemUse");
+    public static final DebugMemUseTracker CompilationMemUse = Debug.memUseTracker("TruffleCompilationMemUse");
+    public static final DebugMemUseTracker CodeInstallationMemUse = Debug.memUseTracker("TruffleCodeInstallationMemUse");
+
     public void compileMethodImpl(final OptimizedCallTarget compilable) {
         final StructuredGraph graph;
 
@@ -111,7 +116,7 @@
 
         long timeCompilationStarted = System.nanoTime();
         Assumptions assumptions = new Assumptions(true);
-        try (TimerCloseable a = PartialEvaluationTime.start()) {
+        try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
             graph = partialEvaluator.createGraph(compilable, assumptions);
         }
 
@@ -156,7 +161,7 @@
         }
 
         CompilationResult result = null;
-        try (TimerCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache())) {
+        try (TimerCloseable a = CompilationTime.start(); Scope s = Debug.scope("TruffleGraal.GraalCompiler", graph, providers.getCodeCache()); Closeable c = CompilationMemUse.start()) {
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
@@ -183,7 +188,7 @@
         result.setAssumptions(newAssumptions);
 
         InstalledCode installedCode;
-        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start()) {
+        try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start(); Closeable c = CodeInstallationMemUse.start()) {
             installedCode = providers.getCodeCache().addMethod(graph.method(), result, speculationLog, predefinedInstalledCode);
         } catch (Throwable e) {
             throw Debug.handle(e);