changeset 11440:f406557f1a0d

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 27 Aug 2013 22:08:52 +0200
parents efe58aa92f86 58b72cc17109
children fc509b6fbfdf
files
diffstat 37 files changed, 598 insertions(+), 282 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -309,7 +309,7 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
         new InliningPhase().apply(graph, context);
-        new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false).apply(graph, context);
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet) {
@@ -332,7 +332,7 @@
                 }
                 new DeadCodeEliminationPhase().apply(graph);
                 canonicalizer.apply(graph, context);
-                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
+                new PartialEscapePhase(false).apply(graph, context);
 
                 new DeadCodeEliminationPhase().apply(graph);
                 canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -43,7 +43,6 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
         new InliningPhase().apply(graph, context);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+        new EarlyReadEliminationPhase().apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -236,7 +236,7 @@
                 HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
                 new InliningPhase().apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
-                new PartialEscapePhase(iterativeEscapeAnalysis, new CanonicalizerPhase(true)).apply(graph, context);
+                new PartialEscapePhase(iterativeEscapeAnalysis).apply(graph, context);
                 Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
                 ReturnNode returnNode = graph.getNodes(ReturnNode.class).first();
                 if (expectedConstantResult != null) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -245,7 +245,6 @@
         Assumptions assumptions = new Assumptions(false);
         HighTierContext context = new HighTierContext(runtime(), assumptions, replacements, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
         new InliningPhase().apply(graph, context);
-        CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        new PartialEscapePhase(false, true, canonicalizer).apply(graph, context);
+        new PartialEscapePhase(false, true).apply(graph, context);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -164,7 +164,7 @@
                 new DeadCodeEliminationPhase().apply(graph);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
                 canonicalizer.apply(graph, context);
-                new PartialEscapePhase(false, canonicalizer).apply(graph, context);
+                new PartialEscapePhase(false).apply(graph, context);
 
                 for (MergeNode merge : graph.getNodes(MergeNode.class)) {
                     merge.setStateAfter(null);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Tue Aug 27 22:08:52 2013 +0200
@@ -81,7 +81,7 @@
         }
 
         if (PartialEscapeAnalysis.getValue()) {
-            appendPhase(new PartialEscapePhase(true, canonicalizer));
+            appendPhase(new PartialEscapePhase(true));
         }
 
         if (OptConvertDeoptsToGuards.getValue()) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Tue Aug 27 22:08:52 2013 +0200
@@ -47,7 +47,7 @@
         appendPhase(new LockEliminationPhase());
 
         if (OptReadElimination.getValue()) {
-            appendPhase(new EarlyReadEliminationPhase(canonicalizer));
+            appendPhase(new EarlyReadEliminationPhase());
         }
 
         if (OptFloatingReads.getValue()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Aug 27 22:08:52 2013 +0200
@@ -159,18 +159,22 @@
     }
 
     public void trackInputChange(NodeChangedListener inputChangedListener) {
+        assert this.inputChanged == null;
         this.inputChanged = inputChangedListener;
     }
 
     public void stopTrackingInputChange() {
+        assert inputChanged != null;
         inputChanged = null;
     }
 
     public void trackUsagesDroppedZero(NodeChangedListener usagesDroppedZeroListener) {
+        assert this.usagesDroppedZero == null;
         this.usagesDroppedZero = usagesDroppedZeroListener;
     }
 
     public void stopTrackingUsagesDroppedZero() {
+        assert usagesDroppedZero != null;
         usagesDroppedZero = null;
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Tue Aug 27 22:08:52 2013 +0200
@@ -121,12 +121,10 @@
     private NodeUsagesList usages;
     private Node predecessor;
     private int modCount;
-    private final NodeClass nodeClass;
 
     public Node() {
         this.graph = null;
         this.id = INITIAL_ID;
-        nodeClass = NodeClass.get(getClass());
     }
 
     protected int id() {
@@ -241,7 +239,7 @@
     }
 
     public final NodeClass getNodeClass() {
-        return nodeClass;
+        return NodeClass.get(getClass());
     }
 
     private boolean checkReplaceWith(Node other) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Aug 27 22:08:52 2013 +0200
@@ -25,38 +25,104 @@
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.Map.Entry;
+import java.util.concurrent.*;
 
 import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node.Input;
+import com.oracle.graal.graph.Node.IterableNodeType;
+import com.oracle.graal.graph.Node.Successor;
 import com.oracle.graal.graph.Node.Verbosity;
 
-public class NodeClass extends FieldIntrospection {
+/**
+ * Lazily associated metadata for every {@link Node} type. The metadata includes:
+ * <ul>
+ * <li>The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods
+ * for iterating over such fields.</li>
+ * <li>The identifier for an {@link IterableNodeType} class.</li>
+ * </ul>
+ */
+public final class NodeClass extends FieldIntrospection {
 
-    public static final NodeClass get(Class<?> c) {
-        NodeClass clazz = (NodeClass) allClasses.get(c);
-        if (clazz != null) {
-            return clazz;
+    /**
+     * Maps {@link Class} values (for {@link Node} types) to {@link NodeClass} values.
+     * 
+     * Only a single Registry instance can be created. If a runtime creates a specialized registry,
+     * it must do so before the class initializer of {@link NodeClass} is executed.
+     */
+    public static class Registry {
+
+        private static Registry instance;
+
+        /**
+         * Gets the singleton {@link Registry} instance, creating it first if necessary.
+         */
+        static synchronized Registry instance() {
+            if (instance == null) {
+                return new Registry();
+            }
+            return instance;
         }
 
-        /*
-         * Using putIfAbsent doesn't work here, because the creation of NodeClass needs to be
-         * serialized. (the NodeClass constructor looks at allClasses, and it also uses the static
-         * field nextIterableId)
+        protected Registry() {
+            assert instance == null : "exactly one registry can be created";
+            instance = this;
+        }
+
+        /**
+         * @return the {@link NodeClass} value for {@code key} or {@code null} if no such mapping
+         *         exists
+         */
+        protected NodeClass get(Class<? extends Node> key) {
+            return (NodeClass) allClasses.get(key);
+        }
+
+        /**
+         * Same as {@link #get(Class)} except that a {@link NodeClass} is created if no such mapping
+         * exists. The creation of a {@link NodeClass} must be serialized as
+         * {@link NodeClass#NodeClass(Class)} accesses both {@link FieldIntrospection#allClasses}
+         * and {@link NodeClass#nextIterableId}.
+         * <p>
+         * The fact that {@link ConcurrentHashMap#put} {@link ConcurrentHashMap#get} are used should
+         * make the double-checked locking idiom work in the way {@link NodeClass#get(Class)} uses
+         * this method and {@link #get(Class)}.
+         */
+        final synchronized NodeClass make(Class<? extends Node> key) {
+            NodeClass value = (NodeClass) allClasses.get(key);
+            if (value == null) {
+                value = new NodeClass(key);
+                Object old = allClasses.putIfAbsent(key, value);
+                assert old == null;
+                registered(key, value);
+            }
+            return value;
+        }
+
+        /**
+         * Hook for a subclass to be notified of a new mapping added to the registry.
          * 
-         * The fact that ConcurrentHashMap.put and .get are used should make the double-checked
-         * locking idiom work, since it internally uses volatile.
+         * @param key
+         * @param value
          */
+        protected void registered(Class<? extends Node> key, NodeClass value) {
 
-        synchronized (allClasses) {
-            clazz = (NodeClass) allClasses.get(c);
-            if (clazz == null) {
-                clazz = new NodeClass(c);
-                NodeClass oldClass = (NodeClass) allClasses.putIfAbsent(c, clazz);
-                assert oldClass == null;
-            }
-            return clazz;
         }
     }
 
+    private static final Registry registry = Registry.instance();
+
+    /**
+     * Gets the {@link NodeClass} associated with a given {@link Class}.
+     */
+    @SuppressWarnings("unchecked")
+    public static NodeClass get(Class<?> c) {
+        Class<? extends Node> key = (Class<? extends Node>) c;
+        NodeClass value = registry.get(key);
+        if (value != null) {
+            return value;
+        }
+        return registry.make(key);
+    }
+
     static final int NOT_ITERABLE = -1;
 
     private static final Class<?> NODE_CLASS = Node.class;
@@ -77,7 +143,7 @@
     private final int iterableId;
     private int[] iterableIds;
 
-    public NodeClass(Class<?> clazz) {
+    private NodeClass(Class<?> clazz) {
         super(clazz);
         assert NODE_CLASS.isAssignableFrom(clazz);
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -153,7 +153,7 @@
      */
     @Test
     public void test5() throws Exception {
-        test("test5Snippet", useG1GC() ? 9 : 4);
+        test("test5Snippet", useG1GC() ? 1 : 0);
     }
 
     public static Object test5Snippet() throws Exception {
@@ -262,17 +262,17 @@
                 } else {
                     barriers = graph.getNodes(SerialWriteBarrier.class).count();
                 }
-                Assert.assertTrue(barriers == expectedBarriers);
+                Assert.assertEquals(expectedBarriers, barriers);
                 for (WriteNode write : graph.getNodes(WriteNode.class)) {
                     if (useG1GC()) {
                         if (write.getBarrierType() != BarrierType.NONE) {
-                            Assert.assertTrue(write.successors().count() == 1);
+                            Assert.assertEquals(1, write.successors().count());
                             Assert.assertTrue(write.next() instanceof G1PostWriteBarrier);
                             Assert.assertTrue(write.predecessor() instanceof G1PreWriteBarrier);
                         }
                     } else {
                         if (write.getBarrierType() != BarrierType.NONE) {
-                            Assert.assertTrue(write.successors().count() == 1);
+                            Assert.assertEquals(1, write.successors().count());
                             Assert.assertTrue(write.next() instanceof SerialWriteBarrier);
                         }
                     }
@@ -281,10 +281,10 @@
                 for (ReadNode read : graph.getNodes(ReadNode.class)) {
                     if (read.getBarrierType() != BarrierType.NONE) {
                         if (read.location() instanceof ConstantLocationNode) {
-                            Assert.assertTrue(((ConstantLocationNode) (read.location())).getDisplacement() == referentOffset());
+                            Assert.assertEquals(referentOffset(), ((ConstantLocationNode) (read.location())).getDisplacement());
                         }
                         Assert.assertTrue(useG1GC());
-                        Assert.assertTrue(read.getBarrierType() == BarrierType.PRECISE);
+                        Assert.assertEquals(BarrierType.PRECISE, read.getBarrierType());
                         Assert.assertTrue(read.next() instanceof G1ReferentFieldReadBarrier);
                     }
                 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Tue Aug 27 22:08:52 2013 +0200
@@ -194,9 +194,7 @@
         compilerToVm = toVM;
         compilerToGpu = toGPU;
         vmToCompiler = toCompiler;
-        config = new HotSpotVMConfig();
-        compilerToVm.initializeConfiguration(config);
-        config.check();
+        config = new HotSpotVMConfig(compilerToVm);
 
         // Set some global options:
         if (config.compileTheWorld) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Aug 27 22:08:52 2013 +0200
@@ -22,11 +22,17 @@
  */
 package com.oracle.graal.hotspot;
 
+import java.lang.reflect.*;
+
+import com.oracle.graal.hotspot.bridge.*;
 import com.sun.management.HotSpotDiagnosticMXBean;
+
 import sun.management.ManagementFactoryHelper;
 
 /**
- * Used to communicate configuration details, runtime offsets, etc. to Graal upon compileMethod.
+ * Used to access native configuration details.
+ * 
+ * All non-static, public fields in this class are final so that they can be compiled as constants.
  */
 public final class HotSpotVMConfig extends CompilerObject {
 
@@ -34,7 +40,9 @@
 
     private final HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean();
 
-    HotSpotVMConfig() {
+    HotSpotVMConfig(CompilerToVM c2vm) {
+        c2vm.initializeConfiguration(this);
+        assert check();
     }
 
     /**
@@ -91,10 +99,28 @@
         }
     }
 
+    // Using systenm properties ensures the Java source compilers can never
+    // optimize away an access to a config field
+    private static final boolean UNINITIALIZED_BOOLEAN = Boolean.getBoolean("graal.config.uninitializedBoolean");
+    private static final long UNINITIALIZED_LONG = Long.getLong("graal.config.uninitializedLong", 0L);
+    private static final int UNINITIALIZED_INT = Integer.getInteger("graal.config.uninitializedInt", 0);
+
+    private static int getUninitializedInt() {
+        return UNINITIALIZED_INT;
+    }
+
+    private static long getUninitializedLong() {
+        return UNINITIALIZED_LONG;
+    }
+
+    private static boolean getUninitializedBoolean() {
+        return UNINITIALIZED_BOOLEAN;
+    }
+
     // os information, register layout, code generation, ...
-    public boolean cAssertions;
+    public final boolean cAssertions = getUninitializedBoolean();
     public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
-    public int codeEntryAlignment;
+    public final int codeEntryAlignment = getUninitializedInt();
     public final boolean verifyOops = getVMOption("VerifyOops", false);
     public final boolean ciTime = getVMOption("CITime");
     public final int compileThreshold = getVMOptionInt("CompileThreshold");
@@ -110,17 +136,17 @@
     public final boolean useAESIntrinsics = getVMOption("UseAESIntrinsics");
     public final boolean useCRC32Intrinsics = getVMOption("UseCRC32Intrinsics");
     public final boolean useG1GC = getVMOption("UseG1GC");
-    public long gcTotalCollectionsAddress;
+    public final long gcTotalCollectionsAddress = getUninitializedLong();
 
     // Compressed Oops related values.
-    public boolean useCompressedOops = getVMOption("UseCompressedOops");
-    public boolean useCompressedKlassPointers = getVMOption("UseCompressedKlassPointers");
-    public long narrowOopBase;
-    public int narrowOopShift;
+    public final boolean useCompressedOops = getVMOption("UseCompressedOops");
+    public final boolean useCompressedKlassPointers = getVMOption("UseCompressedKlassPointers");
+    public final long narrowOopBase = getUninitializedLong();
+    public final int narrowOopShift = getUninitializedInt();
     public final int logMinObjAlignment = (int) (Math.log(getVMOptionInt("ObjectAlignmentInBytes")) / Math.log(2));
-    public long narrowKlassBase;
-    public int narrowKlassShift;
-    public int logKlassAlignment;
+    public final long narrowKlassBase = getUninitializedLong();
+    public final int narrowKlassShift = getUninitializedInt();
+    public final int logKlassAlignment = getUninitializedInt();
 
     // CPU capabilities
     public final int useSSE = getVMOptionInt("UseSSE");
@@ -132,127 +158,127 @@
     /**
      * The offset of the mark word in an object's header.
      */
-    public int markOffset;
+    public final int markOffset = getUninitializedInt();
 
     /**
      * The offset of the hub (i.e. Klass*) in an object's header.
      */
-    public int hubOffset;
+    public final int hubOffset = getUninitializedInt();
 
     /**
      * The offset of the _prototype_header field in a Klass.
      */
-    public int prototypeMarkWordOffset;
+    public final int prototypeMarkWordOffset = getUninitializedInt();
 
     /**
      * The offset of the _subklass field in a Klass.
      */
-    public int subklassOffset;
+    public final int subklassOffset = getUninitializedInt();
 
     /**
      * The offset of the _next_sibling field in a Klass.
      */
-    public int nextSiblingOffset;
+    public final int nextSiblingOffset = getUninitializedInt();
 
     /**
      * The offset of the array length word in an array object's header.
      */
-    public int arrayLengthOffset;
+    public final int arrayLengthOffset = getUninitializedInt();
 
     /**
      * The offset of the _length field in an Array metaspace object (see array.hpp).
      */
-    public int metaspaceArrayLengthOffset;
+    public final int metaspaceArrayLengthOffset = getUninitializedInt();
 
     /**
      * The offset of the _data field in an Array metaspace object (see array.hpp).
      */
-    public int metaspaceArrayBaseOffset;
+    public final int metaspaceArrayBaseOffset = getUninitializedInt();
 
     /**
      * The offset of the _super_check_offset field in a Klass.
      */
-    public int superCheckOffsetOffset;
+    public final int superCheckOffsetOffset = getUninitializedInt();
 
     /**
      * The offset of the _secondary_super_cache field in a Klass.
      */
-    public int secondarySuperCacheOffset;
+    public final int secondarySuperCacheOffset = getUninitializedInt();
 
     /**
      * The offset of the _secondary_supers field in a Klass.
      */
-    public int secondarySupersOffset;
+    public final int secondarySupersOffset = getUninitializedInt();
 
     /**
      * The offset of the _init_state field in an instanceKlass.
      */
-    public int klassStateOffset;
+    public final int klassStateOffset = getUninitializedInt();
 
     /**
      * The value of instanceKlass::fully_initialized.
      */
-    public int klassStateFullyInitialized;
+    public final int klassStateFullyInitialized = getUninitializedInt();
 
     /**
      * The value of objArrayKlass::element_klass_offset().
      */
-    public int arrayClassElementOffset;
+    public final int arrayClassElementOffset = getUninitializedInt();
 
     /**
      * The value of JavaThread::tlab_top_offset().
      */
-    public int threadTlabTopOffset;
+    public final int threadTlabTopOffset = getUninitializedInt();
 
     /**
      * The value of JavaThread::tlab_end_offset().
      */
-    public int threadTlabEndOffset;
+    public final int threadTlabEndOffset = getUninitializedInt();
 
     /**
      * The value of JavaThread::threadObj_offset().
      */
-    public int threadObjectOffset;
+    public final int threadObjectOffset = getUninitializedInt();
 
     /**
      * The value of JavaThread::osthread_offset().
      */
-    public int osThreadOffset;
+    public final int osThreadOffset = getUninitializedInt();
 
     /**
      * The value of OSThread::interrupted_offset().
      */
-    public int osThreadInterruptedOffset;
+    public final int osThreadInterruptedOffset = getUninitializedInt();
 
     /**
      * The value of markOopDesc::unlocked_value.
      */
-    public int unlockedMask;
+    public final int unlockedMask = getUninitializedInt();
 
     /**
      * The value of markOopDesc::biased_lock_mask_in_place.
      */
-    public int biasedLockMaskInPlace;
+    public final int biasedLockMaskInPlace = getUninitializedInt();
 
     /**
      * The value of markOopDesc::age_mask_in_place.
      */
-    public int ageMaskInPlace;
+    public final int ageMaskInPlace = getUninitializedInt();
 
     /**
      * The value of markOopDesc::epoch_mask_in_place.
      */
-    public int epochMaskInPlace;
+    public final int epochMaskInPlace = getUninitializedInt();
 
     /**
      * The value of markOopDesc::biased_lock_pattern.
      */
-    public int biasedLockPattern;
+    public final int biasedLockPattern = getUninitializedInt();
 
     /**
      * Identity hash code value when uninitialized.
      */
-    public int uninitializedIdentityHashCodeValue;
+    public final int uninitializedIdentityHashCodeValue = getUninitializedInt();
 
     /**
      * Offset of the _pending_exception field in ThreadShadow (defined in exceptions.hpp). This
@@ -260,83 +286,83 @@
      * <p>
      * <b>NOTE: This is not the same as {@link #threadExceptionOopOffset}.</b>
      */
-    public int pendingExceptionOffset;
+    public final int pendingExceptionOffset = getUninitializedInt();
 
     /**
      * Offset of the pending deoptimization field.
      */
-    public int pendingDeoptimizationOffset;
+    public final int pendingDeoptimizationOffset = getUninitializedInt();
 
     /**
      * Mark word right shift to get identity hash code.
      */
-    public int identityHashCodeShift;
+    public final int identityHashCodeShift = getUninitializedInt();
 
     /**
      * Offset of _access_flags in a metaspace Method object.
      */
-    public int methodAccessFlagsOffset;
+    public final int methodAccessFlagsOffset = getUninitializedInt();
 
     /**
      * JVM_ACC_QUEUED defined in accessFlags.hpp and used for marking a Method object as queued for
      * compilation.
      */
-    public int methodQueuedForCompilationBit;
+    public final int methodQueuedForCompilationBit = getUninitializedInt();
 
     /**
      * Offset of _intrinsic_id in a metaspace Method object.
      */
-    public int methodIntrinsicIdOffset;
+    public final int methodIntrinsicIdOffset = getUninitializedInt();
 
     /**
      * Offset of _max_locals in a metaspace Method object.
      */
-    public int methodMaxLocalsOffset;
+    public final int methodMaxLocalsOffset = getUninitializedInt();
 
     /**
      * Offset of _constMethod in a metaspace Method object.
      */
-    public int methodConstMethodOffset;
+    public final int methodConstMethodOffset = getUninitializedInt();
 
     /**
      * Offset of _max_stack in a metaspace ConstMethod object.
      */
-    public int constMethodMaxStackOffset;
+    public final int constMethodMaxStackOffset = getUninitializedInt();
 
     /**
      * Offset of _constants in a metaspace ConstMethod object.
      */
-    public int constMethodConstantsOffset;
+    public final int constMethodConstantsOffset = getUninitializedInt();
 
     /**
      * Offset of _pool_holder in a metaspace ConstantPool object.
      */
-    public int constantPoolHolderOffset;
+    public final int constantPoolHolderOffset = getUninitializedInt();
 
     /**
      * Value of extra_stack_entries() in method.hpp.
      */
-    public int extraStackEntries;
+    public final int extraStackEntries = getUninitializedInt();
 
     /**
      * Value of JVM_ACC_HAS_FINALIZER in accessFlags.hpp.
      */
-    public int klassHasFinalizerFlag;
+    public final int klassHasFinalizerFlag = getUninitializedInt();
 
     /**
      * The value of JavaThread::is_method_handle_return_offset().
      */
-    public int threadIsMethodHandleReturnOffset;
+    public final int threadIsMethodHandleReturnOffset = getUninitializedInt();
 
     /**
      * Bit pattern that represents a non-oop. Neither the high bits nor the low bits of this value
      * are allowed to look like (respectively) the high or low bits of a real oop.
      */
-    public long nonOopBits;
+    public final long nonOopBits = getUninitializedLong();
 
-    public long verifyOopCounterAddress;
-    public long verifyOopMask;
-    public long verifyOopBits;
+    public final long verifyOopCounterAddress = getUninitializedLong();
+    public final long verifyOopMask = getUninitializedLong();
+    public final long verifyOopBits = getUninitializedLong();
 
     /**
      * Offset of the _exception_oop field in Thread (defined in thread.hpp). This field is used to
@@ -345,207 +371,216 @@
      * <p>
      * <b>NOTE: This is not the same as {@link #pendingExceptionOffset}.</b>
      */
-    public int threadExceptionOopOffset;
+    public final int threadExceptionOopOffset = getUninitializedInt();
 
-    public int threadExceptionPcOffset;
-    public long cardtableStartAddress;
-    public int cardtableShift;
-    public long safepointPollingAddress;
-    public boolean isPollingPageFar;
+    public final int threadExceptionPcOffset = getUninitializedInt();
+    public final long cardtableStartAddress = getUninitializedLong();
+    public final int cardtableShift = getUninitializedInt();
+    public final long safepointPollingAddress = getUninitializedLong();
+    public final boolean isPollingPageFar = getUninitializedBoolean();
 
     /**
      * G1 Collector Related Values.
      */
-    public int g1CardQueueIndexOffset;
-    public int g1CardQueueBufferOffset;
-    public int logOfHRGrainBytes;
-    public int g1SATBQueueMarkingOffset;
-    public int g1SATBQueueIndexOffset;
-    public int g1SATBQueueBufferOffset;
+    public final int g1CardQueueIndexOffset = getUninitializedInt();
+    public final int g1CardQueueBufferOffset = getUninitializedInt();
+    public final int logOfHRGrainBytes = getUninitializedInt();
+    public final int g1SATBQueueMarkingOffset = getUninitializedInt();
+    public final int g1SATBQueueIndexOffset = getUninitializedInt();
+    public final int g1SATBQueueBufferOffset = getUninitializedInt();
 
     /**
      * The offset of the _java_mirror field (of type {@link Class}) in a Klass.
      */
-    public int classMirrorOffset;
+    public final int classMirrorOffset = getUninitializedInt();
 
-    public int runtimeCallStackSize;
+    public final int runtimeCallStackSize = getUninitializedInt();
 
     /**
      * The offset of the _modifier_flags field in a Klass.
      */
-    public int klassModifierFlagsOffset;
+    public final int klassModifierFlagsOffset = getUninitializedInt();
 
     /**
      * The offset of the _access_flags field in a Klass.
      */
-    public int klassAccessFlagsOffset;
+    public final int klassAccessFlagsOffset = getUninitializedInt();
 
     /**
      * The offset of the _layout_helper field in a Klass.
      */
-    public int klassLayoutHelperOffset;
+    public final int klassLayoutHelperOffset = getUninitializedInt();
 
     /**
      * Bit pattern in the klass layout helper that can be used to identify arrays.
      */
-    public int arrayKlassLayoutHelperIdentifier;
+    public final int arrayKlassLayoutHelperIdentifier = getUninitializedInt();
 
     /**
      * The offset of the _componentMirror field in an ArrayKlass.
      */
-    public int arrayKlassComponentMirrorOffset;
+    public final int arrayKlassComponentMirrorOffset = getUninitializedInt();
 
     /**
      * The offset of the _super field in a Klass.
      */
-    public int klassSuperKlassOffset;
+    public final int klassSuperKlassOffset = getUninitializedInt();
 
     /**
      * The offset of the injected klass field in a {@link Class}.
      */
-    public int klassOffset;
+    public final int klassOffset = getUninitializedInt();
 
     /**
      * The offset of the injected array klass field in a {@link Class}.
      */
-    public int arrayKlassOffset;
+    public final int arrayKlassOffset = getUninitializedInt();
 
     /**
      * The offset of the injected graal_mirror field in a {@link Class}.
      */
-    public int graalMirrorInClassOffset;
+    public final int graalMirrorInClassOffset = getUninitializedInt();
 
     /**
      * The offset of the _method_data field in a metaspace Method.
      */
-    public int methodDataOffset;
+    public final int methodDataOffset = getUninitializedInt();
 
-    public int nmethodEntryOffset;
-    public int methodCompiledEntryOffset;
-    public int basicLockSize;
-    public int basicLockDisplacedHeaderOffset;
-    public long tlabIntArrayMarkWord;
-    public long heapEndAddress;
-    public long heapTopAddress;
-    public int threadTlabStartOffset;
-    public int threadTlabSizeOffset;
-    public int threadAllocatedBytesOffset;
-    public int threadLastJavaSpOffset;
-    public int threadLastJavaPcOffset;
+    public final int nmethodEntryOffset = getUninitializedInt();
+    public final int methodCompiledEntryOffset = getUninitializedInt();
+    public final int basicLockSize = getUninitializedInt();
+    public final int basicLockDisplacedHeaderOffset = getUninitializedInt();
+    public final long tlabIntArrayMarkWord = getUninitializedLong();
+    public final long heapEndAddress = getUninitializedLong();
+    public final long heapTopAddress = getUninitializedLong();
+    public final int threadTlabStartOffset = getUninitializedInt();
+    public final int threadTlabSizeOffset = getUninitializedInt();
+    public final int threadAllocatedBytesOffset = getUninitializedInt();
+    public final int threadLastJavaSpOffset = getUninitializedInt();
+    public final int threadLastJavaPcOffset = getUninitializedInt();
 
     /**
      * This value is only valid on AMD64.
      */
-    public int threadLastJavaFpOffset;
+    public final int threadLastJavaFpOffset = getUninitializedInt();
 
     /**
      * This value is only valid on SPARC.
      */
-    public int threadJavaFrameAnchorFlagsOffset;
+    public final int threadJavaFrameAnchorFlagsOffset = getUninitializedInt();
 
-    public int threadObjectResultOffset;
-    public int tlabRefillWasteLimitOffset;
-    public int tlabRefillWasteIncrement;
-    public int tlabAlignmentReserve;
-    public int tlabSlowAllocationsOffset;
-    public int tlabFastRefillWasteOffset;
-    public int tlabNumberOfRefillsOffset;
+    public final int threadObjectResultOffset = getUninitializedInt();
+    public final int tlabRefillWasteLimitOffset = getUninitializedInt();
+    public final int tlabRefillWasteIncrement = getUninitializedInt();
+    public final int tlabAlignmentReserve = getUninitializedInt();
+    public final int tlabSlowAllocationsOffset = getUninitializedInt();
+    public final int tlabFastRefillWasteOffset = getUninitializedInt();
+    public final int tlabNumberOfRefillsOffset = getUninitializedInt();
     public final boolean tlabStats = getVMOption("TLABStats");
-    public int klassInstanceSizeOffset;
-    public boolean inlineContiguousAllocationSupported;
-    public long arrayPrototypeMarkWord;
-    public int layoutHelperLog2ElementSizeShift;
-    public int layoutHelperLog2ElementSizeMask;
-    public int layoutHelperElementTypeShift;
-    public int layoutHelperElementTypeMask;
-    public int layoutHelperElementTypePrimitiveInPlace;
-    public int layoutHelperHeaderSizeShift;
-    public int layoutHelperHeaderSizeMask;
-    public int layoutHelperOffset;
+    public final int klassInstanceSizeOffset = getUninitializedInt();
+    public final boolean inlineContiguousAllocationSupported = getUninitializedBoolean();
+    public final long arrayPrototypeMarkWord = getUninitializedLong();
+    public final int layoutHelperLog2ElementSizeShift = getUninitializedInt();
+    public final int layoutHelperLog2ElementSizeMask = getUninitializedInt();
+    public final int layoutHelperElementTypeShift = getUninitializedInt();
+    public final int layoutHelperElementTypeMask = getUninitializedInt();
+    public final int layoutHelperElementTypePrimitiveInPlace = getUninitializedInt();
+    public final int layoutHelperHeaderSizeShift = getUninitializedInt();
+    public final int layoutHelperHeaderSizeMask = getUninitializedInt();
+    public final int layoutHelperOffset = getUninitializedInt();
 
     // methodData information
-    public int methodDataOopDataOffset;
-    public int methodDataOopTrapHistoryOffset;
-    public int dataLayoutHeaderSize;
-    public int dataLayoutTagOffset;
-    public int dataLayoutFlagsOffset;
-    public int dataLayoutBCIOffset;
-    public int dataLayoutCellsOffset;
-    public int dataLayoutCellSize;
-    public final int bciProfileWidth = getVMOption("BciProfileWidth", 2);  // develop flag; might
-// change
+    public final int methodDataOopDataOffset = getUninitializedInt();
+    public final int methodDataOopTrapHistoryOffset = getUninitializedInt();
+    public final int dataLayoutHeaderSize = getUninitializedInt();
+    public final int dataLayoutTagOffset = getUninitializedInt();
+    public final int dataLayoutFlagsOffset = getUninitializedInt();
+    public final int dataLayoutBCIOffset = getUninitializedInt();
+    public final int dataLayoutCellsOffset = getUninitializedInt();
+    public final int dataLayoutCellSize = getUninitializedInt();
+
+    // develop flag; might change
+    public final int bciProfileWidth = getVMOption("BciProfileWidth", 2);
+
     public final int typeProfileWidth = getVMOptionInt("TypeProfileWidth");
     public final int methodProfileWidth = getVMOptionInt("MethodProfileWidth");
 
-    public long inlineCacheMissStub;
-    public long handleDeoptStub;
-    public long uncommonTrapStub;
+    public final long inlineCacheMissStub = getUninitializedLong();
+    public final long handleDeoptStub = getUninitializedLong();
+    public final long uncommonTrapStub = getUninitializedLong();
 
-    public long aescryptEncryptBlockStub;
-    public long aescryptDecryptBlockStub;
-    public long cipherBlockChainingEncryptAESCryptStub;
-    public long cipherBlockChainingDecryptAESCryptStub;
-    public long updateBytesCRC32Stub;
+    public final long aescryptEncryptBlockStub = getUninitializedLong();
+    public final long aescryptDecryptBlockStub = getUninitializedLong();
+    public final long cipherBlockChainingEncryptAESCryptStub = getUninitializedLong();
+    public final long cipherBlockChainingDecryptAESCryptStub = getUninitializedLong();
+    public final long updateBytesCRC32Stub = getUninitializedLong();
 
-    public long newInstanceAddress;
-    public long newArrayAddress;
-    public long newMultiArrayAddress;
-    public long dynamicNewArrayAddress;
-    public long registerFinalizerAddress;
-    public long threadIsInterruptedAddress;
-    public long vmMessageAddress;
-    public long identityHashCodeAddress;
-    public long exceptionHandlerForPcAddress;
-    public long exceptionHandlerForReturnAddressAddress;
-    public long osrMigrationEndAddress;
-    public long monitorenterAddress;
-    public long monitorexitAddress;
-    public long createNullPointerExceptionAddress;
-    public long createOutOfBoundsExceptionAddress;
-    public long logPrimitiveAddress;
-    public long logObjectAddress;
-    public long logPrintfAddress;
-    public long vmErrorAddress;
-    public long writeBarrierPreAddress;
-    public long writeBarrierPostAddress;
-    public long validateObject;
-    public long javaTimeMillisAddress;
-    public long javaTimeNanosAddress;
-    public long arithmeticSinAddress;
-    public long arithmeticCosAddress;
-    public long arithmeticTanAddress;
-    public long loadAndClearExceptionAddress;
-    public long crcTableAddress;
+    public final long newInstanceAddress = getUninitializedLong();
+    public final long newArrayAddress = getUninitializedLong();
+    public final long newMultiArrayAddress = getUninitializedLong();
+    public final long dynamicNewArrayAddress = getUninitializedLong();
+    public final long registerFinalizerAddress = getUninitializedLong();
+    public final long threadIsInterruptedAddress = getUninitializedLong();
+    public final long vmMessageAddress = getUninitializedLong();
+    public final long identityHashCodeAddress = getUninitializedLong();
+    public final long exceptionHandlerForPcAddress = getUninitializedLong();
+    public final long exceptionHandlerForReturnAddressAddress = getUninitializedLong();
+    public final long osrMigrationEndAddress = getUninitializedLong();
+    public final long monitorenterAddress = getUninitializedLong();
+    public final long monitorexitAddress = getUninitializedLong();
+    public final long createNullPointerExceptionAddress = getUninitializedLong();
+    public final long createOutOfBoundsExceptionAddress = getUninitializedLong();
+    public final long logPrimitiveAddress = getUninitializedLong();
+    public final long logObjectAddress = getUninitializedLong();
+    public final long logPrintfAddress = getUninitializedLong();
+    public final long vmErrorAddress = getUninitializedLong();
+    public final long writeBarrierPreAddress = getUninitializedLong();
+    public final long writeBarrierPostAddress = getUninitializedLong();
+    public final long validateObject = getUninitializedLong();
+    public final long javaTimeMillisAddress = getUninitializedLong();
+    public final long javaTimeNanosAddress = getUninitializedLong();
+    public final long arithmeticSinAddress = getUninitializedLong();
+    public final long arithmeticCosAddress = getUninitializedLong();
+    public final long arithmeticTanAddress = getUninitializedLong();
+    public final long loadAndClearExceptionAddress = getUninitializedLong();
+    public final long crcTableAddress = getUninitializedLong();
 
-    public int deoptReasonNone;
-    public int deoptReasonNullCheck;
-    public int deoptReasonRangeCheck;
-    public int deoptReasonClassCheck;
-    public int deoptReasonArrayCheck;
-    public int deoptReasonUnreached0;
-    public int deoptReasonTypeCheckInlining;
-    public int deoptReasonOptimizedTypeCheck;
-    public int deoptReasonNotCompiledExceptionHandler;
-    public int deoptReasonUnresolved;
-    public int deoptReasonJsrMismatch;
-    public int deoptReasonDiv0Check;
-    public int deoptReasonConstraint;
-    public int deoptReasonLoopLimitCheck;
+    public final int deoptReasonNone = getUninitializedInt();
+    public final int deoptReasonNullCheck = getUninitializedInt();
+    public final int deoptReasonRangeCheck = getUninitializedInt();
+    public final int deoptReasonClassCheck = getUninitializedInt();
+    public final int deoptReasonArrayCheck = getUninitializedInt();
+    public final int deoptReasonUnreached0 = getUninitializedInt();
+    public final int deoptReasonTypeCheckInlining = getUninitializedInt();
+    public final int deoptReasonOptimizedTypeCheck = getUninitializedInt();
+    public final int deoptReasonNotCompiledExceptionHandler = getUninitializedInt();
+    public final int deoptReasonUnresolved = getUninitializedInt();
+    public final int deoptReasonJsrMismatch = getUninitializedInt();
+    public final int deoptReasonDiv0Check = getUninitializedInt();
+    public final int deoptReasonConstraint = getUninitializedInt();
+    public final int deoptReasonLoopLimitCheck = getUninitializedInt();
 
-    public int deoptActionNone;
-    public int deoptActionMaybeRecompile;
-    public int deoptActionReinterpret;
-    public int deoptActionMakeNotEntrant;
-    public int deoptActionMakeNotCompilable;
+    public final int deoptActionNone = getUninitializedInt();
+    public final int deoptActionMaybeRecompile = getUninitializedInt();
+    public final int deoptActionReinterpret = getUninitializedInt();
+    public final int deoptActionMakeNotEntrant = getUninitializedInt();
+    public final int deoptActionMakeNotCompilable = getUninitializedInt();
 
-    public int vmIntrinsicInvokeBasic;
-    public int vmIntrinsicLinkToVirtual;
-    public int vmIntrinsicLinkToStatic;
-    public int vmIntrinsicLinkToSpecial;
-    public int vmIntrinsicLinkToInterface;
+    public final int vmIntrinsicInvokeBasic = getUninitializedInt();
+    public final int vmIntrinsicLinkToVirtual = getUninitializedInt();
+    public final int vmIntrinsicLinkToStatic = getUninitializedInt();
+    public final int vmIntrinsicLinkToSpecial = getUninitializedInt();
+    public final int vmIntrinsicLinkToInterface = getUninitializedInt();
 
-    public void check() {
-        assert codeEntryAlignment > 0;
+    public boolean check() {
+        assert codeEntryAlignment > 0 : codeEntryAlignment;
         assert stackShadowPages > 0;
+        for (Field f : getClass().getDeclaredFields()) {
+            int modifiers = f.getModifiers();
+            if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
+                assert Modifier.isFinal(modifiers) : "field should be final: " + f;
+            }
+        }
+        return true;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Tue Aug 27 22:08:52 2013 +0200
@@ -131,6 +131,8 @@
 
     public void startCompiler(boolean bootstrapEnabled) throws Throwable {
 
+        FastNodeClassRegistry.initialize();
+
         bootstrapRunning = bootstrapEnabled;
 
         HotSpotVMConfig config = graalRuntime.getConfig();
@@ -260,6 +262,31 @@
         compilerStartTime = System.nanoTime();
     }
 
+    /**
+     * A fast-path for {@link NodeClass} retrieval using {@link HotSpotResolvedObjectType}.
+     */
+    static class FastNodeClassRegistry extends NodeClass.Registry {
+
+        @SuppressWarnings("unused")
+        static void initialize() {
+            new FastNodeClassRegistry();
+        }
+
+        private static HotSpotResolvedObjectType type(Class<? extends Node> key) {
+            return (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(key);
+        }
+
+        @Override
+        public NodeClass get(Class<? extends Node> key) {
+            return type(key).getNodeClass();
+        }
+
+        @Override
+        protected void registered(Class<? extends Node> key, NodeClass value) {
+            type(key).setNodeClass(value);
+        }
+    }
+
     private final class BenchmarkCountersOutputStream extends CallbackOutputStream {
 
         private long startTime;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Tue Aug 27 22:08:52 2013 +0200
@@ -33,6 +33,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 
 /**
@@ -65,6 +66,11 @@
     private final String simpleName;
 
     /**
+     * Used for implemented a lazy binding from a {@link Node} type to a {@link NodeClass} value.
+     */
+    private NodeClass nodeClass;
+
+    /**
      * The instance size (in bytes) for an instance type,
      * {@link HotSpotResolvedObjectType#INTERFACE_SPECIES_VALUE} denoting an interface type or
      * {@link HotSpotResolvedObjectType#ARRAY_SPECIES_VALUE} denoting an array type.
@@ -554,4 +560,18 @@
     public Constant newArray(int length) {
         return Constant.forObject(Array.newInstance(javaMirror, length));
     }
+
+    /**
+     * @return the {@link NodeClass} value (which may be {@code null}) associated with this type
+     */
+    public NodeClass getNodeClass() {
+        return nodeClass;
+    }
+
+    /**
+     * Sets the {@link NodeClass} value associated with this type.
+     */
+    public void setNodeClass(NodeClass nodeClass) {
+        this.nodeClass = nodeClass;
+    }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -24,13 +24,12 @@
 
 import static com.oracle.graal.phases.GraalOptions.*;
 
-import java.util.*;
-
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.graph.Graph.NodeChangedListener;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.util.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class IterativeConditionalEliminationPhase extends BasePhase<PhaseContext> {
@@ -39,36 +38,28 @@
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext context) {
-        Set<Node> canonicalizationRoots = new HashSet<>();
         ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(context.getRuntime());
-        Listener listener = new Listener(canonicalizationRoots);
+        HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
         int count = 0;
         while (true) {
             graph.trackInputChange(listener);
+            graph.trackUsagesDroppedZero(listener);
             eliminate.apply(graph);
             graph.stopTrackingInputChange();
-            if (canonicalizationRoots.isEmpty()) {
+            graph.stopTrackingUsagesDroppedZero();
+            if (listener.getChangedNodes().isEmpty()) {
                 break;
             }
-            new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), canonicalizationRoots, null).apply(graph);
-            canonicalizationRoots.clear();
+            for (Node node : graph.getNodes()) {
+                if (node instanceof Simplifiable) {
+                    listener.getChangedNodes().add(node);
+                }
+            }
+            new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), listener.getChangedNodes(), null).apply(graph);
+            listener.getChangedNodes().clear();
             if (++count > MAX_ITERATIONS) {
                 throw new BailoutException("Number of iterations in conditional elimination phase exceeds " + MAX_ITERATIONS);
             }
         }
     }
-
-    private static class Listener implements NodeChangedListener {
-
-        private final Set<Node> canonicalizationRoots;
-
-        public Listener(Set<Node> canonicalizationRoots) {
-            this.canonicalizationRoots = canonicalizationRoots;
-        }
-
-        @Override
-        public void nodeChanged(Node node) {
-            canonicalizationRoots.add(node);
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeChangeListener.java	Tue Aug 27 22:08:52 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * 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.phases.common.util;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.*;
+
+/**
+ * A simple {@link NodeChangedListener} implementation that accumulates the changed nodes in a
+ * {@link HashSet}.
+ */
+public class HashSetNodeChangeListener implements NodeChangedListener {
+
+    private final Set<Node> changedNodes;
+
+    public HashSetNodeChangeListener() {
+        this.changedNodes = new HashSet<>();
+    }
+
+    @Override
+    public void nodeChanged(Node node) {
+        changedNodes.add(node);
+    }
+
+    public Set<Node> getChangedNodes() {
+        return changedNodes;
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Tue Aug 27 22:08:52 2013 +0200
@@ -131,7 +131,7 @@
                 }
 
                 new DeadCodeEliminationPhase().apply(resultGraph);
-                new PartialEscapePhase(true, canonicalizer).apply(resultGraph, context);
+                new PartialEscapePhase(true).apply(resultGraph, context);
 
                 if (TruffleInlinePrinter.getValue()) {
                     InlinePrinterProcessor.printTree();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Tue Aug 27 22:08:52 2013 +0200
@@ -100,6 +100,26 @@
     }
 
     @Override
+    public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
+        verifyGet(slot, FrameSlotKind.Byte);
+        return getByteUnsafe(slot);
+    }
+
+    private byte getByteUnsafe(FrameSlot slot) {
+        return unsafe.getByte(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET);
+    }
+
+    @Override
+    public void setByte(FrameSlot slot, byte value) throws FrameSlotTypeException {
+        verifySet(slot, FrameSlotKind.Byte);
+        setByteUnsafe(slot, value);
+    }
+
+    private void setByteUnsafe(FrameSlot slot, byte value) {
+        unsafe.putByte(primitiveLocals, (long) slot.getIndex() * Unsafe.ARRAY_LONG_INDEX_SCALE + Unsafe.ARRAY_LONG_BASE_OFFSET, value);
+    }
+
+    @Override
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
         verifyGet(slot, FrameSlotKind.Boolean);
         return getBooleanUnsafe(slot);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Tue Aug 27 22:08:52 2013 +0200
@@ -178,7 +178,7 @@
 
                 // EA frame and clean up.
                 new VerifyFrameDoesNotEscapePhase().apply(graph, false);
-                new PartialEscapePhase(false, new CanonicalizerPhase(!AOTCompilation.getValue())).apply(graph, context);
+                new PartialEscapePhase(false).apply(graph, context);
                 new VerifyNoIntrinsicsLeftPhase().apply(graph, false);
                 for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
                     materializeNode.replaceAtUsages(materializeNode.getFrame());
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Tue Aug 27 22:08:52 2013 +0200
@@ -112,7 +112,7 @@
                     optimizeGraph(newGraph, tmpAssumptions);
 
                     PhaseContext context = new PhaseContext(metaAccessProvider, tmpAssumptions, replacements);
-                    PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, new CanonicalizerPhase(true));
+                    PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false);
                     partialEscapePhase.apply(newGraph, context);
 
                     cache.put(method, newGraph);
@@ -153,7 +153,7 @@
         ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider);
         ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase = new ConvertDeoptimizeToGuardPhase();
         CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
-        EarlyReadEliminationPhase readEliminationPhase = new EarlyReadEliminationPhase(canonicalizerPhase);
+        EarlyReadEliminationPhase readEliminationPhase = new EarlyReadEliminationPhase();
 
         int maxNodes = TruffleCompilerOptions.TruffleOperationCacheMaxNodes.getValue();
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameAccessNode.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameAccessNode.java	Tue Aug 27 22:08:52 2013 +0200
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.truffle.*;
 import com.oracle.graal.truffle.nodes.*;
+import com.oracle.graal.truffle.substitutions.*;
 import com.oracle.truffle.api.frame.*;
 
 /**
@@ -70,7 +71,7 @@
         return getConstantFrameSlot().getIndex();
     }
 
-    protected boolean isConstantFrameSlot() {
+    public boolean isConstantFrameSlot() {
         return slot.isConstant() && !slot.isNullConstant();
     }
 
@@ -113,14 +114,17 @@
     }
 
     protected final boolean isValidAccessKind() {
-        if (getSlotKind() == Kind.Byte) {
-            // tag access
+        if (isTagAccess()) {
             return true;
         }
 
         return getSlotKind() == getGraalKind(getConstantFrameSlot().getKind());
     }
 
+    protected final boolean isTagAccess() {
+        return field == FrameWithoutBoxingSubstitutions.TAGS_FIELD;
+    }
+
     private static Kind getGraalKind(FrameSlotKind kind) {
         switch (kind) {
             case Object:
@@ -156,6 +160,9 @@
     @Override
     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
         Map<Object, Object> properties = super.getDebugProperties(map);
+        if (isTagAccess()) {
+            properties.put("slotKind", "Tag");
+        }
         if (isConstantFrameSlot()) {
             properties.put("frameSlot", getConstantFrameSlot().toString());
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameGetNode.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameGetNode.java	Tue Aug 27 22:08:52 2013 +0200
@@ -78,12 +78,12 @@
         LoadFieldNode loadFieldNode = graph().add(new LoadFieldNode(getFrame(), field));
         structuredGraph.addBeforeFixed(this, loadFieldNode);
         FixedWithNextNode loadNode;
-        if (!getSlotKind().isPrimitive()) {
+        if (isTagAccess()) {
+            ValueNode slotIndex = getSlotOffset(1, tool.getRuntime());
+            loadNode = graph().add(new LoadIndexedNode(loadFieldNode, slotIndex, getSlotKind()));
+        } else if (!getSlotKind().isPrimitive()) {
             ValueNode slotIndex = getSlotOffset(1, tool.getRuntime());
             loadNode = graph().add(new LoadIndexedNode(loadFieldNode, slotIndex, Kind.Object));
-        } else if (getSlotKind() == Kind.Byte) {
-            ValueNode slotIndex = getSlotOffset(1, tool.getRuntime());
-            loadNode = graph().add(new LoadIndexedNode(loadFieldNode, slotIndex, Kind.Byte));
         } else {
             ValueNode slotOffset = getSlotOffset(Unsafe.ARRAY_LONG_INDEX_SCALE, tool.getRuntime());
             loadNode = graph().add(new UnsafeLoadNode(loadFieldNode, Unsafe.ARRAY_LONG_BASE_OFFSET, slotOffset, getSlotKind()));
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameSetNode.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/FrameSetNode.java	Tue Aug 27 22:08:52 2013 +0200
@@ -79,10 +79,10 @@
         structuredGraph.addBeforeFixed(this, loadFieldNode);
         FixedWithNextNode storeNode;
         ValueNode slotIndex = getSlotOffset(1, tool.getRuntime());
-        if (!getSlotKind().isPrimitive()) {
+        if (isTagAccess()) {
+            storeNode = graph().add(new StoreIndexedNode(loadFieldNode, slotIndex, getSlotKind(), value));
+        } else if (!getSlotKind().isPrimitive()) {
             storeNode = graph().add(new StoreIndexedNode(loadFieldNode, slotIndex, Kind.Object, value));
-        } else if (getSlotKind() == Kind.Byte) {
-            storeNode = graph().add(new StoreIndexedNode(loadFieldNode, slotIndex, Kind.Byte, value));
         } else {
             storeNode = graph().add(new StoreIndexedNode(loadFieldNode, slotIndex, Kind.Long, value));
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -37,9 +37,8 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        NewFrameNode frame = graph.getNodes(NewFrameNode.class).first();
-        if (frame != null) {
-            for (MethodCallTargetNode callTarget : frame.usages().filter(MethodCallTargetNode.class)) {
+        for (NewFrameNode virtualFrame : graph.getNodes(NewFrameNode.class)) {
+            for (MethodCallTargetNode callTarget : virtualFrame.usages().filter(MethodCallTargetNode.class)) {
                 if (callTarget.invoke() != null) {
                     String properties = callTarget.getDebugProperties().toString();
                     String arguments = callTarget.arguments().toString();
@@ -47,6 +46,12 @@
                     throw GraphUtil.approxSourceException(callTarget, exception);
                 }
             }
+            for (FrameAccessNode frameAccess : virtualFrame.usages().filter(FrameAccessNode.class)) {
+                if (!frameAccess.isConstantFrameSlot()) {
+                    Throwable exception = new VerificationError("Frame slot must be compile-time constant in virtual frame access at: %s frameSlot=%s", frameAccess, frameAccess.getSlot());
+                    throw GraphUtil.approxSourceException(frameAccess, exception);
+                }
+            }
         }
     }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Tue Aug 27 22:08:52 2013 +0200
@@ -36,7 +36,7 @@
 
     private static final ResolvedJavaField LOCALS_FIELD;
     private static final ResolvedJavaField PRIMITIVELOCALS_FIELD;
-    private static final ResolvedJavaField TAGS_FIELD;
+    public static final ResolvedJavaField TAGS_FIELD;
 
     static {
         try {
@@ -80,6 +80,18 @@
     }
 
     @MethodSubstitution(isStatic = false, forced = true)
+    public static byte getByte(FrameWithoutBoxing frame, FrameSlot slot) {
+        verifyGet(frame, slot, FrameSlotKind.Byte);
+        return getByteUnsafe(frame, slot);
+    }
+
+    @MethodSubstitution(isStatic = false, forced = true)
+    public static void setByte(FrameWithoutBoxing frame, FrameSlot slot, byte value) {
+        verifySet(frame, slot, FrameSlotKind.Byte);
+        setByteUnsafe(frame, slot, value);
+    }
+
+    @MethodSubstitution(isStatic = false, forced = true)
     public static float getFloat(FrameWithoutBoxing frame, FrameSlot slot) {
         verifyGet(frame, slot, FrameSlotKind.Float);
         return getFloatUnsafe(frame, slot);
@@ -148,6 +160,16 @@
     }
 
     @MethodSubstitution(isStatic = false)
+    public static byte getByteUnsafe(FrameWithoutBoxing frame, FrameSlot slot) {
+        return FrameGetNode.get(Kind.Byte, frame, slot, PRIMITIVELOCALS_FIELD);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static void setByteUnsafe(FrameWithoutBoxing frame, FrameSlot slot, byte value) {
+        FrameSetNode.set(Kind.Byte, frame, slot, value, PRIMITIVELOCALS_FIELD);
+    }
+
+    @MethodSubstitution(isStatic = false)
     public static int getIntUnsafe(FrameWithoutBoxing frame, FrameSlot slot) {
         return FrameGetNode.get(Kind.Int, frame, slot, PRIMITIVELOCALS_FIELD);
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -25,14 +25,13 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
 
-    public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
-        super(1, canonicalizer);
+    public EarlyReadEliminationPhase() {
+        super(1);
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -27,9 +27,12 @@
 import java.util.concurrent.*;
 
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.util.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
@@ -44,11 +47,9 @@
     }
 
     private final int maxIterations;
-    private CanonicalizerPhase canonicalizer;
 
-    public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+    public EffectsPhase(int maxIterations) {
         this.maxIterations = maxIterations;
-        this.canonicalizer = canonicalizer;
     }
 
     @Override
@@ -73,15 +74,23 @@
                     }
 
                     // apply the effects collected during this iteration
+                    HashSetNodeChangeListener listener = new HashSetNodeChangeListener();
+                    graph.trackInputChange(listener);
+                    graph.trackUsagesDroppedZero(listener);
                     closure.applyEffects();
+                    graph.stopTrackingInputChange();
+                    graph.stopTrackingUsagesDroppedZero();
 
                     Debug.dump(graph, "after " + getName() + " iteration");
 
                     new DeadCodeEliminationPhase().apply(graph);
 
-                    if (OptCanonicalizer.getValue()) {
-                        canonicalizer.apply(graph, context);
+                    for (Node node : graph.getNodes()) {
+                        if (node instanceof Simplifiable) {
+                            listener.getChangedNodes().add(node);
+                        }
                     }
+                    new CanonicalizerPhase.Instance(context.getRuntime(), context.getAssumptions(), !AOTCompilation.getValue(), listener.getChangedNodes(), null).apply(graph);
 
                     return true;
                 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -60,7 +60,7 @@
                 @Override
                 public Boolean call() {
                     boolean progress = false;
-                    PartialEscapePhase ea = new PartialEscapePhase(false, canonicalizer);
+                    PartialEscapePhase ea = new PartialEscapePhase(false);
                     boolean eaResult = ea.runAnalysis(graph, context);
                     progress |= eaResult;
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Tue Aug 27 22:08:52 2013 +0200
@@ -33,7 +33,6 @@
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
@@ -47,12 +46,12 @@
 
     private final boolean readElimination;
 
-    public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
-        this(iterative, OptEarlyReadElimination.getValue(), canonicalizer);
+    public PartialEscapePhase(boolean iterative) {
+        this(iterative, OptEarlyReadElimination.getValue());
     }
 
-    public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) {
-        super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
+    public PartialEscapePhase(boolean iterative, boolean readElimination) {
+        super(iterative ? EscapeAnalysisIterations.getValue() : 1);
         this.readElimination = readElimination;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/Frame.java	Tue Aug 27 22:08:52 2013 +0200
@@ -67,6 +67,23 @@
     void setObject(FrameSlot slot, Object value) throws FrameSlotTypeException;
 
     /**
+     * Read access to a local variable of type byte.
+     * 
+     * @param slot the slot of the local variable
+     * @return the current value of the local variable
+     */
+    byte getByte(FrameSlot slot) throws FrameSlotTypeException;
+
+    /**
+     * Write access to a local variable of type byte.
+     * 
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+
+    void setByte(FrameSlot slot, byte value) throws FrameSlotTypeException;
+
+    /**
      * Read access to a local variable of type boolean.
      * 
      * @param slot the slot of the local variable
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Tue Aug 27 22:08:52 2013 +0200
@@ -25,5 +25,5 @@
 package com.oracle.truffle.api.frame;
 
 public enum FrameSlotKind {
-    Illegal, Object, Long, Int, Double, Float, Boolean;
+    Illegal, Object, Long, Int, Double, Float, Boolean, Byte;
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Tue Aug 27 22:08:52 2013 +0200
@@ -46,6 +46,25 @@
     }
 
     /**
+     * Write access to a local variable of type {@code byte}.
+     * 
+     * Sets the frame slot type to {@code byte} if it isn't already.
+     * 
+     * @param slot the slot of the local variable
+     * @param value the new value of the local variable
+     */
+    public static void setByteSafe(Frame frame, FrameSlot slot, byte value) {
+        if (slot.getKind() != FrameSlotKind.Byte) {
+            slot.setKind(FrameSlotKind.Byte);
+        }
+        try {
+            frame.setByte(slot, value);
+        } catch (FrameSlotTypeException e) {
+            throw new IllegalStateException();
+        }
+    }
+
+    /**
      * Write access to a local variable of type {@code boolean}.
      * 
      * Sets the frame slot type to {@code boolean} if it isn't already.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/NativeFrame.java	Tue Aug 27 22:08:52 2013 +0200
@@ -57,6 +57,16 @@
     }
 
     @Override
+    public byte getByte(FrameSlot slot) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
+    public void setByte(FrameSlot slot, byte value) {
+        throw new UnsupportedOperationException("native frame");
+    }
+
+    @Override
     public boolean getBoolean(FrameSlot slot) {
         throw new UnsupportedOperationException("native frame");
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultMaterializedFrame.java	Tue Aug 27 22:08:52 2013 +0200
@@ -51,6 +51,16 @@
     }
 
     @Override
+    public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
+        return wrapped.getByte(slot);
+    }
+
+    @Override
+    public void setByte(FrameSlot slot, byte value) throws FrameSlotTypeException {
+        wrapped.setByte(slot, value);
+    }
+
+    @Override
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
         return wrapped.getBoolean(slot);
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Tue Aug 27 22:08:26 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Tue Aug 27 22:08:52 2013 +0200
@@ -79,6 +79,18 @@
     }
 
     @Override
+    public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
+        verifyGet(slot, FrameSlotKind.Byte);
+        return (byte) locals[slot.getIndex()];
+    }
+
+    @Override
+    public void setByte(FrameSlot slot, byte value) throws FrameSlotTypeException {
+        verifySet(slot, FrameSlotKind.Byte);
+        locals[slot.getIndex()] = value;
+    }
+
+    @Override
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
         verifyGet(slot, FrameSlotKind.Boolean);
         return (boolean) locals[slot.getIndex()];
--- a/mx/commands.py	Tue Aug 27 22:08:26 2013 +0200
+++ b/mx/commands.py	Tue Aug 27 22:08:52 2013 +0200
@@ -680,7 +680,7 @@
 
     if cwd is None:
         cwd = _vm_cwd
-    elif _vm_cwd != cwd:
+    elif _vm_cwd is not None and _vm_cwd != cwd:
         mx.abort("conflicting working directories: do not set --vmcwd for this command")
 
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'