changeset 15883:9b6d45071187

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 24 May 2014 00:38:23 +0200
parents e751da27fd48 (current diff) fe608a56e3f7 (diff)
children 0e6f83eeb0ab
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java
diffstat 28 files changed, 755 insertions(+), 546 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Sat May 24 00:38:23 2014 +0200
@@ -84,11 +84,11 @@
             // structure changes significantly
             StructuredGraph graph = parse(snippet);
             PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
-            new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+            CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
+            new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
             new OptimizeGuardAnchorsPhase().apply(graph);
-            new ReadEliminationPhase().apply(graph);
-            new CanonicalizerPhase(true).apply(graph, context);
+            canonicalizer.apply(graph, context);
 
             Debug.dump(graph, "After lowering");
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/MidTier.java	Sat May 24 00:38:23 2014 +0200
@@ -52,9 +52,6 @@
 
         if (OptFloatingReads.getValue()) {
             appendPhase(new IncrementalCanonicalizerPhase<>(canonicalizer, new FloatingReadPhase()));
-            if (OptReadElimination.getValue()) {
-                appendPhase(new ReadEliminationPhase());
-            }
         }
         appendPhase(new RemoveValueProxyPhase());
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Sat May 24 00:38:23 2014 +0200
@@ -20,103 +20,38 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
+import static com.oracle.graal.hotspot.HotSpotOptionsLoader.*;
 import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
-import static java.nio.file.Files.*;
+import static java.lang.Double.*;
 
-import java.io.*;
 import java.lang.reflect.*;
-import java.nio.charset.*;
-import java.nio.file.*;
 import java.util.*;
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.hotspot.logging.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.inlining.*;
 
 /**
- * Called from {@code graalCompiler.cpp} to parse any Graal specific options. Such options are
- * (currently) distinguished by a {@code "-G:"} prefix.
+ * Called from {@code graalCompiler.cpp} to set Graal options from the HotSpot command line. Such
+ * options are (currently) distinguished by a {@code "-G:"} prefix.
  */
 public class HotSpotOptions {
 
-    private static final Map<String, OptionDescriptor> options = new HashMap<>();
-
     /**
-     * Initializes {@link #options} from {@link Options} services.
-     */
-    private static void initializeOptions() {
-        ServiceLoader<Options> sl = ServiceLoader.loadInstalled(Options.class);
-        for (Options opts : sl) {
-            for (OptionDescriptor desc : opts) {
-                if (isHotSpotOption(desc)) {
-                    String name = desc.getName();
-                    OptionDescriptor existing = options.put(name, desc);
-                    assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
-                }
-            }
-        }
-    }
-
-    /**
-     * Determines if a given option is a HotSpot command line option.
+     * Parses the Graal specific options specified to HotSpot (e.g., on the command line).
+     *
+     * @return true if the CITime or CITimeEach HotSpot VM options are set
      */
-    public static boolean isHotSpotOption(OptionDescriptor desc) {
-        return desc.getClass().getName().startsWith("com.oracle.graal");
-    }
-
-    /**
-     * Loads default option value overrides from a {@code graal.options} file if it exists. Each
-     * line in this file starts with {@code "#"} and is ignored or must have the format of a Graal
-     * command line option without the leading {@code "-G:"} prefix. These option value are set
-     * prior to processing of any Graal options present on the command line.
-     */
-    private static void loadOptionOverrides() throws InternalError {
-        String javaHome = System.getProperty("java.home");
-        Path graalDotOptions = Paths.get(javaHome, "lib", "graal.options");
-        if (!exists(graalDotOptions)) {
-            graalDotOptions = Paths.get(javaHome, "jre", "lib", "graal.options");
-        }
-        if (exists(graalDotOptions)) {
-            try {
-                for (String line : Files.readAllLines(graalDotOptions, Charset.defaultCharset())) {
-                    if (!line.startsWith("#")) {
-                        if (!parseOption(line, null)) {
-                            throw new InternalError("Invalid option \"" + line + "\" specified in " + graalDotOptions);
-                        }
-                    }
-                }
-            } catch (IOException e) {
-                throw (InternalError) new InternalError().initCause(e);
-            }
-        }
-    }
-
-    /**
-     * Gets the Graal specific options specified to HotSpot (e.g., on the command line).
-     *
-     * @param timeCompilations (out) true if the CITime or CITimeEach HotSpot VM options are set
-     */
-    private static native String[] getVMOptions(boolean[] timeCompilations);
+    private static native boolean parseVMOptions();
 
     static {
-        initializeOptions();
-        loadOptionOverrides();
-
-        boolean[] timeCompilations = {false};
-        for (String option : getVMOptions(timeCompilations)) {
-            if (!parseOption(option, null)) {
-                throw new InternalError("Invalid Graal option \"-G:" + option + "\"");
-            }
-        }
-
-        if (timeCompilations[0] || PrintCompRate.getValue() != 0) {
+        boolean timeCompilations = parseVMOptions();
+        if (timeCompilations || PrintCompRate.getValue() != 0) {
             unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
             unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
         }
@@ -138,6 +73,42 @@
     }
 
     /**
+     * Helper for the VM code called by {@link #parseVMOptions()}.
+     *
+     * @param name the name of a parsed option
+     * @param option the object encapsulating the option
+     * @param spec specification of boolean option value, type of option value or action to take
+     */
+    static void setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue) {
+        switch (spec) {
+            case '+':
+                option.setValue(Boolean.TRUE);
+                break;
+            case '-':
+                option.setValue(Boolean.FALSE);
+                break;
+            case '?':
+                printFlags();
+                break;
+            case ' ':
+                printNoMatchMessage(name);
+                break;
+            case 'i':
+                option.setValue((int) primitiveValue);
+                break;
+            case 'f':
+                option.setValue((float) longBitsToDouble(primitiveValue));
+                break;
+            case 'd':
+                option.setValue(longBitsToDouble(primitiveValue));
+                break;
+            case 's':
+                option.setValue(stringValue);
+                break;
+        }
+    }
+
+    /**
      * Parses a given option value specification.
      *
      * @param option the specification of an option and its value
@@ -176,15 +147,7 @@
 
         OptionDescriptor desc = options.get(optionName);
         if (desc == null) {
-            Logger.info("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
-            List<OptionDescriptor> matches = fuzzyMatch(optionName);
-            if (!matches.isEmpty()) {
-                Logger.info("Did you mean one of the following?");
-                for (OptionDescriptor match : matches) {
-                    boolean isBoolean = match.getType() == boolean.class;
-                    Logger.info(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
-                }
-            }
+            printNoMatchMessage(optionName);
             return false;
         }
 
@@ -192,12 +155,12 @@
 
         if (value == null) {
             if (optionType == Boolean.TYPE || optionType == Boolean.class) {
-                Logger.info("Value for boolean option '" + optionName + "' must use '-G:+" + optionName + "' or '-G:-" + optionName + "' format");
+                System.out.println("Value for boolean option '" + optionName + "' must use '-G:+" + optionName + "' or '-G:-" + optionName + "' format");
                 return false;
             }
 
             if (valueString == null) {
-                Logger.info("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
+                System.out.println("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
                 return false;
             }
 
@@ -212,7 +175,7 @@
             }
         } else {
             if (optionType != Boolean.class) {
-                Logger.info("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
+                System.out.println("Value for option '" + optionName + "' must use '-G:" + optionName + "=<value>' format");
                 return false;
             }
         }
@@ -223,16 +186,28 @@
             } else {
                 OptionValue<?> optionValue = desc.getOptionValue();
                 optionValue.setValue(value);
-                // Logger.info("Set option " + desc.getName() + " to " + value);
+                // System.out.println("Set option " + desc.getName() + " to " + value);
             }
         } else {
-            Logger.info("Wrong value \"" + valueString + "\" for option " + optionName);
+            System.out.println("Wrong value \"" + valueString + "\" for option " + optionName);
             return false;
         }
 
         return true;
     }
 
+    protected static void printNoMatchMessage(String optionName) {
+        System.out.println("Could not find option " + optionName + " (use -G:+PrintFlags to see Graal options)");
+        List<OptionDescriptor> matches = fuzzyMatch(optionName);
+        if (!matches.isEmpty()) {
+            System.out.println("Did you mean one of the following?");
+            for (OptionDescriptor match : matches) {
+                boolean isBoolean = match.getType() == boolean.class;
+                System.out.println(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
+            }
+        }
+    }
+
     /**
      * Sets the relevant system property such that a {@link DebugTimer} or {@link DebugMetric}
      * associated with a field in a class will be unconditionally enabled when it is created.
@@ -255,7 +230,7 @@
             }
             String previous = System.setProperty(propertyName, "true");
             if (previous != null) {
-                Logger.info("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
+                System.out.println("Overrode value \"" + previous + "\" of system property \"" + propertyName + "\" with \"true\"");
             }
         } catch (Exception e) {
             throw new GraalInternalError(e);
@@ -305,16 +280,16 @@
     }
 
     private static void printFlags() {
-        Logger.info("[Graal flags]");
-        SortedMap<String, OptionDescriptor> sortedOptions = new TreeMap<>(options);
+        System.out.println("[Graal flags]");
+        SortedMap<String, OptionDescriptor> sortedOptions = options;
         for (Map.Entry<String, OptionDescriptor> e : sortedOptions.entrySet()) {
             e.getKey();
             OptionDescriptor desc = e.getValue();
             Object value = desc.getOptionValue().getValue();
             List<String> helpLines = wrap(desc.getHelp(), 70);
-            Logger.info(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0)));
+            System.out.println(String.format("%9s %-40s = %-14s %s", desc.getType().getSimpleName(), e.getKey(), value, helpLines.get(0)));
             for (int i = 1; i < helpLines.size(); i++) {
-                Logger.info(String.format("%67s %s", " ", helpLines.get(i)));
+                System.out.println(String.format("%67s %s", " ", helpLines.get(i)));
             }
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java	Sat May 24 00:38:23 2014 +0200
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.options.*;
+
+/**
+ * Helper class for separating loading of options from option initialization at runtime.
+ */
+class HotSpotOptionsLoader {
+    static final SortedMap<String, OptionDescriptor> options = new TreeMap<>();
+
+    /**
+     * Initializes {@link #options} from {@link Options} services.
+     */
+    static {
+        ServiceLoader<Options> sl = ServiceLoader.load(Options.class);
+        for (Options opts : sl) {
+            for (OptionDescriptor desc : opts) {
+                if (isHotSpotOption(desc)) {
+                    String name = desc.getName();
+                    OptionDescriptor existing = options.put(name, desc);
+                    assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
+                }
+            }
+        }
+    }
+
+    /**
+     * Determines if a given option is a HotSpot command line option.
+     */
+    private static boolean isHotSpotOption(OptionDescriptor desc) {
+        return desc.getClass().getName().startsWith("com.oracle.graal");
+    }
+
+    /**
+     * Command line utility for generating the source code of GraalRuntime::set_option().
+     *
+     * @param args one element array with the path of the source file to be created
+     */
+    public static void main(String[] args) throws Exception {
+        File outputFile = new File(args[0]);
+        PrintStream out = new PrintStream(outputFile);
+        Set<Integer> lengths = new TreeSet<>();
+        for (String s : options.keySet()) {
+            lengths.add(s.length());
+        }
+        lengths.add("PrintFlags".length());
+
+        out.println("bool GraalRuntime::set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS) {");
+        out.println("  if (value[0] == '+' || value[0] == '-') {");
+        out.println("    // boolean options");
+        genMatchers(out, lengths, true);
+        out.println("  } else {");
+        out.println("    // non-boolean options");
+        genMatchers(out, lengths, false);
+        out.println("  }");
+        out.println("  return false;");
+        out.println("}");
+
+        out.flush();
+    }
+
+    protected static void genMatchers(PrintStream out, Set<Integer> lengths, boolean isBoolean) throws Exception {
+        out.println("    switch (name_len) {");
+        for (int len : lengths) {
+            boolean printedCase = false;
+
+            if (len == "PrintFlags".length() && isBoolean) {
+                printedCase = true;
+                out.println("    case " + len + ":");
+                out.printf("      if (strncmp(name, \"PrintFlags\", %d) == 0) {\n", len);
+                out.println("        if (value[0] == '+') {");
+                out.println("          VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), '?', Handle(), 0L);");
+                out.println("        }");
+                out.println("        return true;");
+                out.println("      }");
+            }
+            for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
+                OptionDescriptor desc = e.getValue();
+                if (e.getKey().length() == len && ((desc.getType() == Boolean.class) == isBoolean)) {
+                    if (!printedCase) {
+                        printedCase = true;
+                        out.println("    case " + len + ":");
+                    }
+                    out.printf("      if (strncmp(name, \"%s\", %d) == 0) {\n", e.getKey(), len);
+                    Class<?> declaringClass = desc.getDeclaringClass();
+                    out.printf("        Handle option = get_OptionValue(\"L%s;\", \"%s\", \"L%s;\", CHECK_(true));\n", toInternalName(declaringClass), desc.getFieldName(),
+                                    toInternalName(getFieldType(desc)));
+                    if (isBoolean) {
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, value[0], Handle(), 0L);");
+                    } else if (desc.getType() == String.class) {
+                        out.println("        Handle stringValue = java_lang_String::create_from_str(value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, 's', stringValue, 0L);");
+                    } else {
+                        char spec = getPrimitiveSpecChar(desc);
+                        out.println("        jlong primitiveValue = parse_primitive_option_value('" + spec + "', name_handle, value, CHECK_(true));");
+                        out.println("        VMToCompiler::setOption(hotSpotOptionsClass, name_handle, option, '" + spec + "', Handle(), primitiveValue);");
+                    }
+                    out.println("        return true;");
+                    out.println("      }");
+                }
+            }
+        }
+        out.println("    }");
+    }
+
+    private static Class<?> getFieldType(OptionDescriptor desc) throws Exception {
+        return desc.getDeclaringClass().getDeclaredField(desc.getFieldName()).getType();
+    }
+
+    private static String toInternalName(Class<?> c) {
+        return c.getName().replace('.', '/');
+    }
+
+    /**
+     * @see HotSpotOptions#setOption(String, OptionValue, char, String, long)
+     */
+    private static char getPrimitiveSpecChar(OptionDescriptor desc) {
+        if (desc.getType() == Integer.class) {
+            return 'i';
+        }
+        if (desc.getType() == Float.class) {
+            return 'f';
+        }
+        if (desc.getType() == Double.class) {
+            return 'd';
+        }
+        throw GraalInternalError.shouldNotReachHere("Unexpected primitive option type: " + desc.getType().getName());
+    }
+}
\ No newline at end of file
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sat May 24 00:38:23 2014 +0200
@@ -482,30 +482,23 @@
             AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
             AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
             MergeNode merge = trueEnd.merge();
