changeset 11883:673f93db4adc

Merge.
author Doug Simon <doug.simon@oracle.com>
date Wed, 02 Oct 2013 21:40:29 +0200
parents 51059863da73 (current diff) ef895852aeb4 (diff)
children 008500ebc6c6
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java
diffstat 69 files changed, 1279 insertions(+), 884 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ArithmeticOperation.java	Wed Oct 02 21:40:29 2013 +0200
@@ -22,9 +22,13 @@
  */
 package com.oracle.graal.api.code;
 
+import com.oracle.graal.api.meta.*;
+
 /**
  * An {@code ArithmeticOperation} is an operation that does primitive value arithmetic without side
  * effect.
  */
 public interface ArithmeticOperation {
+
+    Constant evalConst(Constant... inputs);
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Wed Oct 02 21:40:29 2013 +0200
@@ -94,7 +94,7 @@
     /**
      * In this case the read should be scheduled in the first block.
      */
-    public static int testSplitSnippet1(int a) {
+    public static int testSplit1Snippet(int a) {
         try {
             return container.a;
         } finally {
@@ -109,7 +109,7 @@
     @Test
     public void testSplit1() {
         for (TestMode mode : TestMode.values()) {
-            SchedulePhase schedule = getFinalSchedule("testSplitSnippet1", mode, MemoryScheduling.OPTIMAL);
+            SchedulePhase schedule = getFinalSchedule("testSplit1Snippet", mode, MemoryScheduling.OPTIMAL);
             assertReadWithinStartBlock(schedule, true);
             assertReadWithinReturnBlock(schedule, false);
         }
@@ -209,6 +209,42 @@
         assertReadWithinReturnBlock(schedule, false);
     }
 
+    public String testStringReplaceSnippet(String input) {
+        return input.replace('a', 'b');
+    }
+
+    @Test
+    public void testStringReplace() {
+        getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL);
+        test("testStringReplaceSnippet", "acbaaa");
+    }
+
+    /**
+     * Here the read should float out of the loop.
+     */
+    public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) {
+        int ret = 0;
+        int bb = b;
+        for (int i = 0; i < a; i++) {
+            ret = obj.hash;
+            if (a > 10) {
+                bb++;
+            } else {
+                bb--;
+            }
+            ret = ret / 10;
+        }
+        return ret + bb;
+    }
+
+    @Test
+    public void testLoop5() {
+        SchedulePhase schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL);
+        assertEquals(7, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinReturnBlock(schedule, false);
+    }
+
     /**
      * Here the read should float to the end (into the same block as the return).
      */
@@ -312,6 +348,25 @@
     }
 
     /**
+     * Here the read should float to the end.
+     */
+    public static int testIfRead5Snippet(int a) {
+        if (a < 0) {
+            container.a = 10;
+        }
+        return container.a;
+    }
+
+    @Test
+    public void testIfRead5() {
+        SchedulePhase schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES, MemoryScheduling.OPTIMAL);
+        assertEquals(4, schedule.getCFG().getBlocks().length);
+        assertReadWithinStartBlock(schedule, false);
+        assertReadWithinReturnBlock(schedule, true);
+        assertReadAndWriteInSameBlock(schedule, false);
+    }
+
+    /**
      * testing scheduling within a block.
      */
     public static int testBlockScheduleSnippet() {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Oct 02 21:40:29 2013 +0200
@@ -86,7 +86,7 @@
          */
         @Option(help = "Pattern for method(s) to which intrinsification will not be applied. " +
                        "See MethodFilter class for pattern syntax.")
-        public static final OptionValue<String> IntrinsificationsDisabled = new OptionValue<>("Object.clone");
+        public static final OptionValue<String> IntrinsificationsDisabled = new OptionValue<>(null);
         // @formatter:on
 
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Wed Oct 02 21:40:29 2013 +0200
@@ -246,6 +246,16 @@
     public final int osThreadOffset = getUninitializedInt();
 
     /**
+     * The value of JavaThread::graal_counters_offset().
+     */
+    public final int graalCountersThreadOffset = getUninitializedInt();
+
+    /**
+     * The length of the JavaThread::_graal_counters array.
+     */
+    public final int graalCountersSize = getUninitializedInt();
+
+    /**
      * The value of OSThread::interrupted_offset().
      */
     public final int osThreadInterruptedOffset = getUninitializedInt();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed Oct 02 21:40:29 2013 +0200
@@ -228,4 +228,9 @@
     void invalidateInstalledCode(HotSpotInstalledCode hotspotInstalledCode);
 
     boolean isTypeLinked(HotSpotResolvedObjectType hotSpotResolvedObjectType);
+
+    /**
+     * Collects the current values of all Graal benchmark counters, summed up over all threads.
+     */
+    long[] collectCounters();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed Oct 02 21:40:29 2013 +0200
@@ -190,4 +190,6 @@
      * verified entry point of the given native method.
      */
     public static native Object executeCompiledMethodIntrinsic(Object arg1, Object arg2, Object arg3, HotSpotInstalledCode hotspotInstalledCode) throws InvalidInstalledCodeException;
+
+    public native long[] collectCounters();
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed Oct 02 21:40:29 2013 +0200
@@ -47,7 +47,6 @@
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -79,11 +78,6 @@
         }
     };
 
-    @Option(help = "")
-    private static final OptionValue<Boolean> GenericDynamicCounters = new OptionValue<>(false);
-
-    @Option(help = "")
-    private static final OptionValue<String> BenchmarkDynamicCounters = new OptionValue<>(null);
     //@formatter:on
 
     private final HotSpotGraalRuntime graalRuntime;
@@ -234,28 +228,8 @@
             t.start();
         }
 
-        if (BenchmarkDynamicCounters.getValue() != null) {
-            String[] arguments = BenchmarkDynamicCounters.getValue().split(",");
-            if (arguments.length == 0 || (arguments.length % 3) != 0) {
-                throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)");
-            }
-            for (int i = 0; i < arguments.length; i += 3) {
-                if (arguments[i].equals("err")) {
-                    System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2])));
-                } else if (arguments[i].equals("out")) {
-                    System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2])));
-                } else {
-                    throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
-                }
-                // dacapo: "err, starting =====, PASSED in "
-                // specjvm2008: "out,Iteration ~ (~s) begins: ,Iteration ~ (~s) ends:   "
-            }
-            DynamicCounterNode.excludedClassPrefix = "Lcom/oracle/graal/";
-            DynamicCounterNode.enabled = true;
-        }
-        if (GenericDynamicCounters.getValue()) {
-            DynamicCounterNode.enabled = true;
-        }
+        BenchmarkCounters.initialize(graalRuntime.getCompilerToVM());
+
         compilerStartTime = System.nanoTime();
     }
 
@@ -284,84 +258,6 @@
         }
     }
 
-    private final class BenchmarkCountersOutputStream extends CallbackOutputStream {
-
-        private long startTime;
-        private boolean waitingForEnd;
-
-        private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
-            super(delegate, new String[]{start, end, "\n"});
-        }
-
-        @Override
-        protected void patternFound(int index) {
-            switch (index) {
-                case 0:
-                    startTime = System.nanoTime();
-                    DynamicCounterNode.clear();
-                    break;
-                case 1:
-                    waitingForEnd = true;
-                    break;
-                case 2:
-                    if (waitingForEnd) {
-                        waitingForEnd = false;
-                        DynamicCounterNode.dump(delegate, (System.nanoTime() - startTime) / 1000000000d);
-                    }
-                    break;
-            }
-        }
-    }
-
-    public abstract static class CallbackOutputStream extends OutputStream {
-
-        protected final PrintStream delegate;
-        private final byte[][] patterns;
-        private final int[] positions;
-
-        public CallbackOutputStream(PrintStream delegate, String... patterns) {
-            this.delegate = delegate;
-            this.positions = new int[patterns.length];
-            this.patterns = new byte[patterns.length][];
-            for (int i = 0; i < patterns.length; i++) {
-                this.patterns[i] = patterns[i].getBytes();
-            }
-        }
-
-        protected abstract void patternFound(int index);
-
-        @Override
-        public void write(int b) throws IOException {
-            try {
-                delegate.write(b);
-                for (int i = 0; i < patterns.length; i++) {
-                    int j = positions[i];
-                    byte[] cs = patterns[i];
-                    byte patternChar = cs[j];
-                    if (patternChar == '~' && Character.isDigit(b)) {
-                        // nothing to do...
-                    } else {
-                        if (patternChar == '~') {
-                            patternChar = cs[++positions[i]];
-                        }
-                        if (b == patternChar) {
-                            positions[i]++;
-                        } else {
-                            positions[i] = 0;
-                        }
-                    }
-                    if (positions[i] == patterns[i].length) {
-                        positions[i] = 0;
-                        patternFound(i);
-                    }
-                }
-            } catch (RuntimeException e) {
-                e.printStackTrace(delegate);
-                throw e;
-            }
-        }
-    }
-
     /**
      * Take action related to entering a new execution phase.
      * 
@@ -528,9 +424,7 @@
         }
 
         SnippetCounter.printGroups(TTY.out().out());
-        if (GenericDynamicCounters.getValue()) {
-            DynamicCounterNode.dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d);
-        }
+        BenchmarkCounters.shutdown(graalRuntime.getCompilerToVM(), compilerStartTime);
     }
 
     private void flattenChildren(DebugValueMap map, DebugValueMap globalMap) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Oct 02 21:40:29 2013 +0200
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2013, 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.hotspot.debug;
+
+import java.io.*;
+import java.text.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.bridge.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * This class contains infrastructure to maintain counters based on {@link DynamicCounterNode}s. The
+ * infrastructure is enabled by specifying either the GenericDynamicCounters or
+ * BenchmarkDynamicCounters option.<br/>
+ * 
+ * The counters are kept in a special area in the native JavaThread object, and the number of
+ * counters is configured in {@code thread.hpp (GRAAL_COUNTERS_SIZE)}. This file also contains an
+ * option to exclude compiler threads ({@code GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS}, which
+ * defaults to true).
+ * 
+ * The subsystems that use the logging need to have their own options to turn on the counters, and
+ * insert DynamicCounterNodes when they're enabled.
+ */
+public class BenchmarkCounters {
+
+    static class Options {
+
+        //@formatter:off
+        @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown")
+        private static final OptionValue<Boolean> GenericDynamicCounters = new OptionValue<>(false);
+
+        @Option(help = "Turn on the benchmark counters, and listen for specific patterns on System.out/System.err:%n" +
+                       "Format: (err|out),start pattern,end pattern (~ matches multiple digits)%n" +
+                       "Examples:%n" +
+                       "  dacapo = 'err, starting =====, PASSED in'%n" +
+                       "  specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'")
+        private static final OptionValue<String> BenchmarkDynamicCounters = new OptionValue<>(null);
+        //@formatter:on
+    }
+
+    private static final boolean DUMP_STATIC = false;
+
+    public static String excludedClassPrefix = null;
+    public static boolean enabled = false;
+
+    public static final ConcurrentHashMap<String, Integer> indexes = new ConcurrentHashMap<>();
+    public static final ArrayList<String> groups = new ArrayList<>();
+    public static long[] delta;
+    public static final ArrayList<AtomicLong> staticCounters = new ArrayList<>();
+
+    public static int getIndex(DynamicCounterNode counter) {
+        if (!enabled) {
+            throw new GraalInternalError("counter nodes shouldn't exist when counters are not enabled");
+        }
+        String name = counter.getName();
+        String group = counter.getGroup();
+        name = counter.isWithContext() ? name + " @ " + counter.graph().graphId() + ":" + MetaUtil.format("%h.%n", counter.graph().method()) + "#" + group : name + "#" + group;
+        Integer index = indexes.get(name);
+        if (index == null) {
+            synchronized (BenchmarkCounters.class) {
+                index = indexes.get(name);
+                if (index == null) {
+                    index = indexes.size();
+                    indexes.put(name, index);
+                    groups.add(group);
+                    staticCounters.add(new AtomicLong());
+                }
+            }
+        }
+        assert groups.get(index).equals(group) : "mismatching groups: " + groups.get(index) + " vs. " + group;
+        if (counter.getIncrement().isConstant()) {
+            staticCounters.get(index).addAndGet(counter.getIncrement().asConstant().asLong());
+        }
+        return index;
+    }
+
+    public static synchronized void dump(PrintStream out, double seconds, long[] counters) {
+        if (!staticCounters.isEmpty()) {
+            out.println("====== dynamic counters (" + staticCounters.size() + " in total) ======");
+            for (String group : new TreeSet<>(groups)) {
+                if (group != null) {
+                    if (DUMP_STATIC) {
+                        dumpCounters(out, seconds, counters, true, group);
+                    }
+                    dumpCounters(out, seconds, counters, false, group);
+                }
+            }
+            out.println("============================");
+
+            clear(counters);
+        }
+    }
+
+    public static synchronized void clear(long[] counters) {
+        delta = counters;
+    }
+
+    private static synchronized void dumpCounters(PrintStream out, double seconds, long[] counters, boolean staticCounter, String group) {
+        TreeMap<Long, String> sorted = new TreeMap<>();
+
+        long[] array;
+        if (staticCounter) {
+            array = new long[indexes.size()];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = staticCounters.get(i).get();
+            }
+        } else {
+            array = counters.clone();
+            for (int i = 0; i < array.length; i++) {
+                array[i] -= delta[i];
+            }
+        }
+        long sum = 0;
+        for (Map.Entry<String, Integer> entry : indexes.entrySet()) {
+            int index = entry.getValue();
+            if (groups.get(index).equals(group)) {
+                sum += array[index];
+                sorted.put(array[index] * array.length + index, entry.getKey().substring(0, entry.getKey().length() - group.length() - 1));
+            }
+        }
+
+        if (sum > 0) {
+            NumberFormat format = NumberFormat.getInstance(Locale.US);
+            long cutoff = sorted.size() < 10 ? 1 : Math.max(1, sum / 100);
+            if (staticCounter) {
+                out.println("=========== " + group + " static counters: ");
+                for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                    long counter = entry.getKey() / array.length;
+                    if (counter >= cutoff) {
+                        out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
+                    }
+                }
+                out.println(sum + ": total");
+            } else {
+                if (group.startsWith("~")) {
+                    out.println("=========== " + group + " dynamic counters");
+                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                        long counter = entry.getKey() / array.length;
+                        if (counter >= cutoff) {
+                            out.println(format.format(counter) + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
+                        }
+                    }
+                    out.println(format.format(sum) + ": total");
+                } else {
+                    out.println("=========== " + group + " dynamic counters, time = " + seconds + " s");
+                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
+                        long counter = entry.getKey() / array.length;
+                        if (counter >= cutoff) {
+                            out.println(format.format((long) (counter / seconds)) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
+                        }
+                    }
+                    out.println(format.format((long) (sum / seconds)) + "/s: total");
+                }
+            }
+        }
+    }
+
+    public abstract static class CallbackOutputStream extends OutputStream {
+
+        protected final PrintStream delegate;
+        private final byte[][] patterns;
+        private final int[] positions;
+
+        public CallbackOutputStream(PrintStream delegate, String... patterns) {
+            this.delegate = delegate;
+            this.positions = new int[patterns.length];
+            this.patterns = new byte[patterns.length][];
+            for (int i = 0; i < patterns.length; i++) {
+                this.patterns[i] = patterns[i].getBytes();
+            }
+        }
+
+        protected abstract void patternFound(int index);
+
+        @Override
+        public void write(int b) throws IOException {
+            try {
+                delegate.write(b);
+                for (int i = 0; i < patterns.length; i++) {
+                    int j = positions[i];
+                    byte[] cs = patterns[i];
+                    byte patternChar = cs[j];
+                    if (patternChar == '~' && Character.isDigit(b)) {
+                        // nothing to do...
+                    } else {
+                        if (patternChar == '~') {
+                            patternChar = cs[++positions[i]];
+                        }
+                        if (b == patternChar) {
+                            positions[i]++;
+                        } else {
+                            positions[i] = 0;
+                        }
+                    }
+                    if (positions[i] == patterns[i].length) {
+                        positions[i] = 0;
+                        patternFound(i);
+                    }
+                }
+            } catch (RuntimeException e) {
+                e.printStackTrace(delegate);
+                throw e;
+            }
+        }
+    }
+
+    public static void initialize(final CompilerToVM compilerToVM) {
+        final class BenchmarkCountersOutputStream extends CallbackOutputStream {
+
+            private long startTime;
+            private boolean waitingForEnd;
+
+            private BenchmarkCountersOutputStream(PrintStream delegate, String start, String end) {
+                super(delegate, new String[]{start, end, "\n"});
+            }
+
+            @Override
+            protected void patternFound(int index) {
+                switch (index) {
+                    case 0:
+                        startTime = System.nanoTime();
+                        BenchmarkCounters.clear(compilerToVM.collectCounters());
+                        break;
+                    case 1:
+                        waitingForEnd = true;
+                        break;
+                    case 2:
+                        if (waitingForEnd) {
+                            waitingForEnd = false;
+                            BenchmarkCounters.dump(delegate, (System.nanoTime() - startTime) / 1000000000d, compilerToVM.collectCounters());
+                        }
+                        break;
+                }
+            }
+        }
+
+        if (Options.BenchmarkDynamicCounters.getValue() != null) {
+            String[] arguments = Options.BenchmarkDynamicCounters.getValue().split(",");
+            if (arguments.length == 0 || (arguments.length % 3) != 0) {
+                throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: (err|out),start,end,(err|out),start,end,... (~ matches multiple digits)");
+            }
+            for (int i = 0; i < arguments.length; i += 3) {
+                if (arguments[i].equals("err")) {
+                    System.setErr(new PrintStream(new BenchmarkCountersOutputStream(System.err, arguments[i + 1], arguments[i + 2])));
+                } else if (arguments[i].equals("out")) {
+                    System.setOut(new PrintStream(new BenchmarkCountersOutputStream(System.out, arguments[i + 1], arguments[i + 2])));
+                } else {
+                    throw new GraalInternalError("invalid arguments to BenchmarkDynamicCounters: err|out");
+                }
+            }
+            excludedClassPrefix = "Lcom/oracle/graal/";
+            enabled = true;
+        }
+        if (Options.GenericDynamicCounters.getValue()) {
+            enabled = true;
+        }
+        if (Options.GenericDynamicCounters.getValue() || Options.BenchmarkDynamicCounters.getValue() != null) {
+            clear(compilerToVM.collectCounters());
+        }
+    }
+
+    public static void shutdown(CompilerToVM compilerToVM, long compilerStartTime) {
+        if (Options.GenericDynamicCounters.getValue()) {
+            dump(System.out, (System.nanoTime() - compilerStartTime) / 1000000000d, compilerToVM.collectCounters());
+        }
+    }
+
+    public static void lower(DynamicCounterNode counter, HotSpotRuntime runtime) {
+        StructuredGraph graph = counter.graph();
+        if (excludedClassPrefix == null || !counter.graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
+            HotSpotVMConfig config = runtime.config;
+
+            ReadRegisterNode thread = graph.add(new ReadRegisterNode(runtime.threadRegister(), runtime.getTarget().wordKind, true, false));
+
+            int index = BenchmarkCounters.getIndex(counter);
+            if (index >= config.graalCountersSize) {
+                throw new GraalInternalError("too many counters, reduce number of counters or increase GRAAL_COUNTERS_SIZE (current value: " + config.graalCountersSize + ")");
+            }
+            ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, config.graalCountersThreadOffset + Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
+            ReadNode read = graph.add(new ReadNode(thread, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
+            IntegerAddNode add = graph.unique(new IntegerAddNode(Kind.Long, read, counter.getIncrement()));
+            WriteNode write = graph.add(new WriteNode(thread, add, location, BarrierType.NONE, false));
+
+            graph.addBeforeFixed(counter, thread);
+            graph.addBeforeFixed(counter, read);
+            graph.addBeforeFixed(counter, write);
+        }
+        graph.removeFixed(counter);
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaField.java	Wed Oct 02 21:40:29 2013 +0200
@@ -99,7 +99,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = runtime.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class));
+            makeGraphMethod = runtime.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, rjm, SnippetInliningPolicy.class, boolean.class));
             initMethod = runtime.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Wed Oct 02 21:40:29 2013 +0200
