changeset 242:d95b224e9f17

6721093: -XX:AppendRatio=N not supported Summary: Add mechanism to ignore unsupported flags for a set period of time Reviewed-by: acorn, never, coleenp
author kamg
date Mon, 28 Jul 2008 14:07:44 -0400
parents 1fdb98a17101
children 4395df5b73d3 6f17a7c9f8b4
files src/os/linux/vm/os_linux.cpp src/os/solaris/vm/os_solaris.cpp src/os/windows/vm/os_windows.cpp src/share/vm/classfile/javaClasses.cpp src/share/vm/includeDB_core src/share/vm/memory/universe.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/arguments.hpp src/share/vm/runtime/init.cpp src/share/vm/runtime/java.cpp src/share/vm/runtime/java.hpp src/share/vm/runtime/os.cpp src/share/vm/runtime/os.hpp src/share/vm/runtime/thread.cpp src/share/vm/runtime/threadLocalStorage.cpp src/share/vm/runtime/threadLocalStorage.hpp src/share/vm/runtime/vmStructs.cpp src/share/vm/services/threadService.cpp
diffstat 18 files changed, 431 insertions(+), 157 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/linux/vm/os_linux.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/os/linux/vm/os_linux.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -94,6 +94,9 @@
 static int SR_signum = SIGUSR2;
 sigset_t SR_sigset;
 
+/* Used to protect dlsym() calls */
+static pthread_mutex_t dl_mutex;
+
 ////////////////////////////////////////////////////////////////////////////////
 // utility functions
 
@@ -1493,6 +1496,24 @@
 
 const char* os::get_temp_directory() { return "/tmp/"; }
 
+void os::dll_build_name(
+    char* buffer, size_t buflen, const char* pname, const char* fname) {
+  // copied from libhpi
+  const size_t pnamelen = pname ? strlen(pname) : 0;
+
+  /* Quietly truncate on buffer overflow.  Should be an error. */
+  if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
+      *buffer = '\0';
+      return;
+  }
+
+  if (pnamelen == 0) {
+      sprintf(buffer, "lib%s.so", fname);
+  } else {
+      sprintf(buffer, "%s/lib%s.so", pname, fname);
+  }
+}
+
 const char* os::get_current_directory(char *buf, int buflen) {
   return getcwd(buf, buflen);
 }
@@ -1742,7 +1763,17 @@
   return NULL;
 }
 
-
+/*
+ * glibc-2.0 libdl is not MT safe.  If you are building with any glibc,
+ * chances are you might want to run the generated bits against glibc-2.0
+ * libdl.so, so always use locking for any version of glibc.
+ */
+void* os::dll_lookup(void* handle, const char* name) {
+  pthread_mutex_lock(&dl_mutex);
+  void* res = dlsym(handle, name);
+  pthread_mutex_unlock(&dl_mutex);
+  return res;
+}
 
 
 bool _print_ascii_file(const char* filename, outputStream* st) {
@@ -3581,6 +3612,7 @@
 
   Linux::clock_init();
   initial_time_count = os::elapsed_counter();
+  pthread_mutex_init(&dl_mutex, NULL);
 }
 
 // To install functions for atexit system call
--- a/src/os/solaris/vm/os_solaris.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/os/solaris/vm/os_solaris.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -1783,6 +1783,24 @@
 
 const char* os::get_temp_directory() { return "/tmp/"; }
 
+void os::dll_build_name(
+    char* buffer, size_t buflen, const char* pname, const char* fname) {
+  // copied from libhpi
+  const size_t pnamelen = pname ? strlen(pname) : 0;
+
+  /* Quietly truncate on buffer overflow.  Should be an error. */
+  if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
+      *buffer = '\0';
+      return;
+  }
+
+  if (pnamelen == 0) {
+      sprintf(buffer, "lib%s.so", fname);
+  } else {
+      sprintf(buffer, "%s/lib%s.so", pname, fname);
+  }
+}
+
 const char* os::get_current_directory(char *buf, int buflen) {
   return getcwd(buf, buflen);
 }
@@ -2034,6 +2052,9 @@
   return NULL;
 }
 
+void* os::dll_lookup(void* handle, const char* name) {
+  return dlsym(handle, name);
+}
 
 
 bool _print_ascii_file(const char* filename, outputStream* st) {
--- a/src/os/windows/vm/os_windows.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/os/windows/vm/os_windows.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -985,6 +985,28 @@
     }
 }
 