-            if (merge == falseEnd.merge() && merge.forwardEndCount() == 2 && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
+            if (merge == falseEnd.merge() && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
                 Iterator<PhiNode> phis = merge.phis().iterator();
                 if (!phis.hasNext()) {
-                    // empty if construct with no phis: remove it
-                    removeEmptyIf(tool);
+                    tool.addToWorkList(condition());
+                    removeThroughFalseBranch(tool);
                     return true;
                 } else {
                     PhiNode singlePhi = phis.next();
                     if (!phis.hasNext()) {
                         // one phi at the merge of an otherwise empty if construct: try to convert
                         // into a MaterializeNode
-                        boolean inverted = trueEnd == merge.forwardEndAt(1);
-                        ValueNode trueValue = singlePhi.valueAt(inverted ? 1 : 0);
-                        ValueNode falseValue = singlePhi.valueAt(inverted ? 0 : 1);
-                        if (trueValue.getKind() != falseValue.getKind()) {
-                            return false;
-                        }
-                        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
-                            return false;
-                        }
+                        ValueNode trueValue = singlePhi.valueAt(trueEnd);
+                        ValueNode falseValue = singlePhi.valueAt(falseEnd);
                         ConditionalNode conditional = canonicalizeConditionalCascade(trueValue, falseValue);
                         if (conditional != null) {
-                            graph().replaceFloating(singlePhi, conditional);
-                            removeEmptyIf(tool);
+                            singlePhi.setValueAt(trueEnd, conditional);
+                            removeThroughFalseBranch(tool);
                             return true;
                         }
                     }
@@ -519,12 +512,6 @@
             ValueNode falseValue = falseEnd.result();
             ConditionalNode conditional = null;
             if (trueValue != null) {
-                if (trueValue.getKind() != falseValue.getKind()) {
-                    return false;
-                }
-                if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
-                    return false;
-                }
                 conditional = canonicalizeConditionalCascade(trueValue, falseValue);
                 if (conditional == null) {
                     return false;
@@ -538,7 +525,19 @@
         return false;
     }
 
+    protected void removeThroughFalseBranch(SimplifierTool tool) {
+        BeginNode trueBegin = trueSuccessor();
+        graph().removeSplitPropagate(this, trueBegin, tool);
+        tool.addToWorkList(trueBegin);
+    }
+
     private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
+        if (trueValue.getKind() != falseValue.getKind()) {
+            return null;
+        }
+        if (trueValue.getKind() != Kind.Int && trueValue.getKind() != Kind.Long) {
+            return null;
+        }
         if (trueValue.isConstant() && falseValue.isConstant()) {
             return graph().unique(new ConditionalNode(condition(), trueValue, falseValue));
         } else {
@@ -884,38 +883,4 @@
 
         return null;
     }
-
-    private void removeEmptyIf(SimplifierTool tool) {
-        BeginNode originalTrueSuccessor = trueSuccessor();
-        BeginNode originalFalseSuccessor = falseSuccessor();
-        assert originalTrueSuccessor.next() instanceof AbstractEndNode && originalFalseSuccessor.next() instanceof AbstractEndNode;
-
-        AbstractEndNode trueEnd = (AbstractEndNode) originalTrueSuccessor.next();
-        AbstractEndNode falseEnd = (AbstractEndNode) originalFalseSuccessor.next();
-        assert trueEnd.merge() == falseEnd.merge();
-
-        FixedWithNextNode pred = (FixedWithNextNode) predecessor();
-        MergeNode merge = trueEnd.merge();
-        merge.prepareDelete(pred);
-        assert merge.usages().isEmpty();
-        originalTrueSuccessor.prepareDelete();
-        originalFalseSuccessor.prepareDelete();
-
-        FixedNode next = merge.next();
-        FrameState state = merge.stateAfter();
-        merge.setNext(null);
-        setTrueSuccessor(null);
-        setFalseSuccessor(null);
-        pred.setNext(next);
-        safeDelete();
-        originalTrueSuccessor.safeDelete();
-        originalFalseSuccessor.safeDelete();
-        merge.safeDelete();
-        trueEnd.safeDelete();
-        falseEnd.safeDelete();
-        if (state != null) {
-            tool.removeIfUnused(state);
-        }
-        tool.addToWorkList(next);
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Sat May 24 00:38:23 2014 +0200
@@ -82,6 +82,10 @@
         values().set(i, x);
     }
 
+    public void setValueAt(AbstractEndNode end, ValueNode x) {
+        setValueAt(merge().phiPredecessorIndex(end), x);
+    }
+
     public ValueNode valueAt(AbstractEndNode pred) {
         return valueAt(merge().phiPredecessorIndex(pred));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Sat May 24 00:38:23 2014 +0200
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
@@ -303,6 +304,10 @@
     }
 
     public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) {
+        removeSplitPropagate(node, survivingSuccessor, null);
+    }
+
+    public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor, SimplifierTool tool) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -313,7 +318,7 @@
         for (Node successor : snapshot) {
             if (successor != null && successor.isAlive()) {
                 if (successor != survivingSuccessor) {
-                    GraphUtil.killCFG(successor);
+                    GraphUtil.killCFG(successor, tool);
                 }
             }
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sat May 24 00:38:23 2014 +0200
@@ -189,7 +189,9 @@
                                 GraphUtil.tryKillUnused(valueNode);
                             } else if (improvedStamp) {
                                 // the improved stamp may enable additional canonicalization
-                                tryCanonicalize(valueNode, nodeClass);
+                                if (!tryCanonicalize(valueNode, nodeClass)) {
+                                    valueNode.usages().forEach(workList::add);
+                                }
                             }
                         }
                     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ReadEliminationPhase.java	Thu May 22 18:10:04 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2011, 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;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.phases.*;