@@ -74,6 +74,7 @@
 import com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
+import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.replacements.*;
@@ -82,6 +83,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -554,7 +556,7 @@
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
             BarrierType barrierType = getFieldLoadBarrierType(field);
-            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
+            ReadNode memoryRead = graph.add(new ReadNode(object, createFieldLocation(graph, field, false), loadField.stamp(), barrierType, (loadField.kind() == Kind.Object)));
             graph.replaceFixedWithFixed(loadField, memoryRead);
             tool.createNullCheckGuard(memoryRead, object);
 
@@ -569,7 +571,7 @@
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
             BarrierType barrierType = getFieldStoreBarrierType(storeField);
-            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field), barrierType, storeField.field().getKind() == Kind.Object));
+            WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), createFieldLocation(graph, field, false), barrierType, storeField.field().getKind() == Kind.Object));
             tool.createNullCheckGuard(memoryWrite, object);
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
@@ -594,7 +596,7 @@
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
             GuardingNode boundsCheck = createBoundsCheck(loadIndexed, tool);
             Kind elementKind = loadIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index(), false);
             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp(), BarrierType.NONE, elementKind == Kind.Object));
             memoryRead.setGuard(boundsCheck);
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
@@ -602,7 +604,7 @@
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
             GuardingNode boundsCheck = createBoundsCheck(storeIndexed, tool);
             Kind elementKind = storeIndexed.elementKind();
-            LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
+            LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index(), false);
             ValueNode value = storeIndexed.value();
             ValueNode array = storeIndexed.array();
 
@@ -717,7 +719,7 @@
                                 value = allocations[commit.getVirtualObjects().indexOf(value)];
                             }
                             if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i)),
+                                WriteNode write = new WriteNode(newObject, value, createFieldLocation(graph, (HotSpotResolvedJavaField) virtualInstance.field(i), true),
                                                 virtualInstance.field(i).getKind() == Kind.Object ? BarrierType.IMPRECISE : BarrierType.NONE, virtualInstance.field(i).getKind() == Kind.Object);
 
                                 graph.addBeforeFixed(commit, graph.add(write));
@@ -735,7 +737,7 @@
                                 value = allocations[indexOf];
                             }
                             if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
-                                WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph)),
+                                WriteNode write = new WriteNode(newObject, value, createArrayLocation(graph, element.getKind(), ConstantNode.forInt(i, graph), true),
                                                 value.kind() == Kind.Object ? BarrierType.PRECISE : BarrierType.NONE, value.kind() == Kind.Object);
                                 graph.addBeforeFixed(commit, graph.add(write));
                             }
@@ -788,6 +790,10 @@
                 osrStart.replaceAtUsages(newStart);
                 osrStart.safeDelete();
             }
+        } else if (n instanceof DynamicCounterNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.AFTER_FSA) {
+                BenchmarkCounters.lower((DynamicCounterNode) n, this);
+            }
         } else if (n instanceof CheckCastDynamicNode) {
             checkcastDynamicSnippets.lower((CheckCastDynamicNode) n);
         } else if (n instanceof InstanceOfNode) {
@@ -937,8 +943,9 @@
         return barrierType;
     }
 
-    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field) {
-        return ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
+    protected static ConstantLocationNode createFieldLocation(StructuredGraph graph, HotSpotResolvedJavaField field, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : field;
+        return ConstantLocationNode.create(loc, field.getKind(), field.offset(), graph);
     }
 
     public int getScalingFactor(Kind kind) {
@@ -949,9 +956,10 @@
         }
     }
 
-    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index) {
+    protected IndexedLocationNode createArrayLocation(Graph graph, Kind elementKind, ValueNode index, boolean initialization) {
+        LocationIdentity loc = initialization ? INIT_LOCATION : NamedLocationIdentity.getArrayLocation(elementKind);
         int scale = getScalingFactor(elementKind);
-        return IndexedLocationNode.create(NamedLocationIdentity.getArrayLocation(elementKind), elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
+        return IndexedLocationNode.create(loc, elementKind, getArrayBaseOffset(elementKind), index, graph, scale);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Wed Oct 02 21:40:29 2013 +0200
@@ -40,14 +40,17 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
@@ -63,6 +66,22 @@
  */
 public class MonitorSnippets implements Snippets {
 
+    public static class Options {
+
+        //@formatter:off
+        @Option(help = "")
+        private static final OptionValue<Boolean> ProfileMonitors = new OptionValue<>(false);
+        //@formatter:on
+    }
+
+    private static final boolean PROFILE_CONTEXT = false;
+
+    @Fold
+    @SuppressWarnings("unused")
+    private static boolean doProfile(String path) {
+        return Options.ProfileMonitors.getValue();
+    }
+
     /**
      * Monitor operations on objects whose type contains this substring will be traced.
      */
@@ -118,7 +137,7 @@
                 trace(trace, "              tmp: 0x%016lx\n", tmp);
                 if (probability(FREQUENT_PROBABILITY, tmp.equal(0))) {
                     // Object is already biased to current thread -> done
-                    traceObject(trace, "+lock{bias:existing}", object);
+                    traceObject(trace, "+lock{bias:existing}", object, true);
                     return;
                 }
 
@@ -154,13 +173,13 @@
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
                         if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), unbiasedMark, biasedMark, MARK_WORD_LOCATION).equal(unbiasedMark))) {
                             // Object is now biased to current thread -> done
-                            traceObject(trace, "+lock{bias:acquired}", object);
+                            traceObject(trace, "+lock{bias:acquired}", object, true);
                             return;
                         }
                         // If the biasing toward our thread failed, this means that another thread
                         // owns the bias and we need to revoke that bias. The revocation will occur
                         // in the interpreter runtime.
-                        traceObject(trace, "+lock{stub:revoke}", object);
+                        traceObject(trace, "+lock{stub:revoke}", object, true);
                         monitorenterStub(MONITORENTER, object, lock);
                         return;
                     } else {
@@ -174,13 +193,13 @@
                         trace(trace, "       biasedMark: 0x%016lx\n", biasedMark);
                         if (probability(VERY_FAST_PATH_PROBABILITY, compareAndSwap(object, markOffset(), mark, biasedMark, MARK_WORD_LOCATION).equal(mark))) {
                             // Object is now biased to current thread -> done
-                            traceObject(trace, "+lock{bias:transfer}", object);
+                            traceObject(trace, "+lock{bias:transfer}", object, true);
                             return;
                         }
                         // If the biasing toward our thread failed, then another thread
                         // succeeded in biasing it toward itself and we need to revoke that
                         // bias. The revocation will occur in the runtime in the slow case.
-                        traceObject(trace, "+lock{stub:epoch-expired}", object);
+                        traceObject(trace, "+lock{stub:epoch-expired}", object, true);
                         monitorenterStub(MONITORENTER, object, lock);
                         return;
                     }
@@ -237,16 +256,16 @@
             final Word stackPointer = stackPointer();
             if (probability(VERY_SLOW_PATH_PROBABILITY, currentMark.subtract(stackPointer).and(alignedMask.subtract(pageSize())).notEqual(0))) {
                 // Most likely not a recursive lock, go into a slow runtime call
-                traceObject(trace, "+lock{stub:failed-cas}", object);
+                traceObject(trace, "+lock{stub:failed-cas}", object, true);
                 monitorenterStub(MONITORENTER, object, lock);
                 return;
             } else {
                 // Recursively locked => write 0 to the lock slot
                 lock.writeWord(lockDisplacedMarkOffset(), Word.zero(), DISPLACED_MARK_WORD_LOCATION);
-                traceObject(trace, "+lock{recursive}", object);
+                traceObject(trace, "+lock{recursive}", object, true);
             }
         } else {
-            traceObject(trace, "+lock{cas}", object);
+            traceObject(trace, "+lock{cas}", object, true);
         }
     }
 
@@ -263,7 +282,7 @@
         // BeginLockScope nodes do not read from object so a use of object
         // cannot float about the null check above
         final Word lock = beginLockScope(lockDepth);
-        traceObject(trace, "+lock{stub}", object);
+        traceObject(trace, "+lock{stub}", object, true);
         monitorenterStub(MONITORENTER, object, lock);
     }
 
@@ -282,7 +301,7 @@
             if (probability(FREQUENT_PROBABILITY, mark.and(biasedLockMaskInPlace()).equal(Word.unsigned(biasedLockPattern())))) {
                 endLockScope();
                 decCounter();
-                traceObject(trace, "-lock{bias}", object);
+                traceObject(trace, "-lock{bias}", object, false);
                 return;
             }
         }
@@ -295,7 +314,7 @@
 
         if (displacedMark.equal(0)) {
             // Recursive locking => done
-            traceObject(trace, "-lock{recursive}", object);
+            traceObject(trace, "-lock{recursive}", object, false);
         } else {
             verifyOop(object);
             // Test if object's mark word is pointing to the displaced mark word, and if so, restore
@@ -304,10 +323,10 @@
             if (probability(VERY_SLOW_PATH_PROBABILITY, DirectCompareAndSwapNode.compareAndSwap(object, markOffset(), lock, displacedMark, MARK_WORD_LOCATION).notEqual(lock))) {
                 // The object's mark word was not pointing to the displaced header,
                 // we do unlocking via runtime call.
-                traceObject(trace, "-lock{stub}", object);
+                traceObject(trace, "-lock{stub}", object, false);
                 MonitorExitStubCall.call(object, lockDepth);
             } else {
-                traceObject(trace, "-lock{cas}", object);
+                traceObject(trace, "-lock{cas}", object, false);
             }
         }
         endLockScope();
@@ -320,13 +339,16 @@
     @Snippet
     public static void monitorexitStub(Object object, @ConstantParameter int lockDepth, @ConstantParameter boolean trace) {
         verifyOop(object);
-        traceObject(trace, "-lock{stub}", object);
+        traceObject(trace, "-lock{stub}", object, false);
         MonitorExitStubCall.call(object, lockDepth);
         endLockScope();
         decCounter();
     }
 