+void os::dll_build_name(char *holder, size_t holderlen,
+                        const char* pname, const char* fname)
+{
+    // copied from libhpi
+    const size_t pnamelen = pname ? strlen(pname) : 0;
+    const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
+
+    /* Quietly truncates on buffer overflow. Should be an error. */
+    if (pnamelen + strlen(fname) + 10 > holderlen) {
+        *holder = '\0';
+        return;
+    }
+
+    if (pnamelen == 0) {
+        sprintf(holder, "%s.dll", fname);
+    } else if (c == ':' || c == '\\') {
+        sprintf(holder, "%s%s.dll", pname, fname);
+    } else {
+        sprintf(holder, "%s\\%s.dll", pname, fname);
+    }
+}
+
 // Needs to be in os specific directory because windows requires another
 // header file <direct.h>
 const char* os::get_current_directory(char *buf, int buflen) {
@@ -1248,6 +1270,10 @@
   return false;
 }
 
+void* os::dll_lookup(void* handle, const char* name) {
+  return GetProcAddress((HMODULE)handle, name);
+}
+
 // save the start and end address of jvm.dll into param[0] and param[1]
 static int _locate_jvm_dll(int pid, char* mod_fname, address base_addr,
                     unsigned size, void * param) {
--- a/src/share/vm/classfile/javaClasses.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/classfile/javaClasses.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -649,8 +649,8 @@
 }
 
 oop java_lang_Thread::park_blocker(oop java_thread) {
-  assert(JDK_Version::supports_thread_park_blocker() && _park_blocker_offset != 0,
-         "Must support parkBlocker field");
+  assert(JDK_Version::current().supports_thread_park_blocker() &&
+         _park_blocker_offset != 0, "Must support parkBlocker field");
 
   if (_park_blocker_offset > 0) {
     return java_thread->obj_field(_park_blocker_offset);
--- a/src/share/vm/includeDB_core	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/includeDB_core	Mon Jul 28 14:07:44 2008 -0400
@@ -178,6 +178,7 @@
 arguments.cpp                           universe.inline.hpp
 arguments.cpp                           vm_version_<arch_model>.hpp
 
+arguments.hpp                           java.hpp
 arguments.hpp                           perfData.hpp
 arguments.hpp                           top.hpp
 
--- a/src/share/vm/memory/universe.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/memory/universe.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -367,26 +367,31 @@
   // Only 1.3 or later has the java.lang.Shutdown class.
   // Only 1.4 or later has the java.lang.CharSequence interface.
   // Only 1.5 or later has the java.lang.management.MemoryUsage class.
-  if (JDK_Version::is_pre_jdk16_version()) {
-    klassOop k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
+  if (JDK_Version::is_partially_initialized()) {
+    uint8_t jdk_version;
+    klassOop k = SystemDictionary::resolve_or_null(
+        vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
     CLEAR_PENDING_EXCEPTION; // ignore exceptions
     if (k == NULL) {
-      k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_CharSequence(), THREAD);
+      k = SystemDictionary::resolve_or_null(
+          vmSymbolHandles::java_lang_CharSequence(), THREAD);
       CLEAR_PENDING_EXCEPTION; // ignore exceptions
       if (k == NULL) {
-        k = SystemDictionary::resolve_or_null(vmSymbolHandles::java_lang_Shutdown(), THREAD);
+        k = SystemDictionary::resolve_or_null(
+            vmSymbolHandles::java_lang_Shutdown(), THREAD);
         CLEAR_PENDING_EXCEPTION; // ignore exceptions
         if (k == NULL) {
-          JDK_Version::set_jdk12x_version();
+          jdk_version = 2;
         } else {
-          JDK_Version::set_jdk13x_version();
+          jdk_version = 3;
         }
       } else {
-          JDK_Version::set_jdk14x_version();
+        jdk_version = 4;
       }
     } else {
-          JDK_Version::set_jdk15x_version();
+      jdk_version = 5;
     }
+    JDK_Version::fully_initialize(jdk_version);
   }
 
   #ifdef ASSERT
--- a/src/share/vm/runtime/arguments.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/arguments.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -153,37 +153,56 @@
   os::init_system_properties_values();
 }
 
-// String containing commands that will be ignored and cause a
-// warning to be issued.  These commands should be accepted
-// for 1.6 but not 1.7.  The string should be cleared at the
-// beginning of 1.7.
-static const char*  obsolete_jvm_flags_1_5_0[] = {
-                                           "UseTrainGC",
-                                           "UseSpecialLargeObjectHandling",
-                                           "UseOversizedCarHandling",
-                                           "TraceCarAllocation",
-                                           "PrintTrainGCProcessingStats",
-                                           "LogOfCarSpaceSize",
-                                           "OversizedCarThreshold",
-                                           "MinTickInterval",
-                                           "DefaultTickInterval",
-                                           "MaxTickInterval",
-                                           "DelayTickAdjustment",
-                                           "ProcessingToTenuringRatio",
-                                           "MinTrainLength",
-                                           0};
+/**
+ * Provide a slightly more user-friendly way of eliminating -XX flags.
+ * When a flag is eliminated, it can be added to this list in order to
+ * continue accepting this flag on the command-line, while issuing a warning
+ * and ignoring the value.  Once the JDK version reaches the 'accept_until'
+ * limit, we flatly refuse to admit the existence of the flag.  This allows
+ * a flag to die correctly over JDK releases using HSX.
+ */
+typedef struct {
+  const char* name;
+  JDK_Version obsoleted_in; // when the flag went away
+  JDK_Version accept_until; // which version to start denying the existence
+} ObsoleteFlag;
 
-bool Arguments::made_obsolete_in_1_5_0(const char *s) {
+static ObsoleteFlag obsolete_jvm_flags[] = {
+  { "UseTrainGC",                    JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "UseSpecialLargeObjectHandling", JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "UseOversizedCarHandling",       JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "TraceCarAllocation",            JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "PrintTrainGCProcessingStats",   JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "LogOfCarSpaceSize",             JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "OversizedCarThreshold",         JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MinTickInterval",               JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "DefaultTickInterval",           JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MaxTickInterval",               JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "DelayTickAdjustment",           JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "ProcessingToTenuringRatio",     JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "MinTrainLength",                JDK_Version::jdk(5), JDK_Version::jdk(7) },
+  { "AppendRatio",         JDK_Version::jdk_update(6,10), JDK_Version::jdk(7) },
+  { NULL, JDK_Version(0), JDK_Version(0) }
+};
+
+// Returns true if the flag is obsolete and fits into the range specified
+// for being ignored.  In the case that the flag is ignored, the 'version'
+// value is filled in with the version number when the flag became
+// obsolete so that that value can be displayed to the user.
+bool Arguments::is_newly_obsolete(const char *s, JDK_Version* version) {
   int i = 0;
-  while (obsolete_jvm_flags_1_5_0[i] != NULL) {
+  assert(version != NULL, "Must provide a version buffer");
+  while (obsolete_jvm_flags[i].name != NULL) {
+    const ObsoleteFlag& flag_status = obsolete_jvm_flags[i];
     // <flag>=xxx form
     // [-|+]<flag> form
-    if ((strncmp(obsolete_jvm_flags_1_5_0[i], s,
-               strlen(obsolete_jvm_flags_1_5_0[i])) == 0) ||
+    if ((strncmp(flag_status.name, s, strlen(flag_status.name)) == 0) ||
         ((s[0] == '+' || s[0] == '-') &&
-        (strncmp(obsolete_jvm_flags_1_5_0[i], &s[1],
-               strlen(obsolete_jvm_flags_1_5_0[i])) == 0))) {
-      return true;
+        (strncmp(flag_status.name, &s[1], strlen(flag_status.name)) == 0))) {
+      if (JDK_Version::current().compare(flag_status.accept_until) == -1) {
+          *version = flag_status.obsoleted_in;
+          return true;
+      }
     }
     i++;
   }
@@ -705,14 +724,20 @@
   }
 }
 
-bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, FlagValueOrigin origin) {
+bool Arguments::process_argument(const char* arg,
+    jboolean ignore_unrecognized, FlagValueOrigin origin) {
+
+  JDK_Version since = JDK_Version();
 
   if (parse_argument(arg, origin)) {
     // do nothing
-  } else if (made_obsolete_in_1_5_0(arg)) {
+  } else if (is_newly_obsolete(arg, &since)) {
+    enum { bufsize = 256 };
+    char buffer[bufsize];
+    since.to_string(buffer, bufsize);
     jio_fprintf(defaultStream::error_stream(),
-      "Warning: The flag %s has been EOL'd as of 1.5.0 and will"
-      " be ignored\n", arg);
+      "Warning: The flag %s has been EOL'd as of %s and will"
+      " be ignored\n", arg, buffer);
   } else {
     if (!ignore_unrecognized) {
       jio_fprintf(defaultStream::error_stream(),
--- a/src/share/vm/runtime/arguments.hpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/arguments.hpp	Mon Jul 28 14:07:44 2008 -0400
@@ -357,9 +357,11 @@
     short* methodsNum, short* methodsMax, char*** methods, bool** allClasses
   );
 
-  // Returns true if the string s is in the list of
-  // flags made obsolete in 1.5.0.
-  static bool made_obsolete_in_1_5_0(const char* s);
+  // Returns true if the string s is in the list of flags that have recently
+  // been made obsolete.  If we detect one of these flags on the command
+  // line, instead of failing we print a warning message and ignore the
+  // flag.  This gives the user a release or so to stop using the flag.
+  static bool is_newly_obsolete(const char* s, JDK_Version* buffer);
 
   static short  CompileOnlyClassesNum;
   static short  CompileOnlyClassesMax;
--- a/src/share/vm/runtime/init.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/init.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -39,7 +39,6 @@
 void classLoader_init();
 void codeCache_init();
 void VM_Version_init();
-void JDK_Version_init();
 void stubRoutines_init1();
 jint universe_init();  // dependent on codeCache_init and stubRoutines_init
 void interpreter_init();  // before any methods loaded
@@ -88,7 +87,6 @@
   classLoader_init();
   codeCache_init();
   VM_Version_init();
-  JDK_Version_init();
   stubRoutines_init1();
   jint status = universe_init();  // dependent on codeCache_init and stubRoutines_init
   if (status != JNI_OK)
--- a/src/share/vm/runtime/java.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/java.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -563,32 +563,104 @@
   vm_shutdown();
 }
 
-jdk_version_info JDK_Version::_version_info = {0};
-bool JDK_Version::_pre_jdk16_version = false;
-int  JDK_Version::_jdk_version = 0;
+JDK_Version JDK_Version::_current;
 
 void JDK_Version::initialize() {
+  jdk_version_info info;
+  assert(!_current.is_valid(), "Don't initialize twice");
+
   void *lib_handle = os::native_java_library();
-  jdk_version_info_fn_t func =
-    CAST_TO_FN_PTR(jdk_version_info_fn_t, hpi::dll_lookup(lib_handle, "JDK_GetVersionInfo0"));
+  jdk_version_info_fn_t func = CAST_TO_FN_PTR(jdk_version_info_fn_t,
+     os::dll_lookup(lib_handle, "JDK_GetVersionInfo0"));
 
   if (func == NULL) {
     // JDK older than 1.6
-    _pre_jdk16_version = true;
-    return;
+    _current._partially_initialized = true;
+  } else {
+    (*func)(&info, sizeof(info));
+
+    int major = JDK_VERSION_MAJOR(info.jdk_version);
+    int minor = JDK_VERSION_MINOR(info.jdk_version);
+    int micro = JDK_VERSION_MICRO(info.jdk_version);
+    int build = JDK_VERSION_BUILD(info.jdk_version);
+    if (major == 1 && minor > 4) {
+      // We represent "1.5.0" as "5.0", but 1.4.2 as itself.
+      major = minor;
+      minor = micro;
+      micro = 0;
+    }
+    _current = JDK_Version(major, minor, micro, info.update_version,
+                           info.special_update_version, build,
+                           info.thread_park_blocker == 1);
   }
+}
 
-  if (func != NULL) {
-    (*func)(&_version_info, sizeof(_version_info));
+void JDK_Version::fully_initialize(
+    uint8_t major, uint8_t minor, uint8_t micro, uint8_t update) {
+  // This is only called when current is less than 1.6 and we've gotten
+  // far enough in the initialization to determine the exact version.
+  assert(major < 6, "not needed for JDK version >= 6");
+  assert(is_partially_initialized(), "must not initialize");
+  if (major < 5) {
+    // JDK verison sequence: 1.2.x, 1.3.x, 1.4.x, 5.0.x, 6.0.x, etc.
+    micro = minor;
+    minor = major;
+    major = 1;
   }
-  if (jdk_major_version() == 1) {
-    _jdk_version = jdk_minor_version();
-  } else {
-    // If the release version string is changed to n.x.x (e.g. 7.0.0) in a future release
-    _jdk_version = jdk_major_version();
-  }
+  _current = JDK_Version(major, minor, micro, update);
 }
 
 void JDK_Version_init() {
   JDK_Version::initialize();
 }
+
+static int64_t encode_jdk_version(const JDK_Version& v) {
+  return
+    ((int64_t)v.major_version()          << (BitsPerByte * 5)) |
+    ((int64_t)v.minor_version()          << (BitsPerByte * 4)) |
+    ((int64_t)v.micro_version()          << (BitsPerByte * 3)) |
+    ((int64_t)v.update_version()         << (BitsPerByte * 2)) |
+    ((int64_t)v.special_update_version() << (BitsPerByte * 1)) |
+    ((int64_t)v.build_number()           << (BitsPerByte * 0));
+}
+
+int JDK_Version::compare(const JDK_Version& other) const {
+  assert(is_valid() && other.is_valid(), "Invalid version (uninitialized?)");
+  if (!is_partially_initialized() && other.is_partially_initialized()) {
+    return -(other.compare(*this)); // flip the comparators
+  }
+  assert(!other.is_partially_initialized(), "Not initialized yet");
+  if (is_partially_initialized()) {
+    assert(other.major_version() >= 6,
+           "Invalid JDK version comparison during initialization");
+    return -1;
+  } else {
+    uint64_t e = encode_jdk_version(*this);
+    uint64_t o = encode_jdk_version(other);
+    return (e > o) ? 1 : ((e == o) ? 0 : -1);
+  }
+}
+
+void JDK_Version::to_string(char* buffer, size_t buflen) const {
+  size_t index = 0;
+  if (!is_valid()) {
+    jio_snprintf(buffer, buflen, "%s", "(uninitialized)");
+  } else if (is_partially_initialized()) {
+    jio_snprintf(buffer, buflen, "%s", "(uninitialized) pre-1.6.0");
+  } else {
+    index += jio_snprintf(
+        &buffer[index], buflen - index, "%d.%d", _major, _minor);
+    if (_micro > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, ".%d", _micro);
+    }
+    if (_update > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "_%02d", _update);
+    }
+    if (_special > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "%c", _special);
+    }
+    if (_build > 0) {
+      index += jio_snprintf(&buffer[index], buflen - index, "-b%02d", _build);
+    }
+  }
+}
--- a/src/share/vm/runtime/java.hpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/java.hpp	Mon Jul 28 14:07:44 2008 -0400
@@ -48,100 +48,163 @@
 extern void vm_exit_during_initialization(const char* error, const char* message = NULL);
 extern void vm_shutdown_during_initialization(const char* error, const char* message = NULL);
 
-class JDK_Version : AllStatic {
+/**
+ * Discovering the JDK_Version during initialization is tricky when the
+ * running JDK is less than JDK6.  For JDK6 and greater, a "GetVersion"
+ * function exists in libjava.so and we simply call it during the
+ * 'initialize()' call to find the version.  For JDKs with version < 6, no
+ * such call exists and we have to probe the JDK in order to determine
+ * the exact version.  This probing cannot happen during late in
+ * the VM initialization process so there's a period of time during
+ * initialization when we don't know anything about the JDK version other than
+ * that it less than version 6.  This is the "partially initialized" time,
+ * when we can answer only certain version queries (such as, is the JDK
+ * version greater than 5?  Answer: no).  Once the JDK probing occurs, we
+ * know the version and are considered fully initialized.
+ */
+class JDK_Version VALUE_OBJ_CLASS_SPEC {
   friend class VMStructs;
+  friend class Universe;
+  friend void JDK_Version_init();
  private:
-  static jdk_version_info _version_info;
-  static bool             _pre_jdk16_version;
-  static int              _jdk_version;  // JDK version number representing the release
-                                         //  i.e. n in 1.n.x (= jdk_minor_version())
+
+  static JDK_Version _current;
+
+  // In this class, we promote the minor version of release to be the
+  // major version for releases >= 5 in anticipation of the JDK doing the
+  // same thing.  For example, we represent "1.5.0" as major version 5 (we
+  // drop the leading 1 and use 5 as the 'major').
+
+  uint8_t _major;
+  uint8_t _minor;
+  uint8_t _micro;
+  uint8_t _update;
+  uint8_t _special;
+  uint8_t _build;
+
+  // If partially initialized, the above fields are invalid and we know
+  // that we're less than major version 6.
+  bool _partially_initialized;
+
+  bool _thread_park_blocker;
+
+  bool is_valid() const {
+    return (_major != 0 || _partially_initialized);
+  }
+
+  // initializes or partially initializes the _current static field
+  static void initialize();
+
+  // Completes initialization for a pre-JDK6 version.
+  static void fully_initialize(uint8_t major, uint8_t minor = 0,
+                               uint8_t micro = 0, uint8_t update = 0);
 
  public:
-  static void initialize();
-  static int  jdk_major_version() { return JDK_VERSION_MAJOR(_version_info.jdk_version); }
-  static int  jdk_minor_version() { return JDK_VERSION_MINOR(_version_info.jdk_version); }
-  static int  jdk_micro_version() { return JDK_VERSION_MICRO(_version_info.jdk_version); }
-  static int  jdk_build_number()  { return JDK_VERSION_BUILD(_version_info.jdk_version); }
 
-  static bool is_pre_jdk16_version()        { return _pre_jdk16_version; }
-  static bool is_jdk12x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 2; }
-  static bool is_jdk13x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 3; }
-  static bool is_jdk14x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 4; }
-  static bool is_jdk15x_version()           { assert(is_jdk_version_initialized(), "must have been initialized"); return _jdk_version == 5; }
+  // Returns true if the the current version has only been partially initialized
+  static bool is_partially_initialized() {
+    return _current._partially_initialized;
+  }
 
-  static bool is_jdk16x_version() {
-    if (is_jdk_version_initialized()) {
-      return _jdk_version == 6;
+  JDK_Version() : _major(0), _minor(0), _micro(0), _update(0),
+                  _special(0), _build(0), _partially_initialized(false),
+                  _thread_park_blocker(false) {}
+
+  JDK_Version(uint8_t major, uint8_t minor = 0, uint8_t micro = 0,
+              uint8_t update = 0, uint8_t special = 0, uint8_t build = 0,
+              bool thread_park_blocker = false) :
+      _major(major), _minor(minor), _micro(micro), _update(update),
+      _special(special), _build(build), _partially_initialized(false),
+      _thread_park_blocker(thread_park_blocker) {}
+
+  // Returns the current running JDK version
+  static JDK_Version current() { return _current; }
+
+  // Factory methods for convenience
+  static JDK_Version jdk(uint8_t m) {
+    return JDK_Version(m);
+  }
+
+  static JDK_Version jdk_update(uint8_t major, uint8_t update_number) {
+    return JDK_Version(major, 0, 0, update_number);
+  }
+
+  uint8_t major_version() const          { return _major; }
+  uint8_t minor_version() const          { return _minor; }
+  uint8_t micro_version() const          { return _micro; }
+  uint8_t update_version() const         { return _update; }
+  uint8_t special_update_version() const { return _special; }
+  uint8_t build_number() const           { return _build; }
+
+  bool supports_thread_park_blocker() const {
+    return _thread_park_blocker;
+  }
+
+  // Performs a full ordering comparison using all fields (update, build, etc.)
+  int compare(const JDK_Version& other) const;
+
+  /**
+   * Performs comparison using only the major version, returning negative
+   * if the major version of 'this' is less than the parameter, 0 if it is
+   * equal, and a positive value if it is greater.
+   */
+  int compare_major(int version) const {
+    if (_partially_initialized) {
+      if (version >= 6) {
+        return -1;
+      } else {
+        assert(false, "Can't make this comparison during init time");
+        return -1; // conservative
+      }
     } else {
-      assert(is_pre_jdk16_version(), "must have been initialized");
-      return false;
+      return major_version() - version;
     }
   }
 
-  static bool is_jdk17x_version() {
-    if (is_jdk_version_initialized()) {
-      return _jdk_version == 7;
-    } else {
-      assert(is_pre_jdk16_version(), "must have been initialized");
-      return false;
-    }
+  void to_string(char* buffer, size_t buflen) const;
+
+  // Convenience methods for queries on the current major/minor version
+  static bool is_jdk12x_version() {
+    return current().compare_major(2) == 0;
   }
 
-  static bool supports_thread_park_blocker() { return _version_info.thread_park_blocker; }
+  static bool is_jdk13x_version() {
+    return current().compare_major(3) == 0;
+  }
+
+  static bool is_jdk14x_version() {
+    return current().compare_major(4) == 0;
+  }
+
+  static bool is_jdk15x_version() {
+    return current().compare_major(5) == 0;
+  }
+
+  static bool is_jdk16x_version() {
+    return current().compare_major(6) == 0;
+  }
+
+  static bool is_jdk17x_version() {
+    return current().compare_major(7) == 0;
+  }
+
+  static bool is_gte_jdk13x_version() {
+    return current().compare_major(3) >= 0;
+  }
 
   static bool is_gte_jdk14x_version() {
-    // Keep the semantics of this that the version number is >= 1.4
-    assert(is_jdk_version_initialized(), "Not initialized");
-    return _jdk_version >= 4;
+    return current().compare_major(4) >= 0;
   }
+
   static bool is_gte_jdk15x_version() {
-    // Keep the semantics of this that the version number is >= 1.5
-    assert(is_jdk_version_initialized(), "Not initialized");
-    return _jdk_version >= 5;
+    return current().compare_major(5) >= 0;
   }
+
   static bool is_gte_jdk16x_version() {
-    // Keep the semantics of this that the version number is >= 1.6
-    if (is_jdk_version_initialized()) {
-      return _jdk_version >= 6;
-    } else {
-      assert(is_pre_jdk16_version(), "Not initialized");
-      return false;
-    }
+    return current().compare_major(6) >= 0;
   }
 
   static bool is_gte_jdk17x_version() {
-    // Keep the semantics of this that the version number is >= 1.7
-    if (is_jdk_version_initialized()) {
-      return _jdk_version >= 7;
-    } else {
-      assert(is_pre_jdk16_version(), "Not initialized");
-      return false;
-    }
-  }
-
-  static bool is_jdk_version_initialized() {
-    return _jdk_version > 0;
-  }
-
-  // These methods are defined to deal with pre JDK 1.6 versions
-  static void set_jdk12x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 2;
-    _version_info.jdk_version = (1 << 24) | (2 << 16);
-  }
-  static void set_jdk13x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 3;
-    _version_info.jdk_version = (1 << 24) | (3 << 16);
-  }
-  static void set_jdk14x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 4;
-    _version_info.jdk_version = (1 << 24) | (4 << 16);
-  }
-  static void set_jdk15x_version() {
-    assert(_pre_jdk16_version && !is_jdk_version_initialized(), "must not initialize");
-    _jdk_version = 5;
-    _version_info.jdk_version = (1 << 24) | (5 << 16);
+    return current().compare_major(7) >= 0;
   }
 };
