diff src/share/vm/jvmci/jvmciRuntime.cpp @ 21562:47bebae7454f

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 28 May 2015 21:58:33 +0200
parents src/share/vm/graal/graalRuntime.cpp@cecb4e39521c src/share/vm/graal/graalRuntime.cpp@be896a1983c0
children 4f63449b4422
line wrap: on
line diff
--- a/src/share/vm/jvmci/jvmciRuntime.cpp	Thu May 28 17:13:22 2015 +0200
+++ b/src/share/vm/jvmci/jvmciRuntime.cpp	Thu May 28 21:58:33 2015 +0200
@@ -37,6 +37,7 @@
 #include "runtime/arguments.hpp"
 #include "runtime/reflection.hpp"
 #include "utilities/debug.hpp"
+#include "utilities/defaultStream.hpp"
 
 	jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL;
 bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false;
@@ -625,6 +626,11 @@
   SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK);
 JVM_END
 
+// boolean com.oracle.jvmci.hotspot.HotSpotOptions.isCITimingEnabled()
+JVM_ENTRY(jboolean, JVM_IsCITimingEnabled(JNIEnv *env, jclass c))
+  return CITime || CITimeEach;
+JVM_END
+
 // private static JVMCIRuntime JVMCI.initializeRuntime()
 JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
   JVMCIRuntime::initialize_HotSpotJVMCIRuntime();
@@ -665,26 +671,9 @@
   return JNIHandles::make_local(THREAD, (oop) result.get_jobject());
 JVM_END
 
-void JVMCIRuntime::check_generated_sources_sha1(TRAPS) {
-  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/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 JVMCIRuntime::callInitializer(const char* className, const char* methodName, const char* returnType) {
   guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime");
   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,16 +714,6 @@
   JVMCIRuntime::initialize_natives(env, c2vmClass);
 JVM_END
 
-// private static OptionsParsed[] HotSpotOptions.parseVMOptions(Class)
-JVM_ENTRY(jobject, JVM_ParseJVMCIOptions(JNIEnv *env, jclass c, jobject optionsParsedClass_obj))
-  HandleMark hm;
-  KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c)));
-  JVMCIRuntime::parse_arguments(hotSpotOptionsClass, CHECK_NULL);
-  KlassHandle optionsParsedClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(optionsParsedClass_obj)));
-  return JNIHandles::make_local(THREAD, JVMCIRuntime::get_service_impls(optionsParsedClass, THREAD)());
-JVM_END
-
-
 void JVMCIRuntime::ensure_jvmci_class_loader_is_initialized() {
   // This initialization code is guarded by a static pointer to the Factory class.
   // Once it is non-null, the JVMCI class loader and well known JVMCI classes are
@@ -773,235 +752,316 @@
     *((jboolean *) addr) = (jboolean) UseJVMCIClassLoader;
     klass->initialize(CHECK_ABORT);
     _FactoryKlass = klass();
+    assert(!UseJVMCIClassLoader || SystemDictionary::jvmci_loader() != NULL, "JVMCI classloader should have been initialized");
   }
 }
 
-jint JVMCIRuntime::check_arguments(TRAPS) {
-  KlassHandle nullHandle;
-  parse_arguments(nullHandle, THREAD);
-  if (HAS_PENDING_EXCEPTION) {
-    // Errors in parsing JVMCI 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/jvmci/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* JVMCIRuntime::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 JVMCI options: %s", java_lang_String::as_utf8_string(message));
-    } else {
-      call_printStackTrace(exception, THREAD);
-    }
-    return JNI_ERR;
-  }
-  return JNI_OK;
-}
-
-void JVMCIRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) {
-  ResourceMark rm(THREAD);
+  OptionsValueTable* options = new OptionsValueTable(table);
 
   // Process option overrides from jvmci.options first
-  parse_jvmci_options_file(hotSpotOptionsClass, CHECK);
+  parse_jvmci_options_file(options);
 
   // Now process options on the command line
   int numOptions = Arguments::num_jvmci_args();
   for (int i = 0; i < numOptions; i++) {
     char* arg = Arguments::jvmci_args_array()[i];
-    parse_argument(hotSpotOptionsClass, arg, CHECK);
+    if (!parse_argument(options, arg)) {
+      delete options;
+      return NULL;
+    }
   }
+  return options;
 }
 
-void JVMCIRuntime::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 JVMCIRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) {
-  ensure_jvmci_class_loader_is_initialized();
+bool JVMCIRuntime::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 (throw_err) {
-      char buf[200];
-      jio_snprintf(buf, sizeof(buf), "Unrecognized JVMCI option %.*s", name_len, name);
-      THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
+    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;
     }
-  }
-}
-
-void JVMCIRuntime::parse_jvmci_options_file(KlassHandle hotSpotOptionsClass, TRAPS) {
-  const char* home = Arguments::get_java_home();
-  size_t path_len = strlen(home) + strlen("/lib/jvmci.options") + 1;
-  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
-  char sep = os::file_separator()[0];
-  sprintf(path, "%s%clib%cjvmci.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 " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path);
+    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;
       }
-      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;
-          }
+      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;
       }
-    } else {
-      warning("Error opening file %s due to %s", path, strerror(errno));
+      case _string: {
+        char* copy = NEW_C_HEAP_ARRAY(char, strlen(value) + 1, mtCompiler);
+        strcpy(copy, value);
+        optionValue.string_value = copy;
+        break;
+      }
+      default:
+        ShouldNotReachHere();
     }
+    options->put(optionValue);
+    return true;
   }
 }
 