-    private static void traceObject(boolean enabled, String action, Object object) {
+    private static void traceObject(boolean enabled, String action, Object object, boolean enter) {
+        if (doProfile(action)) {
+            DynamicCounterNode.counter(action, enter ? "~monitorenter" : "~monitorexit", 1, PROFILE_CONTEXT);
+        }
         if (enabled) {
             Log.print(action);
             Log.print(' ');
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Oct 02 21:40:29 2013 +0200
@@ -34,17 +34,21 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ConstantNodeParameter;
 import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.debug.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.ConstantParameter;
+import com.oracle.graal.replacements.Snippet.Fold;
 import com.oracle.graal.replacements.Snippet.VarargsParameter;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
@@ -59,6 +63,20 @@
 
     public static final LocationIdentity INIT_LOCATION = new NamedLocationIdentity("Initialization");
 
+    public static class Options {
+
+        //@formatter:off
+        @Option(help = "")
+        private static final OptionValue<Boolean> ProfileAllocations = new OptionValue<>(false);
+        //@formatter:on
+    }
+
+    static enum ProfileMode {
+        AllocatingMethods, InstanceOrArray, AllocatedTypes, AllocatedTypesInMethods, Total
+    }
+
+    public static final ProfileMode PROFILE_MODE = ProfileMode.Total;
+
     @Snippet
     public static Word allocate(int size) {
         Word thread = thread();
@@ -76,8 +94,41 @@
         return Word.zero();
     }
 
+    @Fold
+    private static String createName(String path, String typeContext) {
+        switch (PROFILE_MODE) {
+            case AllocatingMethods:
+                return "";
+            case InstanceOrArray:
+                return path;
+            case AllocatedTypes:
+            case AllocatedTypesInMethods:
+                return typeContext;
+            case Total:
+                return "bytes";
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Fold
+    @SuppressWarnings("unused")
+    private static boolean doProfile(String path, String typeContext) {
+        return Options.ProfileAllocations.getValue();
+    }
+
+    private static void profileAllocation(String path, long size, String typeContext) {
+        if (doProfile(path, typeContext)) {
+            String name = createName(path, typeContext);
+
+            boolean context = PROFILE_MODE == ProfileMode.AllocatingMethods || PROFILE_MODE == ProfileMode.AllocatedTypesInMethods;
+            DynamicCounterNode.counter(name, "~bytes", size, context);
+            DynamicCounterNode.counter(name, "~sites", 1, context);
+        }
+    }
+
     @Snippet
-    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents) {
+    public static Object allocateInstance(@ConstantParameter int size, Word hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
         Object result;
         Word thread = thread();
         Word top = readTlabTop(thread);
@@ -90,6 +141,7 @@
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         }
+        profileAllocation("instance", size, typeContext);
         return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
@@ -99,15 +151,16 @@
     public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
 
     @Snippet
-    public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize, @ConstantParameter boolean fillContents) {
+    public static Object allocateArray(Word hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
+                    @ConstantParameter boolean fillContents, @ConstantParameter String typeContext) {
         if (!belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH)) {
             // This handles both negative array sizes and very large array sizes
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, typeContext);
     }
 
-    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents) {
+    private static Object allocateArrayImpl(Word hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, String typeContext) {
         Object result;
         int alignment = wordSize();
         int allocationSize = computeArrayAllocationSize(length, alignment, headerSize, log2ElementSize);
@@ -123,6 +176,7 @@
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         }
+        profileAllocation("array", allocationSize, typeContext);
         return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
@@ -156,7 +210,7 @@
         int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
         Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
 
-        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents);
+        return allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, "dynamic type");
     }
 
     /**
@@ -261,6 +315,7 @@
             args.add("hub", hub);
             args.add("prototypeMarkWord", type.prototypeMarkWord());
             args.addConst("fillContents", newInstanceNode.fillContents());
+            args.addConst("typeContext", MetaUtil.toJavaName(type, false));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
@@ -286,6 +341,7 @@
             args.addConst("headerSize", headerSize);
             args.addConst("log2ElementSize", log2ElementSize);
             args.addConst("fillContents", newArrayNode.fillContents());
+            args.addConst("typeContext", MetaUtil.toJavaName(arrayType, false));
 
             SnippetTemplate template = template(args);
             Debug.log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -59,49 +59,72 @@
         }
 
         ResolvedJavaType type = ObjectStamp.typeOrNull(getObject());
-        Method method;
-        /*
-         * The first condition tests if the parameter is an array, the second condition tests if the
-         * parameter can be an array. Otherwise, the parameter is known to be a non-array object.
-         */
-        if (type.isArray()) {
-            method = ObjectCloneSnippets.arrayCloneMethod;
-        } else if (type == null || type.isAssignableFrom(tool.getRuntime().lookupJavaType(Object[].class))) {
-            method = ObjectCloneSnippets.genericCloneMethod;
-        } else {
-            method = ObjectCloneSnippets.instanceCloneMethod;
+        if (type != null) {
+            if (type.isArray()) {
+                Method method = ObjectCloneSnippets.arrayCloneMethods.get(type.getComponentType().getKind());
+                if (method != null) {
+                    final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
+                    final Replacements replacements = tool.getReplacements();
+                    StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
+
+                        @Override
+                        public StructuredGraph call() throws Exception {
+                            return replacements.getSnippet(snippetMethod);
+                        }
+                    });
+
+                    assert snippetGraph != null : "ObjectCloneSnippets should be installed";
+                    return lowerReplacement(snippetGraph.copy(), tool);
+                }
+            } else {
+                type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getRuntime());
+                if (type != null) {
+                    StructuredGraph newGraph = new StructuredGraph();
+                    LocalNode local = newGraph.add(new LocalNode(0, getObject().stamp()));
+                    NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true));
+                    newGraph.addAfterFixed(newGraph.start(), newInstance);
+                    ReturnNode returnNode = newGraph.add(new ReturnNode(newInstance));
+                    newGraph.addAfterFixed(newInstance, returnNode);
+
+                    for (ResolvedJavaField field : type.getInstanceFields(true)) {
+                        LoadFieldNode load = newGraph.add(new LoadFieldNode(local, field));
+                        newGraph.addBeforeFixed(returnNode, load);
+                        newGraph.addBeforeFixed(returnNode, newGraph.add(new StoreFieldNode(newInstance, field, load)));
+                    }
+                    return lowerReplacement(newGraph, tool);
+                }
+            }
         }
-        final ResolvedJavaMethod snippetMethod = tool.getRuntime().lookupJavaMethod(method);
-        final Replacements replacements = tool.getReplacements();
-        StructuredGraph snippetGraph = Debug.scope("ArrayCopySnippet", snippetMethod, new Callable<StructuredGraph>() {
-
-            @Override
-            public StructuredGraph call() throws Exception {
-                return replacements.getSnippet(snippetMethod);
-            }
-        });
-
-        assert snippetGraph != null : "ObjectCloneSnippets should be installed";
-        return lowerReplacement(snippetGraph.copy(), tool);
+        return null;
     }
 
     private static boolean isCloneableType(ResolvedJavaType type, MetaAccessProvider metaAccess) {
-        return type != null && metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type);
+        return metaAccess.lookupJavaType(Cloneable.class).isAssignableFrom(type);
     }
 
