changeset 21519:cecb4e39521c

Use files in lib/graal/options to define Graal options (-G:...) instead of generating code for them
author Gilles Duboscq <gilles.m.duboscq@oracle.com>
date Wed, 27 May 2015 17:40:26 +0200
parents c2e58b2a2a76
children b7ac67354c14
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/OptionProcessor.java graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionUtils.java graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionsLoader.java graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java mx/suite.py src/share/vm/graal/graalHashtable.cpp src/share/vm/graal/graalHashtable.hpp src/share/vm/graal/graalOptions.cpp src/share/vm/graal/graalOptions.hpp src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp src/share/vm/prims/nativeLookup.cpp src/share/vm/runtime/thread.cpp
diffstat 20 files changed, 1021 insertions(+), 596 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Wed May 27 17:40:26 2015 +0200
@@ -327,7 +327,7 @@
     @Option(help = "Enable expensive assertions", type = OptionType.Debug)
     public static final OptionValue<Boolean> DetailedAsserts = new StableOptionValue<Boolean>() {
         @Override
-        protected Boolean initialValue() {
+        protected Boolean defaultValue() {
             boolean enabled = false;
             // turn detailed assertions on when the general assertions are on (misusing the assert keyword for this)
             assert (enabled = true) == true;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed May 27 17:40:26 2015 +0200
@@ -29,7 +29,6 @@
 import static com.oracle.graal.compiler.common.UnsafeAccess.*;
 import static com.oracle.graal.debug.Debug.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
-import static com.oracle.graal.hotspot.InitTimer.*;
 import static com.oracle.graal.hotspot.meta.HotSpotSuitesProvider.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
 import static com.oracle.graal.phases.common.inlining.InliningUtil.*;
@@ -62,15 +61,6 @@
 //JaCoCo Exclude
 
 public class CompilationTask {
-
-    static {
-        try (InitTimer t = timer("initialize CompilationTask")) {
-            // Must be first to ensure any options accessed by the rest of the class
-            // initializer are initialized from the command line.
-            HotSpotOptions.initialize();
-        }
-    }
-
     private static final DebugMetric BAILOUTS = Debug.metric("Bailouts");
 
     private final HotSpotBackend backend;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Wed May 27 17:40:26 2015 +0200
@@ -40,7 +40,6 @@
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -120,14 +119,12 @@
          *
          * @param options a space separated set of option value settings with each option setting in
          *            a format compatible with
-         *            {@link HotSpotOptions#parseOption(String, OptionConsumer)}. Ignored if null.
+         *            {@link OptionUtils#parseOption(String, OptionConsumer)}. Ignored if null.
          */
         public Config(String options) {
             if (options != null) {
                 for (String option : options.split("\\s+")) {
-                    if (!HotSpotOptions.parseOption(option, this)) {
-                        throw new GraalInternalError("Invalid option specified: %s", option);
-                    }
+                    OptionUtils.parseOption(option, this);
                 }
             }
         }
@@ -213,7 +210,7 @@
      */
     public void compile() throws Throwable {
         // By default only report statistics for the CTW threads themselves
-        if (GraalDebugConfig.DebugValueThreadFilter.hasInitialValue()) {
+        if (GraalDebugConfig.DebugValueThreadFilter.hasDefaultValue()) {
             GraalDebugConfig.DebugValueThreadFilter.setValue("^CompileTheWorld");
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed May 27 17:40:26 2015 +0200
@@ -65,10 +65,6 @@
     private static final HotSpotGraalRuntime instance;
 
     static {
-        try (InitTimer t = timer("initialize HotSpotOptions")) {
-            HotSpotOptions.initialize();
-        }
-
         try (InitTimer t = timer("HotSpotGraalRuntime.<init>")) {
             instance = new HotSpotGraalRuntime();
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Wed May 27 17:40:26 2015 +0200
@@ -23,8 +23,7 @@
 package com.oracle.graal.hotspot;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
-import static com.oracle.graal.hotspot.HotSpotOptionsLoader.*;
-import static java.lang.Double.*;
+import static com.oracle.graal.options.OptionsLoader.*;
 
 import java.lang.reflect.*;
 
@@ -32,7 +31,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.options.*;
-import com.oracle.graal.options.OptionUtils.OptionConsumer;
 import com.oracle.graal.phases.common.inlining.*;
 
 //JaCoCo Exclude
@@ -45,16 +43,10 @@
 
     private static final String GRAAL_OPTION_PREFIX = "-G:";
 
-    /**
-     * 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
-     */
-    private static native boolean parseVMOptions();
+    private static native boolean isCITimingEnabled();
 
     static {
-        boolean timeCompilations = parseVMOptions();
-        if (timeCompilations) {
+        if (isCITimingEnabled()) {
             unconditionallyEnableTimerOrMetric(InliningUtil.class, "InlinedBytecodes");
             unconditionallyEnableTimerOrMetric(CompilationTask.class, "CompilationTime");
         }
@@ -74,58 +66,8 @@
         }
     }
 
-    /**
-     * Ensures {@link HotSpotOptions} is initialized.
-     */
-    public static void initialize() {
-    }
-
-    /**
-     * 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 '?':
-                OptionUtils.printFlags(options, GRAAL_OPTION_PREFIX);
-                break;
-            case ' ':
-                OptionUtils.printNoMatchMessage(options, name, GRAAL_OPTION_PREFIX);
-                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
-     * @param setter the object to notify of the parsed option and value. If null, the
-     *            {@link OptionValue#setValue(Object)} method of the specified option is called
-     *            instead.
-     */
-    public static boolean parseOption(String option, OptionConsumer setter) {
-        return OptionUtils.parseOption(options, option, GRAAL_OPTION_PREFIX, setter);
+    static void printFlags() {
+        OptionUtils.printFlags(options, GRAAL_OPTION_PREFIX);
     }
 
     /**
@@ -156,4 +98,6 @@
             throw new GraalInternalError(e);
         }
     }
+
+    public native Object getOptionValue(String optionName);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java	Mon May 18 18:30:43 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * 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.util.*;
-
-import com.oracle.graal.api.runtime.*;
-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 {
-        for (Options opts : Services.load(Options.class)) {
-            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");
-    }
-}
--- a/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/OptionProcessor.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.options.processor/src/com/oracle/graal/options/processor/OptionProcessor.java	Wed May 27 17:40:26 2015 +0200
@@ -229,6 +229,7 @@
         String filename = "META-INF/options/" + pkg + "." + relativeName;
         FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements);
         PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+        Types types = processingEnv.getTypeUtils();
         for (OptionInfo option : info.options) {
             String help = option.help;
             if (help.indexOf('\t') >= 0 || help.indexOf('\r') >= 0 || help.indexOf('\n') >= 0) {
@@ -237,13 +238,20 @@
             }
             try {
                 char optionTypeToChar = optionTypeToChar(option);
-                writer.printf("%s\t%s\t%s%n", option.name, optionTypeToChar, help);
+                String fqDeclaringClass = className(types.erasure(option.field.getEnclosingElement().asType()));
+                String fqFieldType = className(types.erasure(option.field.asType()));
+                writer.printf("%s\t%s\t%s\t%s\t%s%n", option.name, optionTypeToChar, help, fqDeclaringClass, fqFieldType);
             } catch (IllegalArgumentException iae) {
             }
         }
         writer.close();
     }
 
+    private String className(TypeMirror t) {
+        DeclaredType dt = (DeclaredType) t;
+        return processingEnv.getElementUtils().getBinaryName((TypeElement) dt.asElement()).toString();
+    }
+
     private char optionTypeToChar(OptionInfo option) {
         switch (option.type) {
             case "Boolean":
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionUtils.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionUtils.java	Wed May 27 17:40:26 2015 +0200
@@ -34,24 +34,19 @@
      * Parses a given option value specification.
      *
      * @param option the specification of an option and its value
-     * @param setter the object to notify of the parsed option and value. If null, the
-     *            {@link OptionValue#setValue(Object)} method of the specified option is called
-     *            instead.
+     * @param setter the object to notify of the parsed option and value.
      */
-    public static boolean parseOption(SortedMap<String, OptionDescriptor> options, String option, String prefix, OptionConsumer setter) {
+    public static void parseOption(String option, OptionConsumer setter) {
+        SortedMap<String, OptionDescriptor> options = OptionsLoader.options;
+        Objects.requireNonNull(setter);
         if (option.length() == 0) {
-            return false;
+            return;
         }
 
         Object value = null;
         String optionName = null;
         String valueString = null;
 
-        if (option.equals("+PrintFlags")) {
-            printFlags(options, prefix);
-            return true;
-        }
-
         char first = option.charAt(0);
         if (first == '+' || first == '-') {
             optionName = option.substring(1);
@@ -69,21 +64,18 @@
 
         OptionDescriptor desc = options.get(optionName);
         if (desc == null) {
-            printNoMatchMessage(options, optionName, prefix);
-            return false;
+            throw new IllegalArgumentException("Option '" + optionName + "' not found");
         }
 
         Class<?> optionType = desc.getType();
 
         if (value == null) {
             if (optionType == Boolean.TYPE || optionType == Boolean.class) {
-                System.err.println("Value for boolean option '" + optionName + "' must use '" + prefix + "+" + optionName + "' or '" + prefix + "-" + optionName + "' format");
-                return false;
+                throw new IllegalArgumentException("Boolean option '" + optionName + "' must use +/- prefix");
             }
 
             if (valueString == null) {
-                System.err.println("Value for option '" + optionName + "' must use '" + prefix + optionName + "=<value>' format");
-                return false;
+                throw new IllegalArgumentException("Missing value for non-boolean option '" + optionName + "' must use " + optionName + "=<value> format");
             }
 
             if (optionType == Float.class) {
@@ -96,28 +88,16 @@
                 value = Long.valueOf(parseLong(valueString));
             } else if (optionType == String.class) {
                 value = valueString;
+            } else {
+                throw new IllegalArgumentException("Wrong value for option '" + optionName + "'");
             }
         } else {
             if (optionType != Boolean.class) {
-                System.err.println("Value for option '" + optionName + "' must use '" + prefix + optionName + "=<value>' format");
-                return false;
+                throw new IllegalArgumentException("Non-boolean option '" + optionName + "' can not use +/- prefix. Use " + optionName + "=<value> format");
             }
         }
 
-        if (value != null) {
-            if (setter != null) {
-                setter.set(desc, value);
-            } else {
-                OptionValue<?> optionValue = desc.getOptionValue();
-                optionValue.setValue(value);
-                // System.err.println("Set option " + desc.getName() + " to " + value);
-            }
-        } else {
-            System.err.println("Wrong value \"" + valueString + "\" for option " + optionName);
-            return false;
-        }
-
-        return true;
+        setter.set(desc, value);
     }
 
     private static long parseLong(String v) {
@@ -141,27 +121,6 @@
         return Long.parseLong(valueString) * scale;
     }
 
-    public static void printNoMatchMessage(SortedMap<String, OptionDescriptor> options, String optionName, String prefix) {
-        OptionDescriptor desc = options.get(optionName);
-        if (desc != null) {
-            if (desc.getType() == Boolean.class) {
-                System.err.println("Boolean option " + optionName + " must be prefixed with '+' or '-'");
-            } else {
-                System.err.println(desc.getType().getSimpleName() + " option " + optionName + " must not be prefixed with '+' or '-'");
-            }
-        } else {
-            System.err.println("Could not find option " + optionName + " (use " + prefix + "+PrintFlags to see options)");
-            List<OptionDescriptor> matches = fuzzyMatch(options, optionName);
-            if (!matches.isEmpty()) {
-                System.err.println("Did you mean one of the following?");
-                for (OptionDescriptor match : matches) {
-                    boolean isBoolean = match.getType() == Boolean.class;
-                    System.err.println(String.format("    %s%s%s", isBoolean ? "(+/-)" : "", match.getName(), isBoolean ? "" : "=<value>"));
-                }
-            }
-        }
-    }
-
     /**
      * Wraps some given text to one or more lines of a given maximum width.
      *
@@ -220,38 +179,4 @@
 
         System.exit(0);
     }
-
-    /**
-     * Compute string similarity based on Dice's coefficient.
-     *
-     * Ported from str_similar() in globals.cpp.
-     */
-    static float stringSimiliarity(String str1, String str2) {
-        int hit = 0;
-        for (int i = 0; i < str1.length() - 1; ++i) {
-            for (int j = 0; j < str2.length() - 1; ++j) {
-                if ((str1.charAt(i) == str2.charAt(j)) && (str1.charAt(i + 1) == str2.charAt(j + 1))) {
-                    ++hit;
-                    break;
-                }
-            }
-        }
-        return 2.0f * hit / (str1.length() + str2.length());
-    }
-
-    private static final float FUZZY_MATCH_THRESHOLD = 0.7F;
-
-    /**
-     * Returns the set of options that fuzzy match a given option name.
-     */
-    private static List<OptionDescriptor> fuzzyMatch(SortedMap<String, OptionDescriptor> options, String optionName) {
-        List<OptionDescriptor> matches = new ArrayList<>();
-        for (Map.Entry<String, OptionDescriptor> e : options.entrySet()) {
-            float score = stringSimiliarity(e.getKey(), optionName);
-            if (score >= FUZZY_MATCH_THRESHOLD) {
-                matches.add(e.getValue());
-            }
-        }
-        return matches;
-    }
 }
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionValue.java	Wed May 27 17:40:26 2015 +0200
@@ -30,7 +30,6 @@
  * An option value.
  */
 public class OptionValue<T> {
-
     /**
      * Temporarily changes the value for an option. The {@linkplain OptionValue#getValue() value} of
      * {@code option} is set to {@code value} until {@link OverrideScope#close()} is called on the
@@ -138,7 +137,7 @@
         overrideScopeTL.set(overrideScope);
     }
 
-    private T initialValue;
+    private T defaultValue;
 
     /**
      * The raw option value.
@@ -164,29 +163,30 @@
 
     @SuppressWarnings("unchecked")
     public OptionValue(T value) {
-        this.initialValue = value;
-        this.value = (T) UNINITIALIZED;
+        this.defaultValue = value;
+        this.value = (T) DEFAULT;
         addToHistogram(this);
     }
 
+    private static final Object DEFAULT = "DEFAULT";
     private static final Object UNINITIALIZED = "UNINITIALIZED";
 
     /**
      * Creates an uninitialized option value for a subclass that initializes itself
-     * {@link #initialValue() lazily}.
+     * {@link #defaultValue() lazily}.
      */
     @SuppressWarnings("unchecked")
     protected OptionValue() {
-        this.initialValue = (T) UNINITIALIZED;
-        this.value = (T) UNINITIALIZED;
+        this.defaultValue = (T) UNINITIALIZED;
+        this.value = (T) DEFAULT;
         addToHistogram(this);
     }
 
     /**
-     * Lazy initialization of value.
+     * Lazy initialization of default value.
      */
-    protected T initialValue() {
-        throw new InternalError("Uninitialized option value must override initialValue()");
+    protected T defaultValue() {
+        throw new InternalError("Option without a default value value must override defaultValue()");
     }
 
     /**
@@ -223,27 +223,19 @@
      * {@link #setValue(Object)} or registering {@link OverrideScope}s. Therefore, it is also not
      * affected by options set on the command line.
      */
-    public T getInitialValue() {
-        if (initialValue == UNINITIALIZED) {
-            initialValue = initialValue();
+    public T getDefaultValue() {
+        if (defaultValue == UNINITIALIZED) {
+            defaultValue = defaultValue();
         }
-        return initialValue;
+        return defaultValue;
     }
 
     /**
      * Returns true if the option has the same value that was set in the source code.
      */
-    public boolean hasInitialValue() {
-        if (!(this instanceof StableOptionValue)) {
-            OverrideScope overrideScope = getOverrideScope();
-            if (overrideScope != null) {
-                T override = overrideScope.getOverride(this);
-                if (override != null) {
-                    return false;
-                }
-            }
-        }
-        return value == UNINITIALIZED || Objects.equals(value, getInitialValue());
+    public boolean hasDefaultValue() {
+        getValue(); // ensure initialized
+        return value == DEFAULT || Objects.equals(value, getDefaultValue());
     }
 
     /**
@@ -262,10 +254,10 @@
                 }
             }
         }
-        if (value != UNINITIALIZED) {
+        if (value != DEFAULT) {
             return value;
         } else {
-            return getInitialValue();
+            return getDefaultValue();
         }
     }
 
@@ -285,10 +277,10 @@
                 overrideScope.getOverrides(this, (Collection<Object>) values);
             }
         }
-        if (value != UNINITIALIZED) {
+        if (value != DEFAULT) {
             values.add(value);
         } else {
-            values.add(getInitialValue());
+            values.add(getDefaultValue());
         }
         return values;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/OptionsLoader.java	Wed May 27 17:40:26 2015 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.options;
+
+import java.util.*;
+
+import com.oracle.graal.api.runtime.*;
+
+/**
+ * Helper class used to load option descriptors. Only to be used in the slow-path.
+ */
+public class OptionsLoader {
+    public static final SortedMap<String, OptionDescriptor> options = new TreeMap<>();
+
+    /**
+     * Initializes {@link #options} from {@link Options} services.
+     */
+    static {
+        for (Options opts : Services.load(Options.class)) {
+            for (OptionDescriptor desc : opts) {
+                String name = desc.getName();
+                OptionDescriptor existing = options.put(name, desc);
+                assert existing == null : "Option named \"" + name + "\" has multiple definitions: " + existing.getLocation() + " and " + desc.getLocation();
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java	Mon May 18 18:30:43 2015 +0200
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/StableOptionValue.java	Wed May 27 17:40:26 2015 +0200
@@ -42,7 +42,7 @@
 
     /**
      * Creates an uninitialized stable option value for a subclass that initializes itself
-     * {@link #initialValue() lazily}.
+     * {@link #defaultValue() lazily}.
      */
     public StableOptionValue() {
     }
--- a/mx/suite.py	Mon May 18 18:30:43 2015 +0200
+++ b/mx/suite.py	Wed May 27 17:40:26 2015 +0200
@@ -442,6 +442,9 @@
     "com.oracle.graal.options" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
+      "dependencies" : [
+        "com.oracle.graal.api.runtime",
+      ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "Graal",
@@ -496,7 +499,6 @@
         "com.oracle.graal.nodeinfo",
         "com.oracle.graal.compiler.common",
         "com.oracle.graal.api.collections",
-        "com.oracle.graal.api.runtime",
         "FINDBUGS",
       ],
       "javaCompliance" : "1.8",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalHashtable.cpp	Wed May 27 17:40:26 2015 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#include "graal/graalHashtable.hpp"
+
+template<class K, class V> bool GraalHashtable<K,V>::add(V value, bool replace) {
+  K key = get_key(value);
+  unsigned int hash = compute_hash(key);
+  unsigned int index = hash_to_index(hash);
+  for (GraalHashtableEntry<V>* e = bucket(index); e != NULL; e = e->next()) {
+    if (key_equals(get_key(e->literal_addr()), key)) {
+      if (replace) {
+        e->set_literal(value);
+      }
+      return false;
+    }
+  }
+  GraalHashtableEntry<V>* e = new GraalHashtableEntry<V>(value);
+  e->set_next(_buckets[index]);
+  _buckets[index] = e;
+  ++_number_of_entries;
+  return true;
+}
+
+template<class K, class V> V* GraalHashtable<K,V>::get(K key) {
+  unsigned int index = index_for(key);
+  for (GraalHashtableEntry<V>* e = bucket(index); e != NULL; e = e->next()) {
+    if (key_equals(get_key(e->literal_addr()), key)) {
+      return e->literal_addr();
+    }
+  }
+  return NULL;
+}
+
+template<class K, class V> void GraalHashtable<K, V>::for_each(ValueClosure<V>* closure) {
+  for (size_t i = 0; i < table_size(); ++i) {
+    for (GraalHashtableEntry<V>* e = bucket(i); e != NULL && !closure->is_aborted(); e = e->next()) {
+      closure->do_value(e->literal_addr());
+    }
+  }
+}
+
+template<class K, class V> GraalHashtable<K,V>::~GraalHashtable() {
+  for (size_t i = 0; i < table_size(); ++i) {
+    GraalHashtableEntry<V>* e = bucket(i);
+    while (e != NULL) {
+      GraalHashtableEntry<V>* current = e;
+      e = e->next();
+      delete current;
+    }
+  }
+  FREE_C_HEAP_ARRAY(GraalHashtableEntry*, _buckets, mtCompiler);
+}
+
+// Instantiation
+#include "graal/graalOptions.hpp"
+template class GraalHashtable<const char*, OptionDesc>;
+template class GraalHashtable<const char*, OptionValue>;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalHashtable.hpp	Wed May 27 17:40:26 2015 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#ifndef SHARE_VM_GRAAL_GRAAL_HASHTABLE_HPP
+#define SHARE_VM_GRAAL_GRAAL_HASHTABLE_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+
+// based on hashtable.hpp
+
+template <class T> class GraalHashtableEntry : public CHeapObj<mtCompiler> {
+  friend class VMStructs;
+private:
+  T               _literal;       // ref to item in table.
+  GraalHashtableEntry*  _next;          // Link to next element in the linked list for this bucket
+
+public:
+  GraalHashtableEntry(T literal) :  _literal(literal), _next(NULL) {}
+
+  T literal() {
+    return _literal;
+  }
+
+  void set_literal(T value) {
+    _literal = value;
+  }
+
+  T* literal_addr() {
+    return &_literal;
+  }
+
+  GraalHashtableEntry* next() const {
+    return _next;
+  }
+
+  void set_next(GraalHashtableEntry* next) {
+    _next = next;
+  }
+};
+
+template <class V>
+class ValueClosure : public StackObj {
+  bool _abort;
+protected:
+  void abort() { _abort = true; }
+public:
+  ValueClosure() : _abort(false) {}
+  virtual void do_value(V* value) = 0;
+  bool is_aborted() { return _abort; }
+};
+
+template <class K, class V> class GraalHashtable : public CHeapObj<mtCompiler> {
+  friend class VMStructs;
+private:
+  // Instance variables
+  unsigned int             _table_size;
+  GraalHashtableEntry<V>** _buckets;
+  unsigned int             _number_of_entries;
+
+public:
+  GraalHashtable(size_t size) : _table_size(size), _number_of_entries(0) {
+    _buckets = NEW_C_HEAP_ARRAY(GraalHashtableEntry<V>*, table_size(), mtCompiler);
+    for (size_t i = 0; i < table_size(); ++i) {
+      _buckets[i] = NULL;
+    }
+  }
+  virtual ~GraalHashtable();
+
+private:
+  // Bucket handling
+  unsigned int hash_to_index(unsigned int full_hash) {
+    unsigned int h = full_hash % _table_size;
+    assert(h >= 0 && h < _table_size, "Illegal hash value");
+    return h;
+  }
+
+  unsigned  int index_for(K key) {
+    return hash_to_index(compute_hash(key));
+  }
+
+  size_t entry_size() {
+    return sizeof(V);
+  }
+
+  size_t table_size() { return _table_size; }
+
+  GraalHashtableEntry<V>* bucket(unsigned int index) {
+    return _buckets[index];
+  }
+
+  bool add(V v, bool replace);
+
+protected:
+  virtual unsigned int compute_hash(K key) = 0;
+  virtual bool key_equals(K k1, K k2) = 0;
+  virtual K get_key(V value) = 0;
+  virtual K get_key(V* value) = 0;
+
+public:
+  /**
+   * Tries to insert the value in the hash table. Returns false if an entry with the same key already exists.
+   * In this case it does *not* replace the existing entry.
+   */
+  bool add(V v) { return add(v, false); }
+  /**
+   * Inserts the value in the hash table. Returns false if an entry with the same key already exists.
+   * In this case it replaces the existing entry.
+   */
+  bool put(V v) { return add(v, true); }
+  V* get(K k);
+  void for_each(ValueClosure<V>* closure);
+  int number_of_entries() { return _number_of_entries; }
+
+};
+
+#endif // SHARE_VM_GRAAL_GRAAL_HASHTABLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalOptions.cpp	Wed May 27 17:40:26 2015 +0200
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#include "precompiled.hpp"
+#include "graal/graalOptions.hpp"
+#include "graal/graalRuntime.hpp"
+#include "runtime/arguments.hpp"
+#include "utilities/hashtable.inline.hpp"
+
+class OptionsParseClosure : public ParseClosure {
+  OptionsTable* _table;
+public:
+  OptionsParseClosure(OptionsTable* table) : _table(table) {}
+  void do_line(char* line) {
+    char* idx = strchr(line, '\t');
+    if (idx == NULL) {
+      warn_and_abort("invalid format: could not find first tab");
+      return;
+    }
+    *idx = '\0';
+    char* name = line;
+    line = idx + 1;
+    idx = strchr(line, '\t');
+    if (idx == NULL) {
+      warn_and_abort("invalid format: could not find second tab");
+      return;
+    }
+    *idx = '\0';
+    if (strlen(line) != 1) {
+      warn_and_abort("invalid format: type should be 1 char long");
+      return;
+    }
+    char typeChar = *line;
+    line = idx + 1;
+    idx = strchr(line, '\t');
+    if (idx == NULL) {
+      warn_and_abort("invalid format: could not find third tab");
+      return;
+    }
+    *idx = '\0';
+    char* help = line;
+    line = idx + 1;
+    idx = strchr(line, '\t');
+    if (idx == NULL) {
+      warn_and_abort("invalid format: could not find fourth tab");
+      return;
+    }
+    *idx = '\0';
+    char* declaringClass = line;
+    line = idx + 1;
+    char* fieldClass = line;
+    OptionType type;
+    switch(typeChar) {
+      case 's':
+        type = _string;
+        break;
+      case 'i':
+        type = _int;
+        break;
+      case 'j':
+        type = _long;
+        break;
+      case 'f':
+        type = _float;
+        break;
+      case 'd':
+        type = _double;
+        break;
+      case 'z':
+        type = _boolean;
+        break;
+      default:
+        warn_and_abort("unkown type");
+        return;
+    }
+    char* name2 = NEW_C_HEAP_ARRAY(char, (strlen(name) + 1 + strlen(help) + 1 + strlen(declaringClass) + 1 + strlen(fieldClass) + 1), mtCompiler);
+    char* help2 = name2 + strlen(name) + 1;
+    char* declaringClass2 = help2 + strlen(help) + 1;
+    char* fieldClass2 = declaringClass2 + strlen(declaringClass) + 1;
+    strcpy(name2, name);
+    strcpy(help2, help);
+    strcpy(declaringClass2, declaringClass);
+    strcpy(fieldClass2, fieldClass);
+    OptionDesc desc = {name2, help2, type, declaringClass2, fieldClass2};
+    if (!_table->add(desc)) {
+      warn_and_abort("duplicate option");
+      return;
+    }
+  }
+};
+
+class FreeNamesClosure : public ValueClosure<OptionDesc> {
+  void do_value(OptionDesc* desc) {
+    FREE_C_HEAP_ARRAY(char, desc->name, mtCompiler);
+  }
+};
+
+OptionsTable::~OptionsTable() {
+  FreeNamesClosure closure;
+  for_each(&closure);
+}
+
+OptionsTable* OptionsTable::load_options() {
+  OptionsTable* table = new OptionsTable();
+  // Add PrintFlags option manually
+  OptionDesc printFlagsDesc;
+  printFlagsDesc.name = PRINT_FLAGS_ARG;
+  printFlagsDesc.type = _boolean;
+  printFlagsDesc.help = PRINT_FLAGS_HELP;
+  printFlagsDesc.declaringClass = NULL;
+  printFlagsDesc.fieldClass = NULL;
+  table->add(printFlagsDesc);
+
+  char optionsDir[JVM_MAXPATHLEN];
+  const char* fileSep = os::file_separator();
+  jio_snprintf(optionsDir, sizeof(optionsDir), "%s%slib%sgraal%soptions",
+               Arguments::get_java_home(), fileSep, fileSep, fileSep);
+  DIR* dir = os::opendir(optionsDir);
+  if (dir != NULL) {
+    struct dirent *entry;
+    char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(optionsDir), mtInternal);
+    OptionsParseClosure closure(table);
+    while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) {
+      const char* name = entry->d_name;
+      char optionFilePath[JVM_MAXPATHLEN];
+      jio_snprintf(optionFilePath, sizeof(optionFilePath), "%s%s%s",optionsDir, fileSep, name);
+      GraalRuntime::parse_lines(optionFilePath, &closure, false);
+    }
+    FREE_C_HEAP_ARRAY(char, dbuf, mtInternal);
+    os::closedir(dir);
+    if (closure.is_aborted()) {
+      delete table;
+      return NULL;
+    }
+    return table;
+  }
+  // TODO(gd) should this be silent?
+  warning("Could not open graal options directory (%s)",optionsDir);
+  return table;
+}
+
+OptionDesc* OptionsTable::get(const char* name, size_t arglen) {
+  char nameOnly[256];
+  guarantee(arglen < 256, "Max supported option name len is 256");
+  strncpy(nameOnly, name, arglen);
+  nameOnly[arglen] = '\0';
+  return GraalHashtable<const char*, OptionDesc>::get(nameOnly);
+}
+
+// Compute string similarity based on Dice's coefficient
+static float str_similar(const char* str1, const char* str2) {
+  size_t len1 = strlen(str1);
+  size_t len2 = strlen(str2);
+
+  if (len1 == 0 || len2 == 0) {
+    return 0;
+  }
+
+  int hits = 0;
+  for (size_t i = 0; i < len1 - 1; ++i) {
+    for (size_t j = 0; j < len2 -1; ++j) {
+      if ((str1[i] == str2[j]) && (str1[i+1] == str2[j+1])) {
+        ++hits;
+        break;
+      }
+    }
+  }
+
+  size_t total = len1 + len2;
+  return 2.0f * (float) hits / (float) total;
+}
+
+float VMOptionsFuzzyMatchSimilarity = 0.7f;
+
+class FuzzyMatchClosure : public ValueClosure<OptionDesc> {
+  OptionDesc* _match;
+  float _max_score;
+  const char* _name;
+public:
+  FuzzyMatchClosure(const char* name) : _name(name), _match(NULL), _max_score(-1) {}
+  void do_value(OptionDesc* value) {
+    float score = str_similar(value->name, _name);
+    if (score > VMOptionsFuzzyMatchSimilarity && score > _max_score) {
+      _max_score = score;
+      _match = value;
+    }
+  }
+  OptionDesc* get_match() {
+    return _match;
+  }
+};
+
+OptionDesc * OptionsTable::fuzzy_match(const char* name, size_t length) {
+  FuzzyMatchClosure closure(name);
+  for_each(&closure);
+  return closure.get_match();
+}
+
+class FreeStringsClosure : public ValueClosure<OptionValue> {
+  void do_value(OptionValue* value) {
+    if (value->desc.type == _string) {
+      FREE_C_HEAP_ARRAY(char, value->string_value, mtCompiler);
+    }
+  }
+};
+
+OptionsValueTable::~OptionsValueTable() {
+  FreeStringsClosure closure;
+  for_each(&closure);
+  delete _table;
+}
+
+
+
+OptionValue* OptionsValueTable::get(const char* name, size_t arglen) {
+  char nameOnly[256];
+  guarantee(arglen < 256, "Max supported option name len is 256");
+  strncpy(nameOnly, name, arglen);
+  nameOnly[arglen] = '\0';
+  return GraalHashtable<const char*, OptionValue>::get(nameOnly);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/graal/graalOptions.hpp	Wed May 27 17:40:26 2015 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#ifndef SHARE_VM_GRAAL_GRAAL_OPTIONS_HPP
+#define SHARE_VM_GRAAL_GRAAL_OPTIONS_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/exceptions.hpp"
+#include "graal/graalHashtable.hpp"
+
+#define PRINT_FLAGS_ARG "PrintFlags"
+#define PRINT_FLAGS_HELP "Prints all Graal flags (similar to XX's PrintFlagsFinal)"
+
+enum OptionType {
+  _string,
+  _int,
+  _long,
+  _float,
+  _double,
+  _boolean
+};
+
+struct OptionDesc {
+  const char* name;
+  const char* help;
+  OptionType type;
+  const char* declaringClass;
+  const char* fieldClass;
+};
+
+inline unsigned int compute_string_hash(const char *s, int n) {
+  unsigned int val = 0;
+  while (--n >= 0) {
+    val = *s++ + 31 * val;
+  }
+  return val;
+}
+
+class OptionsTable : public GraalHashtable<const char*, OptionDesc> {
+protected:
+  unsigned int compute_hash(const char* key) { return compute_string_hash(key, strlen(key)); }
+  bool key_equals(const char* k1, const char* k2) { return strcmp(k1, k2) == 0; }
+  const char* get_key(OptionDesc value) { return value.name; } ;
+  const char* get_key(OptionDesc* value) { return value->name; } ;
+public:
+  OptionsTable() : GraalHashtable<const char*, OptionDesc>(100) {}
+  ~OptionsTable();
+  using GraalHashtable<const char*, OptionDesc>::get;
+  OptionDesc* get(const char* name, size_t arglen);
+  OptionDesc * fuzzy_match(const char* name, size_t length);
+
+  static OptionsTable* load_options();
+};
+
+struct OptionValue {
+  OptionDesc desc;
+  union {
+    const char* string_value;
+    jint int_value;
+    jlong long_value;
+    jfloat float_value;
+    jdouble double_value;
+    jboolean boolean_value;
+  };
+};
+
+class OptionsValueTable : public GraalHashtable<const char*, OptionValue> {
+  OptionsTable* _table;
+protected:
+  unsigned int compute_hash(const char* key) { return compute_string_hash(key, strlen(key)); }
+  bool key_equals(const char* k1, const char* k2) { return strcmp(k1, k2) == 0; }
+  const char* get_key(OptionValue value) { return value.desc.name; } ;
+  const char* get_key(OptionValue* value) { return value->desc.name; } ;
+public:
+  OptionsValueTable(OptionsTable* table) : _table(table), GraalHashtable<const char*, OptionValue>(100) {}
+  ~OptionsValueTable();
+  using GraalHashtable<const char*, OptionValue>::get;
+  OptionValue* get(const char* name, size_t arglen);
+  OptionsTable* options_table() { return _table; }
+};
+
+
+#endif // SHARE_VM_GRAAL_GRAAL_OPTIONS_HPP
--- a/src/share/vm/graal/graalRuntime.cpp	Mon May 18 18:30:43 2015 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Wed May 27 17:40:26 2015 +0200
@@ -37,6 +37,7 @@
 #include "runtime/arguments.hpp"
 #include "runtime/reflection.hpp"
 #include "utilities/debug.hpp"
+#include "utilities/defaultStream.hpp"
 
 jobject GraalRuntime::_HotSpotGraalRuntime_instance = NULL;
 bool GraalRuntime::_HotSpotGraalRuntime_initialized = false;
@@ -625,6 +626,11 @@
   SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_GRAAL_WKID, scan, CHECK);
 JVM_END
 
+// boolean com.oracle.graal.hotspot.HotSpotOptions.isCITimingEnabled()
+JVM_ENTRY(jboolean, JVM_IsCITimingEnabled(JNIEnv *env, jclass c))
+  return CITime || CITimeEach;
+JVM_END
+
 // private static GraalRuntime Graal.initializeRuntime()
 JVM_ENTRY(jobject, JVM_GetGraalRuntime(JNIEnv *env, jclass c))
   GraalRuntime::initialize_HotSpotGraalRuntime();
@@ -665,26 +671,9 @@
   return JNIHandles::make_local(THREAD, (oop) result.get_jobject());
 JVM_END
 
-void GraalRuntime::check_generated_sources_sha1(TRAPS) {
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/sourcegen/GeneratedSourcesSha1", CHECK_ABORT);
-  KlassHandle klass = load_required_class(name);
-  fieldDescriptor fd;
-  if (!InstanceKlass::cast(klass())->find_field(vmSymbols::value_name(), vmSymbols::string_signature(), true, &fd)) {
-    THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), "GeneratedSourcesSha1.value");
-  }
-
-  Symbol* value = java_lang_String::as_symbol(klass->java_mirror()->obj_field(fd.offset()), CHECK);
-  if (!value->equals(_generated_sources_sha1)) {
-    char buf[200];
-    jio_snprintf(buf, sizeof(buf), "Generated sources SHA1 check failed (%s != %s) - need to rebuild the VM", value->as_C_string(), _generated_sources_sha1);
-    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
-  }
-}
-
 Handle GraalRuntime::callInitializer(const char* className, const char* methodName, const char* returnType) {
   guarantee(!_HotSpotGraalRuntime_initialized, "cannot reinitialize HotSpotGraalRuntime");
   Thread* THREAD = Thread::current();
-  check_generated_sources_sha1(CHECK_ABORT_(Handle()));
 
   TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_ABORT_(Handle()));
   KlassHandle klass = load_required_class(name);
@@ -725,15 +714,6 @@
   GraalRuntime::initialize_natives(env, c2vmClass);
 JVM_END
 
-// 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)));
-  bool result = GraalRuntime::parse_arguments(hotSpotOptionsClass, CHECK_false);
-  return result;
-JVM_END
-
-
 void GraalRuntime::ensure_graal_class_loader_is_initialized() {
   // This initialization code is guarded by a static pointer to the Factory class.
   // Once it is non-null, the Graal class loader and well known Graal classes are
@@ -772,212 +752,316 @@
     *((jboolean *) addr) = (jboolean) UseGraalClassLoader;
     klass->initialize(CHECK_ABORT);
     _FactoryKlass = klass();
+    assert(!UseGraalClassLoader || SystemDictionary::graal_loader() != NULL, "Graal classloader should have been initialized");
   }
 }
 
-jint GraalRuntime::check_arguments(TRAPS) {
-  KlassHandle nullHandle;
-  parse_arguments(nullHandle, THREAD);
-  if (HAS_PENDING_EXCEPTION) {
-    // Errors in parsing Graal arguments cause exceptions.
-    // We now load and initialize HotSpotOptions which in turn
-    // causes argument parsing to be redone with better error messages.
-    CLEAR_PENDING_EXCEPTION;
-    TempNewSymbol name = SymbolTable::new_symbol("Lcom/oracle/graal/hotspot/HotSpotOptions;", CHECK_ABORT_(JNI_ERR));
-    instanceKlassHandle hotSpotOptionsClass = resolve_or_fail(name, CHECK_ABORT_(JNI_ERR));
-
-    parse_arguments(hotSpotOptionsClass, THREAD);
-    assert(HAS_PENDING_EXCEPTION, "must be");
+OptionsValueTable* GraalRuntime::parse_arguments() {
+  OptionsTable* table = OptionsTable::load_options();
+  if (table == NULL) {
+    return NULL;
+  }
 
-    ResourceMark rm;
-    Handle exception = PENDING_EXCEPTION;
-    CLEAR_PENDING_EXCEPTION;
-    oop message = java_lang_Throwable::message(exception);
-    if (message != NULL) {
-      tty->print_cr("Error parsing Graal options: %s", java_lang_String::as_utf8_string(message));
-    } else {
-      call_printStackTrace(exception, THREAD);
-    }
-    return JNI_ERR;
-  }
-  return JNI_OK;
-}
-
-bool GraalRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
-  ResourceMark rm(THREAD);
+  OptionsValueTable* options = new OptionsValueTable(table);
 
   // Process option overrides from graal.options first
-  parse_graal_options_file(hotSpotOptionsClass, CHECK_false);
+  parse_graal_options_file(options);
 
   // Now process options on the command line
   int numOptions = Arguments::num_graal_args();
   for (int i = 0; i < numOptions; i++) {
     char* arg = Arguments::graal_args_array()[i];
-    parse_argument(hotSpotOptionsClass, arg, CHECK_false);
+    if (!parse_argument(options, arg)) {
+      delete options;
+      return NULL;
+    }
   }
-  return CITime || CITimeEach;
+  return options;
 }
 
-void GraalRuntime::check_required_value(const char* name, size_t name_len, const char* value, TRAPS) {
-  if (value == NULL) {
-    char buf[200];
-    jio_snprintf(buf, sizeof(buf), "Must use '-G:%.*s=<value>' format for %.*s option", name_len, name, name_len, name);
-    THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+void not_found(OptionsTable* table, const char* argname, size_t namelen) {
+  jio_fprintf(defaultStream::error_stream(),"Unrecognized VM option '%.*s'\n", namelen, argname);
+  OptionDesc* fuzzy_matched = table->fuzzy_match(argname, strlen(argname));
+  if (fuzzy_matched != NULL) {
+    jio_fprintf(defaultStream::error_stream(),
+                "Did you mean '%s%s%s'?\n",
+                (fuzzy_matched->type == _boolean) ? "(+/-)" : "",
+                fuzzy_matched->name,
+                (fuzzy_matched->type == _boolean) ? "" : "=<value>");
   }
 }
 
-void GraalRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
-  ensure_graal_class_loader_is_initialized();
+bool GraalRuntime::parse_argument(OptionsValueTable* options, const char* arg) {
+  OptionsTable* table = options->options_table();
   char first = arg[0];
-  char* name;
+  const char* name;
   size_t name_len;
-  bool recognized = true;
   if (first == '+' || first == '-') {
     name = arg + 1;
-    name_len = strlen(name);
-    recognized = set_option_bool(hotSpotOptionsClass, name, name_len, first, CHECK);
+    OptionDesc* optionDesc = table->get(name);
+    if (optionDesc == NULL) {
+      not_found(table, name, strlen(name));
+      return false;
+    }
+    if (optionDesc->type != _boolean) {
+      jio_fprintf(defaultStream::error_stream(), "Unexpected +/- setting in VM option '%s'\n", name);
+      return false;
+    }
+    OptionValue value;
+    value.desc = *optionDesc;
+    value.boolean_value = first == '+';
+    options->put(value);
+    return true;
   } else {
-    char* sep = strchr(arg, '=');
+    const char* sep = strchr(arg, '=');
     name = arg;
-    char* value = NULL;
+    const char* value = NULL;
     if (sep != NULL) {
       name_len = sep - name;
       value = sep + 1;
     } else {
       name_len = strlen(name);
     }
-    recognized = set_option(hotSpotOptionsClass, name, name_len, value, CHECK);
-  }
-
-  if (!recognized) {
-    bool throw_err = hotSpotOptionsClass.is_null();
-    if (!hotSpotOptionsClass.is_null()) {
-      set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), ' ', Handle(), 0L);
-      if (!HAS_PENDING_EXCEPTION) {
-        throw_err = true;
+    OptionDesc* optionDesc = table->get(name, name_len);
+    if (optionDesc == NULL) {
+      not_found(table, name, name_len);
+      return false;
+    }
+    if (optionDesc->type == _boolean) {
+      jio_fprintf(defaultStream::error_stream(), "Missing +/- setting for VM option '%s'\n", name);
+      return false;
+    }
+    if (value == NULL) {
+      jio_fprintf(defaultStream::error_stream(), "Must use '-G:%.*s=<value>' format for %.*s option", name_len, name, name_len, name);
+      return false;
+    }
+    OptionValue optionValue;
+    optionValue.desc = *optionDesc;
+    char* check;
+    errno = 0;
+    switch(optionDesc->type) {
+      case _int: {
+        long int int_value = ::strtol(value, &check, 10);
+        if (*check != '\0' || errno == ERANGE || int_value > max_jint || int_value < min_jint) {
+          jio_fprintf(defaultStream::error_stream(), "Expected int value for VM option '%s'\n", name);
+          return false;
+        }
+        optionValue.int_value = int_value;
+        break;
       }
+      case _long: {
+        long long int long_value = ::strtoll(value, &check, 10);
+        if (*check != '\0' || errno == ERANGE || long_value > max_jlong || long_value < min_jlong) {
+          jio_fprintf(defaultStream::error_stream(), "Expected long value for VM option '%s'\n", name);
+          return false;
+        }
+        optionValue.long_value = long_value;
+        break;
+      }
+      case _float: {
+        optionValue.float_value = ::strtof(value, &check);
+        if (*check != '\0' || errno == ERANGE) {
+          jio_fprintf(defaultStream::error_stream(), "Expected float value for VM option '%s'\n", name);
+          return false;
+        }
+        break;
+      }
+      case _double: {
+        optionValue.double_value = ::strtod(value, &check);
+        if (*check != '\0' || errno == ERANGE) {
+          jio_fprintf(defaultStream::error_stream(), "Expected double value for VM option '%s'\n", name);
+          return false;
+        }
+        break;
+      }
+      case _string: {
+        char* copy = NEW_C_HEAP_ARRAY(char, strlen(value) + 1, mtCompiler);
+        strcpy(copy, value);
+        optionValue.string_value = copy;
+        break;
+      }
+      default:
+        ShouldNotReachHere();
     }
-
-    if (throw_err) {
-      char buf[200];
-      jio_snprintf(buf, sizeof(buf), "Unrecognized Graal option %.*s", name_len, name);
-      THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
-    }
+    options->put(optionValue);
+    return true;
   }
 }
 
 class GraalOptionParseClosure : public ParseClosure {
-  TRAPS;
-  KlassHandle _hotSpotOptionsClass;
+  OptionsValueTable* _options;
 public:
-  GraalOptionParseClosure(KlassHandle hotSpotOptionsClass, TRAPS) : THREAD(THREAD), _hotSpotOptionsClass(hotSpotOptionsClass) {}
+  GraalOptionParseClosure(OptionsValueTable* options) : _options(options) {}
   void do_line(char* line) {
-    GraalRuntime::parse_argument(_hotSpotOptionsClass, line, THREAD);
-    if (HAS_PENDING_EXCEPTION) {
-      warn_and_abort("Exception thrown while parsing argument");
+    if (!GraalRuntime::parse_argument(_options, line)) {
+      warn("There was an error parsing an argument. Skipping it.");
     }
   }
 };
 
-void GraalRuntime::parse_graal_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
+void GraalRuntime::parse_graal_options_file(OptionsValueTable* options) {
   const char* home = Arguments::get_java_home();
   size_t path_len = strlen(home) + strlen("/lib/graal.options") + 1;
-  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
+  char path[JVM_MAXPATHLEN];
   char sep = os::file_separator()[0];
-  sprintf(path, "%s%clib%cgraal.options", home, sep, sep);
-  GraalOptionParseClosure closure(hotSpotOptionsClass, THREAD);
-  parse_lines(path, &closure, false, THREAD);
-}
-
-jlong GraalRuntime::parse_primitive_option_value(char spec, const char* name, size_t name_len, const char* value, TRAPS) {
-  check_required_value(name, name_len, value, CHECK_(0L));
-  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 (jlong)uu.i;
-      }
-      break;
-    }
-    default:
-      ShouldNotReachHere();
-  }
-  ResourceMark rm(THREAD);
-  char buf[200];
-  bool missing = strlen(value) == 0;
-  if (missing) {
-    jio_snprintf(buf, sizeof(buf), "Missing %s value for Graal option %.*s", (spec == 'i' ? "numeric" : "float/double"), name_len, name);
-  } else {
-    jio_snprintf(buf, sizeof(buf), "Invalid %s value for Graal option %.*s: %s", (spec == 'i' ? "numeric" : "float/double"), name_len, name, value);
-  }
-  THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L);
+  jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cgraal.options", home, sep, sep);
+  GraalOptionParseClosure closure(options);
+  parse_lines(path, &closure, false);
 }
 
-void GraalRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) {
-  Thread* THREAD = Thread::current();
-  Handle name_handle;
-  if (name != NULL) {
-    if (strlen(name) > name_len) {
-      // Temporarily replace '=' with NULL to create the Java string for the option name
-      char save = name[name_len];
-      name[name_len] = '\0';
-      name_handle = java_lang_String::create_from_str(name, THREAD);
-      name[name_len] = '=';
-      if (HAS_PENDING_EXCEPTION) {
-        return;
+#define CHECK_WARN_ABORT_(message) THREAD); \
+  if (HAS_PENDING_EXCEPTION) { \
+    warning(message); \
+    char buf[512]; \
+    jio_snprintf(buf, 512, "Uncaught exception at %s:%d", __FILE__, __LINE__); \
+    GraalRuntime::abort_on_pending_exception(PENDING_EXCEPTION, buf); \
+    return; \
+  } \
+  (void)(0
+
+class SetOptionClosure : public ValueClosure<OptionValue> {
+  Thread* _thread;
+public:
+  SetOptionClosure(TRAPS) : _thread(THREAD) {}
+  void do_value(OptionValue* optionValue) {
+    TRAPS = _thread;
+    const char* declaringClass = optionValue->desc.declaringClass;
+    if (declaringClass == NULL) {
+      // skip PrintFlags pseudo-option
+      return;
+    }
+    const char* fieldName = optionValue->desc.name;
+    const char* fieldClass = optionValue->desc.fieldClass;
+
+    size_t fieldSigLen = 2 + strlen(fieldClass);
+    char* fieldSig = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, fieldSigLen + 1);
+    jio_snprintf(fieldSig, fieldSigLen + 1, "L%s;", fieldClass);
+    for (size_t i = 0; i < fieldSigLen; ++i) {
+      if (fieldSig[i] == '.') {
+        fieldSig[i] = '/';
+      }
+    }
+    fieldSig[fieldSigLen] = '\0';
+    size_t declaringClassLen = strlen(declaringClass);
+    char* declaringClassBinary = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, declaringClassLen + 1);
+    for (size_t i = 0; i < declaringClassLen; ++i) {
+      if (declaringClass[i] == '.') {
+        declaringClassBinary[i] = '/';
+      } else {
+        declaringClassBinary[i] = declaringClass[i];
       }
-    } else {
-      assert(strlen(name) == name_len, "must be");
-      name_handle = java_lang_String::create_from_str(name, CHECK);
+    }
+    declaringClassBinary[declaringClassLen] = '\0';
+
+    TempNewSymbol name = SymbolTable::new_symbol(declaringClassBinary, CHECK_WARN_ABORT_("Declaring class could not be found"));
+    Klass* klass = GraalRuntime::resolve_or_null(name, CHECK_WARN_ABORT_("Declaring class could not be resolved"));
+
+    if (klass == NULL) {
+      warning("Declaring class for option %s could not be resolved", declaringClass);
+      abort();
+      return;
+    }
+
+    // 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)fieldSigLen);
+    if (fieldname == NULL || signame == NULL) {
+      warning("Symbols for field for option %s not found (in %s)", fieldName, declaringClass);
+      abort();
+      return;
+    }
+    // Make sure class is initialized before handing id's out to fields
+    klass->initialize(CHECK_WARN_ABORT_("Error while initializing declaring class for option"));
+
+    fieldDescriptor fd;
+    if (!InstanceKlass::cast(klass)->find_field(fieldname, signame, true, &fd)) {
+      warning("Field for option %s not found (in %s)", fieldName, declaringClass);
+      abort();
+      return;
+    }
+    oop value;
+    switch(optionValue->desc.type) {
+    case _boolean: {
+      jvalue jv;
+      jv.z = optionValue->boolean_value;
+      value = java_lang_boxing_object::create(T_BOOLEAN, &jv, THREAD);
+      break;
+    }
+    case _int: {
+      jvalue jv;
+      jv.i = optionValue->int_value;
+      value = java_lang_boxing_object::create(T_INT, &jv, THREAD);
+      break;
+    }
+    case _long: {
+      jvalue jv;
+      jv.j = optionValue->long_value;
+      value = java_lang_boxing_object::create(T_LONG, &jv, THREAD);
+      break;
+    }
+    case _float: {
+      jvalue jv;
+      jv.f = optionValue->float_value;
+      value = java_lang_boxing_object::create(T_FLOAT, &jv, THREAD);
+      break;
+    }
+    case _double: {
+      jvalue jv;
+      jv.d = optionValue->double_value;
+      value = java_lang_boxing_object::create(T_DOUBLE, &jv, THREAD);
+      break;
+    }
+    case _string:
+      value = java_lang_String::create_from_str(optionValue->string_value, THREAD)();
+      break;
+    default:
+      ShouldNotReachHere();
+    }
+
+    oop optionValueOop = klass->java_mirror()->obj_field(fd.offset());
+
+    if (optionValueOop == NULL) {
+      warning("Option field was null, can not set %s", fieldName);
+      abort();
+      return;
+    }
+
+    if (!InstanceKlass::cast(optionValueOop->klass())->find_field(vmSymbols::value_name(), vmSymbols::object_signature(), false, &fd)) {
+      warning("'Object value' field not found in option class %s, can not set option %s", fieldClass, fieldName);
+      abort();
+      return;
+    }
+
+    optionValueOop->obj_field_put(fd.offset(), value);
+  }
+};
+
+void GraalRuntime::set_options(OptionsValueTable* options, TRAPS) {
+  ensure_graal_class_loader_is_initialized();
+  {
+    ResourceMark rm;
+    SetOptionClosure closure(THREAD);
+    options->for_each(&closure);
+    if (closure.is_aborted()) {
+      vm_abort(false);
     }
   }
+  OptionValue* printFlags = options->get(PRINT_FLAGS_ARG);
+  if (printFlags != NULL && printFlags->boolean_value) {
+    print_flags_helper(CHECK_ABORT);
+  }
+}
 
-  TempNewSymbol setOption = SymbolTable::new_symbol("setOption", CHECK);
-  TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;Lcom/oracle/graal/options/OptionValue;CLjava/lang/String;J)V", CHECK);
+void GraalRuntime::print_flags_helper(TRAPS) {
+  // TODO(gd) write this in C++?
+  HandleMark hm(THREAD);
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/hotspot/HotSpotOptions", CHECK_ABORT);
+  KlassHandle hotSpotOptionsClass = load_required_class(name);
+  TempNewSymbol setOption = SymbolTable::new_symbol("printFlags", CHECK);
   JavaValue result(T_VOID);
   JavaCallArguments args;
-  args.push_oop(name_handle());
-  args.push_oop(option());
-  args.push_int(spec);
-  args.push_oop(stringValue());
-  args.push_long(primitiveValue);
-  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, CHECK);
-}
-
-Handle GraalRuntime::get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS) {
-  TempNewSymbol name = SymbolTable::new_symbol(declaringClass, CHECK_NH);
-  Klass* klass = resolve_or_fail(name, 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;
+  JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, vmSymbols::void_method_signature(), &args, CHECK);
 }
 
 Handle GraalRuntime::create_Service(const char* name, TRAPS) {
@@ -1052,68 +1136,69 @@
   return klass;
 }
 
-void GraalRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure, TRAPS) {
+void GraalRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) {
   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 + 1);
-        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 " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path);
-        }
-        os::close(file_handle);
-        closure->set_filename(path);
-        if (num_read == st.st_size) {
-          buffer[num_read] = '\0';
+  if (os::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file
+    int file_handle = os::open(path, 0, 0);
+    if (file_handle != -1) {
+      char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal);
+      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 " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path);
+      }
+      os::close(file_handle);
+      closure->set_filename(path);
+      if (num_read == st.st_size) {
+        buffer[num_read] = '\0';
 
-          char* line = buffer;
-          while (line - buffer < num_read && !closure->is_aborted()) {
-            // find line end (\r, \n or \r\n)
-            char* nextline = NULL;
-            char* cr = strchr(line, '\r');
-            char* lf = strchr(line, '\n');
-            if (cr != NULL && lf != NULL) {
-              char* min = MIN2(cr, lf);
-              *min = '\0';
-              if (lf == cr + 1) {
-                nextline = lf + 1;
-              } else {
-                nextline = min + 1;
-              }
-            } else if (cr != NULL) {
-              *cr = '\0';
-              nextline = cr + 1;
-            } else if (lf != NULL) {
-              *lf = '\0';
+        char* line = buffer;
+        while (line - buffer < num_read && !closure->is_aborted()) {
+          // find line end (\r, \n or \r\n)
+          char* nextline = NULL;
+          char* cr = strchr(line, '\r');
+          char* lf = strchr(line, '\n');
+          if (cr != NULL && lf != NULL) {
+            char* min = MIN2(cr, lf);
+            *min = '\0';
+            if (lf == cr + 1) {
               nextline = lf + 1;
+            } else {
+              nextline = min + 1;
             }
-            // trim left
-            while (*line == ' ' || *line == '\t') line++;
-            char* end = line + strlen(line);
-            // trim right
-            while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--;
-            *end = '\0';
-            // skip comments and empty lines
-            if (*line != '#' && strlen(line) > 0) {
-              closure->parse_line(line);
-            }
-            if (nextline != NULL) {
-              line = nextline;
-            } else {
-              // File without newline at the end
-              break;
-            }
+          } else if (cr != NULL) {
+            *cr = '\0';
+            nextline = cr + 1;
+          } else if (lf != NULL) {
+            *lf = '\0';
+            nextline = lf + 1;
+          }
+          // trim left
+          while (*line == ' ' || *line == '\t') line++;
+          char* end = line + strlen(line);
+          // trim right
+          while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--;
+          *end = '\0';
+          // skip comments and empty lines
+          if (*line != '#' && strlen(line) > 0) {
+            closure->parse_line(line);
+          }
+          if (nextline != NULL) {
+            line = nextline;
+          } else {
+            // File without newline at the end
+            break;
           }
         }
-      } else {
-        warning("Error opening file %s due to %s", path, strerror(errno));
       }
-    } else if (warnStatFailure) {
-      warning("Could not stat file %s due to %s", path, strerror(errno));
+      FREE_C_HEAP_ARRAY(char, buffer, mtInternal);
+    } else {
+      warning("Error opening file %s due to %s", path, strerror(errno));
     }
+  } else if (warnStatFailure) {
+    warning("Could not stat file %s due to %s", path, strerror(errno));
+  }
 }
 
 class ServiceParseClosure : public ParseClosure {
@@ -1121,13 +1206,18 @@
 public:
   ServiceParseClosure() : _implNames() {}
   void do_line(char* line) {
+    size_t lineLen = strlen(line);
+    char* implName = NEW_C_HEAP_ARRAY(char, lineLen + 1, mtCompiler); // TODO (gd) i'm leaking
     // Turn all '.'s into '/'s
-    for (size_t index = 0; line[index] != '\0'; index++) {
+    for (size_t index = 0; index < lineLen; ++index) {
       if (line[index] == '.') {
-        line[index] = '/';
+        implName[index] = '/';
+      } else {
+        implName[index] = line[index];
       }
     }
-    _implNames.append(line);
+    implName[lineLen] = '\0';
+    _implNames.append(implName);
   }
   GrowableArray<char*>* implNames() {return &_implNames;}
 };
@@ -1141,7 +1231,7 @@
   char sep = os::file_separator()[0];
   sprintf(path, "%s%clib%cgraal%cservices%c%s", home, sep, sep, sep, sep, serviceName);
   ServiceParseClosure closure;
-  parse_lines(path, &closure, true, THREAD);
+  parse_lines(path, &closure, true); // TODO(gd) cache parsing results?
 
   GrowableArray<char*>* implNames = closure.implNames();
   objArrayOop servicesOop = oopFactory::new_objArray(serviceKlass(), implNames->length(), CHECK_NH);
@@ -1153,5 +1243,3 @@
   }
   return services;
 }
-
-#include "graalRuntime.inline.hpp"
--- a/src/share/vm/graal/graalRuntime.hpp	Mon May 18 18:30:43 2015 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Wed May 27 17:40:26 2015 +0200
@@ -27,19 +27,23 @@
 #include "interpreter/interpreter.hpp"
 #include "memory/allocation.hpp"
 #include "runtime/deoptimization.hpp"
+#include "graal/graalOptions.hpp"
 
 class ParseClosure : public StackObj {
-protected:
   int _lineNo;
   char* _filename;
   bool _abort;
+protected:
   void abort() { _abort = true; }
   void warn_and_abort(const char* message) {
-    warning("Error at line %d while parsing %s: %s", _lineNo, _filename == NULL ? "?" : _filename, message);
+    warn(message);
     abort();
   }
+  void warn(const char* message) {
+    warning("Error at line %d while parsing %s: %s", _lineNo, _filename == NULL ? "?" : _filename, message);
+  }
  public:
-  ParseClosure() : _lineNo(0), _filename(NULL) {}
+  ParseClosure() : _lineNo(0), _filename(NULL), _abort(false) {}
   void parse_line(char* line) {
     _lineNo++;
     do_line(line);
@@ -47,86 +51,31 @@
   virtual void do_line(char* line) = 0;
   int lineNo() { return _lineNo; }
   bool is_aborted() { return _abort; }
-  void set_filename(char* path) {_filename = path; }
+  void set_filename(char* path) {_filename = path; _lineNo = 0;}
 };
 
+class GraalOptionParseClosure;
+
 class GraalRuntime: public CHeapObj<mtCompiler> {
+  friend GraalOptionParseClosure;
  private:
 
   static jobject _HotSpotGraalRuntime_instance;
   static bool _HotSpotGraalRuntime_initialized;
-  static const char* _generated_sources_sha1;
 
   static bool _shutdown_called;
 
   /**
-   * 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 option name
-   * @param name_len length of option name
-   * @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, const char* name, size_t name_len, 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);
-
-  /**
-   * Searches for a Boolean Graal option denoted by a given name and sets it value.
-   *
-   * The definition of this method is in graalRuntime.inline.hpp
-   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
-   *
-   * @param hotSpotOptionsClass the HotSpotOptions klass or NULL if only checking for valid option
-   * @param name option name
-   * @param name_len length of option name
-   * @param value '+' to set the option, '-' to reset the option
-   * @returns true if the option was found
-   * @throws InternalError if there was a problem setting the option's value
-   */
-  static bool set_option_bool(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, char value, TRAPS);
+  static void parse_graal_options_file(OptionsValueTable* options);
 
-  /**
-   * Searches for a Graal option denoted by a given name and sets it value.
-   *
-   * The definition of this method is in graalRuntime.inline.hpp
-   * which is generated by com.oracle.graal.hotspot.sourcegen.GenGraalRuntimeInlineHpp.
-   *
-   * @param hotSpotOptionsClass the HotSpotOptions klass or NULL if only checking for valid option
-   * @param name option name
-   * @param name_len length of option name
-   * @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, char* name, size_t name_len, const char* value, TRAPS);
+  static bool parse_argument(OptionsValueTable* options, const char* arg);
 
-  /**
-   * Raises an InternalError for an option that expects a value but was specified without a "=<value>" prefix.
-   */
-  static void check_required_value(const char* name, size_t name_len, const char* value, TRAPS);
-
-  /**
-   * Java call to HotSpotOptions.setOption(String name, OptionValue<?> option, char spec, String stringValue, long primitiveValue)
-   *
-   * @param name option name
-   * @param name_len length of option name
-   */
-  static void set_option_helper(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue);
-
+  static void print_flags_helper(TRAPS);
   /**
    * Instantiates a service object, calls its default constructor and returns it.
    *
@@ -134,19 +83,15 @@
    */
   static Handle create_Service(const char* name, TRAPS);
 
-  /**
-   * Checks that _generated_sources_sha1 equals GeneratedSourcesSha1.value.
-   */
-  static void check_generated_sources_sha1(TRAPS);
-
  public:
 
   /**
-   * Parses a given argument and sets the denoted Graal option.
-   *
-   * @throws InternalError if there was a problem parsing or setting the option
+   * Parses the Graal specific VM options that were presented by the launcher and sets
+   * the relevants Java fields.
    */
-  static void parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS);
+  static OptionsValueTable* parse_arguments();
+
+  static void set_options(OptionsValueTable* options, TRAPS);
 
   /**
    * Ensures that the Graal class loader is initialized and the well known Graal classes are loaded.
@@ -199,7 +144,7 @@
    */
   static Handle get_service_impls(KlassHandle serviceKlass, TRAPS);
 
-  static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure, TRAPS);
+  static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure);
 
   /**
    * Aborts the VM due to an unexpected exception.
@@ -246,20 +191,6 @@
 
   static BufferBlob* initialize_buffer_blob();
 
-  /**
-   * Checks that all Graal specific VM options presented by the launcher are recognized
-   * and formatted correctly. To set relevant Java fields from the option, parse_arguments()
-   * must be called. This method makes no Java calls apart from creating exception objects
-   * if there is an errors in the Graal options.
-   */
-  static jint check_arguments(TRAPS);
-
-  /**
-   * Parses the Graal specific VM options that were presented by the launcher and sets
-   * the relevants Java fields.
-   */
-  static bool parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS);
-
   static BasicType kindToBasicType(jchar ch);
 
   // The following routines are all called from compiled Graal code
--- a/src/share/vm/prims/nativeLookup.cpp	Mon May 18 18:30:43 2015 +0200
+++ b/src/share/vm/prims/nativeLookup.cpp	Wed May 27 17:40:26 2015 +0200
@@ -133,7 +133,7 @@
   jobject  JNICALL JVM_GetGraalServiceImpls(JNIEnv *env, jclass c, jclass serviceClass);
   jobject  JNICALL JVM_CreateTruffleRuntime(JNIEnv *env, jclass c);
   jobject  JNICALL JVM_CreateNativeFunctionInterface(JNIEnv *env, jclass c);
-  jboolean JNICALL JVM_ParseGraalOptions(JNIEnv *env, jclass hotspotOptionsClass);
+  jboolean JNICALL JVM_IsCITimingEnabled(JNIEnv *env);
 #ifdef COMPILERGRAAL
   void     JNICALL JVM_PrintAndResetGraalCompRate(JNIEnv *env, jclass c);
 #endif
@@ -155,7 +155,7 @@
   { CC"Java_com_oracle_truffle_api_Truffle_createRuntime",                                                NULL, FN_PTR(JVM_CreateTruffleRuntime)               },
   { CC"Java_com_oracle_nfi_NativeFunctionInterfaceRuntime_createInterface",                               NULL, FN_PTR(JVM_CreateNativeFunctionInterface)      },
   { CC"Java_com_oracle_graal_hotspot_bridge_CompilerToVMImpl_init",                                       NULL, FN_PTR(JVM_InitializeGraalNatives)             },
-  { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_parseVMOptions",                                      NULL, FN_PTR(JVM_ParseGraalOptions)                  },
+  { CC"Java_com_oracle_graal_hotspot_HotSpotOptions_isCITimingEnabled",                                   NULL, FN_PTR(JVM_IsCITimingEnabled)                  },
 #endif
 };
 
--- a/src/share/vm/runtime/thread.cpp	Mon May 18 18:30:43 2015 +0200
+++ b/src/share/vm/runtime/thread.cpp	Wed May 27 17:40:26 2015 +0200
@@ -3395,6 +3395,13 @@
   jint parse_result = Arguments::parse(args);
   if (parse_result != JNI_OK) return parse_result;
 
+#ifdef GRAAL
+  OptionsValueTable* options = GraalRuntime::parse_arguments();
+  if (options == NULL) {
+    return JNI_ERR;
+  }
+#endif
+
   os::init_before_ergo();
 
   jint ergo_result = Arguments::apply_ergo();
@@ -3703,11 +3710,7 @@
   }
 
 #ifdef GRAAL
-  status = GraalRuntime::check_arguments(main_thread);
-  if (status != JNI_OK) {
-    *canTryAgain = false; // don't let caller call JNI_CreateJavaVM again
-    return status;
-  }
+  GraalRuntime::set_options(options, main_thread);
 #endif
 
   // initialize compiler(s)