-
-public class ReadEliminationPhase extends Phase {
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) {
-            if (isReadEliminable(n)) {
-                NodeMap<ValueNode> nodeMap = n.graph().createNodeMap();
-                ValueNode value = getValue(n, n.getLastLocationAccess(), nodeMap);
-                Debug.log("Eliminated memory read %1.1s and replaced with node %s", n, value);
-                graph.replaceFloating(n, value);
-            }
-        }
-    }
-
-    private static boolean isReadEliminable(FloatingReadNode n) {
-        return isWrites(n, n.getLastLocationAccess(), n.graph().createNodeBitMap());
-    }
-
-    private static boolean isWrites(FloatingReadNode n, MemoryNode lastLocationAccess, NodeBitMap visited) {
-        if (lastLocationAccess == null) {
-            return false;
-        }
-        if (visited.isMarked(ValueNodeUtil.asNode(lastLocationAccess))) {
-            return true; // dataflow loops must come from Phis assume them ok until proven wrong
-        }
-        if (lastLocationAccess instanceof ProxyNode) {
-            return isWrites(n, (MemoryNode) ((ProxyNode) lastLocationAccess).value(), visited);
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            WriteNode other = (WriteNode) lastLocationAccess;
-            return other.object() == n.object() && other.location() == n.location();
-        }
-        if (lastLocationAccess instanceof MemoryPhiNode) {
-            visited.mark(ValueNodeUtil.asNode(lastLocationAccess));
-            for (ValueNode value : ((MemoryPhiNode) lastLocationAccess).values()) {
-                if (!isWrites(n, (MemoryNode) value, visited)) {
-                    return false;
-                }
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private static ValueNode getValue(FloatingReadNode n, MemoryNode lastLocationAccess, NodeMap<ValueNode> nodeMap) {
-        ValueNode exisiting = nodeMap.get(ValueNodeUtil.asNode(lastLocationAccess));
-        if (exisiting != null) {
-            return exisiting;
-        }
-        if (lastLocationAccess instanceof MemoryProxyNode) {
-            MemoryProxyNode proxy = (MemoryProxyNode) lastLocationAccess;
-            ValueNode value = getValue(n, proxy.getOriginalMemoryNode(), nodeMap);
-            return ProxyNode.forValue(value, proxy.proxyPoint(), proxy.graph());
-        }
-        if (lastLocationAccess instanceof WriteNode) {
-            return ((WriteNode) lastLocationAccess).value();
-        }
-        if (lastLocationAccess instanceof MemoryPhiNode) {
-            MemoryPhiNode phi = (MemoryPhiNode) lastLocationAccess;
-            ValuePhiNode newPhi = phi.graph().addWithoutUnique(new ValuePhiNode(n.stamp().unrestricted(), phi.merge()));
-            nodeMap.set(phi, newPhi);
-            for (ValueNode value : phi.values()) {
-                newPhi.addInput(getValue(n, (MemoryNode) value, nodeMap));
-            }
-            return newPhi;
-        }
-        throw GraalInternalError.shouldNotReachHere();
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Sat May 24 00:38:23 2014 +0200
@@ -332,13 +332,13 @@
             assert concretes.size() > 0;
             Debug.log("Method check cascade with %d methods", concretes.size());
 
-            ValueNode[] constantMethods = new ValueNode[concretes.size()];
+            ConstantNode[] constantMethods = new ConstantNode[concretes.size()];
             double[] probability = new double[concretes.size()];
             for (int i = 0; i < concretes.size(); ++i) {
                 ResolvedJavaMethod firstMethod = concretes.get(i);
                 Constant firstMethodConstant = firstMethod.getEncoding();
 
-                ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
+                ConstantNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
                 constantMethods[i] = firstMethodConstantNode;
                 double concretesProbability = concretesProbabilities.get(i);
                 assert concretesProbability >= 0.0;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolder.java	Sat May 24 00:38:23 2014 +0200
@@ -51,23 +51,23 @@
 
     public CallsiteHolder(StructuredGraph graph, double probability, double relevance) {
         this.graph = graph;
-        if (graph == null) {
-            this.remainingInvokes = new LinkedList<>();
-        } else {
-            LinkedList<Invoke> invokes = new InliningIterator(graph).apply();
-            assert invokes.size() == count(graph.getInvokes());
-            this.remainingInvokes = invokes;
-        }
         this.probability = probability;
         this.relevance = relevance;
-
-        if (graph != null && !remainingInvokes.isEmpty()) {
-            probabilities = new FixedNodeProbabilityCache();
-            computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
-            computeProbabilities();
-        } else {
+        if (graph == null) {
+            remainingInvokes = new LinkedList<>();
             probabilities = null;
             computeInliningRelevance = null;
+        } else {
+            remainingInvokes = new InliningIterator(graph).apply();
+            assert remainingInvokes.size() == count(graph.getInvokes());
+            if (remainingInvokes.isEmpty()) {
+                probabilities = null;
+                computeInliningRelevance = null;
+            } else {
+                probabilities = new FixedNodeProbabilityCache();
+                computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+                computeProbabilities();
+            }
         }
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Sat May 24 00:38:23 2014 +0200
@@ -264,11 +264,6 @@
                 }
             }
 
-            if (concreteMethods.size() > maxMethodPerInlining) {
-                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
-                return null;
-            }
-
             // Clear methods that fall below the threshold.
             if (notRecordedTypeProbability > 0) {
                 ArrayList<ResolvedJavaMethod> newConcreteMethods = new ArrayList<>();
@@ -280,7 +275,7 @@
                     }
                 }
 
-                if (newConcreteMethods.size() == 0) {
+                if (newConcreteMethods.isEmpty()) {
                     // No method left that is worth inlining.
                     InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
                                     concreteMethods.size());
@@ -291,6 +286,11 @@
                 concreteMethodsProbabilities = newConcreteMethodsProbabilities;
             }
 
+            if (concreteMethods.size() > maxMethodPerInlining) {
+                InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxMethodPerInlining);
+                return null;
+            }
+
             // Clean out types whose methods are no longer available.
             ArrayList<JavaTypeProfile.ProfiledType> usedTypes = new ArrayList<>();
             ArrayList<Integer> typesToConcretes = new ArrayList<>();
@@ -306,7 +306,7 @@
                 }
             }
 
-            if (usedTypes.size() == 0) {
+            if (usedTypes.isEmpty()) {
                 // No type left that is worth checking for.
                 InliningUtil.logNotInlinedInvoke(invoke, inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
                 return null;
@@ -410,17 +410,7 @@
             double invokeProbability = callsiteHolder.invokeProbability(invoke);
             double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
             MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
-            pushInvocation(methodInvocation);
-
-            for (int i = 0; i < info.numberOfMethods(); i++) {
-                Inlineable elem = info.inlineableElementAt(i);
-                if (elem instanceof InlineableGraph) {
-                    pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
-                } else {
-                    assert elem instanceof InlineableMacroNode;
-                    pushDummyGraph();
-                }
-            }
+            pushInvocationAndGraphs(methodInvocation);
         }
     }
 
@@ -449,6 +439,7 @@
 
     private void pushDummyGraph() {
         graphQueue.push(DUMMY_CALLSITE_HOLDER);
+        assert graphQueue.size() <= maxGraphs;
     }
 
     public boolean hasUnprocessedGraphs() {
@@ -492,10 +483,22 @@
         return invocationQueue.peekFirst();
     }
 
-    private void pushInvocation(MethodInvocation methodInvocation) {
+    private void pushInvocationAndGraphs(MethodInvocation methodInvocation) {
         invocationQueue.addFirst(methodInvocation);
-        maxGraphs += methodInvocation.callee().numberOfMethods();
+        InlineInfo info = methodInvocation.callee();
+        maxGraphs += info.numberOfMethods();
         assert graphQueue.size() <= maxGraphs;
+        double invokeProbability = methodInvocation.probability();
+        double invokeRelevance = methodInvocation.relevance();
+        for (int i = 0; i < info.numberOfMethods(); i++) {
+            Inlineable elem = info.inlineableElementAt(i);
+            if (elem instanceof InlineableGraph) {
+                pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+            } else {
+                assert elem instanceof InlineableMacroNode;
+                pushDummyGraph();
+            }
+        }
     }
 
     private void popInvocation() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Sat May 24 00:38:23 2014 +0200
@@ -34,8 +34,13 @@
 
     public static class LoopInfo<StateT> {
 
-        public final List<StateT> endStates = new ArrayList<>();
-        public final List<StateT> exitStates = new ArrayList<>();
+        public final List<StateT> endStates;
+        public final List<StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = new ArrayList<>(endCount);
+            exitStates = new ArrayList<>(exitCount);
+        }
     }
 
     public abstract static class BlockIteratorClosure<StateT> {
@@ -58,8 +63,8 @@
     public static <StateT> LoopInfo<StateT> processLoop(BlockIteratorClosure<StateT> closure, Loop<Block> loop, StateT initialState) {
         Map<FixedNode, StateT> blockEndStates = apply(closure, loop.getHeader(), initialState, new HashSet<>(loop.getBlocks()));
 
-        LoopInfo<StateT> info = new LoopInfo<>();
         List<Block> predecessors = loop.getHeader().getPredecessors();
+        LoopInfo<StateT> info = new LoopInfo<>(predecessors.size() - 1, loop.getExits().size());
         for (int i = 1; i < predecessors.size(); i++) {
             StateT endState = blockEndStates.get(predecessors.get(i).getEndNode());
             // make sure all end states are unique objects
@@ -67,7 +72,7 @@
         }
         for (Block loopExit : loop.getExits()) {
             assert loopExit.getPredecessorCount() == 1;
-            assert blockEndStates.containsKey(loopExit.getBeginNode());
+            assert blockEndStates.containsKey(loopExit.getBeginNode()) : loopExit.getBeginNode() + " " + blockEndStates;
             StateT exitState = blockEndStates.get(loopExit.getBeginNode());
             // make sure all exit states are unique objects
             info.exitStates.add(closure.cloneState(exitState));
@@ -90,7 +95,9 @@
         Block current = start;
 
         while (true) {
-            if (boundary == null || boundary.contains(current)) {
+            if (boundary != null && !boundary.contains(current)) {
+                states.put(current.getBeginNode(), state);
+            } else {
                 state = closure.processBlock(current, state);
 
                 if (current.getSuccessors().isEmpty()) {
@@ -117,45 +124,47 @@
                                 blockQueue.addFirst(exit);
                             }
                         }
-                    } else {
-                        if (successor.getBeginNode() instanceof LoopExitNode) {
-                            assert successor.getPredecessors().size() == 1;
-                            states.put(successor.getBeginNode(), state);
+                    } else if (current.getEndNode() instanceof AbstractEndNode) {
+                        assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
+                        AbstractEndNode end = (AbstractEndNode) current.getEndNode();
+
+                        // add the end node and see if the merge is ready for processing
+                        MergeNode merge = end.merge();
+                        boolean endsVisited = true;
+                        for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
+                            if (forwardEnd != current.getEndNode() && !states.containsKey(forwardEnd)) {
+                                endsVisited = false;
+                                break;
+                            }
+                        }
+                        if (endsVisited) {
+                            ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
+                            for (Block predecessor : successor.getPredecessors()) {
+                                assert predecessor == current || states.containsKey(predecessor.getEndNode());
+                                StateT endState = predecessor == current ? state : states.remove(predecessor.getEndNode());
+                                mergedStates.add(endState);
+                            }
+                            state = closure.merge(successor, mergedStates);
                             current = successor;
                             continue;
                         } else {
-                            if (current.getEndNode() instanceof AbstractEndNode) {
-                                assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
-                                AbstractEndNode end = (AbstractEndNode) current.getEndNode();
-
-                                // add the end node and see if the merge is ready for processing
-                                assert !states.containsKey(end);
-                                states.put(end, state);
-                                MergeNode merge = end.merge();
-                                boolean endsVisited = true;
-                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
-                                    if (!states.containsKey(forwardEnd)) {
-                                        endsVisited = false;
-                                        break;
-                                    }
-                                }
-                                if (endsVisited) {
-                                    blockQueue.addFirst(successor);
-                                }
-                            } else {
-                                assert successor.getPredecessors().size() == 1 : "invalid block schedule at " + successor.getBeginNode();
-                                current = successor;
-                                continue;
-                            }
+                            assert !states.containsKey(end);
+                            states.put(end, state);
                         }
+                    } else {
+                        assert successor.getPredecessors().size() == 1 : "invalid block schedule at " + successor.getBeginNode();
+                        current = successor;
+                        continue;
                     }
                 } else {
                     assert current.getSuccessors().size() > 1;
-                    for (int i = 0; i < current.getSuccessors().size(); i++) {
+                    for (int i = 1; i < current.getSuccessors().size(); i++) {
                         Block successor = current.getSuccessors().get(i);
                         blockQueue.addFirst(successor);
-                        states.put(successor.getBeginNode(), i == 0 ? state : closure.cloneState(state));
+                        states.put(successor.getBeginNode(), closure.cloneState(state));
                     }
+                    current = current.getSuccessors().get(0);
+                    continue;
                 }
             }
 
@@ -164,20 +173,9 @@
                 return states;
             } else {
                 current = blockQueue.removeFirst();
-                if (current.getPredecessors().size() == 1) {
-                    assert states.containsKey(current.getBeginNode());
-                    state = states.get(current.getBeginNode());
-                } else {
-                    assert current.getPredecessors().size() > 1;
-                    MergeNode merge = (MergeNode) current.getBeginNode();
-                    ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
-                    for (Block predecessor : current.getPredecessors()) {
-                        AbstractEndNode end = (AbstractEndNode) predecessor.getEndNode();
-                        mergedStates.add(states.get(end));
-                    }
-                    state = closure.merge(current, mergedStates);
-                    states.put(merge, state);
-                }
+                assert current.getPredecessorCount() == 1;
+                assert states.containsKey(current.getBeginNode());
+                state = states.remove(current.getBeginNode());
             }
         }
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Sat May 24 00:38:23 2014 +0200
@@ -33,8 +33,13 @@
 
     public static class LoopInfo<StateT> {
 
-        public final Map<LoopEndNode, StateT> endStates = newNodeIdentityMap(4);
-        public final Map<LoopExitNode, StateT> exitStates = newNodeIdentityMap(2);
+        public final Map<LoopEndNode, StateT> endStates;
+        public final Map<LoopExitNode, StateT> exitStates;
+
+        public LoopInfo(int endCount, int exitCount) {
+            endStates = newNodeIdentityMap(endCount);
+            exitStates = newNodeIdentityMap(exitCount);
+        }
     }
 
     public abstract static class NodeIteratorClosure<StateT> {
@@ -64,7 +69,7 @@
     public static <StateT> LoopInfo<StateT> processLoop(NodeIteratorClosure<StateT> closure, LoopBeginNode loop, StateT initialState) {
         Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, loop);
 
-        LoopInfo<StateT> info = new LoopInfo<>();
+        LoopInfo<StateT> info = new LoopInfo<>(loop.loopEnds().count(), loop.loopExits().count());
         for (LoopEndNode end : loop.loopEnds()) {
             if (blockEndStates.containsKey(end)) {
                 info.endStates.put(end, blockEndStates.get(end));
@@ -119,11 +124,9 @@
                                     nodeQueue.add(entry.getKey());
                                 }
                             } else {
-                                assert !blockEndStates.containsKey(current);
-                                blockEndStates.put(current, state);
                                 boolean endsVisited = true;
                                 for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
-                                    if (!blockEndStates.containsKey(forwardEnd)) {
+                                    if (forwardEnd != current && !blockEndStates.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
                                     }
@@ -132,13 +135,16 @@
                                     ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
                                     for (int i = 0; i < merge.forwardEndCount(); i++) {
                                         AbstractEndNode forwardEnd = merge.forwardEndAt(i);
-                                        assert blockEndStates.containsKey(forwardEnd);
-                                        StateT other = blockEndStates.get(forwardEnd);
+                                        assert forwardEnd == current || blockEndStates.containsKey(forwardEnd);
+                                        StateT other = forwardEnd == current ? state : blockEndStates.remove(forwardEnd);
                                         states.add(other);
                                     }
                                     state = closure.merge(merge, states);
                                     current = closure.continueIteration(state) ? merge : null;
                                     continue;
+                                } else {
+                                    assert !blockEndStates.containsKey(current);
+                                    blockEndStates.put(current, state);
                                 }
                             }
                         }
@@ -148,14 +154,15 @@
                             current = firstSuccessor;
                             continue;
                         } else {
-                            while (successors.hasNext()) {
+                            do {
                                 BeginNode successor = (BeginNode) successors.next();
                                 StateT successorState = closure.afterSplit(successor, state);
                                 if (closure.continueIteration(successorState)) {
                                     blockEndStates.put(successor, successorState);
                                     nodeQueue.add(successor);
                                 }
-                            }
+                            } while (successors.hasNext());
+
                             state = closure.afterSplit((BeginNode) firstSuccessor, state);
                             current = closure.continueIteration(state) ? firstSuccessor : null;
                             continue;
@@ -169,7 +176,8 @@
                 return blockEndStates;
             } else {
                 current = nodeQueue.removeFirst();
-                state = blockEndStates.get(current);
+                assert blockEndStates.containsKey(current);
+                state = blockEndStates.remove(current);
                 assert !(current instanceof MergeNode) && current instanceof BeginNode;
             }
         } while (true);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EarlyReadEliminationPhase.java	Sat May 24 00:38:23 2014 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
