changeset 15870:fe608a56e3f7

made HotSpotOptions processing faster by removing use of service loader in VM startup and only doing work for options specified on the command line
author Doug Simon <doug.simon@oracle.com>
date Fri, 23 May 2014 19:36:34 +0200
parents 387b15da0f68
children 11bf5b8973c9 9b6d45071187
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptionsLoader.java mx/mx_graal.py src/share/vm/graal/graalRuntime.cpp src/share/vm/graal/graalRuntime.hpp src/share/vm/graal/graalVMToCompiler.cpp src/share/vm/graal/graalVMToCompiler.hpp src/share/vm/prims/nativeLookup.cpp
diffstat 8 files changed, 475 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri May 23 17:47:44 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java	Fri May 23 19:36:34 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	Fri May 23 19:36:34 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/mx/mx_graal.py	Fri May 23 17:47:44 2014 +0200
+++ b/mx/mx_graal.py	Fri May 23 19:36:34 2014 +0200
@@ -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/src/share/vm/graal/graalRuntime.cpp	Fri May 23 17:47:44 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Fri May 23 19:36:34 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	Fri May 23 17:47:44 2014 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Fri May 23 19:36:34 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	Fri May 23 17:47:44 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.cpp	Fri May 23 19:36:34 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	Fri May 23 17:47:44 2014 +0200
+++ b/src/share/vm/graal/graalVMToCompiler.hpp	Fri May 23 19:36:34 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	Fri May 23 17:47:44 2014 +0200
+++ b/src/share/vm/prims/nativeLookup.cpp	Fri May 23 19:36:34 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
 };