changeset 16998:e4cfc9ea2bd3

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Thu, 28 Aug 2014 17:49:37 -0700
parents c9c416d90a4e (current diff) 9cf849d5b3f9 (diff)
children f8565347bb3b e91533b86166
files graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java
diffstat 91 files changed, 2353 insertions(+), 562 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Thu Aug 28 17:15:23 2014 -0700
+++ b/CHANGELOG.md	Thu Aug 28 17:49:37 2014 -0700
@@ -5,7 +5,7 @@
 * ...
 
 ### Truffle
-* ...
+* Added TruffleRuntime#getCallTargets() to get all call targets that were created and are still referenced.
 
 ## Version 0.4
 19-Aug-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/rev/graal-0.4)
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Thu Aug 28 17:49:37 2014 -0700
@@ -275,63 +275,63 @@
 
     protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
         Kind memoryKind = getMemoryKind(access);
-        if (operation.getClass() == IntegerAddNode.getGenClass()) {
+        if (operation.getNodeClass().is(IntegerAddNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IADD;
                 case Long:
                     return LADD;
             }
-        } else if (operation.getClass() == FloatAddNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(FloatAddNode.class)) {
             switch (memoryKind) {
                 case Float:
                     return FADD;
                 case Double:
                     return DADD;
             }
-        } else if (operation.getClass() == AndNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(AndNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IAND;
                 case Long:
                     return LAND;
             }
-        } else if (operation.getClass() == OrNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(OrNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IOR;
                 case Long:
                     return LOR;
             }
-        } else if (operation.getClass() == XorNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(XorNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IXOR;
                 case Long:
                     return LXOR;
             }
-        } else if (operation.getClass() == IntegerSubNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(IntegerSubNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return ISUB;
                 case Long:
                     return LSUB;
             }
-        } else if (operation.getClass() == FloatSubNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(FloatSubNode.class)) {
             switch (memoryKind) {
                 case Float:
                     return FSUB;
                 case Double:
                     return DSUB;
             }
-        } else if (operation.getClass() == IntegerMulNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(IntegerMulNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IMUL;
                 case Long:
                     return LMUL;
             }
-        } else if (operation.getClass() == FloatMulNode.getGenClass()) {
+        } else if (operation.getNodeClass().is(FloatMulNode.class)) {
             switch (memoryKind) {
                 case Float:
                     return FMUL;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/DominatorOptimizationProblem.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.cfg;
+
+import java.util.*;
+import java.util.stream.*;
+
+/**
+ * This class represents a dominator tree problem, i.e. a problem which can be solved by traversing
+ * the dominator (sub-)tree.
+ *
+ * @param <E> An enum that describes the flags that can be associated with a block.
+ * @param <C> An arbitrary cost type that is associated with a block. It is intended to carry
+ *            information needed to calculate the solution. Note that {@code C} should not contain
+ *            boolean flags. Use an enum entry in {@code E} instead.
+ */
+public abstract class DominatorOptimizationProblem<E extends Enum<E>, C> {
+
+    private List<? extends AbstractBlock<?>> blocks;
+    private EnumMap<E, BitSet> flags;
+    private BlockMap<C> costs;
+
+    protected DominatorOptimizationProblem(Class<E> flagType, AbstractControlFlowGraph<?> cfg) {
+        this.blocks = cfg.getBlocks();
+        flags = new EnumMap<>(flagType);
+        costs = new BlockMap<>(cfg);
+        assert verify(blocks);
+    }
+
+    private static boolean verify(List<? extends AbstractBlock<?>> blocks) {
+        for (int i = 0; i < blocks.size(); i++) {
+            AbstractBlock<?> block = blocks.get(i);
+            if (i != block.getId()) {
+                assert false : String.format("Id index mismatch @ %d vs. %s.getId()==%d", i, block, block.getId());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public final List<? extends AbstractBlock<?>> getBlocks() {
+        return blocks;
+    }
+
+    public final AbstractBlock<?> getBlockForId(int id) {
+        AbstractBlock<?> block = blocks.get(id);
+        assert block.getId() == id : "wrong block-to-id mapping";
+        return block;
+    }
+
+    /**
+     * Sets a flag for a block.
+     */
+    public final void set(E flag, AbstractBlock<?> block) {
+        BitSet bitSet = flags.get(flag);
+        if (bitSet == null) {
+            bitSet = new BitSet(blocks.size());
+            flags.put(flag, bitSet);
+        }
+        bitSet.set(block.getId());
+    }
+
+    /**
+     * Checks whether a flag is set for a block.
+     */
+    public final boolean get(E flag, AbstractBlock<?> block) {
+        BitSet bitSet = flags.get(flag);
+        return bitSet == null ? false : bitSet.get(block.getId());
+    }
+
+    /**
+     * Returns a {@linkplain Stream} of blocks for which {@code flag} is set.
+     */
+    public final Stream<? extends AbstractBlock<?>> stream(E flag) {
+        return getBlocks().stream().filter(block -> get(flag, block));
+    }
+
+    /**
+     * Returns the cost object associated with {@code block}. Might return {@code null} if not set.
+     */
+    public final C getCost(AbstractBlock<?> block) {
+        C cost = costs.get(block);
+        return cost;
+    }
+
+    /**
+     * Sets the cost for a {@code block}.
+     */
+    public final void setCost(AbstractBlock<?> block, C cost) {
+        costs.put(block, cost);
+    }
+
+    /**
+     * Sets {@code flag} for all blocks along the dominator path from {@code block} to the root
+     * until a block it finds a block where {@code flag} is already set.
+     */
+    public final void setDominatorPath(E flag, AbstractBlock<?> block) {
+        BitSet bitSet = flags.get(flag);
+        if (bitSet == null) {
+            bitSet = new BitSet(blocks.size());
+            flags.put(flag, bitSet);
+        }
+        for (AbstractBlock<?> b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) {
+            // mark block
+            bitSet.set(b.getId());
+        }
+    }
+
+    /**
+     * Returns a {@link Stream} of flags associated with {@code block}.
+     */
+    public final Stream<E> getFlagsForBlock(AbstractBlock<?> block) {
+        return getFlags().stream().filter(flag -> get(flag, block));
+    }
+
+    /**
+     * Returns the {@link Set} of flags that can be set for this
+     * {@linkplain DominatorOptimizationProblem problem}.
+     */
+    public final Set<E> getFlags() {
+        return flags.keySet();
+    }
+
+    /**
+     * Returns the name of a flag.
+     */
+    public String getName(E flag) {
+        return flag.toString();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableCFG.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.cfg;
+
+import java.util.*;
+import java.util.function.*;
+
+/**
+ * Represents a control-flow graph where each node can be annotated with arbitrary property pairs of
+ * the form ({@linkplain String name}, {@linkplain String value}).
+ */
+public interface PrintableCFG {
+
+    List<? extends AbstractBlock<?>> getBlocks();
+
+    /**
+     * Applies {@code action} to all extra property pairs (name, value) of {@code block}.
+     *
+     * @param block a block from {@link #getBlocks()}.
+     * @param action a {@link BiConsumer consumer}.
+     */
+    default void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+        // no extra properties per default
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableDominatorOptimizationProblem.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.cfg;
+
+import java.util.function.*;
+
+/**
+ * A {@linkplain PrintableCFG printable} {@link DominatorOptimizationProblem}.
+ */
+public abstract class PrintableDominatorOptimizationProblem<E extends Enum<E>, C extends PropertyConsumable> extends DominatorOptimizationProblem<E, C> implements PrintableCFG {
+
+    protected PrintableDominatorOptimizationProblem(Class<E> keyType, AbstractControlFlowGraph<?> cfg) {
+        super(keyType, cfg);
+    }
+
+    public void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+        // for each flag
+        getFlags().forEach(flag -> ((BiConsumer<String, Boolean>) (name, value) -> action.accept(name, value ? "true" : "false")).accept(getName(flag), get(flag, block)));
+        // for each property
+        C cost = getCost(block);
+        if (cost != null) {
+            cost.forEachProperty((name, value) -> action.accept(name, value));
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PropertyConsumable.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.cfg;
+
+import java.util.function.*;
+
+public interface PropertyConsumable {
+
+    void forEachProperty(BiConsumer<String, String> action);
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Thu Aug 28 17:49:37 2014 -0700
@@ -189,11 +189,7 @@
                     throw new AssertionError(String.format("Node subclass %s requires %s annotation", c.getName(), NodeClass.class.getSimpleName()));
                 }
                 if (!Modifier.isAbstract(c.getModifiers())) {
-                    try {
-                        Class.forName(c.getName().replace('$', '_') + "Gen");
-                    } catch (ClassNotFoundException e) {
-                        throw new AssertionError(String.format("Missing generated Node class %s", c.getName() + "Gen"));
-                    }
+                    NodeClass.get(c).getGenClass();
                 }
             }
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Aug 28 17:49:37 2014 -0700
@@ -41,6 +41,7 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.constopt.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
@@ -256,6 +257,15 @@
                 throw Debug.handle(e);
             }
 
+            if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) {
+                try (Scope s = Debug.scope("ConstantLoadOptimization", lir)) {
+                    ConstantLoadOptimization.optimize(lirGenRes.getLIR(), lirGen);
+                    Debug.dump(lir, "After constant load optimization");
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            }
+
             try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
                 if (backend.shouldAllocateRegisters()) {
                     new LinearScan(target, lir, frameMap).allocate();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchPattern.java	Thu Aug 28 17:49:37 2014 -0700
@@ -151,8 +151,22 @@
         this(null, name, singleUser);
     }
 
+    /**
+     * Gets the {@link Node} class instantiated for a given canonical {@link Node} class depending
+     * on whether or not generated node classes are enabled.
+     */
+    @SuppressWarnings("unchecked")
+    private static Class<? extends ValueNode> asInstantiatedClass(Class<? extends ValueNode> nodeClass) {
+        if (nodeClass != null && Node.USE_GENERATED_NODES) {
+            Class<? extends ValueNode> res = (Class<? extends ValueNode>) NodeClass.get(nodeClass).getGenClass();
+            assert res != null : nodeClass;
+            return res;
+        }
+        return nodeClass;
+    }
+
     public MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser) {
-        this.nodeClass = nodeClass;
+        this.nodeClass = asInstantiatedClass(nodeClass);
         this.name = name;
         this.singleUser = singleUser;
         this.patterns = EMPTY_PATTERNS;
@@ -161,7 +175,7 @@
 
     private MatchPattern(Class<? extends ValueNode> nodeClass, String name, boolean singleUser, MatchPattern[] patterns, Position[] inputs) {
         assert inputs == null || inputs.length == patterns.length;
-        this.nodeClass = nodeClass;
+        this.nodeClass = asInstantiatedClass(nodeClass);
         this.name = name;
         this.singleUser = singleUser;
         this.patterns = patterns;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatement.java	Thu Aug 28 17:49:37 2014 -0700
@@ -144,4 +144,9 @@
     public String getName() {
         return name;
     }
+
+    @Override
+    public String toString() {
+        return pattern.toString();
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Aug 28 17:49:37 2014 -0700
@@ -42,12 +42,12 @@
     /**
      * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time.
      */
-    private Node[] nodes;
+    Node[] nodes;
 
     /**
      * The number of valid entries in {@link #nodes}.
      */
-    private int nodesSize;
+    int nodesSize;
 
     /**
      * Records the modification count for nodes. This is only used in assertions.
@@ -562,56 +562,6 @@
         return new Mark(this);
     }
 
-    private class NodeIterator implements Iterator<Node> {
-
-        private int index;
-
-        public NodeIterator() {
-            this(0);
-        }
-
-        public NodeIterator(int index) {
-            this.index = index - 1;
-            forward();
-        }
-
-        private void forward() {
-            if (index < nodesSize) {
-                do {
-                    index++;
-                } while (index < nodesSize && nodes[index] == null);
-            }
-        }
-
-        @Override
-        public boolean hasNext() {
-            checkForDeletedNode();
-            return index < nodesSize;
-        }
-
-        private void checkForDeletedNode() {
-            if (index < nodesSize) {
-                while (index < nodesSize && nodes[index] == null) {
-                    index++;
-                }
-            }
-        }
-
-        @Override
-        public Node next() {
-            try {
-                return nodes[index];
-            } finally {
-                forward();
-            }
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     /**
      * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark()
      * mark}.
@@ -622,7 +572,7 @@
 
             @Override
             public Iterator<Node> iterator() {
-                return new NodeIterator(index);
+                return new GraphNodeIterator(Graph.this, index);
             }
         };
     }
@@ -637,7 +587,7 @@
 
             @Override
             public Iterator<Node> iterator() {
-                return new NodeIterator();
+                return new GraphNodeIterator(Graph.this);
             }
 
             @Override
@@ -658,7 +608,7 @@
         }
     }
 
-    private static final Node PLACE_HOLDER = USE_GENERATED_NODES ? new Graph_PlaceHolderNodeGen() : new PlaceHolderNode();
+    static final Node PLACE_HOLDER = USE_GENERATED_NODES ? new Graph_PlaceHolderNodeGen() : new PlaceHolderNode();
 
     /**
      * When the percent of live nodes in {@link #nodes} fall below this number, a call to
@@ -709,107 +659,6 @@
         return true;
     }
 
-    private static class TypedNodeIterator<T extends IterableNodeType> implements Iterator<T> {
-
-        private final Graph graph;
-        private final int[] ids;
-        private final Node[] current;
-
-        private int currentIdIndex;
-        private boolean needsForward;
-
-        public TypedNodeIterator(NodeClass clazz, Graph graph) {
-            this.graph = graph;
-            ids = clazz.iterableIds();
-            currentIdIndex = 0;
-            current = new Node[ids.length];
-            Arrays.fill(current, PLACE_HOLDER);
-            needsForward = true;
-        }
-
-        private Node findNext() {
-            if (needsForward) {
-                forward();
-            } else {
-                Node c = current();
-                Node afterDeleted = skipDeleted(c);
-                if (afterDeleted == null) {
-                    needsForward = true;
-                } else if (c != afterDeleted) {
-                    setCurrent(afterDeleted);
-                }
-            }
-            if (needsForward) {
-                return null;
-            }
-            return current();
-        }
-
-        private static Node skipDeleted(Node node) {
-            Node n = node;
-            while (n != null && n.isDeleted()) {
-                n = n.typeCacheNext;
-            }
-            return n;
-        }
-
-        private void forward() {
-            needsForward = false;
-            int startIdx = currentIdIndex;
-            while (true) {
-                Node next;
-                if (current() == PLACE_HOLDER) {
-                    next = graph.getStartNode(ids[currentIdIndex]);
-                } else {
-                    next = current().typeCacheNext;
-                }
-                next = skipDeleted(next);
-                if (next == null) {
-                    currentIdIndex++;
-                    if (currentIdIndex >= ids.length) {
-                        currentIdIndex = 0;
-                    }
-                    if (currentIdIndex == startIdx) {
-                        needsForward = true;
-                        return;
-                    }
-                } else {
-                    setCurrent(next);
-                    break;
-                }
-            }
-        }
-
-        private Node current() {
-            return current[currentIdIndex];
-        }
-
-        private void setCurrent(Node n) {
-            current[currentIdIndex] = n;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return findNext() != null;
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public T next() {
-            Node result = findNext();
-            if (result == null) {
-                throw new NoSuchElementException();
-            }
-            needsForward = true;
-            return (T) result;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     /**
      * Returns an {@link Iterable} providing all the live nodes whose type is compatible with
      * {@code type}.
@@ -823,7 +672,7 @@
 
             @Override
             public Iterator<T> iterator() {
-                return new TypedNodeIterator<>(nodeClass, Graph.this);
+                return new TypedGraphNodeIterator<>(nodeClass, Graph.this);
             }
         };
     }
@@ -838,7 +687,7 @@
         return getNodes(type).iterator().hasNext();
     }
 
-    private Node getStartNode(int iterableId) {
+    Node getStartNode(int iterableId) {
         Node start = nodeCacheFirst.size() <= iterableId ? null : nodeCacheFirst.get(iterableId);
         return start;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/GraphNodeIterator.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph;
+
+import java.util.*;
+
+/**
+ * Iterates over the nodes in a given graph.
+ */
+class GraphNodeIterator implements Iterator<Node> {
+
+    private final Graph graph;
+    private int index;
+
+    public GraphNodeIterator(Graph graph) {
+        this(graph, 0);
+    }
+
+    public GraphNodeIterator(Graph graph, int index) {
+        this.graph = graph;
+        this.index = index - 1;
+        forward();
+    }
+
+    private void forward() {
+        if (index < graph.nodesSize) {
+            do {
+                index++;
+            } while (index < graph.nodesSize && graph.nodes[index] == null);
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        checkForDeletedNode();
+        return index < graph.nodesSize;
+    }
+
+    private void checkForDeletedNode() {
+        while (index < graph.nodesSize && graph.nodes[index] == null) {
+            index++;
+        }
+    }
+
+    @Override
+    public Node next() {
+        try {
+            return graph.nodes[index];
+        } finally {
+            forward();
+        }
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Aug 28 17:49:37 2014 -0700
@@ -56,7 +56,7 @@
 @NodeInfo
 public abstract class Node implements Cloneable, Formattable {
 
-    public final static boolean USE_GENERATED_NODES = Boolean.getBoolean("graal.useGeneratedNodes");
+    public final static boolean USE_GENERATED_NODES = Boolean.parseBoolean(System.getProperty("graal.useGeneratedNodes", "true"));
 
     static final int DELETED_ID_START = -1000000000;
     static final int INITIAL_ID = -1;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Thu Aug 28 17:49:37 2014 -0700
@@ -25,6 +25,7 @@
 import static com.oracle.graal.graph.Graph.*;
 import static com.oracle.graal.graph.Node.*;
 import static com.oracle.graal.graph.util.CollectionsAccess.*;
+import static java.lang.reflect.Modifier.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -54,8 +55,7 @@
      */
     @SuppressWarnings("unchecked")
     public static NodeClass get(Class<?> c) {
-        GeneratedNode gen = c.getAnnotation(GeneratedNode.class);
-        Class<? extends Node> key = gen == null ? (Class<? extends Node>) c : (Class<? extends Node>) gen.value();
+        Class<? extends Node> key = (Class<? extends Node>) c;
 
         NodeClass value = (NodeClass) allClasses.get(key);
         // The fact that {@link ConcurrentHashMap#put} and {@link ConcurrentHashMap#get}
@@ -66,7 +66,19 @@
             synchronized (GetNodeClassLock) {
                 value = (NodeClass) allClasses.get(key);
                 if (value == null) {
-                    value = new NodeClass(key);
+                    GeneratedNode gen = c.getAnnotation(GeneratedNode.class);
+                    if (gen != null) {
+                        Class<? extends Node> originalNodeClass = (Class<? extends Node>) gen.value();
+                        value = (NodeClass) allClasses.get(originalNodeClass);
+                        assert value != null;
+                        if (value.genClass == null) {
+                            value.genClass = (Class<? extends Node>) c;
+                        } else {
+                            assert value.genClass == c;
+                        }
+                    } else {
+                        value = new NodeClass(key);
+                    }
                     Object old = allClasses.putIfAbsent(key, value);
                     assert old == null : old + "   " + key;
                 }
@@ -96,6 +108,13 @@
     private final EnumSet<InputType> allowedUsageTypes;
     private int[] iterableIds;
 
+    /**
+     * The {@linkplain GeneratedNode generated} node class denoted by this object. This value is
+     * lazily initialized to avoid class initialization circularity issues. A sentinel value of
+     * {@code Node.class} is used to denote absence of a generated class.
+     */
+    private Class<? extends Node> genClass;
+
     private static final DebugMetric ITERABLE_NODE_TYPES = Debug.metric("IterableNodeTypes");
     private final DebugMetric nodeIterableCount;
 
@@ -158,15 +177,12 @@
         }
         String newNameTemplate = null;
         NodeInfo info = clazz.getAnnotation(NodeInfo.class);
-        if (info != null) {
-            if (!info.shortName().isEmpty()) {
-                newShortName = info.shortName();
-            }
-            if (!info.nameTemplate().isEmpty()) {
-                newNameTemplate = info.nameTemplate();
-            }
-        } else {
-            System.out.println("No NodeInfo for " + clazz);
+        assert info != null : "missing " + NodeInfo.class.getSimpleName() + " annotation on " + clazz;
+        if (!info.shortName().isEmpty()) {
+            newShortName = info.shortName();
+        }
+        if (!info.nameTemplate().isEmpty()) {
+            newNameTemplate = info.nameTemplate();
         }
         EnumSet<InputType> newAllowedUsageTypes = EnumSet.noneOf(InputType.class);
         Class<?> current = clazz;
@@ -190,13 +206,19 @@
             this.iterableId = nextIterableId++;
             List<NodeClass> existingClasses = new LinkedList<>();
             for (FieldIntrospection nodeClass : allClasses.values()) {
+                // There are duplicate entries in allClasses when using generated nodes
+                // hence the extra logic below guarded by USE_GENERATED_NODES
                 if (clazz.isAssignableFrom(nodeClass.getClazz())) {
-                    existingClasses.add((NodeClass) nodeClass);
+                    if (!USE_GENERATED_NODES || !existingClasses.contains(nodeClass)) {
+                        existingClasses.add((NodeClass) nodeClass);
+                    }
                 }
                 if (nodeClass.getClazz().isAssignableFrom(clazz) && IterableNodeType.class.isAssignableFrom(nodeClass.getClazz())) {
                     NodeClass superNodeClass = (NodeClass) nodeClass;
-                    superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
-                    superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
+                    if (!USE_GENERATED_NODES || !containsId(this.iterableId, superNodeClass.iterableIds)) {
+                        superNodeClass.iterableIds = Arrays.copyOf(superNodeClass.iterableIds, superNodeClass.iterableIds.length + 1);
+                        superNodeClass.iterableIds[superNodeClass.iterableIds.length - 1] = this.iterableId;
+                    }
                 }
             }
             int[] ids = new int[existingClasses.size() + 1];
@@ -214,6 +236,39 @@
         nodeIterableCount = Debug.metric("NodeIterable_%s", shortName);
     }
 
+    /**
+     * Gets the {@linkplain GeneratedNode generated} node class (if any) described by the object.
+     */
+    @SuppressWarnings("unchecked")
+    public Class<? extends Node> getGenClass() {
+        if (USE_GENERATED_NODES) {
+            if (genClass == null) {
+                if (!isAbstract(getClazz().getModifiers())) {
+                    String genClassName = getClazz().getName().replace('$', '_') + "Gen";
+                    try {
+                        genClass = (Class<? extends Node>) Class.forName(genClassName);
+                    } catch (ClassNotFoundException e) {
+                        throw new GraalInternalError("Could not find generated class " + genClassName + " for " + getClazz());
+                    }
+                } else {
+                    // Sentinel value denoting no generated class
+                    genClass = Node.class;
+                }
+            }
+            return genClass.equals(Node.class) ? null : genClass;
+        }
+        return null;
+    }
+
+    private static boolean containsId(int iterableId, int[] iterableIds) {
+        for (int i : iterableIds) {
+            if (i == iterableId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
         FieldScanner scanner = new FieldScanner(calc);
@@ -234,14 +289,14 @@
         fieldTypes.putAll(scanner.fieldTypes);
     }
 
-    private boolean isNodeClassFor(Node n) {
-        if (Node.USE_GENERATED_NODES) {
-            GeneratedNode gen = n.getClass().getAnnotation(GeneratedNode.class);
-            assert gen != null;
-            return gen.value() == getClazz();
-        } else {
-            return n.getNodeClass().getClazz() == n.getClass();
-        }
+    /**
+     * Determines if a given {@link Node} class is described by the {@link NodeClass} object.
+     *
+     * @param nodeClass a {@linkplain GeneratedNode non-generated} {@link Node} class
+     */
+    public boolean is(Class<? extends Node> nodeClass) {
+        assert nodeClass.getAnnotation(GeneratedNode.class) == null : "cannot test NodeClas against generated " + nodeClass;
+        return nodeClass == getClazz();
     }
 
     public String shortName() {
@@ -1214,7 +1269,7 @@
      * @param newNode the node to which the inputs should be copied.
      */
     public void copyInputs(Node node, Node newNode) {
-        assert isNodeClassFor(node) && isNodeClassFor(newNode);
+        assert node.getNodeClass() == this && newNode.getNodeClass() == this;
 
         int index = 0;
         while (index < directInputCount) {
@@ -1236,7 +1291,7 @@
      * @param newNode the node to which the successors should be copied.
      */
     public void copySuccessors(Node node, Node newNode) {
-        assert isNodeClassFor(node) && isNodeClassFor(newNode);
+        assert node.getNodeClass() == this && newNode.getNodeClass() == this;
 
         int index = 0;
         while (index < directSuccessorCount) {
@@ -1255,7 +1310,7 @@
     }
 
     public boolean inputsEqual(Node node, Node other) {
-        assert isNodeClassFor(node) && isNodeClassFor(other);
+        assert node.getNodeClass() == this && other.getNodeClass() == this;
         int index = 0;
         while (index < directInputCount) {
             if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
@@ -1274,7 +1329,7 @@
     }
 
     public boolean successorsEqual(Node node, Node other) {
-        assert isNodeClassFor(node) && isNodeClassFor(other);
+        assert node.getNodeClass() == this && other.getNodeClass() == this;
         int index = 0;
         while (index < directSuccessorCount) {
             if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
@@ -1293,7 +1348,7 @@
     }
 
     public boolean inputContains(Node node, Node other) {
-        assert isNodeClassFor(node);
+        assert node.getNodeClass() == this;
 
         int index = 0;
         while (index < directInputCount) {
@@ -1313,7 +1368,7 @@
     }
 
     public boolean successorContains(Node node, Node other) {
-        assert isNodeClassFor(node);
+        assert node.getNodeClass() == this;
 
         int index = 0;
         while (index < directSuccessorCount) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/TypedGraphNodeIterator.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.graph;
+
+import java.util.*;
+
+class TypedGraphNodeIterator<T extends IterableNodeType> implements Iterator<T> {
+
+    private final Graph graph;
+    private final int[] ids;
+    private final Node[] current;
+
+    private int currentIdIndex;
+    private boolean needsForward;
+
+    public TypedGraphNodeIterator(NodeClass clazz, Graph graph) {
+        this.graph = graph;
+        ids = clazz.iterableIds();
+        currentIdIndex = 0;
+        current = new Node[ids.length];
+        Arrays.fill(current, Graph.PLACE_HOLDER);
+        needsForward = true;
+    }
+
+    private Node findNext() {
+        if (needsForward) {
+            forward();
+        } else {
+            Node c = current();
+            Node afterDeleted = skipDeleted(c);
+            if (afterDeleted == null) {
+                needsForward = true;
+            } else if (c != afterDeleted) {
+                setCurrent(afterDeleted);
+            }
+        }
+        if (needsForward) {
+            return null;
+        }
+        return current();
+    }
+
+    private static Node skipDeleted(Node node) {
+        Node n = node;
+        while (n != null && n.isDeleted()) {
+            n = n.typeCacheNext;
+        }
+        return n;
+    }
+
+    private void forward() {
+        needsForward = false;
+        int startIdx = currentIdIndex;
+        while (true) {
+            Node next;
+            if (current() == Graph.PLACE_HOLDER) {
+                next = graph.getStartNode(ids[currentIdIndex]);
+            } else {
+                next = current().typeCacheNext;
+            }
+            next = skipDeleted(next);
+            if (next == null) {
+                currentIdIndex++;
+                if (currentIdIndex >= ids.length) {
+                    currentIdIndex = 0;
+                }
+                if (currentIdIndex == startIdx) {
+                    needsForward = true;
+                    return;
+                }
+            } else {
+                setCurrent(next);
+                break;
+            }
+        }
+    }
+
+    private Node current() {
+        return current[currentIdIndex];
+    }
+
+    private void setCurrent(Node n) {
+        current[currentIdIndex] = n;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return findNext() != null;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T next() {
+        Node result = findNext();
+        if (result == null) {
+            throw new NoSuchElementException();
+        }
+        needsForward = true;
+        return (T) result;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Aug 28 17:49:37 2014 -0700
@@ -146,8 +146,12 @@
 
     private HotSpotNativeFunctionHandle createHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
         HotSpotNativeFunctionPointer hs = (HotSpotNativeFunctionPointer) functionPointer;
-        InstalledCode code = installNativeFunctionStub(hs.value, returnType, argumentTypes);
-        return new HotSpotNativeFunctionHandle(code, hs.name, argumentTypes);
+        if (hs != null) {
+            InstalledCode code = installNativeFunctionStub(hs.value, returnType, argumentTypes);
+            return new HotSpotNativeFunctionHandle(code, hs.name, argumentTypes);
+        } else {
+            return null;
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Thu Aug 28 17:49:37 2014 -0700
@@ -31,9 +31,9 @@
 @NodeInfo
 public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
 
-    @Input ValueNode object;
-    @OptionalInput ValueNode value;
-    @OptionalInput(InputType.Association) LocationNode location;
+    @Input protected ValueNode object;
+    @OptionalInput protected ValueNode value;
+    @OptionalInput(InputType.Association) protected LocationNode location;
     private final boolean precise;
 
     public WriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Aug 28 17:49:37 2014 -0700
@@ -1334,7 +1334,7 @@
                         frameState.clearNonLiveLocals(currentBlock, liveness, false);
                     }
                     if (lastInstr instanceof StateSplit) {
-                        if (lastInstr.getClass() == BeginNode.getGenClass()) {
+                        if (lastInstr.getNodeClass().is(BeginNode.class)) {
                             // BeginNodes do not need a frame state
                         } else {
                             StateSplit stateSplit = (StateSplit) lastInstr;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_ddiv.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_ddiv.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,4 +39,8 @@
         runTest("test", 311.0D, 10D);
     }
 
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 311.0D, 0D);
+    }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_fdiv.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/bytecode/BC_fdiv.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,4 +39,8 @@
         runTest("test", 311.0f, 10f);
     }
 
+    @Test
+    public void run1() throws Throwable {
+        runTest("test", 311.0f, 0f);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.constopt.ConstantTree.Flags;
+import com.oracle.graal.lir.constopt.ConstantTree.NodeCost;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.options.*;
+
+/**
+ * This optimization tries to improve the handling of constants by replacing a single definition of
+ * a constant, which is potentially scheduled into a block with high probability, with one or more
+ * definitions in blocks with a lower probability.
+ */
+public class ConstantLoadOptimization {
+
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable constant load optimization.")
+        public static final OptionValue<Boolean> ConstantLoadOptimization = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    public static void optimize(LIR lir, LIRGeneratorTool lirGen) {
+        new ConstantLoadOptimization(lir, lirGen).apply();
+    }
+
+    private LIR lir;
+    private LIRGeneratorTool lirGen;
+    private VariableMap<DefUseTree> map;
+    private BitSet phiConstants;
+    private BitSet defined;
+    private BlockMap<List<UseEntry>> blockMap;
+    private BlockMap<LIRInsertionBuffer> insertionBuffers;
+
+    private static DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]");
+    private static DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]");
+    private static DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]");
+    private static DebugMetric usageAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[UsageAtDefinitionSkipped]");
+    private static DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
+    private static DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]");
+
+    private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) {
+        this.lir = lir;
+        this.lirGen = lirGen;
+        this.map = new VariableMap<>();
+        this.phiConstants = new BitSet();
+        this.defined = new BitSet();
+        this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
+        this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
+    }
+
+    private void apply() {
+        try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
+            try (Scope s = Debug.scope("BuildDefUseTree")) {
+                // build DefUseTree
+                lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock);
+                // remove all with only one use
+                map.filter(t -> {
+                    if (t.usageCount() > 1) {
+                        return true;
+                    } else {
+                        singleUsageConstantsSkipped.increment();
+                        return false;
+                    }
+                });
+                // collect block map
+                map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+
+            try (Scope s = Debug.scope("BuildConstantTree")) {
+                // create ConstantTree
+                map.forEach(this::createConstantTree);
+
+                // insert moves, delete null instructions and reset instruction ids
+                lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+    }
+
+    private static boolean isConstantLoad(LIRInstruction inst) {
+        if (!(inst instanceof MoveOp)) {
+            return false;
+        }
+        MoveOp move = (MoveOp) inst;
+        return isConstant(move.getInput()) && isVariable(move.getResult());
+    }
+
+    private void addUsageToBlockMap(UseEntry entry) {
+        AbstractBlock<?> block = entry.getBlock();
+        List<UseEntry> list = blockMap.get(block);
+        if (list == null) {
+            list = new ArrayList<>();
+            blockMap.put(block, list);
+        }
+        list.add(entry);
+    }
+
+    /**
+     * Collects def-use information for a {@code block}.
+     */
+    private void analyzeBlock(AbstractBlock<?> block) {
+        try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
+
+            InstructionValueConsumer loadConsumer = new InstructionValueConsumer() {
+                @Override
+                public void visitValue(LIRInstruction instruction, Value value) {
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+
+                        if (!phiConstants.get(var.index)) {
+                            if (!defined.get(var.index)) {
+                                defined.set(var.index);
+                                if (isConstantLoad(instruction)) {
+                                    Debug.log("constant load: %s", instruction);
+                                    map.put(var, new DefUseTree(instruction, block));
+                                    constantsTotal.increment();
+                                }
+                            } else {
+                                // Variable is redefined, this only happens for constant loads
+                                // introduced by phi resolution -> ignore.
+                                DefUseTree removed = map.remove(var);
+                                if (removed != null) {
+                                    phiConstantsSkipped.increment();
+                                }
+                                phiConstants.set(var.index);
+                                Debug.log(3, "Removing phi variable: %s", var);
+                            }
+                        } else {
+                            assert defined.get(var.index) : "phi but not defined? " + var;
+                        }
+
+                    }
+                }
+
+            };
+
+            ValuePositionProcedure useProcedure = new ValuePositionProcedure() {
+                @Override
+                public void doValue(LIRInstruction instruction, ValuePosition position) {
+                    Value value = position.get(instruction);
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+                        if (!phiConstants.get(var.index)) {
+                            DefUseTree tree = map.get(var);
+                            if (tree != null) {
+                                tree.addUsage(block, instruction, position);
+                                Debug.log("usage of %s : %s", var, instruction);
+                            }
+                        }
+                    }
+                }
+
+            };
+
+            int opId = 0;
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                // set instruction id to the index in the lir instruction list
+                inst.setId(opId++);
+                inst.visitEachOutput(loadConsumer);
+                inst.forEachInput(useProcedure);
+                inst.forEachAlive(useProcedure);
+
+            }
+        }
+    }
+
+    /**
+     * Creates the dominator tree and searches for an solution.
+     */
+    private void createConstantTree(DefUseTree tree) {
+        ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
+        constTree.set(Flags.SUBTREE, tree.getBlock());
+        tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
+
+        if (constTree.get(Flags.USAGE, tree.getBlock())) {
+            // usage in the definition block -> no optimization
+            usageAtDefinitionSkipped.increment();
+            return;
+        }
+
+        constTree.markBlocks();
+
+        NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
+        int usageCount = cost.getUsages().size();
+        assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
+
+        if (Debug.isLogEnabled()) {
+            try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
+                Debug.log("Usages result: %s", cost);
+            }
+
+        }
+
+        if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
+            try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
+                // mark original load for removal
+                deleteInstruction(tree);
+                constantsOptimized.increment();
+
+                // collect result
+                createLoads(tree, constTree, tree.getBlock());
+
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        } else {
+            // no better solution found
+            materializeAtDefinitionSkipped.increment();
+        }
+        Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
+    }
+
+    private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
+        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        worklist.add(startBlock);
+        while (!worklist.isEmpty()) {
+            AbstractBlock<?> block = worklist.pollLast();
+            if (constTree.get(Flags.CANDIDATE, block)) {
+                constTree.set(Flags.MATERIALIZE, block);
+                // create and insert load
+                insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages());
+            } else {
+                for (AbstractBlock<?> dominated : block.getDominated()) {
+                    if (constTree.isMarked(dominated)) {
+                        worklist.addLast(dominated);
+                    }
+                }
+            }
+        }
+    }
+
+    private void insertLoad(Constant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
+        assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
+        // create variable
+        Variable variable = lirGen.newVariable(kind);
+        // create move
+        LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant);
+        // insert instruction
+        getInsertionBuffer(block).append(1, move);
+        Debug.log("new move (%s) and inserted in block %s", move, block);
+        // update usages
+        for (UseEntry u : usages) {
+            u.getPosition().set(u.getInstruction(), variable);
+            Debug.log("patched instruction %s", u.getInstruction());
+        }
+    }
+
+    /**
+     * Inserts the constant loads created in {@link #createConstantTree} and deletes the original
+     * definition.
+     */
+    private void rewriteBlock(AbstractBlock<?> block) {
+        // insert moves
+        LIRInsertionBuffer buffer = insertionBuffers.get(block);
+        if (buffer != null) {
+            assert buffer.initialized() : "not initialized?";
+            buffer.finish();
+        }
+
+        // delete instructions
+        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+        boolean hasDead = false;
+        for (LIRInstruction inst : instructions) {
+            if (inst == null) {
+                hasDead = true;
+            } else {
+                inst.setId(-1);
+            }
+        }
+        if (hasDead) {
+            // Remove null values from the list.
+            instructions.removeAll(Collections.singleton(null));
+        }
+    }
+
+    private void deleteInstruction(DefUseTree tree) {
+        AbstractBlock<?> block = tree.getBlock();
+        LIRInstruction instruction = tree.getInstruction();
+        Debug.log("deleting instruction %s from block %s", instruction, block);
+        lir.getLIRforBlock(block).set(instruction.id(), null);
+    }
+
+    private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) {
+        LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
+        if (insertionBuffer == null) {
+            insertionBuffer = new LIRInsertionBuffer();
+            insertionBuffers.put(block, insertionBuffer);
+            assert !insertionBuffer.initialized() : "already initialized?";
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            insertionBuffer.init(instructions);
+        }
+        return insertionBuffer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+
+/**
+ * Represents a dominator (sub-)tree for a constant definition.
+ */
+public class ConstantTree extends PrintableDominatorOptimizationProblem<ConstantTree.Flags, ConstantTree.NodeCost> {
+
+    public enum Flags {
+        SUBTREE,
+        USAGE,
+        MATERIALIZE,
+        CANDIDATE,
+    }
+
+    /**
+     * Costs associated with a block.
+     */
+    public static class NodeCost implements PropertyConsumable {
+        private List<UseEntry> usages;
+        private double bestCost;
+        private int numMat;
+
+        public NodeCost(double bestCost, List<UseEntry> usages, int numMat) {
+            this.bestCost = bestCost;
+            this.usages = usages;
+            this.numMat = numMat;
+        }
+
+        public void forEachProperty(BiConsumer<String, String> action) {
+            action.accept("bestCost", Double.toString(getBestCost()));
+            action.accept("numMat", Integer.toString(getNumMaterializations()));
+            action.accept("numUsages", Integer.toString(usages.size()));
+        }
+
+        public void addUsage(UseEntry usage) {
+            if (usages == null) {
+                usages = new ArrayList<>();
+            }
+            usages.add(usage);
+        }
+
+        public List<UseEntry> getUsages() {
+            if (usages == null) {
+                Collections.emptyList();
+            }
+            return usages;
+        }
+
+        public double getBestCost() {
+            return bestCost;
+        }
+
+        public int getNumMaterializations() {
+            return numMat;
+        }
+
+        public void setBestCost(double cost) {
+            bestCost = cost;
+        }
+
+        @Override
+        public String toString() {
+            return "NodeCost [bestCost=" + bestCost + ", numUsages=" + usages.size() + ", numMat=" + numMat + "]";
+        }
+    }
+
+    private final BlockMap<List<UseEntry>> blockMap;
+
+    public ConstantTree(AbstractControlFlowGraph<?> cfg, DefUseTree tree) {
+        super(Flags.class, cfg);
+        this.blockMap = new BlockMap<>(cfg);
+        tree.forEach(u -> getOrInitList(u.getBlock()).add(u));
+    }
+
+    private List<UseEntry> getOrInitList(AbstractBlock<?> block) {
+        List<UseEntry> list = blockMap.get(block);
+        if (list == null) {
+            list = new ArrayList<>();
+            blockMap.put(block, list);
+        }
+        return list;
+    }
+
+    public List<UseEntry> getUsages(AbstractBlock<?> block) {
+        List<UseEntry> list = blockMap.get(block);
+        if (list == null) {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableList(list);
+    }
+
+    /**
+     * Returns the cost object associated with {@code block}. If there is none, a new cost object is
+     * created.
+     */
+    NodeCost getOrInitCost(AbstractBlock<?> block) {
+        NodeCost cost = getCost(block);
+        if (cost == null) {
+            cost = new NodeCost(block.probability(), blockMap.get(block), 1);
+            setCost(block, cost);
+        }
+        return cost;
+    }
+
+    @Override
+    public String getName(Flags type) {
+        switch (type) {
+            case USAGE:
+                return "hasUsage";
+            case SUBTREE:
+                return "inSubtree";
+            case MATERIALIZE:
+                return "materialize";
+            case CANDIDATE:
+                return "candidate";
+        }
+        return super.getName(type);
+    }
+
+    @Override
+    public void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+        if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) {
+            action.accept("hasDefinition", "true");
+        }
+        super.forEachPropertyPair(block, action);
+    }
+
+    public long subTreeSize() {
+        return stream(Flags.SUBTREE).count();
+    }
+
+    public AbstractBlock<?> getStartBlock() {
+        return stream(Flags.SUBTREE).findFirst().get();
+    }
+
+    public void markBlocks() {
+        stream(Flags.USAGE).forEach(block -> setDominatorPath(Flags.SUBTREE, block));
+    }
+
+    public boolean isMarked(AbstractBlock<?> block) {
+        return get(Flags.SUBTREE, block);
+    }
+
+    public boolean isLeafBlock(AbstractBlock<?> block) {
+        return block.getDominated().stream().noneMatch(this::isMarked);
+    }
+
+    public void setSolution(AbstractBlock<?> block) {
+        set(Flags.MATERIALIZE, block);
+    }
+
+    public int size() {
+        return getBlocks().size();
+    }
+
+    public void traverseTreeWhileTrue(AbstractBlock<?> block, Predicate<AbstractBlock<?>> action) {
+        assert block != null : "block must not be null!";
+        if (action.test(block)) {
+            block.getDominated().stream().filter(this::isMarked).forEach(dominated -> traverseTreeWhileTrue(dominated, action));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTreeAnalyzer.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.lir.constopt.ConstantTree.Flags;
+import com.oracle.graal.lir.constopt.ConstantTree.NodeCost;
+
+/**
+ * Analyzes a {@link ConstantTree} and marks potential materialization positions.
+ */
+public class ConstantTreeAnalyzer {
+    private final ConstantTree tree;
+    private final BitSet visited;
+
+    public static NodeCost analyze(ConstantTree tree, AbstractBlock<?> startBlock) {
+        try (Scope s = Debug.scope("ConstantTreeAnalyzer")) {
+            ConstantTreeAnalyzer analyzer = new ConstantTreeAnalyzer(tree);
+            analyzer.analyzeBlocks(startBlock);
+            return tree.getCost(startBlock);
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    private ConstantTreeAnalyzer(ConstantTree tree) {
+        this.tree = tree;
+        this.visited = new BitSet(tree.size());
+    }
+
+    /**
+     * Queues all relevant blocks for {@linkplain #process processing}.
+     *
+     * This is a worklist-style algorithm because a (more elegant) recursive implementation may
+     * cause {@linkplain StackOverflowError stack overflows} on larger graphs.
+     *
+     * @param startBlock The start block of the dominator subtree.
+     */
+    private void analyzeBlocks(AbstractBlock<?> startBlock) {
+        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        worklist.offerLast(startBlock);
+        while (!worklist.isEmpty()) {
+            AbstractBlock<?> block = worklist.pollLast();
+            try (Indent i = Debug.logAndIndent(3, "analyze: %s", block)) {
+                assert block != null : "worklist is empty!";
+                assert isMarked(block) : "Block not part of the dominator tree: " + block;
+
+                if (isLeafBlock(block)) {
+                    Debug.log(3, "leaf block");
+                    leafCost(block);
+                    continue;
+                }
+
+                if (!visited.get(block.getId())) {
+                    // if not yet visited (and not a leaf block) process all children first!
+                    Debug.log(3, "not marked");
+                    worklist.offerLast(block);
+                    List<? extends AbstractBlock<?>> children = block.getDominated();
+                    children.forEach(child -> filteredPush(worklist, child));
+                    visited.set(block.getId());
+                } else {
+                    Debug.log(3, "marked");
+                    // otherwise, process block
+                    process(block);
+                }
+            }
+        }
+    }
+
+    /**
+     * Calculates the cost of a {@code block}. It is assumed that all {@code children} have already
+     * been {@linkplain #process processed}
+     *
+     * @param block The block to be processed.
+     */
+    private void process(AbstractBlock<?> block) {
+        List<UseEntry> usages = new ArrayList<>();
+        double bestCost = 0;
+        int numMat = 0;
+        List<? extends AbstractBlock<?>> children = block.getDominated();
+        assert children.stream().anyMatch(this::isMarked) : "no children? should have called leafCost(): " + block;
+
+        // collect children costs
+        for (AbstractBlock<?> child : children) {
+            if (isMarked(child)) {
+                NodeCost childCost = tree.getCost(child);
+                assert childCost != null : "Child with null cost? block: " + child;
+                usages.addAll(childCost.getUsages());
+                numMat += childCost.getNumMaterializations();
+                bestCost += childCost.getBestCost();
+            }
+        }
+        assert numMat > 0 : "No materialization? " + numMat;
+
+        // choose block
+        List<UseEntry> usagesBlock = tree.getUsages(block);
+        double probabilityBlock = block.probability();
+
+        if (!usagesBlock.isEmpty() || shouldMaterializerInCurrentBlock(probabilityBlock, bestCost, numMat)) {
+            // mark current block as potential materialization position
+            usages.addAll(usagesBlock);
+            bestCost = probabilityBlock;
+            numMat = 1;
+            tree.set(Flags.CANDIDATE, block);
+        } else {
+            // stick with the current solution
+        }
+
+        assert (new HashSet<>(usages)).size() == usages.size() : "doulbe entries? " + usages;
+        NodeCost nodeCost = new NodeCost(bestCost, usages, numMat);
+        tree.setCost(block, nodeCost);
+    }
+
+    /**
+     * This is the cost function that decides whether a materialization should be inserted in the
+     * current block.
+     * <p>
+     * Note that this function does not take into account if a materialization is required despite
+     * the probabilities (e.g. there are usages in the current block).
+     *
+     * @param probabilityBlock Probability of the current block.
+     * @param probabilityChildren Accumulated probability of the children.
+     * @param numMat Number of materializations along the subtrees. We use {@code numMat - 1} to
+     *            insert materializations as late as possible if the probabilities are the same.
+     */
+    private static boolean shouldMaterializerInCurrentBlock(double probabilityBlock, double probabilityChildren, int numMat) {
+        return probabilityBlock * Math.pow(0.9, numMat - 1) < probabilityChildren;
+    }
+
+    private void filteredPush(Deque<AbstractBlock<?>> worklist, AbstractBlock<?> block) {
+        if (isMarked(block)) {
+            Debug.log(3, "adding %s to the worklist", block);
+            worklist.offerLast(block);
+        }
+    }
+
+    private void leafCost(AbstractBlock<?> block) {
+        tree.set(Flags.CANDIDATE, block);
+        tree.getOrInitCost(block);
+    }
+
+    private boolean isMarked(AbstractBlock<?> block) {
+        return tree.isMarked(block);
+    }
+
+    private boolean isLeafBlock(AbstractBlock<?> block) {
+        return tree.isLeafBlock(block);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/DefUseTree.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.MoveOp;
+
+/**
+ * Represents def-use tree of a constant.
+ */
+class DefUseTree {
+    private final LIRInstruction instruction;
+    private final AbstractBlock<?> block;
+    private final List<UseEntry> uses;
+
+    public DefUseTree(LIRInstruction instruction, AbstractBlock<?> block) {
+        assert instruction instanceof MoveOp : "Not a MoveOp: " + instruction;
+        this.instruction = instruction;
+        this.block = block;
+        this.uses = new ArrayList<>();
+    }
+
+    public Variable getVariable() {
+        return (Variable) ((MoveOp) instruction).getResult();
+    }
+
+    public Constant getConstant() {
+        return (Constant) ((MoveOp) instruction).getInput();
+    }
+
+    public LIRInstruction getInstruction() {
+        return instruction;
+    }
+
+    public AbstractBlock<?> getBlock() {
+        return block;
+    }
+
+    @Override
+    public String toString() {
+        return "DefUseTree [" + instruction + "|" + block + "," + uses + "]";
+    }
+
+    public void addUsage(AbstractBlock<?> b, LIRInstruction inst, ValuePosition position) {
+        uses.add(new UseEntry(b, inst, position));
+    }
+
+    public int usageCount() {
+        return uses.size();
+    }
+
+    public void forEach(Consumer<? super UseEntry> action) {
+        uses.forEach(action);
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/UseEntry.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Represents a usage of a constant.
+ */
+class UseEntry {
+
+    private final AbstractBlock<?> block;
+    private final LIRInstruction instruction;
+    private final ValuePosition position;
+
+    public UseEntry(AbstractBlock<?> block, LIRInstruction instruction, ValuePosition position) {
+        this.block = block;
+        this.instruction = instruction;
+        this.position = position;
+    }
+
+    public LIRInstruction getInstruction() {
+        return instruction;
+    }
+
+    public AbstractBlock<?> getBlock() {
+        return block;
+    }
+
+    public ValuePosition getPosition() {
+        return position;
+    }
+
+    public Value getValue() {
+        return position.get(instruction);
+    }
+
+    @Override
+    public String toString() {
+        return "Use[" + getValue() + ":" + instruction + ":" + block + "]";
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/VariableMap.java	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.constopt;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.lir.*;
+
+/**
+ * Maps variables to a generic type.
+ *
+ * TODO (je) evaluate data structure
+ */
+class VariableMap<T> {
+
+    private final ArrayList<T> content;
+
+    public VariableMap() {
+        content = new ArrayList<>();
+    }
+
+    public T get(Variable key) {
+        if (key == null || key.index >= content.size()) {
+            return null;
+        }
+        return content.get(key.index);
+    }
+
+    public T put(Variable key, T value) {
+        assert key != null : "Key cannot be null";
+        assert value != null : "Value cannot be null";
+        while (key.index >= content.size()) {
+            content.add(null);
+        }
+        return content.set(key.index, value);
+    }
+
+    public T remove(Variable key) {
+        assert key != null : "Key cannot be null";
+        if (key.index >= content.size()) {
+            return null;
+        }
+        return content.set(key.index, null);
+    }
+
+    public void forEach(Consumer<T> action) {
+        for (T e : content) {
+            if (e != null) {
+                action.accept(e);
+            }
+        }
+    }
+
+    /**
+     * Keeps only keys which match the given predicate.
+     */
+    public void filter(Predicate<T> predicate) {
+        for (int i = 0; i < content.size(); i++) {
+            T e = content.get(i);
+            if (e != null && !predicate.test(e)) {
+                content.set(i, null);
+            }
+        }
+    }
+
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java	Thu Aug 28 17:49:37 2014 -0700
@@ -379,7 +379,7 @@
                 callArgs.format("%s%s", sep, v.getSimpleName());
                 sep = ", ";
             }
-            f.format(") { return new %s(%s); }", genClassName, callArgs);
+            f.format(") { return USE_GENERATED_NODES ? new %s(%s) : new %s(%s); }", genClassName, callArgs, node.getSimpleName(), callArgs);
             throw new ElementException(constructor, "Missing Node class factory method '%s'", f);
         }
         if (!create.getModifiers().containsAll(asList(PUBLIC, STATIC))) {
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Thu Aug 28 17:49:37 2014 -0700
@@ -22,8 +22,11 @@
  */
 package com.oracle.graal.nodeinfo.processor;
 
+import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
+
 import java.io.*;
 import java.util.*;
+import java.util.stream.*;
 
 import javax.annotation.processing.*;
 import javax.lang.model.*;
@@ -46,23 +49,39 @@
         return SourceVersion.latest();
     }
 
+    /**
+     * Node class currently being processed.
+     */
+    private Element scope;
+
+    public static boolean isEnclosedIn(Element e, Element scopeElement) {
+        List<Element> elementHierarchy = getElementHierarchy(e);
+        return elementHierarchy.contains(scopeElement);
+    }
+
     void errorMessage(Element element, String format, Object... args) {
         message(Kind.ERROR, element, format, args);
     }
 
     void message(Kind kind, Element element, String format, Object... args) {
-        processingEnv.getMessager().printMessage(kind, String.format(format, args), element);
+        if (scope != null && !isEnclosedIn(element, scope)) {
+            // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=428357#c1
+            String loc = getElementHierarchy(element).stream().map(Object::toString).collect(Collectors.joining("."));
+            processingEnv.getMessager().printMessage(kind, String.format(loc + ": " + format, args), scope);
+        } else {
+            processingEnv.getMessager().printMessage(kind, String.format(format, args), element);
+        }
     }
 
     /**
      * Bugs in an annotation processor can cause silent failure so try to report any exception
      * throws as errors.
      */
-    private void reportException(Element element, Throwable t) {
+    private void reportException(Kind kind, Element element, Throwable t) {
         StringWriter buf = new StringWriter();
         t.printStackTrace(new PrintWriter(buf));
         buf.toString();
-        errorMessage(element, "Exception thrown during processing: %s", buf.toString());
+        message(kind, element, "Exception thrown during processing: %s", buf.toString());
     }
 
     ProcessingEnvironment getProcessingEnv() {
@@ -94,6 +113,7 @@
         GraphNodeGenerator gen = new GraphNodeGenerator(this);
 
         for (Element element : roundEnv.getElementsAnnotatedWith(NodeInfo.class)) {
+            scope = element;
             try {
                 if (!isNodeType(element)) {
                     errorMessage(element, "%s can only be applied to Node subclasses", NodeInfo.class.getSimpleName());
@@ -126,11 +146,9 @@
             } catch (ElementException ee) {
                 errorMessage(ee.element, ee.getMessage());
             } catch (Throwable t) {
-                if (!isBug367599(t)) {
-                    reportException(element, t);
-                } else {
-                    message(Kind.NOTE, element, t.toString());
-                }
+                reportException(isBug367599(t) ? Kind.NOTE : Kind.ERROR, element, t);
+            } finally {
+                scope = null;
             }
         }
         return false;
@@ -141,14 +159,16 @@
      * href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
      */
     public static boolean isBug367599(Throwable t) {
-        for (StackTraceElement ste : t.getStackTrace()) {
-            if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
-                // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
-                return true;
+        if (t instanceof FilerException) {
+            for (StackTraceElement ste : t.getStackTrace()) {
+                if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
+                    // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
+                    return true;
+                }
             }
-        }
-        if (t.getCause() != null) {
-            return isBug367599(t.getCause());
+            if (t.getCause() != null) {
+                return isBug367599(t.getCause());
+            }
         }
         return false;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -32,7 +32,7 @@
 @NodeInfo
 public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode {
 
-    @Input(InputType.Condition) LogicNode condition;
+    @Input(InputType.Condition) protected LogicNode condition;
     private final DeoptimizationReason reason;
     private final DeoptimizationAction action;
     private boolean negated;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -42,10 +42,6 @@
         return USE_GENERATED_NODES ? new BeginNodeGen() : new BeginNode();
     }
 
-    public static Class<? extends BeginNode> getGenClass() {
-        return USE_GENERATED_NODES ? BeginNodeGen.class : BeginNode.class;
-    }
-
     protected BeginNode() {
         super(StampFactory.forVoid());
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -30,10 +30,6 @@
         return USE_GENERATED_NODES ? new EndNodeGen() : new EndNode();
     }
 
-    public static Class<? extends EndNode> getGenClass() {
-        return USE_GENERATED_NODES ? EndNodeGen.class : EndNode.class;
-    }
-
     EndNode() {
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingAnchoredNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingAnchoredNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -30,7 +30,7 @@
 @NodeInfo
 public abstract class FloatingAnchoredNode extends FloatingNode {
 
-    @Input(InputType.Anchor) AnchoringNode anchor;
+    @Input(InputType.Anchor) protected AnchoringNode anchor;
 
     public FloatingAnchoredNode(Stamp stamp) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -44,7 +44,7 @@
 @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}", allowedUsageTypes = {InputType.Guard})
 public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, IterableNodeType, GuardingNode {
 
-    @Input(InputType.Condition) LogicNode condition;
+    @Input(InputType.Condition) protected LogicNode condition;
     private final DeoptimizationReason reason;
     private Constant speculation;
     private DeoptimizationAction action;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -220,7 +220,7 @@
         do {
             BeginNode trueSucc = trueSuccessor();
             BeginNode falseSucc = falseSuccessor();
-            if (trueSucc.getClass() == BeginNode.getGenClass() && falseSucc.getClass() == BeginNode.getGenClass() && trueSucc.next() instanceof FixedWithNextNode &&
+            if (trueSucc.getNodeClass().is(BeginNode.class) && falseSucc.getNodeClass().is(BeginNode.class) && trueSucc.next() instanceof FixedWithNextNode &&
                             falseSucc.next() instanceof FixedWithNextNode) {
                 FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -37,7 +37,7 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}", allowedUsageTypes = {InputType.Memory})
-public class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, IterableNodeType {
+public class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
 
     @Input(InputType.Extension) CallTargetNode callTarget;
     @OptionalInput(InputType.State) FrameState stateDuring;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -43,14 +43,10 @@
         return USE_GENERATED_NODES ? new MergeNodeGen() : new MergeNode();
     }
 
-    public static Class<? extends MergeNode> getGenClass() {
-        return USE_GENERATED_NODES ? MergeNodeGen.class : MergeNode.class;
+    protected MergeNode() {
     }
 
-    MergeNode() {
-    }
-
-    @Input(InputType.Association) NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
+    @Input(InputType.Association) protected NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,7 +39,7 @@
 @NodeInfo
 public abstract class PhiNode extends FloatingNode implements Simplifiable {
 
-    @Input(InputType.Association) MergeNode merge;
+    @Input(InputType.Association) protected MergeNode merge;
 
     protected PhiNode(Stamp stamp, MergeNode merge) {
         super(stamp);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -33,7 +33,7 @@
 @NodeInfo(nameTemplate = "ValuePhi({i#values})")
 public class ValuePhiNode extends PhiNode {
 
-    @Input NodeInputList<ValueNode> values;
+    @Input protected NodeInputList<ValueNode> values;
 
     /**
      * Create a value phi with the specified stamp.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,10 +39,6 @@
         return USE_GENERATED_NODES ? new AndNodeGen(x, y) : new AndNode(x, y);
     }
 
-    public static Class<? extends AndNode> getGenClass() {
-        return USE_GENERATED_NODES ? AndNodeGen.class : AndNode.class;
-    }
-
     AndNode(ValueNode x, ValueNode y) {
         super(StampTool.and(x.stamp(), y.stamp()), x, y);
         assert x.stamp().isCompatible(y.stamp());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -37,10 +37,6 @@
         return USE_GENERATED_NODES ? new FloatAddNodeGen(x, y, isStrictFP) : new FloatAddNode(x, y, isStrictFP);
     }
 
-    public static Class<? extends FloatAddNode> getGenClass() {
-        return USE_GENERATED_NODES ? FloatAddNodeGen.class : FloatAddNode.class;
-    }
-
     protected FloatAddNode(ValueNode x, ValueNode y, boolean isStrictFP) {
         super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -37,10 +37,6 @@
         return USE_GENERATED_NODES ? new FloatMulNodeGen(x, y, isStrictFP) : new FloatMulNode(x, y, isStrictFP);
     }
 
-    public static Class<? extends FloatMulNode> getGenClass() {
-        return USE_GENERATED_NODES ? FloatMulNodeGen.class : FloatMulNode.class;
-    }
-
     protected FloatMulNode(ValueNode x, ValueNode y, boolean isStrictFP) {
         super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -38,10 +38,6 @@
         return USE_GENERATED_NODES ? new FloatSubNodeGen(x, y, isStrictFP) : new FloatSubNode(x, y, isStrictFP);
     }
 
-    public static Class<? extends FloatSubNode> getGenClass() {
-        return USE_GENERATED_NODES ? FloatSubNodeGen.class : FloatSubNode.class;
-    }
-
     protected FloatSubNode(ValueNode x, ValueNode y, boolean isStrictFP) {
         super(x.stamp().unrestricted(), x, y, isStrictFP);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -38,10 +38,6 @@
         return USE_GENERATED_NODES ? new IntegerAddNodeGen(x, y) : new IntegerAddNode(x, y);
     }
 
-    public static Class<? extends IntegerAddNode> getGenClass() {
-        return USE_GENERATED_NODES ? IntegerAddNodeGen.class : IntegerAddNode.class;
-    }
-
     protected IntegerAddNode(ValueNode x, ValueNode y) {
         super(StampTool.add(x.stamp(), y.stamp()), x, y);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -97,7 +97,7 @@
         }
 
         if (next() instanceof IntegerDivNode) {
-            NodeClass nodeClass = NodeClass.get(this.getClass());
+            NodeClass nodeClass = getNodeClass();
             if (next().getClass() == this.getClass() && nodeClass.inputsEqual(this, next()) && nodeClass.valueEqual(this, next())) {
                 return next();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -38,10 +38,6 @@
         return USE_GENERATED_NODES ? new IntegerMulNodeGen(x, y) : new IntegerMulNode(x, y);
     }
 
-    public static Class<? extends IntegerMulNode> getGenClass() {
-        return USE_GENERATED_NODES ? IntegerMulNodeGen.class : IntegerMulNode.class;
-    }
-
     protected IntegerMulNode(ValueNode x, ValueNode y) {
         super(x.stamp().unrestricted(), x, y);
         assert x.stamp().isCompatible(y.stamp());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,10 +39,6 @@
         return USE_GENERATED_NODES ? new IntegerSubNodeGen(x, y) : new IntegerSubNode(x, y);
     }
 
-    public static Class<? extends IntegerSubNode> getGenClass() {
-        return USE_GENERATED_NODES ? IntegerSubNodeGen.class : IntegerSubNode.class;
-    }
-
     protected IntegerSubNode(ValueNode x, ValueNode y) {
         super(StampTool.sub(x.stamp(), y.stamp()), x, y);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,10 +39,6 @@
         return USE_GENERATED_NODES ? new OrNodeGen(x, y) : new OrNode(x, y);
     }
 
-    public static Class<? extends OrNode> getGenClass() {
-        return USE_GENERATED_NODES ? OrNodeGen.class : OrNode.class;
-    }
-
     OrNode(ValueNode x, ValueNode y) {
         super(StampTool.or(x.stamp(), y.stamp()), x, y);
         assert x.stamp().isCompatible(y.stamp());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -39,10 +39,6 @@
         return USE_GENERATED_NODES ? new XorNodeGen(x, y) : new XorNode(x, y);
     }
 
-    public static Class<? extends XorNode> getGenClass() {
-        return USE_GENERATED_NODES ? XorNodeGen.class : XorNode.class;
-    }
-
     protected XorNode(ValueNode x, ValueNode y) {
         super(StampTool.xor(x.stamp(), y.stamp()), x, y);
         assert x.stamp().isCompatible(y.stamp());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -34,7 +34,7 @@
 @NodeInfo
 public class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider {
 
-    @Input ValueNode length;
+    @Input protected ValueNode length;
 
     @Override
     public ValueNode length() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -42,7 +42,7 @@
         return USE_GENERATED_NODES ? new MonitorIdNodeGen(lockDepth) : new MonitorIdNode(lockDepth);
     }
 
-    MonitorIdNode(int lockDepth) {
+    protected MonitorIdNode(int lockDepth) {
         super(StampFactory.forVoid());
         this.lockDepth = lockDepth;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -51,7 +51,7 @@
         return USE_GENERATED_NODES ? new NewArrayNodeGen(elementType, length, fillContents) : new NewArrayNode(elementType, length, fillContents);
     }
 
-    NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+    protected NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
         super(StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Thu Aug 28 17:49:37 2014 -0700
@@ -116,7 +116,7 @@
                         parent = loops.get(null);
                         break;
                     } else {
-                        assert current.getClass() == MergeNode.getGenClass() : current;
+                        assert current.getNodeClass().is(MergeNode.class) : current;
                         // follow any path upwards - it doesn't matter which one
                         current = ((MergeNode) current).forwardEndAt(0);
                     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyNoNodeClassLiteralIdentityTests.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyNoNodeClassLiteralIdentityTests.java	Thu Aug 28 17:49:37 2014 -0700
@@ -38,8 +38,8 @@
  * Since only {@linkplain GeneratedNode generated} {@link Node} types can be instantiated (which is
  * checked by an assertion in {@link Node#Node()}), any identity test of a node's
  * {@linkplain Object#getClass() class} against a class literal of a non-generated node types will
- * always return false. Instead, a static {@code getGenClass()} helper method should be used for
- * such identity tests. For example, instead of:
+ * always return false. Instead, the {@link NodeClass#is(Class)} method should be used. For example,
+ * instead of:
  *
  * <pre>
  *     if (operation.getClass() == IntegerAddNode.class) { ... }
@@ -48,7 +48,7 @@
  * this should be used:
  *
  * <pre>
- *     if (operation.getClass() == IntegerAddNode.getGenClass()) { ... }
+ *     if (operation.getNodeClass().is(IntegerAddNode.class)) { ... }
  * </pre>
  *
  * This phase verifies there are no identity tests against class literals for non-generated Node
@@ -60,8 +60,10 @@
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         Map<String, String> errors = new HashMap<>();
 
+        MetaAccessProvider metaAccess = context.getMetaAccess();
+        ResolvedJavaType nodeClassType = metaAccess.lookupJavaType(Node.class);
+
         for (ConstantNode c : ConstantNode.getConstantNodes(graph)) {
-            ResolvedJavaType nodeClassType = context.getMetaAccess().lookupJavaType(Node.class);
             ResolvedJavaType nodeType = context.getConstantReflection().asJavaType(c.asConstant());
             if (nodeType != null && nodeClassType.isAssignableFrom(nodeType)) {
                 NodeIterable<Node> usages = c.usages();
@@ -69,10 +71,7 @@
                     if (!(n instanceof ObjectEqualsNode)) {
                         continue;
                     }
-                    String loc = GraphUtil.approxSourceLocation(n);
-                    if (loc == null) {
-                        loc = graph.method().asStackTraceElement(0).toString() + "  " + n;
-                    }
+                    String loc = getLocation(n, graph);
                     errors.put(nodeType.toJavaName(false), loc);
                 }
             }
@@ -92,4 +91,15 @@
         }
         throw new VerificationError(f.toString());
     }
+
+    private static String getLocation(Node node, StructuredGraph graph) {
+        String loc = GraphUtil.approxSourceLocation(node);
+        StackTraceElement ste = graph.method().asStackTraceElement(0);
+        if (loc == null) {
+            loc = ste.toString();
+        } else {
+            loc = ste.getClassName() + "." + ste.getMethodName() + "(" + loc + ")";
+        }
+        return loc;
+    }
 }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Thu Aug 28 17:49:37 2014 -0700
@@ -273,24 +273,20 @@
             }
         }
 
-        // Currently no node printing for lir
-        if (lir == null) {
-            Node cur = block.getBeginNode();
-            while (true) {
-                printNode(cur, false);
+        Node cur = block.getBeginNode();
+        while (true) {
+            printNode(cur, false);
 
-                if (cur == block.getEndNode()) {
-                    for (Map.Entry<Node, Block> entry : latestScheduling.entries()) {
-                        if (entry.getValue() == block && !inFixedSchedule(entry.getKey()) && !printedNodes.isMarked(entry.getKey())) {
-                            printNode(entry.getKey(), true);
-                        }
+            if (cur == block.getEndNode()) {
+                for (Map.Entry<Node, Block> entry : latestScheduling.entries()) {
+                    if (entry.getValue() == block && !inFixedSchedule(entry.getKey()) && !printedNodes.isMarked(entry.getKey())) {
+                        printNode(entry.getKey(), true);
                     }
-                    break;
                 }
-                assert cur.successors().count() == 1;
-                cur = cur.successors().first();
+                break;
             }
-
+            assert cur.successors().count() == 1;
+            cur = cur.successors().first();
         }
 
         out.enableIndentation();
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Thu Aug 28 17:49:37 2014 -0700
@@ -50,7 +50,6 @@
     private JavaMethod curMethod;
     private List<String> curDecorators = Collections.emptyList();
     private final boolean dumpFrontend;
-    private Object previousObject;
 
     public CFGPrinterObserver(boolean dumpFrontend) {
         this.dumpFrontend = dumpFrontend;
@@ -162,10 +161,8 @@
             }
 
         } else if (object instanceof LIR) {
-            // No need to print the HIR nodes again if this is not the first
-            // time dumping the same LIR since the HIR will not have changed.
-            boolean printNodes = previousObject != object && cfgPrinter.cfg != null;
-            cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), printNodes);
+            // Currently no node printing for lir
+            cfgPrinter.printCFG(message, cfgPrinter.lir.codeEmittingOrder(), false);
 
         } else if (object instanceof SchedulePhase) {
             cfgPrinter.printSchedule(message, (SchedulePhase) object);
@@ -193,7 +190,6 @@
         cfgPrinter.cfg = null;
         cfgPrinter.flush();
 
-        previousObject = object;
     }
 
     private static boolean isCompilationResultAndInstalledCode(Object object) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Thu Aug 28 17:49:37 2014 -0700
@@ -174,9 +174,9 @@
                     printProperty(bit, "true");
                 }
             }
-            if (node.getClass() == BeginNode.getGenClass()) {
+            if (node.getNodeClass().is(BeginNode.class)) {
                 printProperty("shortName", "B");
-            } else if (node.getClass() == EndNode.getGenClass()) {
+            } else if (node.getNodeClass().is(EndNode.class)) {
                 printProperty("shortName", "E");
             }
             if (node.predecessor() != null) {
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Aug 28 17:49:37 2014 -0700
@@ -81,6 +81,7 @@
     private final ResolvedJavaMethod[] callNodeMethod;
     private final ResolvedJavaMethod[] callTargetMethod;
     private final ResolvedJavaMethod[] anyFrameMethod;
+    private final Map<RootCallTarget, Void> callTargets = Collections.synchronizedMap(new WeakHashMap<RootCallTarget, Void>());
 
     private HotSpotTruffleRuntime() {
         installOptimizedCallTargetCallMethod();
@@ -115,7 +116,10 @@
         } else {
             compilationPolicy = new InterpreterOnlyCompilationPolicy();
         }
-        return new OptimizedCallTarget(rootNode, this, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), compilationPolicy, new HotSpotSpeculationLog());
+        OptimizedCallTarget target = new OptimizedCallTarget(rootNode, this, TruffleMinInvokeThreshold.getValue(), TruffleCompilationThreshold.getValue(), compilationPolicy,
+                        new HotSpotSpeculationLog());
+        callTargets.put(target, null);
+        return target;
     }
 
     public LoopNode createLoopNode(RepeatingNode repeating) {
@@ -361,6 +365,11 @@
         installOptimizedCallTargetCallMethod();
     }
 
+    @Override
+    public List<RootCallTarget> getCallTargets() {
+        return new ArrayList<>(callTargets.keySet());
+    }
+
     public void notifyTransferToInterpreter() {
         CompilerAsserts.neverPartOfCompilation();
         if (TraceTruffleTransferToInterpreter.getValue()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Thu Aug 28 17:49:37 2014 -0700
@@ -333,6 +333,9 @@
     public final Object callInlined(Object[] arguments) {
         if (CompilerDirectives.inInterpreter()) {
             compilationProfile.reportInlinedCall();
+            if (isValid()) {
+                return callDirect(arguments);
+            }
         }
         VirtualFrame frame = createFrame(getRootNode().getFrameDescriptor(), arguments);
         return callProxy(frame);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -23,7 +23,6 @@
 package com.oracle.graal.truffle;
 
 import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -33,36 +32,24 @@
  */
 public final class OptimizedLoopNode extends LoopNode {
 
-    @CompilationFinal private int loopCount;
-
     public OptimizedLoopNode(RepeatingNode body) {
         super(body);
     }
 
     @Override
     public void executeLoop(VirtualFrame frame) {
+        int loopCount = 0;
         try {
-            do {
-            } while (executeBody(frame));
+            while (executeRepeatingNode(frame)) {
+                if (CompilerDirectives.inInterpreter()) {
+                    loopCount++;
+                }
+            }
         } finally {
-            loopDone();
+            if (CompilerDirectives.inInterpreter()) {
+                getRootNode().reportLoopCount(loopCount);
+            }
         }
     }
 
-    private final boolean executeBody(VirtualFrame frame) {
-        boolean result = executeRepeatNode(frame);
-        if (CompilerDirectives.inInterpreter()) {
-            if (result) {
-                loopCount++;
-            }
-        }
-        return result;
-    }
-
-    private void loopDone() {
-        if (CompilerDirectives.inInterpreter()) {
-            getRootNode().reportLoopCount(loopCount);
-            loopCount = 0;
-        }
-    }
-}
\ No newline at end of file
+}
--- a/graal/com.oracle.nfi.test/test/com/oracle/nfi/test/NativeFunctionInterfaceTest.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.nfi.test/test/com/oracle/nfi/test/NativeFunctionInterfaceTest.java	Thu Aug 28 17:49:37 2014 -0700
@@ -347,46 +347,50 @@
     @Test
     public void test15() {
         assumeTrue(nfi.isDefaultLibrarySearchSupported());
-        try {
-            nfi.getFunctionHandle("an invalid function name", int.class);
+        NativeFunctionHandle functionHandle = nfi.getFunctionHandle("an invalid function name", int.class);
+        if (functionHandle != null) {
             fail();
-        } catch (UnsatisfiedLinkError e) {
         }
     }
 
     @Test
     public void test16() {
         NativeLibraryHandle javaLib = nfi.getLibraryHandle(getJavaLibPath());
-        try {
-
-            nfi.getFunctionHandle(javaLib, "an invalid function name", int.class);
+        NativeFunctionHandle functionHandle = nfi.getFunctionHandle(javaLib, "an invalid function name", int.class);
+        if (functionHandle != null) {
             fail();
-        } catch (UnsatisfiedLinkError e) {
         }
     }
 
     @Test
     public void test17() {
         NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())};
-        try {
-            nfi.getFunctionPointer(libs, "an invalid function name");
+        NativeFunctionHandle functionHandle = nfi.getFunctionHandle(libs, "an invalid function name", int.class);
+        if (functionHandle != null) {
             fail();
-        } catch (UnsatisfiedLinkError e) {
         }
     }
 
     @Test
     public void test18() {
         NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())};
-        try {
-            nfi.getFunctionHandle(libs, "an invalid function name", int.class);
+        NativeFunctionHandle functionHandle = nfi.getFunctionHandle(libs, "an invalid function name", int.class);
+        if (functionHandle != null) {
             fail();
-        } catch (UnsatisfiedLinkError e) {
         }
     }
 
     @Test
     public void test19() {
+        NativeLibraryHandle[] libs = {nfi.getLibraryHandle(getVMLibPath()), nfi.getLibraryHandle(getJavaLibPath())};
+        NativeFunctionPointer functionPointer = nfi.getFunctionPointer(libs, "an invalid function name");
+        if (functionPointer != null) {
+            fail();
+        }
+    }
+
+    @Test
+    public void test20() {
         try {
             nfi.getLibraryHandle("an invalid library name");
             fail();
--- a/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionInterface.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionInterface.java	Thu Aug 28 17:49:37 2014 -0700
@@ -51,8 +51,8 @@
      *
      * @param libraries the ordered list of libraries to search for the function
      * @param name the name of the function to be resolved
-     * @return a pointer to the native function
-     * @throws UnsatisfiedLinkError if the function could not be resolved
+     * @return a pointer to the native function, or <code>null</code> if the function pointer could
+     *         not be resolved
      */
     NativeFunctionPointer getFunctionPointer(NativeLibraryHandle[] libraries, String name);
 
@@ -65,8 +65,8 @@
      * @param name the name of the function to be resolved
      * @param returnType the type of the return value
      * @param argumentTypes the types of the arguments
-     * @return the function handle of the native function
-     * @throws UnsatisfiedLinkError if the function handle could not be resolved
+     * @return the function handle of the native function, or <code>null</code> if the function
+     *         handle could not be resolved
      */
     NativeFunctionHandle getFunctionHandle(NativeLibraryHandle library, String name, Class<?> returnType, Class<?>... argumentTypes);
 
@@ -78,8 +78,8 @@
      * @param functionPointer a function pointer
      * @param returnType the type of the return value
      * @param argumentTypes the types of the arguments
-     * @return the function handle of the native function
-     * @throws UnsatisfiedLinkError the function handle could not be created
+     * @return the function handle of the native function, or <code>null</code> if the function
+     *         handle could not be resolved
      */
     NativeFunctionHandle getFunctionHandle(NativeFunctionPointer functionPointer, Class<?> returnType, Class<?>... argumentTypes);
 
@@ -92,8 +92,8 @@
      * @param name the name of the function to be resolved
      * @param returnType the type of the return value
      * @param argumentTypes the types of the arguments
-     * @return the function handle of the native function
-     * @throws UnsatisfiedLinkError if the function handle could not be created
+     * @return the function handle of the native function, or <code>null</code> if the function
+     *         handle could not be resolved
      */
     NativeFunctionHandle getFunctionHandle(NativeLibraryHandle[] libraries, String name, Class<?> returnType, Class<?>... argumentTypes);
 
@@ -105,10 +105,9 @@
      * @param name the name of the function to be resolved
      * @param returnType the type of the return value
      * @param argumentTypes the types of the arguments
-     * @return the function handle of the native function
-     * @throws UnsatisfiedLinkError if default library searching is not
-     *             {@linkplain #isDefaultLibrarySearchSupported() supported} or if the function
-     *             could not be resolved
+     * @return the function handle of the native function, or <code>null</code> if default library
+     *         searching is not {@linkplain #isDefaultLibrarySearchSupported() supported} or if the
+     *         function could not be resolved
      */
     NativeFunctionHandle getFunctionHandle(String name, Class<?> returnType, Class<?>... argumentTypes);
 
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Thu Aug 28 17:49:37 2014 -0700
@@ -26,12 +26,16 @@
 import static org.hamcrest.CoreMatchers.*;
 import static org.junit.Assert.*;
 
+import org.junit.*;
 import org.junit.experimental.theories.*;
 import org.junit.runner.*;
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.dsl.test.SourceSectionTestFactory.SourceSection0Factory;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.*;
+import com.oracle.truffle.api.dsl.test.SourceSectionTestFactory.SourceSection1Factory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 
@@ -54,7 +58,7 @@
         expectSourceSection(root.getNode(), section);
     }
 
-    private void expectSourceSection(Node root, SourceSection section) {
+    private static void expectSourceSection(Node root, SourceSection section) {
         assertThat(root.getSourceSection(), is(sameInstance(section)));
         for (Node child : root.getChildren()) {
             if (child instanceof ArgumentNode) {
@@ -101,4 +105,33 @@
             return a; // the generic answer to all questions
         }
     }
+
+    @Test
+    public void testCreateCast() {
+        SourceSection section = new NullSourceSection("a", "b");
+        TestRootNode<SourceSection1> root = createRootPrefix(SourceSection1Factory.getInstance(), true, section);
+        expectSourceSection(root.getNode(), section);
+        assertThat((int) executeWith(root, 1), is(1));
+        expectSourceSection(root.getNode(), section);
+    }
+
+    @NodeChild("a")
+    static class SourceSection1 extends ValueNode {
+
+        public SourceSection1(SourceSection section) {
+            super(section);
+        }
+
+        @CreateCast("a")
+        public ValueNode cast(ValueNode node) {
+            assert getSourceSection() != null;
+            return node;
+        }
+
+        @Specialization
+        int do0(int a) {
+            return a;
+        }
+
+    }
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,7 +24,6 @@
 
 import static org.junit.Assert.*;
 
-import java.lang.reflect.*;
 import java.util.*;
 
 import com.oracle.truffle.api.*;
@@ -47,41 +46,32 @@
         return nodes;
     }
 
-    static <E extends ValueNode> E createNode(NodeFactory<E> factory, Object... constants) {
+    static <E extends ValueNode> E createNode(NodeFactory<E> factory, boolean prefixConstants, Object... constants) {
         ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size());
 
         List<Object> argumentList = new ArrayList<>();
+        if (prefixConstants) {
+            argumentList.addAll(Arrays.asList(constants));
+        }
         if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass())) {
             argumentList.add(argumentNodes);
         } else {
             argumentList.addAll(Arrays.asList(argumentNodes));
         }
-        argumentList.addAll(Arrays.asList(constants));
+        if (!prefixConstants) {
+            argumentList.addAll(Arrays.asList(constants));
+        }
         return factory.createNode(argumentList.toArray(new Object[argumentList.size()]));
     }
 
-    static <E extends ValueNode> E createGenericNode(NodeFactory<E> factory, Object... constants) {
-        Method createGenericMethod;
-        try {
-            createGenericMethod = factory.getClass().getMethod("createGeneric", factory.getNodeClass());
-        } catch (NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        }
-        try {
-            return factory.getNodeClass().cast(createGenericMethod.invoke(null, createNode(factory, constants)));
-        } catch (IllegalAccessException | InvocationTargetException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     static <E extends ValueNode> TestRootNode<E> createRoot(NodeFactory<E> factory, Object... constants) {
-        TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, constants));
+        TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, false, constants));
         rootNode.adoptChildren();
         return rootNode;
     }
 
-    static <E extends ValueNode> TestRootNode<E> createGenericRoot(NodeFactory<E> factory, Object... constants) {
-        TestRootNode<E> rootNode = new TestRootNode<>(createGenericNode(factory, constants));
+    static <E extends ValueNode> TestRootNode<E> createRootPrefix(NodeFactory<E> factory, boolean prefixConstants, Object... constants) {
+        TestRootNode<E> rootNode = new TestRootNode<>(createNode(factory, prefixConstants, constants));
         rootNode.adoptChildren();
         return rootNode;
     }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java	Thu Aug 28 17:49:37 2014 -0700
@@ -28,6 +28,7 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 public class TypeSystemTest {
 
@@ -69,6 +70,10 @@
             super(null);
         }
 
+        public ValueNode(SourceSection sourceSection) {
+            super(sourceSection);
+        }
+
         public int executeInt(VirtualFrame frame) throws UnexpectedResultException {
             return SimpleTypesGen.SIMPLETYPES.expectInteger(execute(frame));
         }
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleRuntimeTest.java	Thu Aug 28 17:49:37 2014 -0700
@@ -22,13 +22,20 @@
  */
 package com.oracle.truffle.api.test;
 
+import static org.junit.Assert.*;
+
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.source.*;
 
 /**
  * <h3>Accessing the Truffle Runtime</h3>
- * 
+ *
  * <p>
  * The Truffle runtime can be accessed at any point in time globally using the static method
  * {@link Truffle#getRuntime()}. This method is guaranteed to return a non-null Truffle runtime
@@ -36,7 +43,7 @@
  * default implementation of the {@link TruffleRuntime} interface with its own implementation for
  * providing improved performance.
  * </p>
- * 
+ *
  * <p>
  * The next part of the Truffle API introduction is at
  * {@link com.oracle.truffle.api.test.RootNodeTest}.
@@ -44,10 +51,104 @@
  */
 public class TruffleRuntimeTest {
 
+    private TruffleRuntime runtime;
+
+    @Before
+    public void setup() {
+        this.runtime = Truffle.getRuntime();
+    }
+
+    private static RootNode createTestRootNode() {
+        return new RootNode() {
+            @Override
+            public Object execute(VirtualFrame frame) {
+                return 42;
+            }
+        };
+    }
+
     @Test
     public void test() {
-        TruffleRuntime runtime = Truffle.getRuntime();
-        Assert.assertNotNull(runtime);
-        Assert.assertNotNull(runtime.getName());
+        assertNotNull(runtime);
+        assertNotNull(runtime.getName());
+    }
+
+    @Test
+    public void testCreateCallTarget() {
+        RootNode rootNode = createTestRootNode();
+        RootCallTarget target = runtime.createCallTarget(rootNode);
+        assertNotNull(target);
+        assertEquals(target.call(), 42);
+        assertSame(rootNode, target.getRootNode());
+    }
+
+    @Test
+    public void testGetCallTargets1() {
+        RootNode rootNode = createTestRootNode();
+        RootCallTarget target = runtime.createCallTarget(rootNode);
+        assertTrue(runtime.getCallTargets().indexOf(target) != -1);
+    }
+
+    @Test
+    public void testGetCallTargets2() {
+        RootNode rootNode = createTestRootNode();
+        RootCallTarget target1 = runtime.createCallTarget(rootNode);
+        RootCallTarget target2 = runtime.createCallTarget(rootNode);
+        assertTrue(runtime.getCallTargets().indexOf(target1) != -1);
+        assertTrue(runtime.getCallTargets().indexOf(target2) != -1);
+    }
+
+    /*
+     * This test case documents the use case for profilers and debuggers where they need to access
+     * multiple call targets for the same source section. This case may happen when the optimization
+     * system decides to duplicate call targets to achieve better performance.
+     */
+    @Test
+    public void testGetCallTargets3() {
+        Source source1 = Source.fromText("a\nb\n", "");
+        SourceSection sourceSection1 = source1.createSection("foo", 1);
+        SourceSection sourceSection2 = source1.createSection("bar", 2);
+
+        RootNode rootNode1 = createTestRootNode();
+        rootNode1.assignSourceSection(sourceSection1);
+        RootNode rootNode2 = createTestRootNode();
+        rootNode2.assignSourceSection(sourceSection2);
+        RootNode rootNode2Copy = NodeUtil.cloneNode(rootNode2);
+
+        assertSame(rootNode2.getSourceSection(), rootNode2Copy.getSourceSection());
+
+        RootCallTarget target1 = runtime.createCallTarget(rootNode1);
+        RootCallTarget target2 = runtime.createCallTarget(rootNode2);
+        RootCallTarget target2Copy = runtime.createCallTarget(rootNode2Copy);
+
+        Map<SourceSection, List<RootCallTarget>> groupedTargets = groupUniqueCallTargets();
+
+        List<RootCallTarget> targets1 = groupedTargets.get(sourceSection1);
+        assertEquals(1, targets1.size());
+        assertEquals(target1, targets1.get(0));
+
+        List<RootCallTarget> targets2 = groupedTargets.get(sourceSection2);
+        assertEquals(2, targets2.size());
+        // order of targets2 is not guaranteed
+        assertTrue(target2 == targets2.get(0) ^ target2Copy == targets2.get(0));
+        assertTrue(target2 == targets2.get(1) ^ target2Copy == targets2.get(1));
+    }
+
+    private static Map<SourceSection, List<RootCallTarget>> groupUniqueCallTargets() {
+        Map<SourceSection, List<RootCallTarget>> groupedTargets = new HashMap<>();
+        for (RootCallTarget target : Truffle.getRuntime().getCallTargets()) {
+            SourceSection section = target.getRootNode().getSourceSection();
+            if (section == null) {
+                // can not identify root node to a unique call target. Print warning?
+                continue;
+            }
+            List<RootCallTarget> targets = groupedTargets.get(section);
+            if (targets == null) {
+                targets = new ArrayList<>();
+                groupedTargets.put(section, targets);
+            }
+            targets.add(target);
+        }
+        return groupedTargets;
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleRuntime.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,6 +24,8 @@
  */
 package com.oracle.truffle.api;
 
+import java.util.*;
+
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -137,6 +139,12 @@
     FrameInstance getCurrentFrame();
 
     /**
+     * Returns a list of all still referenced {@link RootCallTarget} instances that were created
+     * using {@link #createCallTarget(RootNode)}.
+     */
+    List<RootCallTarget> getCallTargets();
+
+    /**
      * Internal API method. Do not use.
      */
     void notifyTransferToInterpreter();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -35,7 +35,7 @@
 
     @Override
     public void executeLoop(VirtualFrame frame) {
-        do {
-        } while (executeRepeatNode(frame));
+        while (executeRepeatingNode(frame)) {
+        }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Aug 28 17:49:37 2014 -0700
@@ -41,6 +41,7 @@
 
     private ThreadLocal<LinkedList<FrameInstance>> stackTraces = new ThreadLocal<>();
     private ThreadLocal<FrameInstance> currentFrames = new ThreadLocal<>();
+    private final Map<RootCallTarget, Void> callTargets = Collections.synchronizedMap(new WeakHashMap<RootCallTarget, Void>());
 
     public DefaultTruffleRuntime() {
         if (Truffle.getRuntime() != null) {
@@ -55,7 +56,9 @@
 
     @Override
     public RootCallTarget createCallTarget(RootNode rootNode) {
-        return new DefaultCallTarget(rootNode, this);
+        DefaultCallTarget target = new DefaultCallTarget(rootNode, this);
+        callTargets.put(target, null);
+        return target;
     }
 
     public DirectCallNode createDirectCallNode(CallTarget target) {
@@ -132,6 +135,11 @@
     }
 
     @Override
+    public List<RootCallTarget> getCallTargets() {
+        return new ArrayList<>(callTargets.keySet());
+    }
+
+    @Override
     public FrameInstance getCurrentFrame() {
         return currentFrames.get();
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumentable.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrumentable.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,25 +24,20 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
-
+/**
+ * Any Truffle node implementing this interface can be "instrumented" by installing a {@link Probe}
+ * that intercepts {@link ExecutionEvents} at the node and routes them to any {@link Instrument}s
+ * that have been attached to the {@link Probe}. Only one {@link Probe} may be installed at each
+ * node; subsequent calls return the one already installed.
+ */
 public interface Instrumentable {
 
     /**
-     * Optionally applies <em>instrumentation</em> at a Truffle AST node, depending on guest
-     * language characteristics and use-case policy. Ideally, the parent node of the guest language
-     * implements this interface.
-     * <ul>
-     * <li>if no instrumentation is to be applied, returns the AST node unmodified;</li>
-     * <li>if an AST node is to be instrumented, then creates a new Wrapper that <em>decorates</em>
-     * the AST node. Additionally, this creates a probe on the wrapper that is to be used for
-     * attaching instruments. This {@link Probe} is notified of all {@link ExecutionEvents} at the
-     * wrapped AST node.</li>
-     * </ul>
+     * Enables "instrumentation" of this Truffle node by tools, where this node is presumed to be
+     * part (and not the root of) of a well-formed Truffle AST that is not being executed. The AST
+     * may be modified.
      *
-     * @param context The {@link ExecutionContext} of the guest language used to create probes on
-     *            the wrapper.
      * @return The probe that was created.
      */
-    public Probe probe(ExecutionContext context);
+    Probe probe();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Visualizer.java	Thu Aug 28 17:49:37 2014 -0700
@@ -37,6 +37,7 @@
  */
 public interface Visualizer {
 
+    // TODO (mlvdv) "Visualizer" is misleading: rename.
     /**
      * Gets a printer for Truffle ASTs, possibly specialized to be helpful for a specific guest
      * language implementation.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/InstrumentationNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -343,18 +343,18 @@
          * {@link Node#getSourceSection()}, which is {@code null} for all instances of
          * {@link InstrumentationNode} since they have no corresponding source of their own.
          */
-        private final SourceSection source;
+        private final SourceSection probedSourceSection;
 
         /**
          * Constructor.
          *
-         * @param source The {@link SourceSection} associated with this probe.
+         * @param probedSourceSection The {@link SourceSection} associated with this probe.
          * @param probeCallback The {@link ProbeCallback} to inform when tags have been added to
          *            this probe.
          */
-        private ProbeImpl(SourceSection source, ProbeCallback probeCallback) {
+        private ProbeImpl(SourceSection probedSourceSection, ProbeCallback probeCallback) {
             this.probeCallback = probeCallback;
-            this.source = source;
+            this.probedSourceSection = probedSourceSection;
             this.probeUnchanged = Truffle.getRuntime().createAssumption();
             this.next = null;
         }
@@ -363,7 +363,7 @@
          * Returns the {@link SourceSection} associated with this probe.
          */
         public SourceSection getSourceLocation() {
-            return source;
+            return probedSourceSection;
         }
 
         /**
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToProbeCollectionMap.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,6 +24,7 @@
  */
 package com.oracle.truffle.api.instrument.impl;
 
+import java.io.*;
 import java.util.*;
 
 import com.oracle.truffle.api.instrument.*;
@@ -35,6 +36,9 @@
  */
 public class LineLocationToProbeCollectionMap implements ProbeListener {
 
+    private static final boolean TRACE = false;
+    private static final PrintStream OUT = System.out;
+
     /**
      * Map: Source line ==> probes associated with source sections starting on the line.
      */
@@ -44,8 +48,13 @@
     }
 
     public void newProbeInserted(SourceSection source, Probe probe) {
-        if (source != null && !(source instanceof NullSourceSection))
-            this.addProbeToLine(source.getLineLocation(), probe);
+        if (source != null && !(source instanceof NullSourceSection)) {
+            final LineLocation lineLocation = source.getLineLocation();
+            if (TRACE) {
+                OUT.println("LineLocationToProbeCollectionMap: adding " + lineLocation + " Probe=" + probe);
+            }
+            this.addProbeToLine(lineLocation, probe);
+        }
     }
 
     public void probeTaggedAs(Probe probe, SyntaxTag tag) {
@@ -98,9 +107,9 @@
     }
 
     /**
-     * 
+     *
      * Returns a collection of {@link Probe}s whose associated source begins at the given
-     * {@link LineLocation}. If there are no probes at that line, an empty list is returned.
+     * {@link LineLocation}, an empty list if none.
      *
      * @param line The line to check.
      * @return A collection of probes at the given line.
@@ -108,24 +117,28 @@
     public Collection<Probe> getProbesAtLine(LineLocation line) {
         Collection<Probe> probeList = lineToProbesMap.get(line);
 
-        if (probeList == null)
-            probeList = new ArrayList<>(1);
-
+        if (probeList == null) {
+            return Collections.emptyList();
+        }
         return probeList;
     }
 
     /**
      * Convenience method to get probes according to a int line number. Returns a collection of
-     * {@link Probe}s at the given line number. If there are no probes at that line, a new empty
-     * list is returned.
+     * {@link Probe}s at the given line number, an empty list if none.
      *
      * @param lineNumber The line number to check.
-     * @return A iterable collection of probes at the given line.
+     * @return A collection of probes at the given line.
      */
     public Collection<Probe> getProbesAtLineNumber(int lineNumber) {
-        ArrayList<Probe> probes = new ArrayList<>();
 
-        for (LineLocation line : lineToProbesMap.keySet()) {
+        final Set<LineLocation> keySet = lineToProbesMap.keySet();
+        if (keySet.size() == 0) {
+            return Collections.emptyList();
+        }
+
+        ArrayList<Probe> probes = new ArrayList<>();
+        for (LineLocation line : keySet) {
             if (line.getLineNumber() == lineNumber)
                 probes.addAll(lineToProbesMap.get(line));
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/LineLocationToSourceSectionCollectionMap.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,6 +24,7 @@
  */
 package com.oracle.truffle.api.instrument.impl;
 
+import java.io.*;
 import java.util.*;
 
 import com.oracle.truffle.api.instrument.*;
@@ -37,18 +38,24 @@
  */
 public class LineLocationToSourceSectionCollectionMap implements ProbeListener {
 
+    private static final boolean TRACE = false;
+    private static final PrintStream OUT = System.out;
+
     /**
      * Map: Source line ==> source sections that exist on the line.
      */
     private final Map<LineLocation, Collection<SourceSection>> lineToSourceSectionsMap = new HashMap<>();
 
     public LineLocationToSourceSectionCollectionMap() {
-
     }
 
     public void newProbeInserted(SourceSection sourceSection, Probe probe) {
         if (sourceSection != null && !(sourceSection instanceof NullSourceSection)) {
-            this.addSourceSectionToLine(sourceSection.getLineLocation(), sourceSection);
+            final LineLocation lineLocation = sourceSection.getLineLocation();
+            if (TRACE) {
+                OUT.println("LineLocationToSourceSectionCollectionMap: adding " + lineLocation + " Probe=" + probe);
+            }
+            this.addSourceSectionToLine(lineLocation, sourceSection);
         }
     }
 
@@ -82,33 +89,38 @@
     }
 
     /**
-     * Returns a collection of {@link SourceSection}s at the given {@link LineLocation}. If there
-     * are no source sections at that line, a new empty list of size 1 is returned.
+     * Returns a collection of {@link SourceSection}s at the given {@link LineLocation}, an empty
+     * list if none.
      *
      * @param line The line to check.
-     * @return A iterable collection of source sections at the given line.
+     * @return the source sections at the given line.
      */
     public Collection<SourceSection> getSourceSectionsAtLine(LineLocation line) {
         Collection<SourceSection> sourceSectionList = lineToSourceSectionsMap.get(line);
 
-        if (sourceSectionList == null)
-            sourceSectionList = new ArrayList<>(1);
-
+        if (sourceSectionList == null) {
+            return Collections.emptyList();
+        }
         return sourceSectionList;
     }
 
     /**
      * Convenience method to get source sections according to a int line number. Returns a
      * collection of {@link SourceSection}s at the given line number. If there are no source
-     * sections at that line, a new empty list is returned.
+     * sections at that line, an empty list is returned.
      *
      * @param lineNumber The line number to check.
-     * @return A iterable collection of source sections at the given line.
+     * @return A collection of source sections at the given line.
      */
     public Collection<SourceSection> getSourceSectionsAtLineNumber(int lineNumber) {
-        ArrayList<SourceSection> sourceSections = new ArrayList<>();
 
-        for (LineLocation line : lineToSourceSectionsMap.keySet()) {
+        final Set<LineLocation> keySet = lineToSourceSectionsMap.keySet();
+        if (keySet.size() == 0) {
+            return Collections.emptyList();
+        }
+
+        final ArrayList<SourceSection> sourceSections = new ArrayList<>();
+        for (LineLocation line : keySet) {
             if (line.getLineNumber() == lineNumber)
                 sourceSections.addAll(lineToSourceSectionsMap.get(line));
         }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -36,17 +36,17 @@
      */
     @Child protected Node repeatingNode;
 
-    public LoopNode(RepeatingNode repeatintNode) {
-        this.repeatingNode = (Node) repeatintNode;
+    public LoopNode(RepeatingNode repeatingNode) {
+        this.repeatingNode = (Node) repeatingNode;
     }
 
     public abstract void executeLoop(VirtualFrame frame);
 
-    protected final boolean executeRepeatNode(VirtualFrame frame) {
-        return getRepeatNode().executeRepeating(frame);
+    protected final boolean executeRepeatingNode(VirtualFrame frame) {
+        return getRepeatingNode().executeRepeating(frame);
     }
 
-    public final RepeatingNode getRepeatNode() {
+    public final RepeatingNode getRepeatingNode() {
         return (RepeatingNode) repeatingNode;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/Source.java	Thu Aug 28 17:49:37 2014 -0700
@@ -73,7 +73,7 @@
     // TOOD (mlvdv) connect SourceSections into a spatial tree for fast geometric lookup
 
     // Files and pseudo files are indexed.
-    private static final Map<String, WeakReference<Source>> filePathToSource = new HashMap<>();
+    private static final Map<String, WeakReference<Source>> filePathToSource = new Hashtable<>();
 
     private static boolean fileCacheEnabled = true;
 
@@ -171,6 +171,7 @@
         return source;
     }
 
+    // TODO (mlvdv) enable per-file choice whether to cache?
     /**
      * Enables/disables caching of file contents, <em>disabled</em> by default. Caching of sources
      * created from literal text or readers is always enabled.
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Aug 28 17:49:37 2014 -0700
@@ -34,7 +34,6 @@
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.model.*;
 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.DeclaredCodeTypeMirror;
-import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.WildcardTypeMirror;
 
 /**
  * THIS IS NOT PUBLIC API.
@@ -217,7 +216,7 @@
     }
 
     public static boolean isSubtype(TypeMirror type1, TypeMirror type2) {
-        if (type1 instanceof CodeTypeMirror && type2 instanceof CodeTypeMirror) {
+        if (type1 instanceof CodeTypeMirror || type2 instanceof CodeTypeMirror) {
             throw new UnsupportedOperationException();
         }
         return ProcessorContext.getInstance().getEnvironment().getTypeUtils().isSubtype(type1, type2);
@@ -1046,11 +1045,7 @@
         }
         int typeParameters = element.getTypeParameters().size();
         if (typeParameters > 0 && declaredType.getTypeArguments().size() != typeParameters) {
-            List<TypeMirror> genericTypes = new ArrayList<>();
-            for (int i = 0; i < typeParameters; i++) {
-                genericTypes.add(new WildcardTypeMirror(null, null));
-            }
-            return new DeclaredCodeTypeMirror(element, genericTypes);
+            return ProcessorContext.getInstance().getEnvironment().getTypeUtils().erasure(type);
         }
         return type;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JDTCompiler.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/compiler/JDTCompiler.java	Thu Aug 28 17:49:37 2014 -0700
@@ -52,7 +52,7 @@
     private static List<? extends Element> sortBySourceOrder(List<Element> elements) {
         final Map<TypeElement, List<Object>> declarationOrders = new HashMap<>();
 
-        Collections.sort(elements, new Comparator<Element>() {
+        Comparator<Element> comparator = new Comparator<Element>() {
             public int compare(Element o1, Element o2) {
                 try {
                     TypeMirror enclosing1 = o1.getEnclosingElement().asType();
@@ -60,6 +60,7 @@
 
                     if (ElementUtils.typeEquals(enclosing1, enclosing2)) {
                         List<Object> declarationOrder = lookupDeclarationOrder(declarationOrders, (TypeElement) o1.getEnclosingElement());
+
                         if (declarationOrder == null) {
                             return 0;
                         }
@@ -69,21 +70,25 @@
                         int i1 = declarationOrder.indexOf(o1Binding);
                         int i2 = declarationOrder.indexOf(o2Binding);
 
+                        if (i1 == -1 || i2 == -1) {
+                            return 0;
+                        }
+
                         return i1 - i2;
                     } else {
                         if (ElementUtils.isSubtype(enclosing1, enclosing2)) {
                             return 1;
-                        } else if (ElementUtils.isSubtype(enclosing2, enclosing1)) {
+                        } else {
                             return -1;
-                        } else {
-                            return 0;
                         }
                     }
                 } catch (Exception e) {
                     throw new RuntimeException(e);
                 }
             }
-        });
+        };
+
+        Collections.sort(elements, comparator);
         return elements;
     }
 
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Aug 28 17:49:37 2014 -0700
@@ -213,7 +213,7 @@
 
                 for (SLFunction function : functionList) {
                     RootCallTarget rootCallTarget = function.getCallTarget();
-                    rootCallTarget.getRootNode().accept(new SLInstrumenter(slContext));
+                    rootCallTarget.getRootNode().accept(new SLInstrumenter());
                 }
 
                 // We iterate over all tags the SLInsturmenter tagged as assignments and attach our
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,7 +24,6 @@
 
 import java.math.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
@@ -92,18 +91,23 @@
     }
 
     @Override
-    public Probe probe(ExecutionContext context) {
+    public Probe probe() {
         Node parent = getParent();
 
-        if (parent == null)
+        if (parent == null) {
             throw new IllegalStateException("Cannot probe a node without a parent");
+        }
 
-        if (parent instanceof SLExpressionWrapper)
+        if (parent instanceof SLExpressionWrapper) {
             return ((SLExpressionWrapper) parent).getProbe();
+        }
 
-        SLExpressionWrapper wrapper = new SLExpressionWrapper((SLContext) context, this);
+        // Create a new wrapper/probe with this node as its child.
+        final SLExpressionWrapper wrapper = new SLExpressionWrapper(getRootNodeSLContext(this), this);
+
+        // Replace this node in the AST with the wrapper
         this.replace(wrapper);
-        wrapper.insertChild();
+
         return wrapper.getProbe();
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLRootNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
+import com.oracle.truffle.sl.runtime.*;
 
 /**
  * The root of all SL execution trees. It is a Truffle requirement that the tree root extends the
@@ -49,12 +50,16 @@
     /** The name of the function, for printing purposes only. */
     private final String name;
 
-    public SLRootNode(FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) {
+    /** The Simple execution context for this tree **/
+    private final SLContext context;
+
+    public SLRootNode(SLContext context, FrameDescriptor frameDescriptor, SLExpressionNode bodyNode, String name) {
         super(null, frameDescriptor);
         /* Deep copy the body before any specialization occurs during execution. */
         this.uninitializedBodyNode = NodeUtil.cloneNode(bodyNode);
         this.bodyNode = bodyNode;
         this.name = name;
+        this.context = context;
     }
 
     @Override
@@ -69,11 +74,15 @@
 
     @Override
     public RootNode split() {
-        return new SLRootNode(getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBodyNode), name);
+        return new SLRootNode(this.context, getFrameDescriptor().shallowCopy(), NodeUtil.cloneNode(uninitializedBodyNode), name);
     }
 
     @Override
     public String toString() {
         return "root " + name;
     }
+
+    public SLContext getSLContext() {
+        return this.context;
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLStatementNode.java	Thu Aug 28 17:49:37 2014 -0700
@@ -24,7 +24,6 @@
 
 import java.io.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
@@ -87,18 +86,30 @@
     }
 
     @Override
-    public Probe probe(ExecutionContext context) {
+    public Probe probe() {
         Node parent = getParent();
 
         if (parent == null)
             throw new IllegalStateException("Cannot probe a node without a parent");
 
-        if (parent instanceof SLStatementWrapper)
+        if (parent instanceof SLStatementWrapper) {
             return ((SLStatementWrapper) parent).getProbe();
+        }
 
-        SLStatementWrapper wrapper = new SLStatementWrapper((SLContext) context, this);
+        // Create a new wrapper/probe with this node as its child.
+        final SLStatementWrapper wrapper = new SLStatementWrapper(getRootNodeSLContext(this), this);
+
+        // Replace this node in the AST with the wrapper
         this.replace(wrapper);
-        wrapper.insertChild();
+
         return wrapper.getProbe();
     }
+
+    protected SLContext getRootNodeSLContext(Node node) {
+        assert node != null;
+
+        if (node instanceof SLRootNode)
+            return ((SLRootNode) node).getSLContext();
+        return getRootNodeSLContext(node.getParent());
+    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapper.java	Thu Aug 28 17:49:37 2014 -0700
@@ -32,15 +32,12 @@
 import com.oracle.truffle.sl.runtime.*;
 
 /**
- * SLExpressionWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
- * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
- * themselves contain the instruments. It is through this mechanism that tools can interact directly
- * with the AST. <br/>
- * {@link SLExpressionWrapper} specifically wraps {@link SLExpressionNode}s and overrides the
- * various execute functions in {@link SLExpressionNode} to operate on the child of the wrapper
- * instead of the wrapper itself.
- *
+ * A Truffle node that can be inserted into a Simple AST (assumed not to have executed yet) to
+ * enable "instrumentation" of an {@link SLExpressionNode}. Tools wishing to interact with AST
+ * execution may attach {@link Instrument}s to the {@link Probe} uniquely associated with the
+ * wrapper, and to which this wrapper routes {@link ExecutionEvents}.
  */
+
 public final class SLExpressionWrapper extends SLExpressionNode implements Wrapper {
     @Child private SLExpressionNode child;
 
@@ -154,10 +151,4 @@
         return SLTypesGen.SLTYPES.expectSLNull(executeGeneric(frame));
     }
 
-    /**
-     * Sets the parent pointer of this wrapper's child.
-     */
-    public void insertChild() {
-        insert(this.child);
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLInstrumenter.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLInstrumenter.java	Thu Aug 28 17:49:37 2014 -0700
@@ -29,20 +29,14 @@
 import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.nodes.controlflow.*;
 import com.oracle.truffle.sl.nodes.local.*;
-import com.oracle.truffle.sl.runtime.*;
 
 /**
- * This is a general purpose visitor which traverses a completely parsed Simple AST and instruments
- * all the nodes within it. This visitor is designed to visit the tree immediately after it has been
- * parsed.
- *
+ * A visitor which traverses a completely parsed Simple AST (presumed not yet executed) and
+ * instruments some of them.
  */
 public class SLInstrumenter implements NodeVisitor {
 
-    private final SLContext context;
-
-    public SLInstrumenter(SLContext context) {
-        this.context = context;
+    public SLInstrumenter() {
     }
 
     /**
@@ -57,7 +51,7 @@
         if (node instanceof SLExpressionNode && node.getParent() != null) {
             SLExpressionNode expressionNode = (SLExpressionNode) node;
             if (expressionNode.getSourceSection() != null) {
-                Probe probe = expressionNode.probe(context);
+                Probe probe = expressionNode.probe();
                 // probe.tagAs(STATEMENT);
 
                 if (node instanceof SLWriteLocalVariableNode)
@@ -67,7 +61,7 @@
 
             SLStatementNode statementNode = (SLStatementNode) node;
             if (statementNode.getSourceSection() != null) {
-                Probe probe = statementNode.probe(context);
+                Probe probe = statementNode.probe();
                 probe.tagAs(STATEMENT);
 
                 if (node instanceof SLWhileNode)
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLNodeProber.java	Thu Aug 28 17:15:23 2014 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.sl.nodes.instrument;
-
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.sl.nodes.*;
-
-public interface SLNodeProber extends ASTNodeProber {
-
-    SLStatementNode probeAsStatement(SLStatementNode result);
-
-    SLExpressionNode probeAsCall(SLExpressionNode node, String callName);
-
-    SLExpressionNode probeAsLocalAssignment(SLExpressionNode node, String localName);
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapper.java	Thu Aug 28 17:49:37 2014 -0700
@@ -30,14 +30,10 @@
 import com.oracle.truffle.sl.runtime.*;
 
 /**
- * SLStatmentWrapper is a Truffle AST node that gets inserted as the parent to the node that it is
- * wrapping. Any debugging instruments are attached to this wrapper through {@link Probe}s (which
- * themselves contain the instruments). It is through this mechanism that tools can interact
- * directly with the AST. <br/>
- * SLStatmentWrapper specifically wraps {@link SLStatementWrapper}s and overrides the executeVoid
- * function of {@link SLStatementNode} to operate on the child of the wrapper instead of the wrapper
- * itself.
- *
+ * A Truffle node that can be inserted into a Simple AST (assumed not to have executed yet) to
+ * enable "instrumentation" of a {@link SLStatementNode}. Tools wishing to interact with AST
+ * execution may attach {@link Instrument}s to the {@link Probe} uniquely associated with the
+ * wrapper, and to which this wrapper routes {@link ExecutionEvents}.
  */
 public final class SLStatementWrapper extends SLStatementNode implements Wrapper {
 
@@ -50,8 +46,6 @@
         assert !(child instanceof SLStatementWrapper);
         this.probe = context.createProbe(child.getSourceSection());
         this.child = child;
-        // The child should only be inserted after a replace, so we defer inserting the child to the
-        // creator of the wrapper.
     }
 
     @Override
@@ -98,10 +92,4 @@
         }
     }
 
-    /**
-     * Sets the parent pointer of this wrapper's child.
-     */
-    public void insertChild() {
-        insert(this.child);
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/parser/SLNodeFactory.java	Thu Aug 28 17:49:37 2014 -0700
@@ -115,7 +115,7 @@
         assert lexicalScope == null : "Wrong scoping of blocks in parser";
 
         final SLFunctionBodyNode functionBodyNode = new SLFunctionBodyNode(functionSrc, methodBlock);
-        final SLRootNode rootNode = new SLRootNode(frameDescriptor, functionBodyNode, functionName);
+        final SLRootNode rootNode = new SLRootNode(this.context, frameDescriptor, functionBodyNode, functionName);
 
         context.getFunctionRegistry().register(functionName, rootNode);
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Aug 28 17:15:23 2014 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLContext.java	Thu Aug 28 17:49:37 2014 -0700
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.runtime;
 
 import java.io.*;
+import java.util.*;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
@@ -33,6 +34,7 @@
 import com.oracle.truffle.sl.*;
 import com.oracle.truffle.sl.builtins.*;
 import com.oracle.truffle.sl.nodes.*;
+import com.oracle.truffle.sl.nodes.instrument.*;
 import com.oracle.truffle.sl.nodes.local.*;
 import com.oracle.truffle.sl.parser.*;
 
@@ -130,7 +132,7 @@
         /* The name of the builtin function is specified via an annotation on the node class. */
         String name = builtinBodyNode.getClass().getAnnotation(NodeInfo.class).shortName();
         /* Wrap the builtin in a RootNode. Truffle requires all AST to start with a RootNode. */
-        SLRootNode rootNode = new SLRootNode(new FrameDescriptor(), builtinBodyNode, name);
+        SLRootNode rootNode = new SLRootNode(this, new FrameDescriptor(), builtinBodyNode, name);
 
         /* Register the builtin function in our function registry. */
         getFunctionRegistry().register(name, rootNode);
@@ -154,6 +156,17 @@
 
         Parser.parseSL(this, source);
 
+        List<SLFunction> functionList = getFunctionRegistry().getFunctions();
+
+        // Since only functions can be global in SL, this guarantees that we instrument
+        // everything of interest. Parsing must occur before accepting the visitors since
+        // the visitor which creates our instrumentation points expects a complete AST.
+
+        for (SLFunction function : functionList) {
+            RootCallTarget rootCallTarget = function.getCallTarget();
+            rootCallTarget.getRootNode().accept(new SLInstrumenter());
+        }
+
         if (sourceCallback != null) {
             sourceCallback.endLoading(source);
         }
--- a/mx/mx_graal.py	Thu Aug 28 17:15:23 2014 -0700
+++ b/mx/mx_graal.py	Thu Aug 28 17:49:37 2014 -0700
@@ -1059,7 +1059,7 @@
     else:
         return [], args
 
-def _run_tests(args, harness, annotations, testfile, whitelist, regex):
+def _run_tests(args, harness, annotations, testfile, blacklist, whitelist, regex):
 
 
     vmArgs, tests = _extract_VM_args(args)
@@ -1106,6 +1106,9 @@
                     mx.log('warning: no tests matched by substring "' + t)
         projectsCp = mx.classpath(projs)
 
+    if blacklist:
+        classes = [c for c in classes if not any((glob.match(c) for glob in blacklist))]
+
     if whitelist:
         classes = [c for c in classes if any((glob.match(c) for glob in whitelist))]
 
@@ -1119,7 +1122,7 @@
         f_testfile.close()
         harness(projectsCp, vmArgs)
 
-def _unittest(args, annotations, prefixCp="", whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False, gc_after_test=False):
+def _unittest(args, annotations, prefixCp="", blacklist=None, whitelist=None, verbose=False, enable_timing=False, regex=None, color=False, eager_stacktrace=False, gc_after_test=False):
     testfile = os.environ.get('MX_TESTFILE', None)
     if testfile is None:
         (_, testfile) = tempfile.mkstemp(".testclasses", "graal")
@@ -1169,7 +1172,7 @@
             vm(prefixArgs + vmArgs + ['-cp', cp, 'com.oracle.graal.test.GraalJUnitCore'] + coreArgs + ['@' + testfile])
 
     try:
-        _run_tests(args, harness, annotations, testfile, whitelist, regex)
+        _run_tests(args, harness, annotations, testfile, blacklist, whitelist, regex)
     finally:
         if os.environ.get('MX_TESTFILE') is None:
             os.remove(testfile)
@@ -1177,6 +1180,7 @@
 _unittestHelpSuffix = """
     Unittest options:
 
+      --blacklist <file>     run all testcases not specified in the blacklist
       --whitelist <file>     run only testcases which are included
                              in the given whitelist
       --verbose              enable verbose JUnit output
@@ -1221,6 +1225,7 @@
           formatter_class=RawDescriptionHelpFormatter,
           epilog=_unittestHelpSuffix,
         )
+    parser.add_argument('--blacklist', help='run all testcases not specified in the blacklist', metavar='<path>')
     parser.add_argument('--whitelist', help='run testcases specified in whitelist only', metavar='<path>')
     parser.add_argument('--verbose', help='enable verbose JUnit output', action='store_true')
     parser.add_argument('--enable-timing', help='enable JUnit test timing', action='store_true')
@@ -1252,6 +1257,12 @@
                 parsed_args.whitelist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
         except IOError:
             mx.log('warning: could not read whitelist: ' + parsed_args.whitelist)
+    if parsed_args.blacklist:
+        try:
+            with open(join(_graal_home, parsed_args.blacklist)) as fp:
+                parsed_args.blacklist = [re.compile(fnmatch.translate(l.rstrip())) for l in fp.readlines() if not l.startswith('#')]
+        except IOError:
+            mx.log('warning: could not read blacklist: ' + parsed_args.blacklist)
 
     _unittest(args, ['@Test', '@Parameters'], **parsed_args.__dict__)
 
@@ -1952,8 +1963,12 @@
         'intel/hsdis-amd64.dylib' : 'fdb13ef0d7d23d93dacaae9c98837bea0d4fc5a2',
     }
 
+    flavoredLib = flavor + "/" + lib
+    if flavoredLib not in sha1s:
+        mx.logv("hsdis not supported on this plattform or architecture")
+        return
+
     if not exists(path):
-        flavoredLib = flavor + "/" + lib
         sha1 = sha1s[flavoredLib]
         sha1path = path + '.sha1'
         mx.download_file_with_sha1('hsdis', path, ['http://lafo.ssw.uni-linz.ac.at/hsdis/' + flavoredLib], sha1, sha1path, True, True, sources=False)
--- a/mx/projects	Thu Aug 28 17:15:23 2014 -0700
+++ b/mx/projects	Thu Aug 28 17:49:37 2014 -0700
@@ -390,7 +390,7 @@
 # graal.lir
 project@com.oracle.graal.lir@subDir=graal
 project@com.oracle.graal.lir@sourceDirs=src
-project@com.oracle.graal.lir@dependencies=com.oracle.graal.debug,com.oracle.graal.compiler.common,com.oracle.graal.asm
+project@com.oracle.graal.lir@dependencies=com.oracle.graal.compiler.common,com.oracle.graal.asm,com.oracle.graal.debug
 project@com.oracle.graal.lir@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.lir@javaCompliance=1.8
 project@com.oracle.graal.lir@workingSets=Graal,LIR
--- a/mxtool/mx.py	Thu Aug 28 17:15:23 2014 -0700
+++ b/mxtool/mx.py	Thu Aug 28 17:49:37 2014 -0700
@@ -1247,11 +1247,11 @@
     """
     Get the list of all loaded projects limited by --suite option if opt_limit_to_suite == True
     """
-
+    sortedProjects = sorted(_projects.values(), key=lambda p: p.name)
     if opt_limit_to_suite:
-        return _projects_opt_limit_to_suites(_projects.values())
+        return _projects_opt_limit_to_suites(sortedProjects)
     else:
-        return _projects.values()
+        return sortedProjects
 
 def projects_opt_limit_to_suites():
     """
@@ -2231,8 +2231,13 @@
                 self.proj.definedAnnotationProcessorsDist.make_archive()
 
         finally:
-            for n in toBeDeleted:
-                os.remove(n)
+            # Do not clean up temp files if verbose as there's
+            # a good chance the user wants to copy and paste the
+            # Java compiler command directly
+            if not _opts.verbose:
+                for n in toBeDeleted:
+                    os.remove(n)
+
             self.done = True
 
 def build(args, parser=None):
@@ -2413,6 +2418,8 @@
             logv('[no Java sources for {0} - skipping]'.format(p.name))
             continue
 
+        javafilelist = sorted(javafilelist)
+
         task = JavaCompileTask(args, p, buildReason, javafilelist, jdk, outputDir, jdtJar, taskDeps)
         if p.definedAnnotationProcessorsDist:
             updatedAnnotationProcessorDists.add(p.definedAnnotationProcessorsDist)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/blacklist_sparc.txt	Thu Aug 28 17:49:37 2014 -0700
@@ -0,0 +1,310 @@
+com.oracle.graal.jtt.lang.Object_equals01
+com.oracle.graal.replacements.test.CheckCastTest
+com.oracle.graal.hotspot.test.AheadOfTimeCompilationTest
+com.oracle.graal.jtt.reflect.Invoke_except01
+com.oracle.graal.jtt.bytecode.BC_fastore
+com.oracle.graal.compiler.test.deopt.MonitorDeoptTest
+com.oracle.graal.jtt.loop.LoopParseLong
+com.oracle.graal.jtt.bytecode.BC_baload
+com.oracle.graal.jtt.threads.ThreadLocal01
+com.oracle.graal.jtt.jdk.UnsafeAllocateInstance01
+com.oracle.graal.jtt.threads.ThreadLocal02
+com.oracle.graal.jtt.optimize.ConditionalElimination01
+com.oracle.graal.jtt.threads.ThreadLocal03
+com.oracle.graal.jtt.except.BC_athrow3
+com.oracle.graal.jtt.except.BC_checkcast
+com.oracle.graal.jtt.micro.VarArgs_short01
+com.oracle.graal.replacements.test.InvokeTest
+com.oracle.graal.jtt.reflect.Invoke_virtual01
+com.oracle.graal.jtt.lang.Math_cos
+com.oracle.graal.jtt.lang.Math_log10
+com.oracle.graal.jtt.optimize.Narrow_char02
+com.oracle.graal.jtt.lang.Math_sin
+com.oracle.graal.jtt.bytecode.BC_lookupswitch05
+com.oracle.graal.jtt.except.BC_aastore0
+com.oracle.graal.jtt.reflect.Class_getDeclaredField01
+com.oracle.graal.jtt.micro.VarArgs_double01
+com.oracle.graal.jtt.micro.String_format02
+com.oracle.graal.compiler.hsail.test.lambda.ArrayListSetTest
+com.oracle.graal.jtt.optimize.List_reorder_bug
+com.oracle.graal.jtt.hotpath.HP_idea
+com.oracle.graal.jtt.except.Throw_Synchronized01
+com.oracle.graal.jtt.lang.Bridge_method01
+com.oracle.graal.compiler.test.IfReorderTest
+com.oracle.graal.jtt.optimize.Switch02
+com.oracle.graal.jtt.jdk.Thread_setName
+com.oracle.graal.jtt.reflect.Array_set01
+com.oracle.graal.jtt.reflect.Array_set02
+com.oracle.graal.jtt.except.BC_checkcast5
+com.oracle.graal.jtt.micro.VarArgs_float01
+com.oracle.graal.jtt.bytecode.BC_monitorenter
+com.oracle.graal.jtt.hotpath.HP_array04
+com.oracle.graal.compiler.hsail.test.lambda.StringSubstringTest
+com.oracle.graal.jtt.hotpath.HP_array03
+com.oracle.graal.jtt.hotpath.HP_array02
+com.oracle.graal.jtt.threads.Thread_isInterrupted03
+com.oracle.graal.jtt.threads.Thread_isInterrupted02
+com.oracle.graal.jtt.threads.Thread_isInterrupted05
+com.oracle.graal.jtt.lang.ClassLoader_loadClass01
+com.oracle.graal.jtt.optimize.NCE_02
+com.oracle.graal.jtt.lang.Object_hashCode01
+com.oracle.graal.jtt.loop.Loop09
+com.oracle.graal.compiler.hsail.test.lambda.DremTest
+com.oracle.graal.replacements.test.StandardMethodSubstitutionsTest
+com.oracle.graal.jtt.jdk.UnsafeAccess01
+com.oracle.graal.jtt.loop.LoopSwitch01
+com.oracle.graal.jtt.except.Catch_NASE_2
+com.oracle.graal.jtt.threads.Thread_setPriority01
+com.oracle.graal.jtt.except.BC_checkcast3
+com.oracle.graal.jtt.reflect.Invoke_main03
+com.oracle.graal.jtt.except.BC_aastore1
+com.oracle.graal.jtt.except.BC_saload
+com.oracle.graal.jtt.threads.Monitor_contended01
+com.oracle.graal.jtt.lang.Class_getName02
+com.oracle.graal.jtt.reflect.Invoke_main01
+com.oracle.graal.jtt.lang.Math_sqrt
+com.oracle.graal.jtt.bytecode.BC_ldc_06
+com.oracle.graal.jtt.optimize.ConditionalElimination02
+com.oracle.graal.jtt.lang.String_intern02
+com.oracle.truffle.sl.test.SLSimpleTestSuite
+com.oracle.graal.jtt.micro.Bubblesort
+com.oracle.graal.jtt.lang.String_intern03
+com.oracle.graal.jtt.hotpath.HP_demo01
+com.oracle.graal.jtt.optimize.ArrayLength01
+com.oracle.graal.replacements.test.DynamicNewArrayTest
+com.oracle.graal.jtt.micro.InvokeVirtual_02
+com.oracle.graal.jtt.lang.Object_getClass01
+com.oracle.graal.jtt.micro.Matrix01
+com.oracle.graal.replacements.test.NewInstanceTest
+com.oracle.graal.jtt.lang.Class_getSimpleName01
+com.oracle.graal.jtt.lang.Class_getSimpleName02
+com.oracle.graal.jtt.bytecode.BC_d2l02
+com.oracle.graal.jtt.except.BC_checkcast6
+com.oracle.graal.jtt.lang.Class_getSuperClass01
+com.oracle.graal.jtt.lang.Class_getInterfaces01
+com.oracle.graal.jtt.lang.Class_Literal01
+com.oracle.graal.replacements.test.StringSubstitutionsTest
+com.oracle.graal.jtt.except.BC_checkcast4
+com.oracle.graal.jtt.bytecode.BC_f2l02
+com.oracle.graal.jtt.micro.VarArgs_long01
+com.oracle.graal.compiler.test.ea.UnsafeEATest
+com.oracle.graal.jtt.except.Catch_NASE_1
+com.oracle.graal.jtt.bytecode.BC_iastore
+com.oracle.graal.compiler.test.ShortCircuitNodeTest
+com.oracle.graal.jtt.threads.Thread_isInterrupted04
+com.oracle.graal.jtt.jdk.EnumMap02
+com.oracle.graal.jtt.threads.Monitor_notowner01
+com.oracle.graal.hotspot.test.ArrayCopyIntrinsificationTest
+com.oracle.graal.jtt.bytecode.BC_putfield_01
+com.oracle.graal.jtt.lang.Math_tan
+com.oracle.graal.jtt.bytecode.BC_aaload
+com.oracle.graal.jtt.optimize.Narrow_short03
+com.oracle.graal.jtt.optimize.Narrow_short02
+com.oracle.graal.jtt.optimize.ArrayCopy01
+com.oracle.graal.jtt.bytecode.BC_athrow
+com.oracle.graal.jtt.except.BC_sastore
+com.oracle.graal.jtt.bytecode.BC_d2i02
+com.oracle.graal.jtt.threads.Object_wait01
+com.oracle.graal.jtt.bytecode.BC_sastore
+com.oracle.graal.jtt.bytecode.BC_l2i_2
+com.oracle.graal.jtt.micro.BigObjectParams02
+com.oracle.graal.jtt.except.StackTrace_NPE_01
+com.oracle.graal.compiler.test.CommonedConstantsTest
+com.oracle.graal.jtt.bytecode.BC_getfield
+com.oracle.graal.jtt.bytecode.BC_laload
+com.oracle.graal.hotspot.test.WriteBarrierAdditionTest
+com.oracle.graal.jtt.hotpath.HP_life
+com.oracle.graal.hotspot.test.CRC32SubstitutionsTest
+com.oracle.graal.jtt.lang.Boxed_TYPE_01
+com.oracle.graal.jtt.reflect.Class_getDeclaredMethod01
+com.oracle.graal.jtt.threads.Thread_new02
+com.oracle.graal.jtt.threads.Thread_new01
+com.oracle.graal.jtt.except.BC_caload
+com.oracle.graal.compiler.hsail.test.StaticMethod16InArraysTest
+com.oracle.graal.jtt.jdk.Unsafe_compareAndSwap
+com.oracle.graal.replacements.test.MonitorTest
+com.oracle.graal.jtt.except.Throw_Synchronized05
+com.oracle.graal.jtt.reflect.Array_newInstance02
+com.oracle.graal.jtt.reflect.Array_newInstance03
+com.oracle.graal.jtt.reflect.Array_newInstance01
+com.oracle.graal.jtt.reflect.Array_newInstance06
+com.oracle.graal.jtt.micro.VarArgs_byte01
+com.oracle.graal.jtt.except.BC_laload
+com.oracle.graal.compiler.test.ea.EscapeAnalysisTest
+com.oracle.graal.jtt.except.Throw_Synchronized02
+com.oracle.graal.jtt.except.Throw_Synchronized04
+com.oracle.graal.jtt.optimize.NestedLoop_EA
+com.oracle.graal.jtt.except.BC_newarray
+com.oracle.graal.jtt.loop.Loop15
+com.oracle.graal.compiler.hsail.test.lambda.ObjectArrayInstanceDerivedTest
+com.oracle.graal.jtt.bytecode.BC_checkcast01
+com.oracle.graal.jtt.except.BC_anewarray
+com.oracle.graal.hotspot.amd64.test.CompressedNullCheckTest
+com.oracle.graal.compiler.test.MemoryArithmeticTest
+com.oracle.graal.jtt.bytecode.BC_getfield_o
+com.oracle.graal.jtt.lang.Class_getComponentType01
+com.oracle.graal.jtt.reflect.Array_newInstance04
+com.oracle.graal.jtt.reflect.Method_getParameterTypes01
+com.oracle.graal.compiler.test.inlining.InliningTest
+com.oracle.graal.hotspot.test.InstalledCodeExecuteHelperTest
+com.oracle.graal.jtt.except.BC_castore
+com.oracle.graal.jtt.lang.Class_isInstance06
+com.oracle.graal.jtt.lang.Class_isInstance07
+com.oracle.graal.jtt.threads.Thread_join03
+com.oracle.graal.jtt.threads.Thread_join01
+com.oracle.graal.jtt.except.BC_putfield
+com.oracle.graal.jtt.lang.Class_forName03
+com.oracle.graal.jtt.lang.Class_forName04
+com.oracle.graal.jtt.lang.Class_forName05
+com.oracle.graal.jtt.hotspot.Test6186134
+com.oracle.graal.jtt.optimize.NCE_03
+com.oracle.graal.jtt.micro.String_format01
+com.oracle.graal.jtt.except.BC_lastore
+com.oracle.graal.jtt.bytecode.BC_monitorenter02
+com.oracle.graal.jtt.micro.ReferenceMap01
+com.oracle.graal.jtt.bytecode.BC_instanceof
+com.oracle.graal.jtt.except.Catch_Unresolved
+com.oracle.graal.compiler.test.MemoryScheduleTest
+com.oracle.graal.jtt.bytecode.BC_castore
+com.oracle.graal.jtt.except.Throw_InCatch03
+com.oracle.graal.jtt.except.Throw_InCatch02
+com.oracle.graal.jtt.except.Throw_InCatch01
+com.oracle.graal.jtt.except.BC_iaload
+com.oracle.graal.jtt.lang.Double_toString
+com.oracle.graal.jtt.optimize.ABCE_02
+com.oracle.graal.replacements.test.CompiledExceptionHandlerTest
+com.oracle.graal.jtt.except.Throw_Synchronized03
+com.oracle.graal.jtt.threads.Thread_join02
+com.oracle.graal.jtt.threads.SynchronizedLoopExit01
+com.oracle.graal.jtt.bytecode.BC_daload
+com.oracle.graal.jtt.optimize.Conditional01
+com.oracle.graal.jtt.lang.JDK_ClassLoaders02
+com.oracle.graal.jtt.bytecode.BC_putfield_03
+com.oracle.graal.jtt.bytecode.BC_putfield_02
+com.oracle.graal.jtt.micro.BigInterfaceParams01
+com.oracle.graal.jtt.micro.VarArgs_String01
+com.oracle.graal.jtt.optimize.LongToSomethingArray01
+com.oracle.graal.jtt.except.BC_checkcast1
+com.oracle.graal.jtt.except.Catch_NPE_07
+com.oracle.graal.jtt.except.Catch_NPE_06
+com.oracle.graal.jtt.except.Catch_NPE_02
+com.oracle.graal.jtt.except.Catch_NPE_01
+com.oracle.graal.replacements.test.ArraysSubstitutionsTest
+com.oracle.graal.jtt.except.StackTrace_CCE_00
+com.oracle.graal.jtt.lang.ProcessEnvironment_init
+com.oracle.graal.jtt.except.BC_bastore
+com.oracle.graal.jtt.except.BC_baload
+com.oracle.graal.jtt.lang.Class_asSubclass01
+com.oracle.graal.jtt.bytecode.BC_invokevirtual
+com.oracle.graal.compiler.test.BoxingEliminationTest
+com.oracle.graal.compiler.test.deopt.CompiledMethodTest
+com.oracle.graal.compiler.ptx.test.ArrayPTXTest
+com.oracle.graal.jtt.reflect.Class_getMethod01
+com.oracle.graal.compiler.test.InfopointReasonTest
+com.oracle.graal.jtt.reflect.Class_getMethod02
+com.oracle.graal.jtt.bytecode.BC_invokespecial2
+com.oracle.graal.jtt.reflect.Method_getReturnType01
+com.oracle.graal.replacements.test.InstanceOfTest
+com.oracle.graal.jtt.bytecode.BC_invokespecial
+com.oracle.graal.jtt.lang.Object_toString02
+com.oracle.graal.jtt.lang.Object_toString01
+com.oracle.graal.jtt.jdk.EnumMap01
+com.oracle.graal.jtt.except.BC_checkcast2
+com.oracle.graal.replacements.test.InstanceOfDynamicTest
+com.oracle.graal.hotspot.test.HotSpotNodeSubstitutionsTest
+com.oracle.graal.replacements.test.UnsignedMathTest
+com.oracle.graal.jtt.reflect.Field_get03
+com.oracle.graal.jtt.bytecode.BC_putfield_04
+com.oracle.graal.hotspot.test.CompressedOopTest
+com.oracle.graal.jtt.except.BC_daload
+com.oracle.graal.hotspot.amd64.test.AMD64HotSpotFrameOmissionTest
+com.oracle.graal.jtt.hotpath.HP_allocate04
+com.oracle.graal.jtt.hotpath.HP_allocate03
+com.oracle.graal.jtt.optimize.NCE_01
+com.oracle.graal.jtt.optimize.NCE_04
+com.oracle.graal.jtt.lang.Class_getName01
+com.oracle.graal.hotspot.test.HotSpotMonitorValueTest
+com.oracle.graal.jtt.threads.Thread_getState02
+com.oracle.graal.jtt.except.BC_arraylength
+com.oracle.graal.jtt.bytecode.BC_caload
+com.oracle.graal.replacements.test.UnsafeSubstitutionsTest
+com.oracle.graal.jtt.bytecode.BC_saload
+com.oracle.graal.hotspot.test.HotSpotNmethodTest
+com.oracle.graal.replacements.test.DeoptimizeOnExceptionTest
+com.oracle.graal.jtt.optimize.ArrayCopyGeneric
+com.oracle.graal.jtt.lang.Class_forName01
+com.oracle.graal.jtt.except.BC_monitorenter
+com.oracle.graal.jtt.except.Catch_Loop02
+com.oracle.graal.jtt.bytecode.BC_lastore
+com.oracle.graal.jtt.except.BC_getfield
+com.oracle.graal.jtt.except.BC_aaload1
+com.oracle.graal.jtt.except.BC_aaload0
+com.oracle.graal.jtt.except.BC_dastore
+com.oracle.graal.jtt.micro.VarArgs_char01
+com.oracle.graal.jtt.optimize.NCE_FlowSensitive05
+com.oracle.graal.jtt.optimize.NCE_FlowSensitive03
+com.oracle.graal.jtt.bytecode.BC_aaload_1
+com.oracle.graal.jtt.lang.Math_abs
+com.oracle.graal.hotspot.test.CompileTheWorldTest
+com.oracle.graal.jtt.micro.FloatingReads
+com.oracle.graal.jtt.except.BC_fastore
+com.oracle.graal.jtt.optimize.ArrayCopy05
+com.oracle.graal.jtt.bytecode.BC_aastore
+com.oracle.graal.compiler.test.LockEliminationTest
+com.oracle.graal.jtt.hotpath.HP_invoke01
+com.oracle.graal.jtt.bytecode.BC_dastore
+com.oracle.graal.jtt.loop.DegeneratedLoop
+com.oracle.graal.jtt.hotpath.HP_array01
+com.oracle.graal.jtt.except.BC_iastore
+com.oracle.graal.jtt.except.BC_athrow2
+com.oracle.graal.jtt.except.BC_athrow0
+com.oracle.graal.jtt.except.BC_athrow1
+com.oracle.graal.jtt.micro.VarArgs_int01
+com.oracle.graal.jtt.micro.BigVirtualParams01
+com.oracle.graal.jtt.jdk.Class_getName
+com.oracle.graal.jtt.reflect.Array_newInstance05
+com.oracle.graal.jtt.optimize.ABCE_01
+com.oracle.graal.jtt.micro.InvokeVirtual_01
+com.oracle.graal.jtt.except.StackTrace_AIOOBE_00
+com.oracle.graal.jtt.bytecode.BC_invokeinterface
+com.oracle.graal.jtt.micro.BigMixedParams04
+com.oracle.graal.jtt.reflect.Invoke_main02
+com.oracle.graal.jtt.threads.Object_wait02
+com.oracle.graal.jtt.threads.Object_wait03
+com.oracle.graal.jtt.threads.Object_wait04
+com.oracle.graal.jtt.except.Catch_Unresolved02
+com.oracle.graal.jtt.except.Catch_Unresolved03
+com.oracle.graal.compiler.test.CheckGraalInvariants
+com.oracle.graal.jtt.except.Catch_Unresolved01
+com.oracle.graal.jtt.optimize.Narrow_byte03
+com.oracle.graal.jtt.except.BC_faload
+com.oracle.graal.nodes.test.LoopPhiCanonicalizerTest
+com.oracle.graal.jtt.bytecode.BC_f2i02
+com.oracle.graal.jtt.bytecode.BC_iaload
+com.oracle.graal.jtt.reflect.Array_set03
+com.oracle.graal.jtt.lang.Class_forName02
+com.oracle.graal.compiler.hsail.test.lambda.ObjectArrayInstanceTest
+com.oracle.graal.jtt.micro.VarArgs_boolean01
+com.oracle.graal.jtt.lang.Math_log
+com.oracle.graal.compiler.test.FlowSensitiveReductionTest
+com.oracle.graal.jtt.bytecode.BC_faload
+com.oracle.graal.jtt.bytecode.BC_multianewarray03
+com.oracle.graal.jtt.loop.Loop06
+com.oracle.graal.jtt.loop.Loop07
+com.oracle.graal.jtt.loop.Loop13
+com.oracle.graal.jtt.bytecode.BC_bastore
+com.oracle.graal.jtt.except.Catch_Two02
+com.oracle.graal.jtt.except.Catch_Two03
+com.oracle.graal.jtt.except.Catch_Two01
+com.oracle.graal.jtt.optimize.Narrow_byte02
+com.oracle.graal.jtt.loop.Loop05
+com.oracle.graal.jtt.loop.Loop12
+com.oracle.graal.jtt.jdk.System_setOut
+com.oracle.graal.jtt.except.Catch_Loop03
+com.oracle.graal.jtt.micro.BC_invokevirtual2
+com.oracle.graal.jtt.optimize.Narrow_char03
+com.oracle.graal.jtt.optimize.ArrayCopy02
+com.oracle.graal.jtt.optimize.ArrayCopy04
+com.oracle.graal.jtt.optimize.ArrayCopy06
+com.oracle.graal.replacements.test.NewArrayTest
+com.oracle.graal.jtt.optimize.ArrayCopy03