-jlong JVMCIRuntime::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;
+class JVMCIOptionParseClosure : public ParseClosure {
+  OptionsValueTable* _options;
+public:
+  JVMCIOptionParseClosure(OptionsValueTable* options) : _options(options) {}
+  void do_line(char* line) {
+    if (!JVMCIRuntime::parse_argument(_options, line)) {
+      warn("There was an error parsing an argument. Skipping it.");
     }
-    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 JVMCI option %.*s", (spec == 'i' ? "numeric" : "float/double"), name_len, name);
-  } else {
-    jio_snprintf(buf, sizeof(buf), "Invalid %s value for JVMCI option %.*s: %s", (spec == 'i' ? "numeric" : "float/double"), name_len, name, value);
-  }
-  THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L);
+};
+
+void JVMCIRuntime::parse_jvmci_options_file(OptionsValueTable* options) {
+  const char* home = Arguments::get_java_home();
+  size_t path_len = strlen(home) + strlen("/lib/jvmci.options") + 1;
+  char path[JVM_MAXPATHLEN];
+  char sep = os::file_separator()[0];
+  jio_snprintf(path, JVM_MAXPATHLEN, "%s%clib%cjvmci.options", home, sep, sep);
+  JVMCIOptionParseClosure closure(options);
+  parse_lines(path, &closure, false);
 }
 
-void JVMCIRuntime::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__); \
+    JVMCIRuntime::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 = JVMCIRuntime::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 JVMCIRuntime::set_options(OptionsValueTable* options, TRAPS) {
+  ensure_jvmci_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/jvmci/options/OptionValue;CLjava/lang/String;J)V", CHECK);
+void JVMCIRuntime::print_flags_helper(TRAPS) {
+  // TODO(gd) write this in C++?
+  HandleMark hm(THREAD);
+  TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/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 JVMCIRuntime::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 JVMCIRuntime::create_Service(const char* name, TRAPS) {
@@ -1076,19 +1136,12 @@
   return klass;
 }
 
-Handle JVMCIRuntime::get_service_impls(KlassHandle serviceKlass, TRAPS) {
-  const char* home = Arguments::get_java_home();
-  const char* serviceName = serviceKlass->external_name();
-
-  size_t path_len = strlen(home) + strlen("/lib/jvmci/services/") + strlen(serviceName) + 1;
-  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
-  char sep = os::file_separator()[0];
-  sprintf(path, "%s%clib%cjvmci%cservices%c%s", home, sep, sep, sep, sep, serviceName);
+void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) {
   struct stat st;
-  if (os::stat(path, &st) == 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_RESOURCE_ARRAY_IN_THREAD(THREAD, char, st.st_size + 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));
@@ -1096,11 +1149,12 @@
         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';
-        GrowableArray<char*>* implNames = new GrowableArray<char*>();
+
         char* line = buffer;
-        while (line - buffer < num_read) {
+        while (line - buffer < num_read && !closure->is_aborted()) {
           // find line end (\r, \n or \r\n)
           char* nextline = NULL;
           char* cr = strchr(line, '\r');
@@ -1128,13 +1182,7 @@
           *end = '\0';
           // skip comments and empty lines
           if (*line != '#' && strlen(line) > 0) {
-            // Turn all '.'s into '/'s
-            for (size_t index = 0; line[index] != '\0'; index++) {
-              if (line[index] == '.') {
-                line[index] = '/';
-              }
-            }
-            implNames->append(line);
+            closure->parse_line(line);
           }
           if (nextline != NULL) {
             line = nextline;
@@ -1143,23 +1191,55 @@
             break;
           }
         }
-
-        objArrayOop servicesOop = oopFactory::new_objArray(serviceKlass(), implNames->length(), CHECK_NH);
-        objArrayHandle services(THREAD, servicesOop);
-        for (int i = 0; i < implNames->length(); ++i) {
-          char* implName = implNames->at(i);
-          Handle service = create_Service(implName, CHECK_NH);
-          services->obj_at_put(i, service());
-        }
-        return services;
       }
+      FREE_C_HEAP_ARRAY(char, buffer, mtInternal);
     } else {
       warning("Error opening file %s due to %s", path, strerror(errno));
     }
-  } 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));
   }
-  return Handle();
 }
 
-#include "graalRuntime.inline.hpp"
+class ServiceParseClosure : public ParseClosure {
+  GrowableArray<char*> _implNames;
+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; index < lineLen; ++index) {
+      if (line[index] == '.') {
+        implName[index] = '/';
+      } else {
+        implName[index] = line[index];
+      }
+    }
+    implName[lineLen] = '\0';
+    _implNames.append(implName);
+  }
+  GrowableArray<char*>* implNames() {return &_implNames;}
+};
+
+
+Handle JVMCIRuntime::get_service_impls(KlassHandle serviceKlass, TRAPS) {
+  const char* home = Arguments::get_java_home();
+  const char* serviceName = serviceKlass->external_name();
+  size_t path_len = strlen(home) + strlen("/lib/jvmci/services/") + strlen(serviceName) + 1;
+  char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len);
+  char sep = os::file_separator()[0];
+  sprintf(path, "%s%clib%cjvmci%cservices%c%s", home, sep, sep, sep, sep, serviceName);
+  ServiceParseClosure closure;
+  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);
+  objArrayHandle services(THREAD, servicesOop);
+  for (int i = 0; i < implNames->length(); ++i) {
+    char* implName = implNames->at(i);
+    Handle service = create_Service(implName, CHECK_NH);
+    services->obj_at_put(i, service());
+  }
+  return services;
+}