@@ -32,7 +33,7 @@
 public class EarlyReadEliminationPhase extends EffectsPhase<PhaseContext> {
 
     public EarlyReadEliminationPhase(CanonicalizerPhase canonicalizer) {
-        super(1, canonicalizer);
+        super(1, canonicalizer, true);
     }
 
     @Override
@@ -43,7 +44,8 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
-        return new ReadEliminationClosure(schedule);
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+        assert schedule == null;
+        return new ReadEliminationClosure(cfg);
     }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Sat May 24 00:38:23 2014 +0200
@@ -42,6 +42,7 @@
 
 public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
 
+    private final ControlFlowGraph cfg;
     private final SchedulePhase schedule;
 
     protected final NodeMap<ValueNode> aliases;
@@ -51,11 +52,12 @@
 
     private boolean changed;
 
-    public EffectsClosure(SchedulePhase schedule) {
+    public EffectsClosure(SchedulePhase schedule, ControlFlowGraph cfg) {
         this.schedule = schedule;
-        this.aliases = schedule.getCFG().graph.createNodeMap();
-        this.blockEffects = new BlockMap<>(schedule.getCFG());
-        for (Block block : schedule.getCFG().getBlocks()) {
+        this.cfg = cfg;
+        this.aliases = cfg.graph.createNodeMap();
+        this.blockEffects = new BlockMap<>(cfg);
+        for (Block block : cfg.getBlocks()) {
             blockEffects.put(block, new GraphEffectList());
         }
     }
@@ -67,7 +69,7 @@
 
     @Override
     public void applyEffects() {
-        final StructuredGraph graph = schedule.getCFG().graph;
+        final StructuredGraph graph = cfg.graph;
         final ArrayList<Node> obsoleteNodes = new ArrayList<>(0);
         BlockIteratorClosure<Void> closure = new BlockIteratorClosure<Void>() {
 
@@ -114,7 +116,7 @@
                 return info.exitStates;
             }
         };
-        ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+        ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
         assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
     }
 
@@ -124,7 +126,8 @@
 
         GraphEffectList effects = blockEffects.get(block);
         FixedWithNextNode lastFixedNode = null;
-        for (Node node : schedule.getBlockToNodesMap().get(block)) {
+        Iterable<? extends Node> nodes = schedule != null ? schedule.getBlockToNodesMap().get(block) : block.getNodes();
+        for (Node node : nodes) {
             aliases.set(node, null);
             if (node instanceof LoopExitNode) {
                 LoopExitNode loopExit = (LoopExitNode) node;
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java	Sat May 24 00:38:23 2014 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.util.*;
@@ -49,10 +50,16 @@
 
     private final int maxIterations;
     protected final CanonicalizerPhase canonicalizer;
+    private final boolean unscheduled;
 
-    public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
+        this(maxIterations, canonicalizer, false);
+    }
+
+    protected EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer, boolean unscheduled) {
         this.maxIterations = maxIterations;
         this.canonicalizer = canonicalizer;
+        this.unscheduled = unscheduled;
     }
 
     @Override
@@ -64,10 +71,19 @@
         boolean changed = false;
         for (int iteration = 0; iteration < maxIterations; iteration++) {
             try (Scope s = Debug.scope(isEnabled() ? "iteration " + iteration : null)) {
-                SchedulePhase schedule = new SchedulePhase();
-                schedule.apply(graph, false);
-                Closure<?> closure = createEffectsClosure(context, schedule);
-                ReentrantBlockIterator.apply(closure, schedule.getCFG().getStartBlock());
+                SchedulePhase schedule;
+                ControlFlowGraph cfg;
+                if (unscheduled) {
+                    schedule = null;
+                    cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+                } else {
+                    schedule = new SchedulePhase();
+                    schedule.apply(graph, false);
+                    cfg = schedule.getCFG();
+                }
+
+                Closure<?> closure = createEffectsClosure(context, schedule, cfg);
+                ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
 
                 if (!closure.hasChanged()) {
                     break;
@@ -106,5 +122,5 @@
         }
     }
 
-    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule);
+    protected abstract Closure<?> createEffectsClosure(PhaseContextT context, SchedulePhase schedule, ControlFlowGraph cfg);
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Sat May 24 00:38:23 2014 +0200
@@ -79,7 +79,7 @@
     }
 
     public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
-        super(schedule);
+        super(schedule, schedule.getCFG());
         this.usages = schedule.getCFG().graph.createNodeBitMap();
         this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, assumptions, this);
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Sat May 24 00:38:23 2014 +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.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -84,7 +85,8 @@
     }
 
     @Override