-    private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions) {
+    /*
+     * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
+     * exact type) and if it is a cloneable type.
+     * 
+     * If yes, then the exact type is returned, otherwise it returns null.
+     */
+    private static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
         if (!(stamp instanceof ObjectStamp)) {
             return null;
         }
         ObjectStamp objectStamp = (ObjectStamp) stamp;
-        if (objectStamp.isExactType() || objectStamp.type() == null) {
-            return objectStamp.type();
+        if (objectStamp.type() == null) {
+            return null;
+        } else if (objectStamp.isExactType()) {
+            return isCloneableType(objectStamp.type(), metaAccess) ? objectStamp.type() : null;
         } else {
             ResolvedJavaType type = objectStamp.type().findUniqueConcreteSubtype();
-            if (type != null) {
+            if (type != null && isCloneableType(type, metaAccess)) {
                 assumptions.recordConcreteSubtype(objectStamp.type(), type);
+                return type;
+            } else {
+                return null;
             }
-            return type;
         }
     }
 
@@ -126,21 +149,19 @@
             } else {
                 obj = tool.getReplacedValue(getObject());
             }
-            ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions());
-            if (isCloneableType(type, tool.getMetaAccessProvider())) {
-                if (!type.isArray()) {
-                    VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true);
-                    ResolvedJavaField[] fields = newVirtual.getFields();
+            ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions(), tool.getMetaAccessProvider());
+            if (type != null && !type.isArray()) {
+                VirtualInstanceNode newVirtual = new VirtualInstanceNode(type, true);
+                ResolvedJavaField[] fields = newVirtual.getFields();
 
-                    ValueNode[] state = new ValueNode[fields.length];
-                    final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
-                    for (int i = 0; i < fields.length; i++) {
-                        state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
-                        tool.addNode(loads[i]);
-                    }
-                    tool.createVirtualObject(newVirtual, state, null);
-                    tool.replaceWithVirtual(newVirtual);
+                ValueNode[] state = new ValueNode[fields.length];
+                final LoadFieldNode[] loads = new LoadFieldNode[fields.length];
+                for (int i = 0; i < fields.length; i++) {
+                    state[i] = loads[i] = new LoadFieldNode(obj, fields[i]);
+                    tool.addNode(loads[i]);
                 }
+                tool.createVirtualObject(newVirtual, state, null);
+                tool.replaceWithVirtual(newVirtual);
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneSnippets.java	Wed Oct 02 21:40:29 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, 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
@@ -22,113 +22,77 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.api.meta.LocationIdentity.*;
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.phases.GraalOptions.*;
-
 import java.lang.reflect.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
 
 public class ObjectCloneSnippets implements Snippets {
 
-    public static final Method instanceCloneMethod = getCloneMethod("instanceClone");
-    public static final Method arrayCloneMethod = getCloneMethod("arrayClone");
-    public static final Method genericCloneMethod = getCloneMethod("genericClone");
+    public static final EnumMap<Kind, Method> arrayCloneMethods = new EnumMap<>(Kind.class);
 
-    private static Method getCloneMethod(String name) {
+    static {
+        arrayCloneMethods.put(Kind.Byte, getCloneMethod("byteArrayClone", byte[].class));
+        arrayCloneMethods.put(Kind.Char, getCloneMethod("charArrayClone", char[].class));
+        arrayCloneMethods.put(Kind.Int, getCloneMethod("intArrayClone", int[].class));
+        arrayCloneMethods.put(Kind.Long, getCloneMethod("longArrayClone", long[].class));
+        arrayCloneMethods.put(Kind.Object, getCloneMethod("objectArrayClone", Object[].class));
+    }
+
+    private static Method getCloneMethod(String name, Class<?> param) {
         try {
-            return ObjectCloneSnippets.class.getDeclaredMethod(name, Object.class);
+            return ObjectCloneSnippets.class.getDeclaredMethod(name, param);
         } catch (SecurityException | NoSuchMethodException e) {
             throw new GraalInternalError(e);
         }
     }
 
-    private static Object instanceClone(Object src, Word hub, int layoutHelper) {
-        int instanceSize = layoutHelper;
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateInstance(instanceSize, hub, prototypeMarkWord, false);
-
-        for (int offset = instanceHeaderSize(); offset < instanceSize; offset += wordSize()) {
-            /*
-             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
-             * to be copied atomically, but here they are copied as two 4-byte word values.
-             */
-            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
+    @Snippet(removeAllFrameStates = true)
+    public static byte[] byteArrayClone(byte[] src) {
+        byte[] result = new byte[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
-
         return result;
     }
 
-    private static Object arrayClone(Object src, Word hub, int layoutHelper) {
-        int arrayLength = ArrayLengthNode.arrayLength(src);
-        int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift()) & layoutHelperLog2ElementSizeMask();
-        int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift()) & layoutHelperHeaderSizeMask();
-        int sizeInBytes = NewObjectSnippets.computeArrayAllocationSize(arrayLength, wordSize(), headerSize, log2ElementSize);
-
-        Word prototypeMarkWord = hub.readWord(prototypeMarkWordOffset(), PROTOTYPE_MARK_WORD_LOCATION);
-        Object result = NewObjectSnippets.allocateArray(hub, arrayLength, prototypeMarkWord, headerSize, log2ElementSize, false);
-
-        for (int offset = headerSize; offset < sizeInBytes; offset += wordSize()) {
-            /*
-             * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values
-             * to be copied atomically, but here they are copied as two 4-byte word values.
-             */
-            ObjectAccess.writeWord(result, offset, ObjectAccess.readWord(src, offset, ANY_LOCATION), ANY_LOCATION);
+    @Snippet(removeAllFrameStates = true)
+    public static char[] charArrayClone(char[] src) {
+        char[] result = new char[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
         return result;
     }
 
-    private static Word getAndCheckHub(Object src) {
-        Word hub = loadHub(src);
-        if (!(src instanceof Cloneable)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+    @Snippet(removeAllFrameStates = true)
+    public static int[] intArrayClone(int[] src) {
+        int[] result = new int[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
-        return hub;
-    }
-
-    @Snippet
-    public static Object instanceClone(Object src) {
-        instanceCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        return instanceClone(src, hub, hub.readInt(layoutHelperOffset(), FINAL_LOCATION));
-    }
-
-    @Snippet
-    public static Object arrayClone(Object src) {
-        arrayCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
-        return arrayClone(src, hub, layoutHelper);
+        return result;
     }
 
-    @Snippet
-    public static Object genericClone(Object src) {
-        genericCloneCounter.inc();
-        Word hub = getAndCheckHub(src);
-        int layoutHelper = hub.readInt(layoutHelperOffset(), FINAL_LOCATION);
-        if (probability(LIKELY_PROBABILITY, layoutHelper < 0)) {
-            genericArrayCloneCounter.inc();
-            return arrayClone(src, hub, layoutHelper);
-        } else {
-            genericInstanceCloneCounter.inc();
-            return instanceClone(src, hub, layoutHelper);
+    @Snippet(removeAllFrameStates = true)
+    public static long[] longArrayClone(long[] src) {
+        long[] result = new long[src.length];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
         }
+        return result;
     }
 
-    private static final SnippetCounter.Group cloneCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Object.clone") : null;
-    private static final SnippetCounter instanceCloneCounter = new SnippetCounter(cloneCounters, "instanceClone", "clone snippet for instances");
-    private static final SnippetCounter arrayCloneCounter = new SnippetCounter(cloneCounters, "arrayClone", "clone snippet for arrays");
-    private static final SnippetCounter genericCloneCounter = new SnippetCounter(cloneCounters, "genericClone", "clone snippet for arrays and instances");
-
-    private static final SnippetCounter.Group genericCloneCounters = SnippetCounters.getValue() ? new SnippetCounter.Group("Object.clone generic snippet") : null;
-    private static final SnippetCounter genericInstanceCloneCounter = new SnippetCounter(genericCloneCounters, "genericInstanceClone", "generic clone implementation took instance path");
-    private static final SnippetCounter genericArrayCloneCounter = new SnippetCounter(genericCloneCounters, "genericArrayClone", "generic clone implementation took array path");
-
+    @Snippet(removeAllFrameStates = true)
+    public static Object[] objectArrayClone(Object[] src) {
+        Object[] result = (Object[]) DynamicNewArrayNode.newArray(GuardingPiNode.guardingNonNull(src.getClass().getComponentType()), src.length);
+        for (int i = 0; i < result.length; i++) {
+            result[i] = src[i];
+        }
+        return result;
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Wed Oct 02 21:40:29 2013 +0200
@@ -305,7 +305,7 @@
     private void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
         ReplacementsImpl repl = new ReplacementsImpl(runtime, new Assumptions(false), runtime.getTarget());
-        StructuredGraph calleeGraph = repl.makeGraph(method, null, null);
+        StructuredGraph calleeGraph = repl.makeGraph(method, null, null, false);
         InliningUtil.inline(invoke, calleeGraph, false);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -121,7 +121,7 @@
     @Override
     public void setNext(FixedNode x) {
         if (x != null) {
-            this.setNext(AbstractBeginNode.begin(x));
+            this.setNext(KillingBeginNode.begin(x, getLocationIdentity()));
         } else {
             this.setNext(null);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, 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.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.extended.*;
+
+public class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single {
+
+    private LocationIdentity locationIdentity;
+
+    public KillingBeginNode(LocationIdentity locationIdentity) {
+        this.locationIdentity = locationIdentity;
+    }
+
+    public static KillingBeginNode begin(FixedNode with, LocationIdentity locationIdentity) {
+        if (with instanceof KillingBeginNode) {
+            return (KillingBeginNode) with;
+        }
+        KillingBeginNode begin = with.graph().add(new KillingBeginNode(locationIdentity));
+        begin.setNext(with);
+        return begin;
+    }
+
+    @Override
+    public LocationIdentity getLocationIdentity() {
+        return locationIdentity;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,6 +42,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() & inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return x();
@@ -50,12 +56,7 @@
             return graph().unique(new AndNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() & y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() & y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -151,52 +151,59 @@
         this.value = value;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        Constant c = inputs[0];
+        switch (opcode) {
+            case I2L:
+                return Constant.forLong(c.asInt());
+            case L2I:
+                return Constant.forInt((int) c.asLong());
+            case I2B:
+                return Constant.forByte((byte) c.asInt());
+            case I2C:
+                return Constant.forChar((char) c.asInt());
+            case I2S:
+                return Constant.forShort((short) c.asInt());
+            case F2D:
+                return Constant.forDouble(c.asFloat());
+            case D2F:
+                return Constant.forFloat((float) c.asDouble());
+            case I2F:
+                return Constant.forFloat(c.asInt());
+            case I2D:
+                return Constant.forDouble(c.asInt());
+            case F2I:
+                return Constant.forInt((int) c.asFloat());
+            case D2I:
+                return Constant.forInt((int) c.asDouble());
+            case L2F:
+                return Constant.forFloat(c.asLong());
+            case L2D:
+                return Constant.forDouble(c.asLong());
+            case F2L:
+                return Constant.forLong((long) c.asFloat());
+            case D2L:
+                return Constant.forLong((long) c.asDouble());
+            case UNSIGNED_I2L:
+                return Constant.forLong(c.asInt() & 0xffffffffL);
+            case MOV_I2F:
+                return Constant.forFloat(java.lang.Float.intBitsToFloat(c.asInt()));
+            case MOV_L2D:
+                return Constant.forDouble(java.lang.Double.longBitsToDouble(c.asLong()));
+            case MOV_F2I:
+                return Constant.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()));
+            case MOV_D2L:
+                return Constant.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()));
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (value instanceof ConstantNode) {
-            Constant c = ((ConstantNode) value).asConstant();
-            switch (opcode) {
-                case I2L:
-                    return ConstantNode.forLong(c.asInt(), graph());
-                case L2I:
-                    return ConstantNode.forInt((int) c.asLong(), graph());
-                case I2B:
-                    return ConstantNode.forByte((byte) c.asInt(), graph());
-                case I2C:
-                    return ConstantNode.forChar((char) c.asInt(), graph());
-                case I2S:
-                    return ConstantNode.forShort((short) c.asInt(), graph());
-                case F2D:
-                    return ConstantNode.forDouble(c.asFloat(), graph());
-                case D2F:
-                    return ConstantNode.forFloat((float) c.asDouble(), graph());
-                case I2F:
-                    return ConstantNode.forFloat(c.asInt(), graph());
-                case I2D:
-                    return ConstantNode.forDouble(c.asInt(), graph());
-                case F2I:
-                    return ConstantNode.forInt((int) c.asFloat(), graph());
-                case D2I:
-                    return ConstantNode.forInt((int) c.asDouble(), graph());
-                case L2F:
-                    return ConstantNode.forFloat(c.asLong(), graph());
-                case L2D:
-                    return ConstantNode.forDouble(c.asLong(), graph());
-                case F2L:
-                    return ConstantNode.forLong((long) c.asFloat(), graph());
-                case D2L:
-                    return ConstantNode.forLong((long) c.asDouble(), graph());
-                case UNSIGNED_I2L:
-                    return ConstantNode.forLong(c.asInt() & 0xffffffffL, graph());
-                case MOV_I2F:
-                    return ConstantNode.forFloat(java.lang.Float.intBitsToFloat(c.asInt()), graph());
-                case MOV_L2D:
-                    return ConstantNode.forDouble(java.lang.Double.longBitsToDouble(c.asLong()), graph());
-                case MOV_F2I:
-                    return ConstantNode.forInt(java.lang.Float.floatToRawIntBits(c.asFloat()), graph());
-                case MOV_D2L:
-                    return ConstantNode.forLong(java.lang.Double.doubleToRawLongBits(c.asDouble()), graph());
-            }
+        if (value.isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(value.asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -35,18 +35,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(inputs[0].asFloat() + inputs[1].asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(inputs[0].asDouble() + inputs[1].asDouble());
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new FloatAddNode(kind(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() + y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() + y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Float) {
                 float c = y().asConstant().asFloat();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -35,19 +35,20 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(inputs[0].asFloat() / inputs[1].asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(inputs[0].asDouble() / inputs[1].asDouble());
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                if (y().asConstant().asFloat() != 0) {
-                    return ConstantNode.forFloat(x().asConstant().asFloat() / y().asConstant().asFloat(), graph());
-                }
-            } else {
-                assert kind() == Kind.Double;
-                if (y().asConstant().asDouble() != 0) {
-                    return ConstantNode.forDouble(x().asConstant().asDouble() / y().asConstant().asDouble(), graph());
-                }
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -35,18 +35,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(inputs[0].asFloat() * inputs[1].asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(inputs[0].asDouble() * inputs[1].asDouble());
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new FloatMulNode(kind(), y(), x(), isStrictFP()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() * y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() * y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -35,15 +35,20 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(inputs[0].asFloat() % inputs[1].asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(inputs[0].asDouble() % inputs[1].asDouble());
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() % y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() % y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -35,18 +35,23 @@
         super(kind, x, y, isStrictFP);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Float) {
+            return Constant.forFloat(inputs[0].asFloat() - inputs[1].asFloat());
+        } else {
+            assert kind() == Kind.Double;
+            return Constant.forDouble(inputs[0].asDouble() - inputs[1].asDouble());
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forFloatingKind(kind(), 0.0f, graph());
         }
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Float) {
-                return ConstantNode.forFloat(x().asConstant().asFloat() - y().asConstant().asFloat(), graph());
-            } else {
-                assert kind() == Kind.Double;
-                return ConstantNode.forDouble(x().asConstant().asDouble() - y().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Float) {
                 float c = y().asConstant().asFloat();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,6 +42,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() + inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new IntegerAddNode(kind(), y(), x()));
@@ -61,12 +67,7 @@
             }
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() + y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() + y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -37,17 +37,18 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() * inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant() && !y().isConstant()) {
             return graph().unique(new IntegerMulNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() * y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() * y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 1) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,6 +42,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() - inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forIntegerKind(kind(), 0, graph());
@@ -81,12 +87,7 @@
             }
         }
         if (x().isConstant() && y().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() - y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() - y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             long c = y().asConstant().asLong();
             if (c == 0) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,8 +42,21 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() << inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() << inputs[1].asLong());
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -54,14 +67,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() << amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() << amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
@@ -54,19 +55,26 @@
         this.x = x;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        switch (inputs[0].getKind()) {
+            case Int:
+                return Constant.forInt(-inputs[0].asInt());
+            case Long:
+                return Constant.forLong(-inputs[0].asLong());
+            case Float:
+                return Constant.forFloat(-inputs[0].asFloat());
+            case Double:
+                return Constant.forDouble(-inputs[0].asDouble());
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            switch (x().kind()) {
-                case Int:
-                    return ConstantNode.forInt(-x().asConstant().asInt(), graph());
-                case Long:
-                    return ConstantNode.forLong(-x().asConstant().asLong(), graph());
-                case Float:
-                    return ConstantNode.forFloat(-x().asConstant().asFloat(), graph());
-                case Double:
-                    return ConstantNode.forDouble(-x().asConstant().asDouble(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x.asConstant()), graph());
         }
         if (x() instanceof NegateNode) {
             return ((NegateNode) x()).x();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -45,6 +45,12 @@
         return updateStamp(StampTool.not(x().stamp()));
     }
 
+    @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        return Constant.forIntegerKind(kind(), ~inputs[0].asLong(), null);
+    }
+
     /**
      * Creates new NegateNode instance.
      * 
@@ -59,12 +65,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            switch (x().kind()) {
-                case Int:
-                    return ConstantNode.forInt(~x().asConstant().asInt(), graph());
-                case Long:
-                    return ConstantNode.forLong(~x().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
         }
         if (x() instanceof NotNode) {
             return ((NotNode) x()).x();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,6 +42,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() | inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return x();
@@ -50,12 +56,7 @@
             return graph().unique(new OrNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() | y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() | y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -37,11 +37,24 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() >> inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() >> inputs[1].asLong());
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().stamp() instanceof IntegerStamp && ((IntegerStamp) x().stamp()).isPositive()) {
             return graph().unique(new UnsignedRightShiftNode(kind(), x(), y()));
         }
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -52,14 +65,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() >> amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() >> amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,8 +42,21 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        if (kind() == Kind.Int) {
+            return Constant.forInt(inputs[0].asInt() >>> inputs[1].asInt());
+        } else {
+            assert kind() == Kind.Long;
+            return Constant.forLong(inputs[0].asLong() >>> inputs[1].asLong());
+        }
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
-        if (y().isConstant()) {
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
+        } else if (y().isConstant()) {
             int amount = y().asConstant().asInt();
             int originalAmout = amount;
             int mask;
@@ -54,14 +67,6 @@
                 mask = 0x3f;
             }
             amount &= mask;
-            if (x().isConstant()) {
-                if (kind() == Kind.Int) {
-                    return ConstantNode.forInt(x().asConstant().asInt() >>> amount, graph());
-                } else {
-                    assert kind() == Kind.Long;
-                    return ConstantNode.forLong(x().asConstant().asLong() >>> amount, graph());
-                }
-            }
             if (amount == 0) {
                 return x();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -42,6 +42,12 @@
     }
 
     @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return Constant.forIntegerKind(kind(), inputs[0].asLong() ^ inputs[1].asLong(), null);
+    }
+
+    @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x() == y()) {
             return ConstantNode.forIntegerKind(kind(), 0, graph());
@@ -50,12 +56,7 @@
             return graph().unique(new XorNode(kind(), y(), x()));
         }
         if (x().isConstant()) {
-            if (kind() == Kind.Int) {
-                return ConstantNode.forInt(x().asConstant().asInt() ^ y().asConstant().asInt(), graph());
-            } else {
-                assert kind() == Kind.Long;
-                return ConstantNode.forLong(x().asConstant().asLong() ^ y().asConstant().asLong(), graph());
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant(), y().asConstant()), graph());
         } else if (y().isConstant()) {
             if (kind() == Kind.Int) {
                 int c = y().asConstant().asInt();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -22,200 +22,61 @@
  */
 package com.oracle.graal.nodes.debug;
 
-import java.io.*;
-import java.util.*;
-
-import sun.misc.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.HeapAccess.BarrierType;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
  * This node can be used to add a counter to the code that will estimate the dynamic number of calls
  * by adding an increment to the compiled code. This should of course only be used for
- * debugging/testing purposes, and is not 100% accurate (because of concurrency issues while
- * accessing the counters).
+ * debugging/testing purposes.
  * 
- * A unique counter will be created for each unique String passed to the constructor.
+ * A unique counter will be created for each unique name passed to the constructor. Depending on the
+ * value of withContext, the name of the root method is added to the counter's name.
  */
 public class DynamicCounterNode extends FixedWithNextNode implements Lowerable {
 
-    private static final int MAX_COUNTERS = 10 * 1024;
-    public static final long[] COUNTERS = new long[MAX_COUNTERS];
-    private static final long[] STATIC_COUNTERS = new long[MAX_COUNTERS];
-    private static final String[] GROUPS = new String[MAX_COUNTERS];
-    private static final HashMap<String, Integer> INDEXES = new HashMap<>();
-    public static String excludedClassPrefix = null;
-    public static boolean enabled = false;
+    @Input private ValueNode increment;
 
     private final String name;
     private final String group;
-    private final long increment;
-    private final boolean addContext;
+    private final boolean withContext;
 
-    public DynamicCounterNode(String name, String group, long increment, boolean addContext) {
+    public DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) {
         super(StampFactory.forVoid());
-        if (!enabled) {
-            throw new GraalInternalError("dynamic counters not enabled");
-        }
         this.name = name;
         this.group = group;
         this.increment = increment;
-        this.addContext = addContext;
+        this.withContext = withContext;
+    }
+
+    public ValueNode getIncrement() {
+        return increment;
     }
 
     public String getName() {
         return name;
     }
 
-    public long getIncrement() {
-        return increment;
-    }
-
-    public boolean isAddContext() {
-        return addContext;
-    }
-
-    private static synchronized int getIndex(String name) {
-        Integer index = INDEXES.get(name);
-        if (index == null) {
-            index = INDEXES.size();
-            INDEXES.put(name, index);
-            if (index >= MAX_COUNTERS) {
-                throw new GraalInternalError("too many dynamic counters");
-            }
-            return index;
-        } else {
-            return index;
-        }
-    }
-
-    public static synchronized void dump(PrintStream out, double seconds) {
-        for (String group : new HashSet<>(Arrays.asList(GROUPS))) {
-            if (group != null) {
-                dumpCounters(out, seconds, true, group);
-                dumpCounters(out, seconds, false, group);
-            }
-        }
-        out.println("============================");
-
-        clear();
+    public String getGroup() {
+        return group;
     }
 
-    private static void dumpCounters(PrintStream out, double seconds, boolean staticCounter, String group) {
-        TreeMap<Long, String> sorted = new TreeMap<>();
-
-        long[] array = staticCounter ? STATIC_COUNTERS : COUNTERS;
-        long sum = 0;
-        for (Map.Entry<String, Integer> entry : INDEXES.entrySet()) {
-            int index = entry.getValue();
-            if (GROUPS[index].equals(group)) {
-                sum += array[index];
-                sorted.put(array[index] * MAX_COUNTERS + index, entry.getKey());
-            }
-        }
-
-        if (sum > 0) {
-            long cutoff = sum / 1000;
-            long sum2 = 0;
-            if (staticCounter) {
-                out.println("=========== " + group + " static counters: ");
-                for (Map.Entry<Long, String> entry : sorted.entrySet()) {
-                    long counter = entry.getKey() / MAX_COUNTERS;
-                    sum2 += counter;
-                    if (sum2 >= cutoff) {
-                        out.println(counter + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                    }
-                }
-                out.println(sum + ": total");
-            } else {
-                if (group.startsWith("~")) {
-                    out.println("=========== " + group + " dynamic counters");
-                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
-                        long counter = entry.getKey() / MAX_COUNTERS;
-                        sum2 += counter;
-                        if (sum2 >= cutoff) {
-                            out.println(counter + " \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                        }
-                    }
-                    out.println(sum + "/s: total");
-                } else {
-                    out.println("=========== " + group + " dynamic counters, time = " + seconds + " s");
-                    for (Map.Entry<Long, String> entry : sorted.entrySet()) {
-                        long counter = entry.getKey() / MAX_COUNTERS;
-                        sum2 += counter;
-                        if (sum2 >= cutoff) {
-                            out.println((long) (counter / seconds) + "/s \t" + ((counter * 200 + 1) / sum / 2) + "% \t" + entry.getValue());
-                        }
-                    }
-                    out.println((long) (sum / seconds) + "/s: total");
-                }
-            }
-        }
-    }
-
-    public static void clear() {
-        Arrays.fill(COUNTERS, 0);
+    public boolean isWithContext() {
+        return withContext;
     }
 
     @Override
     public void lower(LoweringTool tool) {
-        if (!enabled) {
-            throw new GraalInternalError("counter nodes shouldn't exist when not enabled");
-        }
-        if (excludedClassPrefix == null || !graph().method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
-            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph().method())) : getIndex(name);
-            STATIC_COUNTERS[index] += increment;
-            GROUPS[index] = group;
-
-            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, tool.getRuntime(), graph());
-            ConstantNode indexConstant = ConstantNode.forInt(index, graph());
-            LoadIndexedNode load = graph().add(new LoadIndexedNode(arrayConstant, indexConstant, Kind.Long));
-            IntegerAddNode add = graph().add(new IntegerAddNode(Kind.Long, load, ConstantNode.forLong(increment, graph())));
-            StoreIndexedNode store = graph().add(new StoreIndexedNode(arrayConstant, indexConstant, Kind.Long, add));
-
-            graph().addBeforeFixed(this, load);
-            graph().addBeforeFixed(this, store);
-            load.lower(tool);
-            store.lower(tool);
-        }
-        graph().removeFixed(this);
+        tool.getRuntime().lower(this, tool);
     }
 
-    public static void addLowLevel(String group, String name, long increment, boolean addContext, FixedNode position, MetaAccessProvider runtime) {
-        if (!enabled) {
-            throw new GraalInternalError("counter nodes shouldn't exist when not enabled");
-        }
+    public static void addCounterBefore(String group, String name, long increment, boolean withContext, FixedNode position) {
         StructuredGraph graph = position.graph();
-        if (excludedClassPrefix == null || !graph.method().getDeclaringClass().getName().startsWith(excludedClassPrefix)) {
-            int index = addContext ? getIndex(name + " @ " + MetaUtil.format("%h.%n", graph.method())) : getIndex(name);
-            STATIC_COUNTERS[index] += increment;
-            GROUPS[index] = group;
-
-            ConstantNode arrayConstant = ConstantNode.forObject(COUNTERS, runtime, graph);
-            ConstantLocationNode location = ConstantLocationNode.create(NamedLocationIdentity.getArrayLocation(Kind.Long), Kind.Long, Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE *
-                            index, graph);
-            ReadNode read = graph.add(new ReadNode(arrayConstant, location, StampFactory.forKind(Kind.Long), BarrierType.NONE, false));
-            IntegerAddNode add = graph.add(new IntegerAddNode(Kind.Long, read, ConstantNode.forLong(increment, graph)));
-            WriteNode write = graph.add(new WriteNode(arrayConstant, add, location, BarrierType.NONE, false));
-
-            graph.addBeforeFixed(position, read);
-            graph.addBeforeFixed(position, write);
-        }
+        graph.addBeforeFixed(position, position.graph().add(new DynamicCounterNode(name, group, ConstantNode.forLong(increment, position.graph()), withContext)));
     }
 
-    public static void addCounterBefore(String group, String name, long increment, boolean addContext, FixedNode position) {
-        if (enabled) {
-            StructuredGraph graph = position.graph();
-            DynamicCounterNode counter = graph.add(new DynamicCounterNode(name, group, increment, addContext));
-            graph.addBeforeFixed(position, counter);
-        }
-    }
+    @NodeIntrinsic
+    public static native void counter(@ConstantNodeParameter String name, @ConstantNodeParameter String group, long increment, @ConstantNodeParameter boolean addContext);
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/SurvivingCounterNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -36,7 +36,7 @@
 
     @Input private ValueNode checkedValue;
 
-    public SurvivingCounterNode(String group, String name, long increment, boolean addContext, ValueNode checkedValue) {
+    public SurvivingCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) {
         super(group, name, increment, addContext);
         this.checkedValue = checkedValue;
     }
@@ -56,4 +56,10 @@
             tool.delete();
         }
     }
+
+    public static void addCounterBefore(String group, String name, long increment, boolean addContext, ValueNode checkedValue, FixedNode position) {
+        StructuredGraph graph = position.graph();
+        SurvivingCounterNode counter = graph.add(new SurvivingCounterNode(name, group, ConstantNode.forLong(increment, graph), addContext, checkedValue));
+        graph.addBeforeFixed(position, counter);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -74,4 +75,25 @@
     public Access asFixedNode() {
         return graph().add(new ReadNode(object(), nullCheckLocation(), stamp(), getGuard(), getBarrierType(), isCompressible()));
     }
+
+    private static boolean isMemoryCheckPoint(Node n) {
+        return n instanceof MemoryCheckpoint.Single || n instanceof MemoryCheckpoint.Multi;
+    }
+
+    private static boolean isMemoryPhi(Node n) {
+        return n instanceof PhiNode && ((PhiNode) n).type() == PhiType.Memory;
+    }
+
+    private static boolean isMemoryProxy(Node n) {
+        return n instanceof ProxyNode && ((ProxyNode) n).type() == PhiType.Memory;
+    }
+
+    @Override
+    public boolean verify() {
+        Node lla = lastLocationAccess();
+        if (lla != null && !(isMemoryCheckPoint(lla) || isMemoryPhi(lla) || isMemoryProxy(lla))) {
+            assert false : "lastLocationAccess of " + this + " should be a MemoryCheckpoint, but is " + lla;
+        }
+        return super.verify();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Wed Oct 02 21:40:29 2013 +0200
@@ -34,7 +34,7 @@
 public interface Virtualizable {
 
     public static enum EscapeState {
-        Virtual, ThreadLocal, Global
+        Virtual, Materialized
     }
 
     public abstract static class State {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Wed Oct 02 21:40:29 2013 +0200
@@ -87,15 +87,6 @@
      */
     void setVirtualEntry(State state, int index, ValueNode value);
 
-    /**
-     * Queries the current state of the given value: if it was materialized or not.
-     * 
-     * @param value the value whose state should be queried.
-     * @return the materialized value (usually a MaterializeObjectNode or a {@link PhiNode}) if it
-     *         was materialized, null otherwise.
-     */
-    ValueNode getMaterializedValue(ValueNode value);
-
     // scalar replacement
 
     /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Wed Oct 02 21:40:29 2013 +0200
@@ -234,7 +234,7 @@
             boolean result = baseTryCanonicalize(node, nodeClass);
             if (!result && customCanonicalizer != null && node instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) node;
-                ValueNode canonical = customCanonicalizer.canonicalize(valueNode);
+                Node canonical = customCanonicalizer.canonicalize(valueNode);
                 result = performReplacement(node, canonical);
             }
             return result;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Wed Oct 02 21:40:29 2013 +0200
@@ -36,6 +36,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
@@ -172,6 +173,9 @@
         int fixedCount = 0;
         while (fixed instanceof FixedWithNextNode) {
             fixed = ((FixedWithNextNode) fixed).next();
+            if (fixed instanceof CommitAllocationNode) {
+                return false;
+            }
             fixedCount++;
         }
         if (fixedCount > 1) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Wed Oct 02 21:40:29 2013 +0200
@@ -70,8 +70,6 @@
     @Option(help = "")
     public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
     @Option(help = "")
-    public static final OptionValue<Boolean> EscapeAnalysisHistogram = new OptionValue<>(false);
-    @Option(help = "")
     public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
     @Option(help = "")
     public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Wed Oct 02 21:40:29 2013 +0200
@@ -33,6 +33,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
@@ -99,7 +100,7 @@
 
         @Override
         protected HashSet<FloatingReadNode> processBlock(Block block, HashSet<FloatingReadNode> currentState) {
-            for (Node node : getBlockToNodesMap().get(block)) {
+            for (Node node : blockToNodesMap.get(block)) {
                 if (node instanceof FloatingReadNode) {
                     currentState.add((FloatingReadNode) node);
                 } else if (node instanceof MemoryCheckpoint.Single) {
@@ -183,37 +184,49 @@
 
         @Override
         protected Map<LocationIdentity, Node> processBlock(Block block, Map<LocationIdentity, Node> currentState) {
-            Map<LocationIdentity, Node> initKillMap = getBlockToKillMap().get(block);
-            initKillMap.putAll(currentState);
+
+            if (block.getBeginNode() instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) block.getBeginNode();
+                for (PhiNode phi : mergeNode.usages().filter(PhiNode.class)) {
+                    if (phi.type() == PhiType.Memory) {
+                        LocationIdentity identity = (LocationIdentity) phi.getIdentity();
+                        locationKilledBy(identity, phi, currentState);
+                    }
+                }
+            }
+            currentState.putAll(blockToKillMapInit.get(block));
 
             for (Node node : block.getNodes()) {
                 if (node instanceof MemoryCheckpoint.Single) {
                     LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
-                    initKillMap.put(identity, node);
+                    locationKilledBy(identity, node, currentState);
                 } else if (node instanceof MemoryCheckpoint.Multi) {
                     for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
-                        initKillMap.put(identity, node);
+                        locationKilledBy(identity, node, currentState);
                     }
                 }
                 assert MemoryCheckpoint.TypeAssertion.correctType(node);
             }
 
-            return cloneState(initKillMap);
+            blockToKillMap.put(block, currentState);
+            return cloneState(currentState);
+        }
+
+        private void locationKilledBy(LocationIdentity identity, Node checkpoint, Map<LocationIdentity, Node> state) {
+            state.put(identity, checkpoint);
+            if (identity == ANY_LOCATION) {
+                for (LocationIdentity locid : state.keySet()) {
+                    state.put(locid, checkpoint);
+                }
+            }
         }
 
         @Override
         protected Map<LocationIdentity, Node> merge(Block merge, List<Map<LocationIdentity, Node>> states) {
-            return merge(merge, states, false);
-        }
-
-        protected Map<LocationIdentity, Node> merge(Block merge, List<Map<LocationIdentity, Node>> states, boolean loopbegin) {
             assert merge.getBeginNode() instanceof MergeNode;
             MergeNode mergeNode = (MergeNode) merge.getBeginNode();
 
             Map<LocationIdentity, Node> initKillMap = new HashMap<>();
-            if (loopbegin) {
-                initKillMap.putAll(getBlockToKillMap().get(merge));
-            }
             for (Map<LocationIdentity, Node> state : states) {
                 for (LocationIdentity locid : state.keySet()) {
                     if (initKillMap.containsKey(locid)) {
@@ -226,10 +239,7 @@
                 }
             }
 
-            getMergeToKillMap().set(mergeNode, cloneState(initKillMap));
-            if (!loopbegin) {
-                initKillMap.putAll(getBlockToKillMap().get(merge));
-            }
+            mergeToKillMap.set(mergeNode, cloneState(initKillMap));
             return initKillMap;
         }
 
@@ -240,18 +250,27 @@
 
         @Override
         protected List<Map<LocationIdentity, Node>> processLoop(Loop loop, Map<LocationIdentity, Node> state) {
-            LoopInfo<Map<LocationIdentity, Node>> info = ReentrantBlockIterator.processLoop(this, loop, new HashMap<>(state));
+            LoopInfo<Map<LocationIdentity, Node>> info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state));
 
             assert loop.header.getBeginNode() instanceof LoopBeginNode;
-            Map<LocationIdentity, Node> headerState = merge(loop.header, info.endStates, true);
-            getBlockToKillMap().put(loop.header, headerState);
+            Map<LocationIdentity, Node> headerState = merge(loop.header, info.endStates);
+            // second iteration, for computing information at loop exits
+            info = ReentrantBlockIterator.processLoop(this, loop, cloneState(headerState));
+
+            int i = 0;
+            for (Block exit : loop.exits) {
+                Map<LocationIdentity, Node> exitState = info.exitStates.get(i++);
 
-            for (Map<LocationIdentity, Node> exitState : info.exitStates) {
-                for (LocationIdentity key : headerState.keySet()) {
-                    exitState.put(key, headerState.get(key));
+                Node begin = exit.getBeginNode();
+                assert begin instanceof LoopExitNode;
+                for (Node usage : begin.usages()) {
+                    if (usage instanceof ProxyNode && ((ProxyNode) usage).type() == PhiType.Memory) {
+                        ProxyNode proxy = (ProxyNode) usage;
+                        LocationIdentity identity = (LocationIdentity) proxy.getIdentity();
+                        locationKilledBy(identity, proxy, exitState);
+                    }
                 }
             }
-
             return info.exitStates;
         }
     }
@@ -263,6 +282,7 @@
      * Map from blocks to the nodes in each block.
      */
     private BlockMap<List<ScheduledNode>> blockToNodesMap;
+    private BlockMap<Map<LocationIdentity, Node>> blockToKillMapInit;
     private BlockMap<Map<LocationIdentity, Node>> blockToKillMap;
     private NodeMap<Map<LocationIdentity, Node>> mergeToKillMap;
     private final Map<FloatingNode, List<FixedNode>> phantomUsages = new IdentityHashMap<>();
@@ -315,8 +335,10 @@
         } else if (memsched == MemoryScheduling.OPTIMAL && selectedStrategy != SchedulingStrategy.EARLIEST && graph.getNodes(FloatingReadNode.class).isNotEmpty()) {
             mergeToKillMap = graph.createNodeMap();
 
+            blockToKillMapInit = new BlockMap<>(cfg);
             blockToKillMap = new BlockMap<>(cfg);
             for (Block b : cfg.getBlocks()) {
+                blockToKillMapInit.put(b, new HashMap<LocationIdentity, Node>());
                 blockToKillMap.put(b, new HashMap<LocationIdentity, Node>());
             }
 
@@ -328,7 +350,7 @@
                 Node first = n.lastLocationAccess();
                 assert first != null;
 
-                Map<LocationIdentity, Node> killMap = blockToKillMap.get(forKillLocation(first));
+                Map<LocationIdentity, Node> killMap = blockToKillMapInit.get(forKillLocation(first));
                 killMap.put(n.location().getLocationIdentity(), first);
             }
 
@@ -357,20 +379,27 @@
     private void printSchedule(String desc) {
         Debug.printf("=== %s / %s / %s (%s) ===\n", getCFG().getStartBlock().getBeginNode().graph(), selectedStrategy, memsched, desc);
         for (Block b : getCFG().getBlocks()) {
-            Debug.printf("==== b: %s. ", b);
+            Debug.printf("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
             Debug.printf("dom: %s. ", b.getDominator());
             Debug.printf("post-dom: %s. ", b.getPostdominator());
             Debug.printf("preds: %s. ", b.getPredecessors());
             Debug.printf("succs: %s ====\n", b.getSuccessors());
-            BlockMap<Map<LocationIdentity, Node>> killMaps = getBlockToKillMap();
+            BlockMap<Map<LocationIdentity, Node>> killMaps = blockToKillMap;
             if (killMaps != null) {
+                if (b.getBeginNode() instanceof MergeNode) {
+                    MergeNode merge = (MergeNode) b.getBeginNode();
+                    Debug.printf("M merge kills: \n");
+                    for (LocationIdentity locId : mergeToKillMap.get(merge).keySet()) {
+                        Debug.printf("M %s killed by %s\n", locId, mergeToKillMap.get(merge).get(locId));
+                    }
+                }
                 Debug.printf("X block kills: \n");
                 for (LocationIdentity locId : killMaps.get(b).keySet()) {
                     Debug.printf("X %s killed by %s\n", locId, killMaps.get(b).get(locId));
                 }
             }
 
-            if (getBlockToNodesMap().get(b) != null) {
+            if (blockToNodesMap.get(b) != null) {
                 for (Node n : nodesFor(b)) {
                     printNode(n);
                 }
@@ -414,14 +443,6 @@
         return blockToNodesMap;
     }
 
-    public BlockMap<Map<LocationIdentity, Node>> getBlockToKillMap() {
-        return blockToKillMap;
-    }
-
-    public NodeMap<Map<LocationIdentity, Node>> getMergeToKillMap() {
-        return mergeToKillMap;
-    }
-
     /**
      * Gets the nodes in a given block.
      */
@@ -465,10 +486,11 @@
             throw new SchedulingError("%s should already have been placed in a block", node);
         }
 
+        Block earliestBlock = earliestBlock(node);
         Block block;
         switch (strategy) {
             case EARLIEST:
-                block = earliestBlock(node);
+                block = earliestBlock;
                 break;
             case LATEST:
             case LATEST_OUT_OF_LOOPS:
@@ -477,23 +499,19 @@
                 } else {
                     block = latestBlock(node, strategy);
                     if (block == null) {
-                        block = earliestBlock(node);
+                        block = earliestBlock;
                     } else if (strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS && !(node instanceof VirtualObjectNode)) {
                         // schedule at the latest position possible in the outermost loop possible
-                        Block earliestBlock = earliestBlock(node);
-                        Block before = block;
                         block = scheduleOutOfLoops(node, block, earliestBlock);
-                        if (!earliestBlock.dominates(block)) {
-                            throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s (before %s))", node.graph(), node,
-                                            node.usages().count(), earliestBlock, block, before);
-                        }
                     }
                 }
                 break;
             default:
                 throw new GraalInternalError("unknown scheduling strategy");
         }
-        assert earliestBlock(node).dominates(block) : "node " + node + " in block " + block + " is not dominated by earliest " + earliestBlock(node);
+        if (!earliestBlock.dominates(block)) {
+            throw new SchedulingError("%s: Graph cannot be scheduled : inconsistent for %s, %d usages, (%s needs to dominate %s)", node.graph(), node, node.usages().count(), earliestBlock, block);
+        }
         cfg.getNodeToBlock().set(node, block);
         blockToNodesMap.get(block).add(node);
     }
@@ -541,9 +559,8 @@
         // iterate the dominator tree
         while (true) {
             iterations++;
-            assert earliestBlock.dominates(previousBlock) : "iterations: " + iterations;
             Node lastKill = blockToKillMap.get(currentBlock).get(locid);
-            boolean isAtEarliest = earliestBlock == previousBlock && previousBlock != currentBlock;
+            assert lastKill != null : "should be never null, due to init of killMaps: " + currentBlock + ", location: " + locid;
 
             if (lastKill.equals(upperBound)) {
                 // assign node to the block which kills the location
@@ -553,7 +570,6 @@
                 // schedule read out of the loop if possible, in terms of killMaps and earliest
                 // schedule
                 if (currentBlock != earliestBlock && previousBlock != earliestBlock) {
-                    assert earliestBlock.dominates(currentBlock);
                     Block t = currentBlock;
                     while (t.getLoop() != null && t.getDominator() != null && earliestBlock.dominates(t)) {
                         Block dom = t.getDominator();
@@ -568,17 +584,12 @@
 
                 if (!outOfLoop && previousBlock.getBeginNode() instanceof MergeNode) {
                     // merges kill locations right at the beginning of a block. if a merge is the
-                    // killing node, we assign it to the dominating node.
+                    // killing node, we assign it to the dominating block.
 
                     MergeNode merge = (MergeNode) previousBlock.getBeginNode();
-                    Node killer = getMergeToKillMap().get(merge).get(locid);
+                    Node killer = mergeToKillMap.get(merge).get(locid);
 
                     if (killer != null && killer == merge) {
-                        // check if we violate earliest schedule condition
-                        if (isAtEarliest) {
-                            printIterations(iterations, "earliest bound in merge: " + earliestBlock);
-                            return earliestBlock;
-                        }
                         printIterations(iterations, "kill by merge: " + currentBlock);
                         return currentBlock;
                     }
@@ -590,11 +601,6 @@
                 return previousBlock;
             }
 
-            if (isAtEarliest) {
-                printIterations(iterations, "earliest bound: " + earliestBlock);
-                return earliestBlock;
-            }
-
             if (upperBoundBlock == currentBlock) {
                 printIterations(iterations, "upper bound: " + currentBlock + ", previous: " + previousBlock);
                 return currentBlock;
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64ConvertNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -22,9 +22,10 @@
  */
 package com.oracle.graal.replacements.amd64;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.ConvertNode.Op;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -44,6 +45,12 @@
         this.value = value;
     }
 
+    public Constant evalConst(Constant... inputs) {
+        // this node should never have been created if its input is constant
+        assert false;
+        return null;
+    }
+
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitConvert(opcode, gen.operand(value)));
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Wed Oct 02 21:40:29 2013 +0200
@@ -57,7 +57,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Wed Oct 02 21:40:29 2013 +0200
@@ -61,7 +61,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Wed Oct 02 21:40:29 2013 +0200
@@ -51,7 +51,7 @@
     @Override
     protected StructuredGraph parse(Method m) {
         ResolvedJavaMethod resolvedMethod = runtime.lookupJavaMethod(m);
-        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get());
+        return installer.makeGraph(resolvedMethod, null, inliningPolicy.get(), false);
     }
 
     @LongTest
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Oct 02 21:40:29 2013 +0200
@@ -84,7 +84,7 @@
 
         StructuredGraph graph = graphs.get(method);
         if (graph == null) {
-            graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method)));
+            graphs.putIfAbsent(method, makeGraph(method, null, inliningPolicy(method), method.getAnnotation(Snippet.class).removeAllFrameStates()));
             graph = graphs.get(method);
         }
         return graph;
@@ -97,7 +97,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute)));
+            graphs.putIfAbsent(substitute, makeGraph(substitute, original, inliningPolicy(substitute), false));
             graph = graphs.get(substitute);
         }
         return graph;
@@ -221,9 +221,10 @@
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
      * @param policy the inlining policy to use during preprocessing
+     * @param removeAllFrameStates removes all frame states from side effecting instructions
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy) {
-        return createGraphMaker(method, original).makeGraph(policy);
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, SnippetInliningPolicy policy, boolean removeAllFrameStates) {
+        return createGraphMaker(method, original).makeGraph(policy, removeAllFrameStates);
     }
 
     /**
@@ -261,7 +262,7 @@
             this.original = original;
         }
 
-        public StructuredGraph makeGraph(final SnippetInliningPolicy policy) {
+        public StructuredGraph makeGraph(final SnippetInliningPolicy policy, final boolean removeAllFrameStates) {
             return Debug.scope("BuildSnippetGraph", new Object[]{method}, new Callable<StructuredGraph>() {
 
                 @Override
@@ -271,7 +272,7 @@
                     // Cannot have a finalized version of a graph in the cache
                     graph = graph.copy();
 
-                    finalizeGraph(graph);
+                    finalizeGraph(graph, removeAllFrameStates);
 
                     Debug.dump(graph, "%s: Final", method.getName());
 
@@ -283,7 +284,7 @@
         /**
          * Does final processing of a snippet graph.
          */
-        protected void finalizeGraph(StructuredGraph graph) {
+        protected void finalizeGraph(StructuredGraph graph, boolean removeAllFrameStates) {
             new NodeIntrinsificationPhase(runtime).apply(graph);
             if (!SnippetTemplate.hasConstantParameter(method)) {
                 NodeIntrinsificationVerificationPhase.verify(graph);
@@ -291,7 +292,15 @@
             new ConvertDeoptimizeToGuardPhase().apply(graph);
 
             if (original == null) {
-                new SnippetFrameStateCleanupPhase().apply(graph);
+                if (removeAllFrameStates) {
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof StateSplit) {
+                            ((StateSplit) node).setStateAfter(null);
+                        }
+                    }
+                } else {
+                    new SnippetFrameStateCleanupPhase().apply(graph);
+                }
             }
             new DeadCodeEliminationPhase().apply(graph);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Wed Oct 02 21:40:29 2013 +0200
@@ -45,6 +45,13 @@
     Class<? extends SnippetInliningPolicy> inlining() default SnippetInliningPolicy.class;
 
     /**
+     * Specifies whether all FrameStates within this snippet should always be removed. If this is
+     * false, FrameStates are only removed if there are no side-effecting instructions in the
+     * snippet.
+     */
+    boolean removeAllFrameStates() default false;
+
+    /**
      * Guides inlining decisions used when installing a snippet.
      */
     public interface SnippetInliningPolicy {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Wed Oct 02 21:40:29 2013 +0200
@@ -86,28 +86,15 @@
         gen.setResult(this, result);
     }
 
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 1;
+        return Constant.forDouble(compute(inputs[0].asDouble(), operation()));
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (x().isConstant()) {
-            double value = x().asConstant().asDouble();
-            switch (operation()) {
-                case ABS:
-                    return ConstantNode.forDouble(Math.abs(value), graph());
-                case SQRT:
-                    return ConstantNode.forDouble(Math.sqrt(value), graph());
-                case LOG:
-                    return ConstantNode.forDouble(Math.log(value), graph());
-                case LOG10:
-                    return ConstantNode.forDouble(Math.log10(value), graph());
-                case SIN:
-                    return ConstantNode.forDouble(Math.sin(value), graph());
-                case COS:
-                    return ConstantNode.forDouble(Math.cos(value), graph());
-                case TAN:
-                    return ConstantNode.forDouble(Math.tan(value), graph());
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
+            return ConstantNode.forPrimitive(evalConst(x().asConstant()), graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectList.java	Wed Oct 02 21:40:29 2013 +0200
@@ -30,8 +30,7 @@
 
 /**
  * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a
- * previous state by truncating the list. It can also maintain a level for each effect, which helps
- * in creating a string representation for the list.
+ * previous state by truncating the list.
  */
 public class EffectList implements Iterable<EffectList.Effect> {
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsBlockState.java	Wed Oct 02 21:40:29 2013 +0200
@@ -24,48 +24,14 @@
 
 import java.util.*;
 
-import com.oracle.graal.nodes.*;
-
 public abstract class EffectsBlockState<T extends EffectsBlockState<T>> {
 
-    protected final IdentityHashMap<ValueNode, ValueNode> scalarAliases;
-
-    protected EffectsBlockState() {
-        scalarAliases = new IdentityHashMap<>();
-    }
-
-    protected EffectsBlockState(EffectsBlockState<T> other) {
-        scalarAliases = new IdentityHashMap<>(other.scalarAliases);
-    }
-
-    public void addScalarAlias(ValueNode alias, ValueNode value) {
-        scalarAliases.put(alias, value);
-    }
-
-    public ValueNode getScalarAlias(ValueNode alias) {
-        ValueNode result = scalarAliases.get(alias);
-        return result == null ? alias : result;
-    }
-
     @Override
     public String toString() {
-        return "Scalar Aliases: " + scalarAliases.toString();
+        return "";
     }
 
-    public void meetAliases(List<T> states) {
-        scalarAliases.putAll(states.get(0).scalarAliases);
-        for (int i = 1; i < states.size(); i++) {
-            EffectsBlockState<T> state = states.get(i);
-            meetMaps(scalarAliases, state.scalarAliases);
-        }
-    }
-
-    public boolean equivalentTo(T other) {
-        if (this == other) {
-            return true;
-        }
-        return scalarAliases.equals(other.scalarAliases);
-    }
+    protected abstract boolean equivalentTo(T other);
 
     protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
         if (left.size() != right.size()) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Wed Oct 02 21:40:29 2013 +0200
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.LoopInfo;
@@ -40,6 +41,7 @@
 
     private final SchedulePhase schedule;
 
+    protected final NodeMap<ValueNode> aliases;
     protected final BlockMap<GraphEffectList> blockEffects;
     private final IdentityHashMap<Loop, GraphEffectList> loopMergeEffects = new IdentityHashMap<>();
 
@@ -47,6 +49,7 @@
 
     public EffectsClosure(SchedulePhase schedule) {
         this.schedule = schedule;
+        this.aliases = schedule.getCFG().graph.createNodeMap();
         this.blockEffects = new BlockMap<>(schedule.getCFG());
         for (Block block : schedule.getCFG().getBlocks()) {
             blockEffects.put(block, new GraphEffectList());
@@ -118,6 +121,7 @@
         GraphEffectList effects = blockEffects.get(block);
         FixedWithNextNode lastFixedNode = null;
         for (Node node : schedule.getBlockToNodesMap().get(block)) {
+            aliases.set(node, null);
             changed |= processNode(node, state, effects, lastFixedNode);
             if (node instanceof FixedWithNextNode) {
                 lastFixedNode = (FixedWithNextNode) node;
@@ -202,9 +206,11 @@
             this.afterMergeEffects = new GraphEffectList();
         }
 
+        /**
+         * @param states the states that should be merged.
+         */
         protected void merge(List<BlockT> states) {
             newState = getInitialState();
-            newState.meetAliases(states);
             mergeEffects.clear();
             afterMergeEffects.clear();
         }
@@ -213,4 +219,18 @@
         protected void commitEnds(List<BlockT> states) {
         }
     }
+
+    public void addScalarAlias(ValueNode node, ValueNode alias) {
+        assert !(alias instanceof VirtualObjectNode);
+        aliases.set(node, alias);
+    }
+
+    public ValueNode getScalarAlias(ValueNode node) {
+        assert !(node instanceof VirtualObjectNode);
+        if (node == null || !node.isAlive() || aliases.isNew(node)) {
+            return node;
+        }
+        ValueNode result = aliases.get(node);
+        return (result == null || result instanceof VirtualObjectNode) ? node : result;
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Wed Oct 02 21:40:29 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -35,9 +34,6 @@
 public class GraphEffectList extends EffectList {
 
     public void addCounterBefore(final String group, final String name, final int increment, final boolean addContext, final FixedNode position) {
-        if (!DynamicCounterNode.enabled) {
-            return;
-        }
         add(new Effect() {
 
             @Override
@@ -48,16 +44,12 @@
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
                 assert position.isAlive();
-                DynamicCounterNode node = graph.add(new DynamicCounterNode(group, name, increment, addContext));
-                graph.addBeforeFixed(position, node);
+                DynamicCounterNode.addCounterBefore(group, name, increment, addContext, position);
             }
         });
     }
 
     public void addSurvivingCounterBefore(final String group, final String name, final int increment, final boolean addContext, final ValueNode checkedValue, final FixedNode position) {
-        if (!DynamicCounterNode.enabled) {
-            return;
-        }
         add(new Effect() {
 
             @Override
@@ -68,8 +60,7 @@
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
                 assert position.isAlive();
-                DynamicCounterNode node = graph.add(new SurvivingCounterNode(group, name, increment, addContext, checkedValue));
-                graph.addBeforeFixed(position, node);
+                SurvivingCounterNode.addCounterBefore(group, name, increment, addContext, checkedValue, position);
             }
         });
     }
@@ -368,24 +359,4 @@
             }
         });
     }
-
-    public void addLowLevelCounterBefore(final String group, final String name, final int increment, final boolean addContext, final FixedNode position, final MetaAccessProvider runtime) {
-        add(new Effect() {
-
-            @Override
-            public String name() {
-                return "addLowLevelCounterBefore";
-            }
-
-            @Override
-            public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
-                DynamicCounterNode.addLowLevel(group, name, increment, addContext, position, runtime);
-            }
-
-            @Override
-            public boolean isVisible() {
-                return true;
-            }
-        });
-    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Wed Oct 02 21:40:29 2013 +0200
@@ -137,7 +137,7 @@
     }
 
     public void escape(ValueNode materialized, EscapeState newState) {
-        assert state == EscapeState.Virtual || (state == EscapeState.ThreadLocal && newState == EscapeState.Global);
+        assert state == EscapeState.Virtual && newState == EscapeState.Materialized;
         state = newState;
         materializedValue = materialized;
         entries = null;
@@ -146,7 +146,7 @@
 
     @Override
     public ValueNode getMaterializedValue() {
-        assert state == EscapeState.ThreadLocal || state == EscapeState.Global;
+        assert state == EscapeState.Materialized;
         return materializedValue;
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationBlockState.java	Wed Oct 02 21:40:29 2013 +0200
@@ -92,9 +92,9 @@
         return super.equivalentTo(other);
     }
 
-    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value) {
+    public void addReadCache(ValueNode object, ResolvedJavaField identity, ValueNode value, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
+        ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheObject = obj.getMaterializedValue();
@@ -104,9 +104,9 @@
         readCache.put(new ReadCacheEntry(identity, cacheObject), value);
     }
 
-    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity) {
+    public ValueNode getReadCache(ValueNode object, ResolvedJavaField identity, PartialEscapeClosure<?> closure) {
         ValueNode cacheObject;
-        ObjectState obj = getObjectState(object);
+        ObjectState obj = closure.getObjectState(this, object);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheObject = obj.getMaterializedValue();
@@ -114,13 +114,13 @@
             cacheObject = object;
         }
         ValueNode cacheValue = readCache.get(new ReadCacheEntry(identity, cacheObject));
-        obj = getObjectState(cacheValue);
+        obj = closure.getObjectState(this, cacheValue);
         if (obj != null) {
             assert !obj.isVirtual();
             cacheValue = obj.getMaterializedValue();
         } else {
             // assert !scalarAliases.containsKey(cacheValue);
-            cacheValue = getScalarAlias(cacheValue);
+            cacheValue = closure.getScalarAlias(cacheValue);
         }
         return cacheValue;
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Wed Oct 02 21:40:29 2013 +0200
@@ -57,13 +57,13 @@
                 LoadFieldNode load = (LoadFieldNode) node;
                 if (!load.isVolatile()) {
                     ValueNode object = GraphUtil.unproxify(load.object());
-                    ValueNode cachedValue = state.getReadCache(object, load.field());
+                    ValueNode cachedValue = state.getReadCache(object, load.field(), this);
                     if (cachedValue != null) {
                         effects.replaceAtUsages(load, cachedValue);
-                        state.addScalarAlias(load, cachedValue);
+                        addScalarAlias(load, cachedValue);
                         deleted = true;
                     } else {
-                        state.addReadCache(object, load.field(), load);
+                        state.addReadCache(object, load.field(), load, this);
                     }
                 } else {
                     processIdentity(state, ANY_LOCATION);
@@ -72,15 +72,15 @@
                 StoreFieldNode store = (StoreFieldNode) node;
                 if (!store.isVolatile()) {
                     ValueNode object = GraphUtil.unproxify(store.object());
-                    ValueNode cachedValue = state.getReadCache(object, store.field());
+                    ValueNode cachedValue = state.getReadCache(object, store.field(), this);
 
-                    ValueNode value = state.getScalarAlias(store.value());
+                    ValueNode value = getScalarAlias(store.value());
                     if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                         effects.deleteFixedNode(store);
                         deleted = true;
                     }
                     state.killReadCache(store.field());
-                    state.addReadCache(object, store.field(), value);
+                    state.addReadCache(object, store.field(), value, this);
                 } else {
                     processIdentity(state, ANY_LOCATION);
                 }
@@ -112,7 +112,7 @@
 
         for (Map.Entry<ReadCacheEntry, ValueNode> entry : exitState.getReadCache().entrySet()) {
             if (initialState.getReadCache().get(entry.getKey()) != entry.getValue()) {
-                ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity);
+                ValueNode value = exitState.getReadCache(entry.getKey().object, entry.getKey().identity, this);
                 if (!(value instanceof ProxyNode) || ((ProxyNode) value).proxyPoint() != exitNode) {
                     ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                     effects.addFloatingNode(proxy, "readCacheProxy");
@@ -165,7 +165,7 @@
                     PhiNode phiNode = getCachedPhi(entry, value.kind());
                     mergeEffects.addFloatingNode(phiNode, "mergeReadCache");
                     for (int i = 0; i < states.size(); i++) {
-                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity));
+                        afterMergeEffects.addPhiInput(phiNode, states.get(i).getReadCache(key.object, key.identity, PEReadEliminationClosure.this));
                     }
                     newState.readCache.put(key, phiNode);
                 } else if (value != null) {
@@ -187,7 +187,7 @@
         private void mergeReadCachePhi(PhiNode phi, ResolvedJavaField identity, List<PEReadEliminationBlockState> states) {
             ValueNode[] values = new ValueNode[phi.valueCount()];
             for (int i = 0; i < phi.valueCount(); i++) {
-                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity);
+                ValueNode value = states.get(i).getReadCache(phi.valueAt(i), identity, PEReadEliminationClosure.this);
                 if (value == null) {
                     return;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Wed Oct 02 21:40:29 2013 +0200
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
@@ -32,7 +31,6 @@
 public abstract class PartialEscapeBlockState<T extends PartialEscapeBlockState<T>> extends EffectsBlockState<T> {
 
     protected final IdentityHashMap<VirtualObjectNode, ObjectState> objectStates = new IdentityHashMap<>();
-    protected final IdentityHashMap<ValueNode, VirtualObjectNode> objectAliases;
 
     /**
      * Final subclass of PartialEscapeBlockState, for performance and to make everything behave
@@ -49,15 +47,12 @@
     }
 
     protected PartialEscapeBlockState() {
-        objectAliases = new IdentityHashMap<>();
     }
 
     protected PartialEscapeBlockState(PartialEscapeBlockState<T> other) {
-        super(other);
         for (Map.Entry<VirtualObjectNode, ObjectState> entry : other.objectStates.entrySet()) {
             objectStates.put(entry.getKey(), entry.getValue().cloneState());
         }
-        objectAliases = new IdentityHashMap<>(other.objectAliases);
     }
 
     public ObjectState getObjectState(VirtualObjectNode object) {
@@ -69,11 +64,6 @@
         return objectStates.get(object);
     }
 
-    public ObjectState getObjectState(ValueNode value) {
-        VirtualObjectNode object = objectAliases.get(value);
-        return object == null ? null : getObjectState(object);
-    }
-
     public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, EscapeState state, GraphEffectList materializeEffects) {
         PartialEscapeClosure.METRIC_MATERIALIZATIONS.increment();
         List<AllocatedObjectNode> objects = new ArrayList<>(2);
@@ -100,8 +90,8 @@
                 values.add(null);
             }
             for (int i = 0; i < entries.length; i++) {
-                ObjectState entryObj = getObjectState(entries[i]);
-                if (entryObj != null) {
+                if (entries[i] instanceof VirtualObjectNode) {
+                    ObjectState entryObj = getObjectState((VirtualObjectNode) entries[i]);
                     if (entryObj.isVirtual()) {
                         materializeWithCommit(fixed, entryObj.getVirtualObject(), objects, locks, values, otherAllocations, state);
                     }
@@ -122,26 +112,6 @@
         VirtualUtil.trace("materialized %s as %s with values %s", virtual, representation, values);
     }
 
-    void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node, NodeBitMap usages) {
-        objectAliases.put(node, virtual);
-        if (node.isAlive()) {
-            for (Node usage : node.usages()) {
-                markVirtualUsages(usage, usages);
-            }
-        }
-    }
-
-    private void markVirtualUsages(Node node, NodeBitMap usages) {
-        if (!usages.isNew(node)) {
-            usages.mark(node);
-        }
-        if (node instanceof VirtualState) {
-            for (Node usage : node.usages()) {
-                markVirtualUsages(usage, usages);
-            }
-        }
-    }
-
     public void addObject(VirtualObjectNode virtual, ObjectState state) {
         objectStates.put(virtual, state);
     }
@@ -150,30 +120,18 @@
         return objectStates.values();
     }
 
-    public Collection<VirtualObjectNode> getVirtualObjects() {
-        return objectAliases.values();
+    public Set<VirtualObjectNode> getVirtualObjects() {
+        return objectStates.keySet();
     }
 
     @Override
     public String toString() {
-        return super.toString() + ", Object Aliases: " + objectAliases + ", Object States: " + objectStates;
-    }
-
-    @Override
-    public void meetAliases(List<T> states) {
-        super.meetAliases(states);
-        objectAliases.putAll(states.get(0).objectAliases);
-        for (int i = 1; i < states.size(); i++) {
-            meetMaps(objectAliases, states.get(i).objectAliases);
-        }
+        return super.toString() + ", Object States: " + objectStates;
     }
 
     @Override
     public boolean equivalentTo(T other) {
-        if (!compareMaps(objectAliases, other.objectAliases) || !compareMaps(objectStates, other.objectStates)) {
-            return false;
-        }
-        return super.equivalentTo(other);
+        return compareMaps(objectStates, other.objectStates);
     }
 
     protected static <K, V> boolean compareMaps(Map<K, V> left, Map<K, V> right) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Wed Oct 02 21:40:29 2013 +0200
@@ -79,7 +79,7 @@
     public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, Assumptions assumptions) {
         super(schedule);
         this.usages = schedule.getCFG().graph.createNodeBitMap();
-        this.tool = new VirtualizerToolImpl(usages, metaAccess, assumptions);
+        this.tool = new VirtualizerToolImpl(metaAccess, assumptions, this);
     }
 
     public Map<Invoke, Double> getHints() {
@@ -129,7 +129,7 @@
 
                         @Override
                         public void apply(Node usage, ValueNode value) {
-                            ObjectState valueObj = state.getObjectState(value);
+                            ObjectState valueObj = getObjectState(state, value);
                             if (valueObj != null) {
                                 virtual.add(valueObj);
                                 effects.replaceFirstInput(usage, value, valueObj.virtual);
@@ -158,8 +158,8 @@
                         ObjectState obj = queue.removeLast();
                         if (obj.isVirtual()) {
                             for (ValueNode field : obj.getEntries()) {
-                                ObjectState fieldObj = state.getObjectState(field);
-                                if (fieldObj != null) {
+                                if (field instanceof VirtualObjectNode) {
+                                    ObjectState fieldObj = state.getObjectState((VirtualObjectNode) field);
                                     if (fieldObj.isVirtual() && !virtual.contains(fieldObj)) {
                                         virtual.add(fieldObj);
                                         queue.addLast(fieldObj);
@@ -173,7 +173,7 @@
                         if (obj.isVirtual()) {
                             ValueNode[] fieldState = obj.getEntries().clone();
                             for (int i = 0; i < fieldState.length; i++) {
-                                ObjectState valueObj = state.getObjectState(fieldState[i]);
+                                ObjectState valueObj = getObjectState(state, fieldState[i]);
                                 if (valueObj != null) {
                                     if (valueObj.isVirtual()) {
                                         fieldState[i] = valueObj.virtual;
@@ -191,7 +191,7 @@
                 }
             }
             for (ValueNode input : node.inputs().filter(ValueNode.class)) {
-                ObjectState obj = state.getObjectState(input);
+                ObjectState obj = getObjectState(state, input);
                 if (obj != null) {
                     if (obj.isVirtual() && node instanceof MethodCallTargetNode) {
                         Invoke invoke = ((MethodCallTargetNode) node).invoke();
@@ -205,18 +205,18 @@
         return false;
     }
 
-    private static void ensureMaterialized(PartialEscapeBlockState state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
+    private void ensureMaterialized(BlockT state, ObjectState obj, FixedNode materializeBefore, GraphEffectList effects, DebugMetric metric) {
         assert obj != null;
         if (obj.getState() == EscapeState.Virtual) {
             metric.increment();
-            state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Global, effects);
+            state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects);
         } else {
-            assert obj.getState() == EscapeState.Global;
+            assert obj.getState() == EscapeState.Materialized;
         }
         assert !obj.isVirtual();
     }
 
-    private static void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, PartialEscapeBlockState state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
+    private void replaceWithMaterialized(ValueNode value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
         ensureMaterialized(state, obj, materializeBefore, effects, metric);
         effects.replaceFirstInput(usage, value, obj.getMaterializedValue());
     }
@@ -226,7 +226,7 @@
         HashMap<VirtualObjectNode, ProxyNode> proxies = new HashMap<>();
 
         for (ProxyNode proxy : exitNode.proxies()) {
-            ObjectState obj = exitState.getObjectState(proxy.value());
+            ObjectState obj = getObjectState(exitState, proxy.value());
             if (obj != null) {
                 proxies.put(obj.virtual, proxy);
             }
@@ -236,8 +236,7 @@
             if (obj.isVirtual()) {
                 for (int i = 0; i < obj.getEntries().length; i++) {
                     ValueNode value = obj.getEntry(i);
-                    ObjectState valueObj = exitState.getObjectState(value);
-                    if (valueObj == null) {
+                    if (!(value instanceof VirtualObjectNode)) {
                         if (exitNode.loopBegin().isPhiAtMerge(value) || initialObj == null || !initialObj.isVirtual() || initialObj.getEntry(i) != value) {
                             ProxyNode proxy = new ProxyNode(value, exitNode, PhiType.Value, null);
                             obj.setEntry(i, proxy);
@@ -327,16 +326,21 @@
              * and so on.
              */
 
-            HashSet<VirtualObjectNode> virtualObjects = new HashSet<>(newState.getVirtualObjects());
+            HashSet<VirtualObjectNode> virtualObjTemp = new HashSet<>(states.get(0).getVirtualObjects());
+            for (int i = 1; i < states.size(); i++) {
+                virtualObjTemp.retainAll(states.get(i).getVirtualObjects());
+            }
+
             boolean materialized;
             do {
                 mergeEffects.clear();
                 afterMergeEffects.clear();
                 materialized = false;
-                for (VirtualObjectNode object : virtualObjects) {
+                for (VirtualObjectNode object : virtualObjTemp) {
                     ObjectState[] objStates = new ObjectState[states.size()];
                     for (int i = 0; i < states.size(); i++) {
-                        objStates[i] = states.get(i).getObjectState(object);
+                        objStates[i] = states.get(i).getObjectStateOptional(object);
+                        assert objStates[i] != null;
                     }
                     int virtual = 0;
                     ObjectState startObj = objStates[0];
@@ -359,16 +363,16 @@
                             PhiNode materializedValuePhi = getCachedPhi(object, Kind.Object);
                             mergeEffects.addFloatingNode(materializedValuePhi, "materializedPhi");
                             for (int i = 0; i < states.size(); i++) {
-                                PartialEscapeBlockState state = states.get(i);
+                                BlockT state = states.get(i);
                                 ObjectState obj = objStates[i];
                                 materialized |= obj.isVirtual();
                                 Block predecessor = mergeBlock.getPredecessors().get(i);
                                 ensureMaterialized(state, obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
                                 afterMergeEffects.addPhiInput(materializedValuePhi, obj.getMaterializedValue());
                             }
-                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Global, null));
+                            newState.addObject(object, new ObjectState(object, materializedValuePhi, EscapeState.Materialized, null));
                         } else {
-                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Global, null));
+                            newState.addObject(object, new ObjectState(object, singleValue, EscapeState.Materialized, null));
                         }
                     } else {
                         assert virtual == states.size();
@@ -396,8 +400,8 @@
                                         break outer;
                                     }
                                     ValueNode[] fields = objStates[i].getEntries();
-                                    ObjectState obj = states.get(i).getObjectState(fields[index]);
-                                    if (obj != null) {
+                                    if (fields[index] instanceof VirtualObjectNode) {
+                                        ObjectState obj = states.get(i).getObjectState((VirtualObjectNode) fields[index]);
                                         materialized |= obj.isVirtual();
                                         Block predecessor = mergeBlock.getPredecessors().get(i);
                                         ensureMaterialized(states.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
@@ -421,6 +425,7 @@
         }
 
         private boolean processPhi(PhiNode phi, List<BlockT> states) {
+            aliases.set(phi, null);
             assert states.size() == phi.valueCount();
             int virtualInputs = 0;
             boolean materialized = false;
@@ -430,7 +435,7 @@
             boolean hasIdentity = false;
             for (int i = 0; i < phi.valueCount(); i++) {
                 ValueNode value = phi.valueAt(i);
-                ObjectState obj = states.get(i).getObjectState(value);
+                ObjectState obj = getObjectState(states.get(i), value);
                 if (obj != null) {
                     if (obj.isVirtual()) {
                         virtualInputs++;
@@ -460,10 +465,10 @@
                 // nothing to do...
             } else if (virtualInputs == phi.valueCount()) {
                 if (sameObject != null) {
-                    newState.addAndMarkAlias(sameObject, phi, usages);
+                    addAndMarkAlias(sameObject, phi);
                 } else if (sameType != null && sameEntryCount != -1) {
                     if (!hasIdentity) {
-                        VirtualObjectNode virtual = getValueObjectVirtual(phi, states.get(0).getObjectState(phi.valueAt(0)).virtual);
+                        VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
 
                         PhiNode[] phis = getValueObjectMergePhis(phi, virtual.entryCount());
                         for (int i = 0; i < virtual.entryCount(); i++) {
@@ -473,13 +478,13 @@
                             }
                             mergeEffects.addFloatingNode(phis[i], "valueObjectPhi");
                             for (int i2 = 0; i2 < phi.valueCount(); i2++) {
-                                afterMergeEffects.addPhiInput(phis[i], states.get(i2).getObjectState(phi.valueAt(i2)).getEntry(i));
+                                afterMergeEffects.addPhiInput(phis[i], getObjectState(states.get(i2), phi.valueAt(i2)).getEntry(i));
                             }
                         }
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
                         newState.addObject(virtual, new ObjectState(virtual, Arrays.copyOf(phis, phis.length, ValueNode[].class), EscapeState.Virtual, null));
-                        newState.addAndMarkAlias(virtual, virtual, usages);
-                        newState.addAndMarkAlias(virtual, phi, usages);
+                        addAndMarkAlias(virtual, virtual);
+                        addAndMarkAlias(virtual, phi);
                     } else {
                         materialize = true;
                     }
@@ -493,7 +498,7 @@
             if (materialize) {
                 for (int i = 0; i < phi.valueCount(); i++) {
                     ValueNode value = phi.valueAt(i);
-                    ObjectState obj = states.get(i).getObjectState(value);
+                    ObjectState obj = getObjectState(states.get(i), value);
                     if (obj != null) {
                         materialized |= obj.isVirtual();
                         Block predecessor = mergeBlock.getPredecessors().get(i);
@@ -504,4 +509,39 @@
             return materialized;
         }
     }
+
+    public ObjectState getObjectState(PartialEscapeBlockState<?> state, ValueNode value) {
+        if (value == null) {
+            return null;
+        }
+        if (value.isAlive() && !aliases.isNew(value)) {
+            ValueNode object = aliases.get(value);
+            return object instanceof VirtualObjectNode ? state.getObjectStateOptional((VirtualObjectNode) object) : null;
+        } else {
+            if (value instanceof VirtualObjectNode) {
+                return state.getObjectStateOptional((VirtualObjectNode) value);
+            }
+            return null;
+        }
+    }
+
+    void addAndMarkAlias(VirtualObjectNode virtual, ValueNode node) {
+        if (node.isAlive()) {
+            aliases.set(node, virtual);
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage);
+            }
+        }
+    }
+
+    private void markVirtualUsages(Node node) {
+        if (!usages.isNew(node)) {
+            usages.mark(node);
+        }
+        if (node instanceof VirtualState) {
+            for (Node usage : node.usages()) {
+                markVirtualUsages(usage);
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Wed Oct 02 21:40:29 2013 +0200
@@ -103,7 +103,6 @@
     }
 
     public ReadEliminationBlockState(ReadEliminationBlockState other) {
-        super(other);
         readCache = new HashMap<>(other.readCache);
     }
 
@@ -114,10 +113,7 @@
 
     @Override
     public boolean equivalentTo(ReadEliminationBlockState other) {
-        if (!compareMapsNoSize(readCache, other.readCache)) {
-            return false;
-        }
-        return super.equivalentTo(other);
+        return compareMapsNoSize(readCache, other.readCache);
     }
 
     public void addCacheEntry(CacheEntry<?> identifier, ValueNode value) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Wed Oct 02 21:40:29 2013 +0200
@@ -61,7 +61,7 @@
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (cachedValue != null) {
                     effects.replaceAtUsages(load, cachedValue);
-                    state.addScalarAlias(load, cachedValue);
+                    addScalarAlias(load, cachedValue);
                     deleted = true;
                 } else {
                     state.addCacheEntry(identifier, load);
@@ -76,7 +76,7 @@
                 LoadCacheEntry identifier = new LoadCacheEntry(object, store.field());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = state.getScalarAlias(store.value());
+                ValueNode value = getScalarAlias(store.value());
                 if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                     effects.deleteFixedNode(store);
                     deleted = true;
@@ -94,7 +94,7 @@
                 ValueNode cachedValue = state.getCacheEntry(identifier);
                 if (cachedValue != null) {
                     effects.replaceAtUsages(read, cachedValue);
-                    state.addScalarAlias(read, cachedValue);
+                    addScalarAlias(read, cachedValue);
                     deleted = true;
                 } else {
                     state.addCacheEntry(identifier, read);
@@ -107,7 +107,7 @@
                 ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = state.getScalarAlias(write.value());
+                ValueNode value = getScalarAlias(write.value());
                 if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
                     effects.deleteFixedNode(write);
                     deleted = true;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Wed Oct 02 21:40:29 2013 +0200
@@ -36,18 +36,18 @@
 
 class VirtualizerToolImpl implements VirtualizerTool {
 
-    private final NodeBitMap usages;
     private final MetaAccessProvider metaAccess;
     private final Assumptions assumptions;
+    private final PartialEscapeClosure<?> closure;
 
-    VirtualizerToolImpl(NodeBitMap usages, MetaAccessProvider metaAccess, Assumptions assumptions) {
-        this.usages = usages;
+    VirtualizerToolImpl(MetaAccessProvider metaAccess, Assumptions assumptions, PartialEscapeClosure<?> closure) {
         this.metaAccess = metaAccess;
         this.assumptions = assumptions;
+        this.closure = closure;
     }
 
     private boolean deleted;
-    private PartialEscapeBlockState state;
+    private PartialEscapeBlockState<?> state;
     private ValueNode current;
     private FixedNode position;
     private GraphEffectList effects;
@@ -76,15 +76,15 @@
 
     @Override
     public State getObjectState(ValueNode value) {
-        return state.getObjectState(value);
+        return closure.getObjectState(state, value);
     }
 
     @Override
     public void setVirtualEntry(State objectState, int index, ValueNode value) {
         ObjectState obj = (ObjectState) objectState;
         assert obj != null && obj.isVirtual() : "not virtual: " + obj;
-        ObjectState valueState = state.getObjectState(value);
-        ValueNode newValue = value;
+        ObjectState valueState = closure.getObjectState(state, value);
+        ValueNode newValue;
         if (valueState == null) {
             newValue = getReplacedValue(value);
             assert obj.getEntry(index) == null || obj.getEntry(index).kind() == newValue.kind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
@@ -105,19 +105,13 @@
     }
 
     @Override
-    public ValueNode getMaterializedValue(ValueNode value) {
-        ObjectState obj = state.getObjectState(value);
-        return obj != null && !obj.isVirtual() ? obj.getMaterializedValue() : null;
-    }
-
-    @Override
     public ValueNode getReplacedValue(ValueNode original) {
-        return state.getScalarAlias(original);
+        return closure.getScalarAlias(original);
     }
 
     @Override
     public void replaceWithVirtual(VirtualObjectNode virtual) {
-        state.addAndMarkAlias(virtual, current, usages);
+        closure.addAndMarkAlias(virtual, current);
         if (current instanceof FixedWithNextNode) {
             effects.deleteFixedNode((FixedWithNextNode) current);
         }
@@ -126,8 +120,8 @@
 
     @Override
     public void replaceWithValue(ValueNode replacement) {
-        effects.replaceAtUsages(current, state.getScalarAlias(replacement));
-        state.addScalarAlias(current, replacement);
+        effects.replaceAtUsages(current, closure.getScalarAlias(replacement));
+        closure.addScalarAlias(current, replacement);
         deleted = true;
     }
 
@@ -154,16 +148,21 @@
     @Override
     public void createVirtualObject(VirtualObjectNode virtualObject, ValueNode[] entryState, int[] locks) {
         VirtualUtil.trace("{{%s}} ", current);
-        if (virtualObject.isAlive()) {
-            state.addAndMarkAlias(virtualObject, virtualObject, usages);
-        } else {
+        if (!virtualObject.isAlive()) {
             effects.addFloatingNode(virtualObject, "newVirtualObject");
         }
         for (int i = 0; i < entryState.length; i++) {
-            entryState[i] = state.getScalarAlias(entryState[i]);
+            if (!(entryState[i] instanceof VirtualObjectNode)) {
+                ObjectState v = closure.getObjectState(state, entryState[i]);
+                if (v != null) {
+                    entryState[i] = v.isVirtual() ? v.getVirtualObject() : v.getMaterializedValue();
+                } else {
+                    entryState[i] = closure.getScalarAlias(entryState[i]);
+                }
+            }
         }
         state.addObject(virtualObject, new ObjectState(virtualObject, entryState, EscapeState.Virtual, locks));
-        state.addAndMarkAlias(virtualObject, virtualObject, usages);
+        closure.addAndMarkAlias(virtualObject, virtualObject);
         PartialEscapeClosure.METRIC_ALLOCATION_REMOVED.increment();
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Oct 02 20:57:11 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Wed Oct 02 21:40:29 2013 +0200
@@ -663,7 +663,7 @@
         }
         final StringBuilder sb = new StringBuilder();
         for (int i = 0; i < level; i++) {
-            sb.append("  ");
+            sb.append("| ");
         }
 
         if (parent != null) {
--- a/mx/commands.py	Wed Oct 02 20:57:11 2013 +0200
+++ b/mx/commands.py	Wed Oct 02 21:40:29 2013 +0200
@@ -1318,6 +1318,14 @@
         mx.abort('jacocoreport takes only one argument : an output directory')
     mx.run_java(['-jar', jacocoreport.get_path(True), '-in', 'jacoco.exec', '-g', join(_graal_home, 'graal'), out])
 
+def sl(args):
+    """run an SL program
+
+    VM args should have a @ prefix."""
+    vmArgs = [a[1:] for a in args if a[0] == '@']
+    slArgs = [a for a in args if a[0] != '@']
+    vm(vmArgs + ['-cp', mx.classpath("com.oracle.truffle.sl"), "com.oracle.truffle.sl.SimpleLanguage"] + slArgs)
+
 def isGraalEnabled(vm):
     return vm != 'original' and not vm.endswith('nograal')
 
@@ -1361,7 +1369,8 @@
         'vmg': [vmg, '[-options] class [args...]'],
         'vmfg': [vmfg, '[-options] class [args...]'],
         'deoptalot' : [deoptalot, '[n]'],
-        'longtests' : [longtests, '']
+        'longtests' : [longtests, ''],
+        'sl' : [sl, '[SL args|@VM options]']
     }
 
     mx.add_argument('--jacoco', help='instruments com.oracle.* classes using JaCoCo', default='off', choices=['off', 'on', 'append'])
--- a/src/share/vm/classfile/systemDictionary.hpp	Wed Oct 02 20:57:11 2013 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Wed Oct 02 21:40:29 2013 +0200
@@ -202,6 +202,7 @@
   do_klass(HotSpotResolvedObjectType_klass,       com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,      Opt) \
   do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Opt) \
   do_klass(LocalImpl_klass,                       com_oracle_graal_hotspot_debug_LocalImpl,                     Opt) \
+  do_klass(CompilerThread_klass,                  com_oracle_graal_hotspot_CompilerThread,                      Opt) \
   /* graal.api.code */                                                                                               \
   do_klass(Assumptions_klass,                     com_oracle_graal_api_code_Assumptions,                        Opt) \
   do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_code_Assumptions_ConcreteMethod,         Opt) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Wed Oct 02 20:57:11 2013 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Wed Oct 02 21:40:29 2013 +0200
@@ -311,6 +311,7 @@
   template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectType,  "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType")       \
   template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue")             \
   template(com_oracle_graal_hotspot_debug_LocalImpl,                 "com/oracle/graal/hotspot/debug/LocalImpl")                      \
+  template(com_oracle_graal_hotspot_CompilerThread,                  "com/oracle/graal/hotspot/CompilerThread")                       \
   template(com_oracle_graal_hotspot_ptx_PTXHotSpotGraalRuntime,      "com/oracle/graal/hotspot/ptx/PTXHotSpotGraalRuntime")\
   AMD64_ONLY(template(com_oracle_graal_hotspot_amd64_AMD64HotSpotGraalRuntime,"com/oracle/graal/hotspot/amd64/AMD64HotSpotGraalRuntime"))\
   SPARC_ONLY(template(com_oracle_graal_hotspot_sparc_SPARCHotSpotGraalRuntime,"com/oracle/graal/hotspot/sparc/SPARCHotSpotGraalRuntime"))\
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Wed Oct 02 20:57:11 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Wed Oct 02 21:40:29 2013 +0200
@@ -875,6 +875,9 @@
 
   set_int("arrayClassElementOffset", in_bytes(ObjArrayKlass::element_klass_offset()));
 
+  set_int("graalCountersThreadOffset", in_bytes(JavaThread::graal_counters_offset()));
+  set_int("graalCountersSize", (jint) GRAAL_COUNTERS_SIZE);
+
 #undef set_boolean
 #undef set_int
 #undef set_long
@@ -1145,6 +1148,12 @@
   return klass;
 C2V_END
 
+C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv *env, jobject))
+  typeArrayOop arrayOop = oopFactory::new_longArray(GRAAL_COUNTERS_SIZE, CHECK_NULL);
+  JavaThread::collect_counters(arrayOop);
+  return (jlongArray) JNIHandles::make_local(arrayOop);
+C2V_END
+
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
 
@@ -1224,6 +1233,7 @@
   {CC"invalidateInstalledCode",       CC"("HS_INSTALLED_CODE")V",                                       FN_PTR(invalidateInstalledCode)},
   {CC"readUnsafeUncompressedPointer", CC"("OBJECT"J)"OBJECT,                                            FN_PTR(readUnsafeUncompressedPointer)},
   {CC"readUnsafeKlassPointer",        CC"("OBJECT")J",                                                  FN_PTR(readUnsafeKlassPointer)},
+  {CC"collectCounters",               CC"()[J",                                                         FN_PTR(collectCounters)},
 };
 
 int CompilerToVM_methods_count() {
--- a/src/share/vm/runtime/thread.cpp	Wed Oct 02 20:57:11 2013 +0200
+++ b/src/share/vm/runtime/thread.cpp	Wed Oct 02 21:40:29 2013 +0200
@@ -1411,6 +1411,36 @@
 
 // ======= JavaThread ========
 
+#ifdef GRAAL
+
+#if GRAAL_COUNTERS_SIZE > 0
+jlong JavaThread::_graal_old_counters[GRAAL_COUNTERS_SIZE];
+
+bool graal_counters_include(oop threadObj) {
+  return !GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS || threadObj == NULL || threadObj->klass() != SystemDictionary::CompilerThread_klass();
+}
+
+void JavaThread::collect_counters(typeArrayOop array) {
+  MutexLocker tl(Threads_lock);
+  for (int i = 0; i < array->length(); i++) {
+    array->long_at_put(i, _graal_old_counters[i]);
+  }
+  for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
+    if (graal_counters_include(tp->threadObj())) {
+      for (int i = 0; i < array->length(); i++) {
+        array->long_at_put(i, array->long_at(i) + tp->_graal_counters[i]);
+      }
+    }
+  }
+}
+#else
+void JavaThread::collect_counters(typeArrayOop array) {
+  // empty
+}
+#endif // GRAAL_COUNTERS_SIZE > 0
+
+#endif // GRAAL
+
 // A JavaThread is a normal Java thread
 
 void JavaThread::initialize() {
@@ -1449,6 +1479,9 @@
   _stack_guard_state = stack_guard_unused;
 #ifdef GRAAL
   _graal_alternate_call_target = NULL;
+  for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) {
+    _graal_counters[i] = 0;
+  }
 #endif
   _exception_oop = NULL;
   _exception_pc  = 0;
@@ -1638,6 +1671,14 @@
   ThreadSafepointState::destroy(this);
   if (_thread_profiler != NULL) delete _thread_profiler;
   if (_thread_stat != NULL) delete _thread_stat;
+
+#if defined(GRAAL) && (GRAAL_COUNTERS_SIZE > 0)
+  if (graal_counters_include(threadObj())) {
+    for (int i = 0; i < GRAAL_COUNTERS_SIZE; i++) {
+      _graal_old_counters[i] += _graal_counters[i];
+    }
+  }
+#endif
 }
 
 
--- a/src/share/vm/runtime/thread.hpp	Wed Oct 02 20:57:11 2013 +0200
+++ b/src/share/vm/runtime/thread.hpp	Wed Oct 02 21:40:29 2013 +0200
@@ -919,6 +919,17 @@
 #ifdef GRAAL
   address   _graal_alternate_call_target;
   address   _graal_implicit_exception_pc;  // pc at which the most recent implicit exception occurred
+
+  // number of counters, increase as needed. 0 == disabled
+#define GRAAL_COUNTERS_SIZE (0)
+#define GRAAL_COUNTERS_EXCLUDE_COMPILER_THREADS (true)
+
+  jlong     _graal_counters[GRAAL_COUNTERS_SIZE];
+  static jlong _graal_old_counters[GRAAL_COUNTERS_SIZE];
+
+ public:
+  static void collect_counters(typeArrayOop array);
+ private:
 #endif
   StackGuardState        _stack_guard_state;
 
@@ -1379,6 +1390,7 @@
 #ifdef GRAAL
   static ByteSize graal_alternate_call_target_offset() { return byte_offset_of(JavaThread, _graal_alternate_call_target); }
   static ByteSize graal_implicit_exception_pc_offset() { return byte_offset_of(JavaThread, _graal_implicit_exception_pc); }
+  static ByteSize graal_counters_offset()              { return byte_offset_of(JavaThread, _graal_counters             ); }
 #endif
   static ByteSize exception_oop_offset()         { return byte_offset_of(JavaThread, _exception_oop       ); }
   static ByteSize exception_pc_offset()          { return byte_offset_of(JavaThread, _exception_pc        ); }