--- a/src/share/vm/runtime/os.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/os.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -336,29 +336,38 @@
     char buffer[JVM_MAXPATHLEN];
     char ebuf[1024];
 
-    // Try to load verify dll first. In 1.3 java dll depends on it and is not always
-    // able to find it when the loading executable is outside the JDK.
+    // Try to load verify dll first. In 1.3 java dll depends on it and is not
+    // always able to find it when the loading executable is outside the JDK.
     // In order to keep working with 1.2 we ignore any loading errors.
-    hpi::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "verify");
-    hpi::dll_load(buffer, ebuf, sizeof(ebuf));
+    dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "verify");
+    dll_load(buffer, ebuf, sizeof(ebuf));
 
     // Load java dll
-    hpi::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "java");
-    _native_java_library = hpi::dll_load(buffer, ebuf, sizeof(ebuf));
+    dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(), "java");
+    _native_java_library = dll_load(buffer, ebuf, sizeof(ebuf));
     if (_native_java_library == NULL) {
       vm_exit_during_initialization("Unable to load native library", ebuf);
     }
-    // The JNI_OnLoad handling is normally done by method load in java.lang.ClassLoader$NativeLibrary,
-    // but the VM loads the base library explicitly so we have to check for JNI_OnLoad as well
-    const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
-    JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(JNI_OnLoad_t, hpi::dll_lookup(_native_java_library, onLoadSymbols[0]));
-    if (JNI_OnLoad != NULL) {
-      JavaThread* thread = JavaThread::current();
-      ThreadToNativeFromVM ttn(thread);
-      HandleMark hm(thread);
-      jint ver = (*JNI_OnLoad)(&main_vm, NULL);
-      if (!Threads::is_supported_jni_version_including_1_1(ver)) {
-        vm_exit_during_initialization("Unsupported JNI version");
+  }
+  static jboolean onLoaded = JNI_FALSE;
+  if (onLoaded) {
+    // We may have to wait to fire OnLoad until TLS is initialized.
+    if (ThreadLocalStorage::is_initialized()) {
+      // The JNI_OnLoad handling is normally done by method load in
+      // java.lang.ClassLoader$NativeLibrary, but the VM loads the base library
+      // explicitly so we have to check for JNI_OnLoad as well
+      const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
+      JNI_OnLoad_t JNI_OnLoad = CAST_TO_FN_PTR(
+          JNI_OnLoad_t, dll_lookup(_native_java_library, onLoadSymbols[0]));
+      if (JNI_OnLoad != NULL) {
+        JavaThread* thread = JavaThread::current();
+        ThreadToNativeFromVM ttn(thread);
+        HandleMark hm(thread);
+        jint ver = (*JNI_OnLoad)(&main_vm, NULL);
+        onLoaded = JNI_TRUE;
+        if (!Threads::is_supported_jni_version_including_1_1(ver)) {
+          vm_exit_during_initialization("Unsupported JNI version");
+        }
       }
     }
   }
--- a/src/share/vm/runtime/os.hpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/os.hpp	Mon Jul 28 14:07:44 2008 -0400
@@ -390,6 +390,10 @@
   static const char*    get_temp_directory();
   static const char*    get_current_directory(char *buf, int buflen);
 
+  // Builds a platform-specific full library path given a ld path and lib name
+  static void           dll_build_name(char* buffer, size_t size,
+                                       const char* pathname, const char* fname);
+
   // Symbol lookup, find nearest function name; basically it implements
   // dladdr() for all platforms. Name of the nearest function is copied
   // to buf. Distance from its base address is returned as offset.
@@ -413,6 +417,9 @@
   // same architecture as Hotspot is running on
   static void* dll_load(const char *name, char *ebuf, int ebuflen);
 
+  // lookup symbol in a shared library
+  static void* dll_lookup(void* handle, const char* name);
+
   // Print out system information; they are called by fatal error handler.
   // Output format may be different on different platforms.
   static void print_os_info(outputStream* st);
--- a/src/share/vm/runtime/thread.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/thread.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -2578,7 +2578,8 @@
 oop JavaThread::current_park_blocker() {
   // Support for JSR-166 locks
   oop thread_oop = threadObj();
-  if (thread_oop != NULL && JDK_Version::supports_thread_park_blocker()) {
+  if (thread_oop != NULL &&
+      JDK_Version::current().supports_thread_park_blocker()) {
     return java_lang_Thread::park_blocker(thread_oop);
   }
   return NULL;
@@ -2761,6 +2762,8 @@
 
 jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
 
+  extern void JDK_Version_init();
+
   // Check version
   if (!is_supported_jni_version(args->version)) return JNI_EVERSION;
 
@@ -2776,6 +2779,9 @@
   // Initialize system properties.
   Arguments::init_system_properties();
 
+  // So that JDK version can be used as a discrimintor when parsing arguments
+  JDK_Version_init();
+
   // Parse arguments
   jint parse_result = Arguments::parse(args);
   if (parse_result != JNI_OK) return parse_result;
--- a/src/share/vm/runtime/threadLocalStorage.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/threadLocalStorage.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -42,8 +42,13 @@
 }
 
 void ThreadLocalStorage::init() {
-  assert(ThreadLocalStorage::thread_index() == -1, "More than one attempt to initialize threadLocalStorage");
+  assert(!is_initialized(),
+         "More than one attempt to initialize threadLocalStorage");
   pd_init();
   set_thread_index(os::allocate_thread_local_storage());
   generate_code_for_get_thread();
 }
+
+bool ThreadLocalStorage::is_initialized() {
+    return (thread_index() != -1);
+}
--- a/src/share/vm/runtime/threadLocalStorage.hpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/threadLocalStorage.hpp	Mon Jul 28 14:07:44 2008 -0400
@@ -47,6 +47,7 @@
   // Initialization
   // Called explicitly from VMThread::activate_system instead of init_globals.
   static void init();
+  static bool is_initialized();
 
  private:
   static int     _thread_index;
--- a/src/share/vm/runtime/vmStructs.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/runtime/vmStructs.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -761,8 +761,9 @@
   static_field(Abstract_VM_Version,            _vm_minor_version,                             int)                                   \
   static_field(Abstract_VM_Version,            _vm_build_number,                              int)                                   \
                                                                                                                                      \
-  static_field(JDK_Version,                    _pre_jdk16_version,                            bool)                                  \
-  static_field(JDK_Version,                    _jdk_version,                                  int)                                   \
+  static_field(JDK_Version,                    _current,                                      JDK_Version)                           \
+  nonstatic_field(JDK_Version,                 _partially_initialized,                        bool)                                  \
+  nonstatic_field(JDK_Version,                 _major,                                        unsigned char)                         \
                                                                                                                                      \
                                                                                                                                      \
                                                                                                                                      \
--- a/src/share/vm/services/threadService.cpp	Sat Jul 19 17:38:22 2008 -0400
+++ b/src/share/vm/services/threadService.cpp	Mon Jul 28 14:07:44 2008 -0400
@@ -744,7 +744,7 @@
   }
 
   // Support for JSR-166 locks
-  if (JDK_Version::supports_thread_park_blocker() &&
+  if (JDK_Version::current().supports_thread_park_blocker() &&
         (_thread_status == java_lang_Thread::PARKED ||
          _thread_status == java_lang_Thread::PARKED_TIMED)) {