-    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule) {
+    protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
+        assert schedule != null;
         if (readElimination) {
             return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getAssumptions());
         } else {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationBlockState.java	Sat May 24 00:38:23 2014 +0200
@@ -132,13 +132,7 @@
     }
 
     public void killReadCache(LocationIdentity identity) {
-        Iterator<Map.Entry<CacheEntry<?>, ValueNode>> iter = readCache.entrySet().iterator();
-        while (iter.hasNext()) {
-            Map.Entry<CacheEntry<?>, ValueNode> entry = iter.next();
-            if (entry.getKey().conflicts(identity)) {
-                iter.remove();
-            }
-        }
+        readCache.entrySet().removeIf(entry -> entry.getKey().conflicts(identity));
     }
 
     public Map<CacheEntry<?>, ValueNode> getReadCache() {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Thu May 22 18:10:04 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Sat May 24 00:38:23 2014 +0200
@@ -34,15 +34,14 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
 import com.oracle.graal.virtual.phases.ea.ReadEliminationBlockState.ReadCacheEntry;
 
 public class ReadEliminationClosure extends EffectsClosure<ReadEliminationBlockState> {
 
-    public ReadEliminationClosure(SchedulePhase schedule) {
-        super(schedule);
+    public ReadEliminationClosure(ControlFlowGraph cfg) {
+        super(null, cfg);
     }
 
     @Override
@@ -53,104 +52,104 @@
     @Override
     protected boolean processNode(Node node, ReadEliminationBlockState state, GraphEffectList effects, FixedWithNextNode lastFixedNode) {
         boolean deleted = false;
-        if (node instanceof LoadFieldNode) {
-            LoadFieldNode load = (LoadFieldNode) node;
-            if (!load.isVolatile()) {
-                ValueNode object = GraphUtil.unproxify(load.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, load.field());
+        if (node instanceof AccessFieldNode) {
+            AccessFieldNode access = (AccessFieldNode) node;
+            if (access.isVolatile()) {
+                processIdentity(state, ANY_LOCATION);
+            } else {
+                ValueNode object = GraphUtil.unproxify(access.object());
+                LoadCacheEntry identifier = new LoadCacheEntry(object, access.field());
                 ValueNode cachedValue = state.getCacheEntry(identifier);
-                if (cachedValue != null) {
-                    effects.replaceAtUsages(load, cachedValue);
-                    addScalarAlias(load, cachedValue);
-                    deleted = true;
+                if (node instanceof LoadFieldNode) {
+                    if (cachedValue != null) {
+                        effects.replaceAtUsages(access, cachedValue);
+                        addScalarAlias(access, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, access);
+                    }
                 } else {
-                    state.addCacheEntry(identifier, load);
+                    assert node instanceof StoreFieldNode;
+                    StoreFieldNode store = (StoreFieldNode) node;
+                    ValueNode value = getScalarAlias(store.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(store);
+                        deleted = true;
+                    }
+                    state.killReadCache(store.field());
+                    state.addCacheEntry(identifier, value);
+                }
+            }
+        } else if (node instanceof FixedAccessNode) {
+            if (node instanceof ReadNode) {
+                ReadNode read = (ReadNode) node;
+                if (read.location() instanceof ConstantLocationNode) {
+                    ValueNode object = GraphUtil.unproxify(read.object());
+                    ReadCacheEntry identifier = new ReadCacheEntry(object, read.location());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+                    if (cachedValue != null) {
+                        if (read.getGuard() != null && !(read.getGuard() instanceof FixedNode)) {
+                            effects.addFixedNodeBefore(new ValueAnchorNode((ValueNode) read.getGuard()), read);
+                        }
+                        effects.replaceAtUsages(read, cachedValue);
+                        addScalarAlias(read, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, read);
+                    }
+                }
+            } else if (node instanceof WriteNode) {
+                WriteNode write = (WriteNode) node;
+                if (write.location() instanceof ConstantLocationNode) {
+                    ValueNode object = GraphUtil.unproxify(write.object());
+                    ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+
+                    ValueNode value = getScalarAlias(write.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(write);
+                        deleted = true;
+                    }
+                    processIdentity(state, write.location().getLocationIdentity());
+                    state.addCacheEntry(identifier, value);
+                } else {
+                    processIdentity(state, write.location().getLocationIdentity());
+                }
+            }
+        } else if (node instanceof UnsafeAccessNode) {
+            if (node instanceof UnsafeLoadNode) {
+                UnsafeLoadNode load = (UnsafeLoadNode) node;
+                if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                    ValueNode object = GraphUtil.unproxify(load.object());
+                    LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
+                    if (cachedValue != null) {
+                        effects.replaceAtUsages(load, cachedValue);
+                        addScalarAlias(load, cachedValue);
+                        deleted = true;
+                    } else {
+                        state.addCacheEntry(identifier, load);
+                    }
                 }
             } else {
-                processIdentity(state, ANY_LOCATION);
-            }
-        } else if (node instanceof StoreFieldNode) {
-            StoreFieldNode store = (StoreFieldNode) node;
-            if (!store.isVolatile()) {
-                ValueNode object = GraphUtil.unproxify(store.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, store.field());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
+                assert node instanceof UnsafeStoreNode;
+                UnsafeStoreNode write = (UnsafeStoreNode) node;
+                if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
+                    ValueNode object = GraphUtil.unproxify(write.object());
+                    LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
+                    ValueNode cachedValue = state.getCacheEntry(identifier);
 
-                ValueNode value = getScalarAlias(store.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(store);
-                    deleted = true;
-                }
-                state.killReadCache(store.field());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, ANY_LOCATION);
-            }
-        } else if (node instanceof ReadNode) {
-            ReadNode read = (ReadNode) node;
-            if (read.location() instanceof ConstantLocationNode) {
-                ValueNode object = GraphUtil.unproxify(read.object());
-                ReadCacheEntry identifier = new ReadCacheEntry(object, read.location());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-                if (cachedValue != null) {
-                    if (read.getGuard() != null && !(read.getGuard() instanceof FixedNode)) {
-                        effects.addFixedNodeBefore(new ValueAnchorNode((ValueNode) read.getGuard()), read);
+                    ValueNode value = getScalarAlias(write.value());
+                    if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
+                        effects.deleteFixedNode(write);
+                        deleted = true;
                     }
-                    effects.replaceAtUsages(read, cachedValue);
-                    addScalarAlias(read, cachedValue);
-                    deleted = true;
+                    processIdentity(state, write.getLocationIdentity());
+                    state.addCacheEntry(identifier, value);
                 } else {
-                    state.addCacheEntry(identifier, read);
+                    processIdentity(state, write.getLocationIdentity());
                 }
             }
-        } else if (node instanceof UnsafeLoadNode) {
-            UnsafeLoadNode load = (UnsafeLoadNode) node;
-            if (load.offset().isConstant() && load.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
-                ValueNode object = GraphUtil.unproxify(load.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, load.getLocationIdentity());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-                if (cachedValue != null) {
-                    effects.replaceAtUsages(load, cachedValue);
-                    addScalarAlias(load, cachedValue);
-                    deleted = true;
-                } else {
-                    state.addCacheEntry(identifier, load);
-                }
-            }
-        } else if (node instanceof WriteNode) {
-            WriteNode write = (WriteNode) node;
-            if (write.location() instanceof ConstantLocationNode) {
-                ValueNode object = GraphUtil.unproxify(write.object());
-                ReadCacheEntry identifier = new ReadCacheEntry(object, write.location());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-
-                ValueNode value = getScalarAlias(write.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(write);
-                    deleted = true;
-                }
-                processIdentity(state, write.location().getLocationIdentity());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, write.location().getLocationIdentity());
-            }
-        } else if (node instanceof UnsafeStoreNode) {
-            UnsafeStoreNode write = (UnsafeStoreNode) node;
-            if (write.offset().isConstant() && write.getLocationIdentity() != LocationIdentity.ANY_LOCATION) {
-                ValueNode object = GraphUtil.unproxify(write.object());
-                LoadCacheEntry identifier = new LoadCacheEntry(object, write.getLocationIdentity());
-                ValueNode cachedValue = state.getCacheEntry(identifier);
-
-                ValueNode value = getScalarAlias(write.value());
-                if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(write);
-                    deleted = true;
-                }
-                processIdentity(state, write.getLocationIdentity());
-                state.addCacheEntry(identifier, value);
-            } else {
-                processIdentity(state, write.getLocationIdentity());
-            }
         } else if (node instanceof MemoryCheckpoint.Single) {
             LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
             processIdentity(state, identity);
--- a/mx/mx_graal.py	Thu May 22 18:10:04 2014 +0200
+++ b/mx/mx_graal.py	Sat May 24 00:38:23 2014 +0200
@@ -46,8 +46,8 @@
 """ The VMs that can be built and run along with an optional description. Only VMs with a
     description are listed in the dialogue for setting the default VM (see _get_vm()). """
 _vmChoices = {
-    'graal' : 'All compilation is performed with Graal. This includes bootstrapping Graal itself unless -XX:-BootstrapGraal is used.',
-    'server' : 'Normal compilation is performed with the tiered system (i.e., client + server), Truffle compilation is performed with Graal. Use this for optimal Truffle performance.',
+    'graal' : 'Normal compilation is performed with a tiered system (C1 + Graal), Truffle compilation is performed with Graal.',
+    'server' : 'Normal compilation is performed with a tiered system (C1 + C2), Truffle compilation is performed with Graal. Use this for optimal Truffle performance.',
     'client' : None,  # normal compilation with client compiler, explicit compilation (e.g., by Truffle) with Graal
     'server-nograal' : None,  # all compilation with tiered system (i.e., client + server), Graal omitted
     'client-nograal' : None,  # all compilation with client compiler, Graal omitted
@@ -154,7 +154,7 @@
         def handleRemoveReadonly(func, path, exc):
             excvalue = exc[1]
             if mx.get_os() == 'windows' and func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES:
-                os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO) # 0777
+                os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
                 func(path)
             else:
                 raise
@@ -212,7 +212,7 @@
     def _genFileName(archivtype, middle):
         idPrefix = infos['revision'] + '_'
         idSuffix = '.tar.gz'
-        return join(_graal_home, "graalvm_" + archivtype + "_"  + idPrefix + middle + idSuffix)
+        return join(_graal_home, "graalvm_" + archivtype + "_" + idPrefix + middle + idSuffix)
 
     def _genFileArchPlatformName(archivtype, middle):
         return _genFileName(archivtype, infos['platform'] + '_' + infos['architecture'] + '_' + middle)
@@ -484,8 +484,34 @@
         if exists(toDelete):
             os.unlink(toDelete)
 
+def _update_HotSpotOptions_inline_hpp(graalJar):
+    p = mx.project('com.oracle.graal.hotspot')
+    mainClass = 'com.oracle.graal.hotspot.HotSpotOptionsLoader'
+    assert exists(join(p.source_dirs()[0], mainClass.replace('.', os.sep) + '.java'))
+    hsSrcGenDir = join(p.source_gen_dir(), 'hotspot')
+    if not exists(hsSrcGenDir):
+        os.makedirs(hsSrcGenDir)
+    path = join(hsSrcGenDir, 'HotSpotOptions.inline.hpp')
+    fd, tmp = tempfile.mkstemp(suffix='', prefix='HotSpotOptions.inline.hpp', dir=hsSrcGenDir)
+    os.close(fd)
+    try:
+        retcode = mx.run_java(['-cp', graalJar, mainClass, tmp], nonZeroIsFatal=False)
+        if retcode != 0:
+            # Suppress the error if it's because the utility class isn't compiled yet
+            with zipfile.ZipFile(graalJar, 'r') as zf:
+                mainClassFile = mainClass.replace('.', '/') + '.class'
+                if mainClassFile not in zf.namelist():
+                    return
+            mx.abort(retcode)
+        with open(tmp) as fp:
+            content = fp.read()
+        mx.update_file(path, content)
+    finally:
+        os.remove(tmp)
+
 def _installGraalJarInJdks(graalDist):
     graalJar = graalDist.path
+    _update_HotSpotOptions_inline_hpp(graalJar)
     jdks = _jdksDir()
 
     if exists(jdks):
--- a/mxtool/mx.py	Thu May 22 18:10:04 2014 +0200
+++ b/mxtool/mx.py	Sat May 24 00:38:23 2014 +0200
@@ -1673,6 +1673,7 @@
         self.javac = exe_suffix(join(self.jdk, 'bin', 'javac'))
         self.javap = exe_suffix(join(self.jdk, 'bin', 'javap'))
         self.javadoc = exe_suffix(join(self.jdk, 'bin', 'javadoc'))
+        self.pack200 = exe_suffix(join(self.jdk, 'bin', 'pack200'))
         self.toolsjar = join(self.jdk, 'lib', 'tools.jar')
         self._bootclasspath = None
         self._extdirs = None
@@ -3398,13 +3399,12 @@
             for ap in p.annotation_processors():
                 for dep in dependency(ap).all_deps([], True):
                     if dep.isLibrary():
-                        if not hasattr(dep, 'eclipse.container') and not hasattr(dep, 'eclipse.project'):
-                            # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
-                            # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
-                            # safest to simply use absolute paths.
-                            path = _make_absolute(dep.get_path(resolve=True), p.suite.dir)
-                            out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
-                            files.append(path)
+                        # Relative paths for "lib" class path entries have various semantics depending on the Eclipse
+                        # version being used (e.g. see https://bugs.eclipse.org/bugs/show_bug.cgi?id=274737) so it's
+                        # safest to simply use absolute paths.
+                        path = _make_absolute(dep.get_path(resolve=True), p.suite.dir)
+                        out.element('factorypathentry', {'kind' : 'EXTJAR', 'id' : path, 'enabled' : 'true', 'runInBatchMode' : 'false'})
+                        files.append(path)
                     elif dep.isProject():
                         out.element('factorypathentry', {'kind' : 'WKSPJAR', 'id' : '/' + dep.name + '/' + dep.name + '.jar', 'enabled' : 'true', 'runInBatchMode' : 'false'})
             out.close('factorypath')
--- a/src/share/vm/graal/graalRuntime.cpp	Thu May 22 18:10:04 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Sat May 24 00:38:23 2014 +0200
@@ -651,17 +651,166 @@
   GraalRuntime::initialize_natives(env, c2vmClass);
 JVM_END
 
-// private static String[] HotSpotOptions.getVMOptions(boolean[] timeCompilations)
-JVM_ENTRY(jobject, JVM_GetGraalOptions(JNIEnv *env, jclass c, jobject timeCompilations))
+// private static boolean HotSpotOptions.parseVMOptions()
+JVM_ENTRY(jboolean, JVM_ParseGraalOptions(JNIEnv *env, jclass c))
   HandleMark hm;
+  KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)));
+  return GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false);
+JVM_END
+
+bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
+  ResourceMark rm(THREAD);
+
+  // Process option overrides from graal.options first
+  parse_graal_options_file(hotSpotOptionsClass, CHECK_false);
+
+  // Now process options on the command line
   int numOptions = Arguments::num_graal_args();
-  objArrayOop options = oopFactory::new_objArray(SystemDictionary::String_klass(),
-      numOptions, CHECK_NULL);
-  objArrayHandle optionsHandle(THREAD, options);
   for (int i = 0; i < numOptions; i++) {
-    Handle option = java_lang_String::create_from_str(Arguments::graal_args_array()[i], CHECK_NULL);
-    optionsHandle->obj_at_put(i, option());
+    char* arg = Arguments::graal_args_array()[i];
+    parse_argument(hotSpotOptionsClass, arg, CHECK_false);
+  }
+  return CITime || CITimeEach;
+}
+
+void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
+  char first = arg[0];
+  char* name;
+  size_t name_len;
+  Handle name_handle;
+  bool valid = true;
+  if (first == '+' || first == '-') {
+    name = arg + 1;
+    name_len = strlen(name);
+    name_handle = java_lang_String::create_from_str(name, CHECK);
+    valid = set_option(hotSpotOptionsClass, name, name_len, name_handle, arg, CHECK);
+  } else {
+    char* sep = strchr(arg, '=');
+    if (sep != NULL) {
+      name = arg;
+      name_len = sep - name;
+      // Temporarily replace '=' with NULL to create the Java string for the option name
+      *sep = '\0';
+      name_handle = java_lang_String::create_from_str(arg, THREAD);
+      *sep = '=';
+      if (HAS_PENDING_EXCEPTION) {
+        return;
+      }
+      valid = set_option(hotSpotOptionsClass, name, name_len, name_handle, sep + 1, CHECK);
+    } else {
+      char buf[200];
+      jio_snprintf(buf, sizeof(buf), "Value for option %s must use '-G:%s=<value>' format", arg, arg);
+      THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+    }
+  }
+
+  if (!valid) {
+    VMToCompiler::setOption(hotSpotOptionsClass, name_handle, Handle(), ' ', Handle(), 0L);
+    char buf[200];
+    jio_snprintf(buf, sizeof(buf), "Invalid Graal option %s", arg);
+    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
   }
-  ((typeArrayOop) JNIHandles::resolve(timeCompilations))->bool_at_put(0, CITime || CITimeEach);
-  return JNIHandles::make_local(THREAD, optionsHandle());
-JVM_END
+}
+
+void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
+  const char* home = Arguments::get_java_home();
+  int path_len = strlen(home) + strlen("/lib/graal.options") + 1;
+  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
+  char sep = os::file_separator()[0];
+  sprintf(path, "%s%clib%cgraal.options", home, sep, sep);
+
+  struct stat st;
+  if (os::stat(path, &st) == 0) {
+    int file_handle = os::open(path, 0, 0);
+    if (file_handle != -1) {
+      char* buffer = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, st.st_size);
+      int num_read = (int) os::read(file_handle, (char*) buffer, st.st_size);
+      if (num_read == -1) {
+        warning("Error reading file %s due to %s", path, strerror(errno));
+      } else if (num_read != st.st_size) {
+        warning("Only read %d of %d bytes from %s", num_read, st.st_size, path);
+      }
+      os::close(file_handle);
+      if (num_read == st.st_size) {
+        char* line = buffer;
+        int lineNo = 1;
+        while (line - buffer < num_read) {
+          char* nl = strchr(line, '\n');
+          if (nl != NULL) {
+            *nl = '\0';
+          }
+          parse_argument(hotSpotOptionsClass, line, THREAD);
+          if (HAS_PENDING_EXCEPTION) {
+            warning("Error in %s:%d", path, lineNo);
+            return;
+          }
+          if (nl != NULL) {
+            line = nl + 1;
+            lineNo++;
+          } else {
+            // File without newline at the end
+            break;
+          }
+        }
+      }
+    } else {
+      warning("Error opening file %s due to %s", path, strerror(errno));
+    }
+  }
+}
+
+jlong GraalRuntime::parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS) {
+  union {
+    jint i;
+    jlong l;
+    double d;
+  } uu;
+  uu.l = 0L;
+  char dummy;
+  switch (spec) {
+    case 'd':
+    case 'f': {
+      if (sscanf(value, "%lf%c", &uu.d, &dummy) == 1) {
+        return uu.l;
+      }
+      break;
+    }
+    case 'i': {
+      if (sscanf(value, "%d%c", &uu.i, &dummy) == 1) {
+        return uu.l;
+      }
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+  }
+  ResourceMark rm(THREAD);
+  char buf[200];
+  jio_snprintf(buf, sizeof(buf), "Invalid %s value for Graal option %s: %s", (spec == 'i' ? "numeric" : "float/double"), java_lang_String::as_utf8_string(name()), value);
+  THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L);
+}
+
+Handle GraalRuntime::get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS) {
+  TempNewSymbol name = SymbolTable::new_symbol(declaringClass, THREAD);
+  Klass* klass = SystemDictionary::resolve_or_fail(name, true, CHECK_NH);
+
+  // The class has been loaded so the field and signature should already be in the symbol
+  // table.  If they're not there, the field doesn't exist.
+  TempNewSymbol fieldname = SymbolTable::probe(fieldName, (int)strlen(fieldName));
+  TempNewSymbol signame = SymbolTable::probe(fieldSig, (int)strlen(fieldSig));
+  if (fieldname == NULL || signame == NULL) {
+    THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle());
+  }
+  // Make sure class is initialized before handing id's out to fields
+  klass->initialize(CHECK_NH);
+
+  fieldDescriptor fd;
+  if (!InstanceKlass::cast(klass)->find_field(fieldname, signame, true, &fd)) {
+    THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle());
+  }
+
+  Handle ret = klass->java_mirror()->obj_field(fd.offset());
+  return ret;
+}
+
+#include "HotSpotOptions.inline.hpp"
--- a/src/share/vm/graal/graalRuntime.hpp	Thu May 22 18:10:04 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Sat May 24 00:38:23 2014 +0200
@@ -31,12 +31,55 @@
 class GraalRuntime: public CHeapObj<mtCompiler> {
  private:
 
-  static address   _external_deopt_i2c_entry;
+  static address _external_deopt_i2c_entry;
+
+  /**
+   * Reads the OptionValue object from a specified static field.
+   *
+   * @throws LinkageError if the field could not be resolved
+   */
+  static Handle get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS);
+
+  /**
+   * Parses the string form of a numeric, float or double option into a jlong (using raw bits for floats/doubles).
+   *
+   * @param spec 'i', 'f' or 'd' (see HotSpotOptions.setOption())
+   * @param name name option option
+   * @param value string value to parse
+   * @throws InternalError if value could not be parsed according to spec
+   */
+  static jlong parse_primitive_option_value(char spec, Handle name, const char* value, TRAPS);
+
+  /**
+   * Loads default option value overrides from a <jre_home>/lib/graal.options if it exists. Each
+   * line in this file must have the format of a Graal command line option without the
+   * leading "-G:" prefix. These option values are set prior to processing of any Graal
+   * options present on the command line.
+   */
+  static void parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS);
+
+  /**
+   * Parses a given argument and sets the denoted Graal option.
+   *
+   * @throws InternalError if there was a problem parsing or setting the option
+   */
+  static void parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS);
+
+  /**
+   * Searches for a Graal option denoted by a given name and sets it value.
+   *
+   * @returns true if the option was found
+   * @throws InternalError if there was a problem setting the option's value
+   */
+  static bool set_option(KlassHandle hotSpotOptionsClass, const char* name, int name_len, Handle name_handle, const char* value, TRAPS);
 
  public:
 
   static void initialize_natives(JNIEnv *env, jclass c2vmClass);
   static BufferBlob* initialize_buffer_blob();
+
+  static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
+
   static BasicType kindToBasicType(jchar ch);
   static address create_external_deopt_i2c();
   static address get_external_deopt_i2c_entry() {return _external_deopt_i2c_entry;}
--- a/src/share/vm/graal/graalVMToCompiler.cpp	Thu May 22 18:10:04 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Sat May 24 00:38:23 2014 +0200
@@ -94,48 +94,20 @@
   return Handle(JNIHandles::resolve_non_null(_VMToCompiler_instance));
 }
 
-void VMToCompiler::initOptions() {
+void VMToCompiler::setOption(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) {
+  assert(!option.is_null(), "npe");
   Thread* THREAD = Thread::current();
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
-  KlassHandle optionsKlass = loadClass(name);
-  optionsKlass->initialize(THREAD);
-  check_pending_exception("Error while calling initOptions");
-}
-
-jboolean VMToCompiler::setOption(Handle option) {
-  assert(!option.is_null(), "");
-  Thread* THREAD = Thread::current();
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
   TempNewSymbol setOption = SymbolTable::new_symbol("setOption", THREAD);
-  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;)Z", THREAD);
-  KlassHandle optionsKlass = loadClass(name);
-  JavaValue result(T_BOOLEAN);
-  JavaCalls::call_static(&result, optionsKlass, setOption, sig, option, THREAD);
-  check_pending_exception("Error while calling setOption");
-  return result.get_jboolean();
-}
-
-void VMToCompiler::finalizeOptions(jboolean ciTime) {
-  Thread* THREAD = Thread::current();
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", THREAD);
-  TempNewSymbol finalizeOptions = SymbolTable::new_symbol("finalizeOptions", THREAD);
-  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;)Z", THREAD);
-  KlassHandle optionsKlass = loadClass(name);
+  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;Lcom/oracle/graal/options/OptionValue;CLjava/lang/String;J)V", THREAD);
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_int(ciTime);
-  JavaCalls::call_static(&result, optionsKlass, finalizeOptions, vmSymbols::bool_void_signature(), &args, THREAD);
-  check_pending_exception("Error while calling finalizeOptions");
-}
-
-void VMToCompiler::startRuntime() {
-  JavaThread* THREAD = JavaThread::current();
-  JavaValue result(T_VOID);
-  JavaCallArguments args;
-  TempNewSymbol startRuntime = SymbolTable::new_symbol("startRuntime", THREAD);
-  args.push_oop(VMToCompiler_instance());
-  JavaCalls::call_interface(&result, VMToCompiler_klass(), startRuntime, vmSymbols::void_method_signature(), &args, THREAD);
-  check_pending_exception("Error while calling startRuntime");
+  args.push_oop(name());
+  args.push_oop(option());
+  args.push_int(spec);
+  args.push_oop(stringValue());
+  args.push_long(primitiveValue);
+  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, THREAD);
+  check_pending_exception("Error while calling setOption");
 }
 
 #ifdef COMPILERGRAAL
--- a/src/share/vm/graal/graalVMToCompiler.hpp	Thu May 22 18:10:04 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Sat May 24 00:38:23 2014 +0200
@@ -55,17 +55,8 @@
     return _HotSpotGraalRuntime_instance;
   }
 
-  // public static boolean HotSpotOptions.<clinit>();
-  static void initOptions();
-
-  // public static boolean HotSpotOptions.setOption(String option);
-  static jboolean setOption(Handle option);
-
-  // public static void HotSpotOptions.finalizeOptions(boolean ciTime);
-  static void finalizeOptions(jboolean ciTime);
-
-  // public abstract void startRuntime();
-  static void startRuntime();
+  // public static void HotSpotOptions.setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue);
+  static void setOption(KlassHandle hotSpotOptionsClass, Handle name, Handle option, jchar spec, Handle stringValue, jlong primitiveValue);
 
 #ifdef COMPILERGRAAL
   // public abstract void startCompiler(boolean bootstrapEnabled);
--- a/src/share/vm/prims/nativeLookup.cpp	Thu May 22 18:10:04 2014 +0200
+++ b/src/share/vm/prims/nativeLookup.cpp	Sat May 24 00:38:23 2014 +0200
@@ -124,10 +124,10 @@
   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
   void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
 #ifdef GRAAL
-  void    JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass c, jclass compilerToVMClass);
-  jobject JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
-  jobject JNICALL JVM_CreateTruffleRuntime(JNIEnv *env, jclass c);
-  jobject JNICALL JVM_GetGraalOptions(JNIEnv *env, jclass hotspotOptionsClass, jobject timeCompilations);
+  void     JNICALL JVM_InitializeGraalNatives(JNIEnv *env, jclass c, jclass compilerToVMClass);
+  jobject  JNICALL JVM_GetGraalRuntime(JNIEnv *env, jclass c);
+  jobject  JNICALL JVM_CreateTruffleRuntime(JNIEnv *env, jclass c);
+  jboolean JNICALL JVM_ParseGraalOptions(JNIEnv *env, jclass hotspotOptionsClass);
 #endif
 }
 
@@ -140,10 +140,10 @@
   { CC"Java_sun_misc_Perf_registerNatives",                        NULL, FN_PTR(JVM_RegisterPerfMethods)         },
   { CC"Java_sun_hotspot_WhiteBox_registerNatives",                 NULL, FN_PTR(JVM_RegisterWhiteBoxMethods)     },
 #ifdef GRAAL
-  { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime", NULL, FN_PTR(JVM_GetGraalRuntime)             },
-  { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",         NULL, FN_PTR(JVM_CreateTruffleRuntime)        },
-  { CC"Java_com_oracle_graal_hotspot_HotSpotGraalRuntime_init",    NULL, FN_PTR(JVM_InitializeGraalNatives)      },
-  { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_getVMOptions", NULL, FN_PTR(JVM_GetGraalOptions)             },
+  { CC"Java_com_oracle_graal_api_runtime_Graal_initializeRuntime",   NULL, FN_PTR(JVM_GetGraalRuntime)             },
+  { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",           NULL, FN_PTR(JVM_CreateTruffleRuntime)        },
+  { CC"Java_com_oracle_graal_hotspot_HotSpotGraalRuntime_init",      NULL, FN_PTR(JVM_InitializeGraalNatives)      },
+  { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_parseVMOptions", NULL, FN_PTR(JVM_ParseGraalOptions)           },
 #endif
 };