changeset 712:6e33bfd4139b

Merge
author never
date Tue, 14 Apr 2009 12:25:54 -0700
parents 68cd0d7ee9bb (diff) 9610b2a8ab4e (current diff)
children 4961a8a726a4 67a2f5ba5582
files src/share/vm/runtime/arguments.cpp src/share/vm/runtime/globals.hpp
diffstat 24 files changed, 442 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Apr 10 15:01:14 2009 -0700
+++ b/.hgtags	Tue Apr 14 12:25:54 2009 -0700
@@ -26,3 +26,5 @@
 8b22ccb5aba2c6c11bddf6488a7bb7ef5b4bf2be jdk7-b49
 dae503d9f04c1a11e182dbf7f770509c28dc0609 jdk7-b50
 2581d90c6c9b2012da930eb4742add94a03069a0 jdk7-b51
+1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52
+032c6af894dae8d939b3dd31d82042549e7793e0 jdk7-b53
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Fri Apr 10 15:01:14 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Tue Apr 14 12:25:54 2009 -0700
@@ -48,6 +48,8 @@
   private static AddressField  lastJavaPCField;
   private static CIntegerField threadStateField;
   private static AddressField  osThreadField;
+  private static AddressField  stackBaseField;
+  private static CIntegerField stackSizeField;
 
   private static JavaThreadPDAccess access;
 
@@ -83,6 +85,8 @@
     lastJavaPCField   = anchorType.getAddressField("_last_Java_pc");
     threadStateField  = type.getCIntegerField("_thread_state");
     osThreadField     = type.getAddressField("_osthread");
+    stackBaseField    = type.getAddressField("_stack_base");
+    stackSizeField    = type.getCIntegerField("_stack_size");
 
     UNINITIALIZED     = db.lookupIntConstant("_thread_uninitialized").intValue();
     NEW               = db.lookupIntConstant("_thread_new").intValue();
@@ -312,6 +316,14 @@
     return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));
   }
 
+  public Address getStackBase() {
+    return stackBaseField.getValue();
+  }
+
+  public long getStackSize() {
+    return stackSizeField.getValue();
+  }
+
   /** Gets the Java-side thread object for this JavaThread */
   public Oop getThreadObj() {
     return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
@@ -345,11 +357,18 @@
     if (Assert.ASSERTS_ENABLED) {
       Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
     }
-    Address highest = highestLock();
     Address sp      = lastSPDbg();
+    Address stackBase = getStackBase();
     // Be robust
-    if ((highest == null) || (sp == null)) return false;
-    return (highest.greaterThanOrEqual(a) && sp.lessThanOrEqual(a));
+    if (sp == null) return false;
+    return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a);
+  }
+
+  public boolean isLockOwned(Address a) {
+    Address stackBase = getStackBase();
+    Address stackLimit = stackBase.addOffsetTo(-getStackSize());
+
+    return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a);
 
     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
   }
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java	Fri Apr 10 15:01:14 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java	Tue Apr 14 12:25:54 2009 -0700
@@ -38,7 +38,6 @@
   private static int HAS_ASYNC_EXCEPTION;
 
   private static AddressField activeHandlesField;
-  private static AddressField highestLockField;
   private static AddressField currentPendingMonitorField;
   private static AddressField currentWaitingMonitorField;
 
@@ -60,7 +59,6 @@
 
     tlabFieldOffset    = type.getField("_tlab").getOffset();
     activeHandlesField = type.getAddressField("_active_handles");
-    highestLockField   = type.getAddressField("_highest_lock");
     currentPendingMonitorField = type.getAddressField("_current_pending_monitor");
     currentWaitingMonitorField = type.getAddressField("_current_waiting_monitor");
   }
@@ -121,10 +119,6 @@
     // pending exception
   }
 
-  public Address highestLock() {
-    return highestLockField.getValue(addr);
-  }
-
   public ObjectMonitor getCurrentPendingMonitor() {
     Address monitorAddr = currentPendingMonitorField.getValue(addr);
     if (monitorAddr == null) {
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Fri Apr 10 15:01:14 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Tue Apr 14 12:25:54 2009 -0700
@@ -164,20 +164,11 @@
             }
         }
 
-        long leastDiff = 0;
-        boolean leastDiffInitialized = false;
-        JavaThread theOwner = null;
         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
-            Address addr = thread.highestLock();
-            if (addr == null || addr.lessThan(o)) continue;
-            long diff = addr.minus(o);
-            if (!leastDiffInitialized || diff < leastDiff) {
-                leastDiffInitialized = true;
-                leastDiff = diff;
-                theOwner = thread;
-            }
+          if (thread.isLockOwned(o))
+            return thread;
         }
-        return theOwner;
+        return null;
     }
 
     public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Fri Apr 10 15:01:14 2009 -0700
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/VM.java	Tue Apr 14 12:25:54 2009 -0700
@@ -342,8 +342,10 @@
       throw new RuntimeException("Attempt to initialize VM twice");
     }
     soleInstance = new VM(db, debugger, debugger.getMachineDescription().isBigEndian());
+
     debugger.putHeapConst(soleInstance.getHeapOopSize(), Universe.getNarrowOopBase(),
                           Universe.getNarrowOopShift());
+
     for (Iterator iter = vmInitializedObservers.iterator(); iter.hasNext(); ) {
       ((Observer) iter.next()).update(null, null);
     }
--- a/make/hotspot_version	Fri Apr 10 15:01:14 2009 -0700
+++ b/make/hotspot_version	Tue Apr 14 12:25:54 2009 -0700
@@ -31,11 +31,11 @@
 #
 
 # Don't put quotes (fail windows build).
-HOTSPOT_VM_COPYRIGHT=Copyright 2008
+HOTSPOT_VM_COPYRIGHT=Copyright 2009
 
-HS_MAJOR_VER=15
+HS_MAJOR_VER=16
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=04
+HS_BUILD_NUMBER=01
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=7
--- a/src/os/linux/vm/os_linux.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/os/linux/vm/os_linux.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -1518,21 +1518,51 @@
 
 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
+static bool file_exists(const char* filename) {
+  struct stat statbuf;
+  if (filename == NULL || strlen(filename) == 0) {
+    return false;
+  }
+  return os::stat(filename, &statbuf) == 0;
+}
+
+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. */
+  // 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);
+    snprintf(buffer, buflen, "lib%s.so", fname);
+  } else if (strchr(pname, *os::path_separator()) != NULL) {
+    int n;
+    char** pelements = split_path(pname, &n);
+    for (int i = 0 ; i < n ; i++) {
+      // Really shouldn't be NULL, but check can't hurt
+      if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
+        continue; // skip the empty path values
+      }
+      snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
+      if (file_exists(buffer)) {
+        break;
+      }
+    }
+    // release the storage
+    for (int i = 0 ; i < n ; i++) {
+      if (pelements[i] != NULL) {
+        FREE_C_HEAP_ARRAY(char, pelements[i]);
+      }
+    }
+    if (pelements != NULL) {
+      FREE_C_HEAP_ARRAY(char*, pelements);
+    }
   } else {
-      sprintf(buffer, "%s/lib%s.so", pname, fname);
+    snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
   }
 }
 
--- a/src/os/solaris/vm/os_solaris.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/os/solaris/vm/os_solaris.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -1827,21 +1827,51 @@
 
 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
+static bool file_exists(const char* filename) {
+  struct stat statbuf;
+  if (filename == NULL || strlen(filename) == 0) {
+    return false;
+  }
+  return os::stat(filename, &statbuf) == 0;
+}
+
+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. */
+  // 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);
+    snprintf(buffer, buflen, "lib%s.so", fname);
+  } else if (strchr(pname, *os::path_separator()) != NULL) {
+    int n;
+    char** pelements = split_path(pname, &n);
+    for (int i = 0 ; i < n ; i++) {
+      // really shouldn't be NULL but what the heck, check can't hurt
+      if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
+        continue; // skip the empty path values
+      }
+      snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
+      if (file_exists(buffer)) {
+        break;
+      }
+    }
+    // release the storage
+    for (int i = 0 ; i < n ; i++) {
+      if (pelements[i] != NULL) {
+        FREE_C_HEAP_ARRAY(char, pelements[i]);
+      }
+    }
+    if (pelements != NULL) {
+      FREE_C_HEAP_ARRAY(char*, pelements);
+    }
   } else {
-      sprintf(buffer, "%s/lib%s.so", pname, fname);
+    snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
   }
 }
 
--- a/src/os/windows/vm/os_windows.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/os/windows/vm/os_windows.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -1004,26 +1004,61 @@
     }
 }
 
-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;
+static bool file_exists(const char* filename) {
+  if (filename == NULL || strlen(filename) == 0) {
+    return false;
+  }
+  return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
+}
+
+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;
+  const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
+
+  // Quietly truncates on buffer overflow. Should be an error.
+  if (pnamelen + strlen(fname) + 10 > buflen) {
+    *buffer = '\0';
+    return;
+  }
+
+  if (pnamelen == 0) {
+    jio_snprintf(buffer, buflen, "%s.dll", fname);
+  } else if (c == ':' || c == '\\') {
+    jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
+  } else if (strchr(pname, *os::path_separator()) != NULL) {
+    int n;
+    char** pelements = split_path(pname, &n);
+    for (int i = 0 ; i < n ; i++) {
+      char* path = pelements[i];
+      // Really shouldn't be NULL, but check can't hurt
+      size_t plen = (path == NULL) ? 0 : strlen(path);
+      if (plen == 0) {
+        continue; // skip the empty path values
+      }
+      const char lastchar = path[plen - 1];
+      if (lastchar == ':' || lastchar == '\\') {
+        jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
+      } else {
+        jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
+      }
+      if (file_exists(buffer)) {
+        break;
+      }
     }
-
-    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);
+    // release the storage
+    for (int i = 0 ; i < n ; i++) {
+      if (pelements[i] != NULL) {
+        FREE_C_HEAP_ARRAY(char, pelements[i]);
+      }
     }
+    if (pelements != NULL) {
+      FREE_C_HEAP_ARRAY(char*, pelements);
+    }
+  } else {
+    jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
+  }
 }
 
 // Needs to be in os specific directory because windows requires another
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -34,10 +34,12 @@
                                        Generation* old_gen_,
                                        int thread_num_,
                                        ObjToScanQueueSet* work_queue_set_,
+                                       GrowableArray<oop>**  overflow_stack_set_,
                                        size_t desired_plab_sz_,
                                        ParallelTaskTerminator& term_) :
   _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_),
   _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false),
+  _overflow_stack(overflow_stack_set_[thread_num_]),
   _ageTable(false), // false ==> not the global age table, no perf data.
   _to_space_alloc_buffer(desired_plab_sz_),
   _to_space_closure(gen_, this), _old_gen_closure(gen_, this),
@@ -57,11 +59,6 @@
   _start = os::elapsedTime();
   _old_gen_closure.set_generation(old_gen_);
   _old_gen_root_closure.set_generation(old_gen_);
-  if (UseCompressedOops) {
-    _overflow_stack = new (ResourceObj::C_HEAP) GrowableArray<oop>(512, true);
-  } else {
-    _overflow_stack = NULL;
-  }
 }
 #ifdef _MSC_VER
 #pragma warning( pop )
@@ -155,7 +152,7 @@
 }
 
 bool ParScanThreadState::take_from_overflow_stack() {
-  assert(UseCompressedOops, "Else should not call");
+  assert(ParGCUseLocalOverflow, "Else should not call");
   assert(young_gen()->overflow_list() == NULL, "Error");
   ObjToScanQueue* queue = work_queue();
   GrowableArray<oop>* of_stack = overflow_stack();
@@ -183,7 +180,7 @@
 }
 
 void ParScanThreadState::push_on_overflow_stack(oop p) {
-  assert(UseCompressedOops, "Else should not call");
+  assert(ParGCUseLocalOverflow, "Else should not call");
   overflow_stack()->push(p);
   assert(young_gen()->overflow_list() == NULL, "Error");
 }
@@ -260,6 +257,7 @@
                         ParNewGeneration&       gen,
                         Generation&             old_gen,
                         ObjToScanQueueSet&      queue_set,
+                        GrowableArray<oop>**    overflow_stacks_,
                         size_t                  desired_plab_sz,
                         ParallelTaskTerminator& term);
   inline ParScanThreadState& thread_sate(int i);
@@ -282,6 +280,7 @@
 ParScanThreadStateSet::ParScanThreadStateSet(
   int num_threads, Space& to_space, ParNewGeneration& gen,
   Generation& old_gen, ObjToScanQueueSet& queue_set,
+  GrowableArray<oop>** overflow_stack_set_,
   size_t desired_plab_sz, ParallelTaskTerminator& term)
   : ResourceArray(sizeof(ParScanThreadState), num_threads),
     _gen(gen), _next_gen(old_gen), _term(term),
@@ -292,7 +291,7 @@
   for (int i = 0; i < num_threads; ++i) {
     new ((ParScanThreadState*)_data + i)
         ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set,
-                           desired_plab_sz, term);
+                           overflow_stack_set_, desired_plab_sz, term);
   }
 }
 
@@ -519,6 +518,17 @@
   for (uint i2 = 0; i2 < ParallelGCThreads; i2++)
     _task_queues->queue(i2)->initialize();
 
+  _overflow_stacks = NEW_C_HEAP_ARRAY(GrowableArray<oop>*, ParallelGCThreads);
+  guarantee(_overflow_stacks != NULL, "Overflow stack set allocation failure");
+  for (uint i = 0; i < ParallelGCThreads; i++) {
+    if (ParGCUseLocalOverflow) {
+      _overflow_stacks[i] = new (ResourceObj::C_HEAP) GrowableArray<oop>(512, true);
+      guarantee(_overflow_stacks[i] != NULL, "Overflow Stack allocation failure.");
+    } else {
+      _overflow_stacks[i] = NULL;
+    }
+  }
+
   if (UsePerfData) {
     EXCEPTION_MARK;
     ResourceMark rm;
@@ -784,7 +794,7 @@
   ParallelTaskTerminator _term(workers->total_workers(), task_queues());
   ParScanThreadStateSet thread_state_set(workers->total_workers(),
                                          *to(), *this, *_next_gen, *task_queues(),
-                                         desired_plab_sz(), _term);
+                                         _overflow_stacks, desired_plab_sz(), _term);
 
   ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set);
   int n_workers = workers->total_workers();
@@ -1238,11 +1248,12 @@
 #define BUSY (oop(0x1aff1aff))
 void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) {
   assert(is_in_reserved(from_space_obj), "Should be from this generation");
-  if (UseCompressedOops) {
+  if (ParGCUseLocalOverflow) {
     // In the case of compressed oops, we use a private, not-shared
     // overflow stack.
     par_scan_state->push_on_overflow_stack(from_space_obj);
   } else {
+    assert(!UseCompressedOops, "Error");
     // if the object has been forwarded to itself, then we cannot
     // use the klass pointer for the linked list.  Instead we have
     // to allocate an oopDesc in the C-Heap and use that for the linked list.
@@ -1275,9 +1286,10 @@
 bool ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) {
   bool res;
 
-  if (UseCompressedOops) {
+  if (ParGCUseLocalOverflow) {
     res = par_scan_state->take_from_overflow_stack();
   } else {
+    assert(!UseCompressedOops, "Error");
     res = take_from_overflow_list_work(par_scan_state);
   }
   return res;
@@ -1305,6 +1317,7 @@
                                  (size_t)ParGCDesiredObjsFromOverflowList);
 
   assert(par_scan_state->overflow_stack() == NULL, "Error");
+  assert(!UseCompressedOops, "Error");
   if (_overflow_list == NULL) return false;
 
   // Otherwise, there was something there; try claiming the list.
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -33,8 +33,8 @@
 // but they must be here to allow ParScanClosure::do_oop_work to be defined
 // in genOopClosures.inline.hpp.
 
-typedef OopTaskQueue    ObjToScanQueue;
-typedef OopTaskQueueSet ObjToScanQueueSet;
+typedef OopTaskQueue       ObjToScanQueue;
+typedef OopTaskQueueSet    ObjToScanQueueSet;
 
 // Enable this to get push/pop/steal stats.
 const int PAR_STATS_ENABLED = 0;
@@ -116,7 +116,9 @@
 
   ParScanThreadState(Space* to_space_, ParNewGeneration* gen_,
                      Generation* old_gen_, int thread_num_,
-                     ObjToScanQueueSet* work_queue_set_, size_t desired_plab_sz_,
+                     ObjToScanQueueSet* work_queue_set_,
+                     GrowableArray<oop>** overflow_stack_set_,
+                     size_t desired_plab_sz_,
                      ParallelTaskTerminator& term_);
 
  public:
@@ -296,9 +298,12 @@
         char pad[64 - sizeof(ObjToScanQueue)];  // prevent false sharing
   };
 
-  // The per-thread work queues, available here for stealing.
+  // The per-worker-thread work queues
   ObjToScanQueueSet* _task_queues;
 
+  // Per-worker-thread local overflow stacks
+  GrowableArray<oop>** _overflow_stacks;
+
   // Desired size of survivor space plab's
   PLABStats _plab_stats;
 
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -508,6 +508,7 @@
   assert(destination <= target_end, "sanity");
   assert(destination + _region_data[src_region].data_size() > target_end,
     "region should not fit into target space");
+  assert(is_region_aligned(target_end), "sanity");
 
   size_t split_region = src_region;
   HeapWord* split_destination = destination;
@@ -538,14 +539,12 @@
     //         max(top, max(new_top, clear_top))
     //
     // where clear_top is a new field in SpaceInfo.  Would have to set clear_top
-    // to destination + partial_obj_size, where both have the values passed to
-    // this routine.
+    // to target_end.
     const RegionData* const sr = region(split_region);
     const size_t beg_idx =
       addr_to_region_idx(region_align_up(sr->destination() +
                                          sr->partial_obj_size()));
-    const size_t end_idx =
-      addr_to_region_idx(region_align_up(destination + partial_obj_size));
+    const size_t end_idx = addr_to_region_idx(target_end);
 
     if (TraceParallelOldGCSummaryPhase) {
         gclog_or_tty->print_cr("split:  clearing source_region field in ["
--- a/src/share/vm/runtime/arguments.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/arguments.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -852,16 +852,13 @@
       FreeHeap(value);
     }
     return true;
-  }
-  else if (strcmp(key, "sun.java.command") == 0) {
-
+  } else if (strcmp(key, "sun.java.command") == 0) {
     _java_command = value;
 
     // don't add this property to the properties exposed to the java application
     FreeHeap(key);
     return true;
-  }
-  else if (strcmp(key, "sun.java.launcher.pid") == 0) {
+  } else if (strcmp(key, "sun.java.launcher.pid") == 0) {
     // launcher.pid property is private and is processed
     // in process_sun_java_launcher_properties();
     // the sun.java.launcher property is passed on to the java application
@@ -870,13 +867,14 @@
       FreeHeap(value);
     }
     return true;
-  }
-  else if (strcmp(key, "java.vendor.url.bug") == 0) {
+  } else if (strcmp(key, "java.vendor.url.bug") == 0) {
     // save it in _java_vendor_url_bug, so JVM fatal error handler can access
     // its value without going through the property list or making a Java call.
     _java_vendor_url_bug = value;
+  } else if (strcmp(key, "sun.boot.library.path") == 0) {
+    PropertyList_unique_add(&_system_properties, key, value, true);
+    return true;
   }
-
   // Create new property and add at the end of the list
   PropertyList_unique_add(&_system_properties, key, value);
   return true;
@@ -895,7 +893,7 @@
   // Ensure Agent_OnLoad has the correct initial values.
   // This may not be the final mode; mode may change later in onload phase.
   PropertyList_unique_add(&_system_properties, "java.vm.info",
-     (char*)Abstract_VM_Version::vm_info_string());
+                          (char*)Abstract_VM_Version::vm_info_string(), false);
 
   UseInterpreter             = true;
   UseCompiler                = true;
@@ -971,7 +969,7 @@
   } else {
     no_shared_spaces();
 
-    // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 correspondinly,
+    // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 respectively,
     // these settings are default for Parallel Scavenger. For ParNew+Tenured configuration
     // we set them to 1024 and 1024.
     // See CR 6362902.
@@ -987,6 +985,16 @@
     if (AlwaysTenure) {
       FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0);
     }
+    // When using compressed oops, we use local overflow stacks,
+    // rather than using a global overflow list chained through
+    // the klass word of the object's pre-image.
+    if (UseCompressedOops && !ParGCUseLocalOverflow) {
+      if (!FLAG_IS_DEFAULT(ParGCUseLocalOverflow)) {
+        warning("Forcing +ParGCUseLocalOverflow: needed if using compressed references");
+      }
+      FLAG_SET_DEFAULT(ParGCUseLocalOverflow, true);
+    }
+    assert(ParGCUseLocalOverflow || !UseCompressedOops, "Error");
   }
 }
 
@@ -2771,7 +2779,7 @@
 }
 
 // This add maintains unique property key in the list.
-void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
+void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
   if (plist == NULL)
     return;
 
@@ -2779,7 +2787,11 @@
   SystemProperty* prop;
   for (prop = *plist; prop != NULL; prop = prop->next()) {
     if (strcmp(k, prop->key()) == 0) {
-      prop->set_value(v);
+      if (append) {
+        prop->append_value(v);
+      } else {
+        prop->set_value(v);
+      }
       return;
     }
   }
--- a/src/share/vm/runtime/arguments.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/arguments.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -475,10 +475,13 @@
   // System properties
   static void init_system_properties();
 
-  // Proptery List manipulation
+  // Property List manipulation
   static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
   static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
-  static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v);
+  static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
+    PropertyList_unique_add(plist, k, v, false);
+  }
+  static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append);
   static const char* PropertyList_get_value(SystemProperty* plist, const char* key);
   static int  PropertyList_count(SystemProperty* pl);
   static const char* PropertyList_get_key_at(SystemProperty* pl,int index);
--- a/src/share/vm/runtime/globals.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/globals.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -1323,8 +1323,11 @@
   product(intx, ParGCArrayScanChunk, 50,                                    \
           "Scan a subset and push remainder, if array is bigger than this") \
                                                                             \
+  product(bool, ParGCUseLocalOverflow, false,                               \
+          "Instead of a global overflow list, use local overflow stacks")   \
+                                                                            \
   product(bool, ParGCTrimOverflow, true,                                    \
-          "Eagerly trim the overflow lists (useful for UseCompressedOops")  \
+          "Eagerly trim the local overflow lists (when ParGCUseLocalOverflow") \
                                                                             \
   notproduct(bool, ParGCWorkQueueOverflowALot, false,                       \
           "Whether we should simulate work queue overflow in ParNew")       \
--- a/src/share/vm/runtime/hpi.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/hpi.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -90,7 +90,7 @@
   static inline struct protoent* get_proto_by_name(char* name);
 
   // HPI_LibraryInterface
-  static inline void   dll_build_name(char *buf, int buf_len, char* path,
+  static inline void   dll_build_name(char *buf, int buf_len, const char* path,
                                       const char *name);
   static inline void*  dll_load(const char *name, char *ebuf, int ebuflen);
   static inline void   dll_unload(void *lib);
@@ -137,7 +137,15 @@
     return result;                            \
   }
 
-
+#define VM_HPIDECL_VOID(name, names, func, arg_type, arg_print, arg)   \
+  inline void  hpi::name arg_type {           \
+    if (TraceHPI) {                           \
+      tty->print("hpi::" names "(");          \
+      tty->print arg_print;                   \
+      tty->print(") = ");                     \
+    }                                         \
+    func arg;                                 \
+  }
 
 #define HPIDECL_VOID(name, names, intf, func, arg_type, arg_print, arg) \
   inline void hpi::name arg_type {            \
@@ -197,11 +205,11 @@
         (fd, size));
 
 // HPI_LibraryInterface
-HPIDECL_VOID(dll_build_name, "dll_build_name", _library, BuildLibName,
-             (char *buf, int buf_len, char *path, const char *name),
-             ("buf = %p, buflen = %d, path = %s, name = %s",
-              buf, buf_len, path, name),
-             (buf, buf_len, path, name));
+VM_HPIDECL_VOID(dll_build_name, "dll_build_name", os::dll_build_name,
+               (char *buf, int buf_len, const char *path, const char *name),
+               ("buf = %p, buflen = %d, path = %s, name = %s",
+                buf, buf_len, path, name),
+               (buf, buf_len, path, name));
 
 VM_HPIDECL(dll_load, "dll_load", os::dll_load,
         void *, "(void *)%p",
--- a/src/share/vm/runtime/javaCalls.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/javaCalls.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -37,11 +37,6 @@
   guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
   _result   = result;
 
-  // Make sure that that the value of the  higest_lock is at least the same as the current stackpointer,
-  // since, the Java code is highly likely to use locks.
-  // Use '(address)this' to guarantee that highest_lock address is conservative and inside our thread
-  thread->update_highest_lock((address)this);
-
   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
   // since it can potentially block.
   JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
--- a/src/share/vm/runtime/os.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/os.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -863,7 +863,6 @@
 
 
 bool os::set_boot_path(char fileSep, char pathSep) {
-
     const char* home = Arguments::get_java_home();
     int home_len = (int)strlen(home);
 
@@ -893,6 +892,60 @@
     return true;
 }
 
+/*
+ * Splits a path, based on its separator, the number of
+ * elements is returned back in n.
+ * It is the callers responsibility to:
+ *   a> check the value of n, and n may be 0.
+ *   b> ignore any empty path elements
+ *   c> free up the data.
+ */
+char** os::split_path(const char* path, int* n) {
+  *n = 0;
+  if (path == NULL || strlen(path) == 0) {
+    return NULL;
+  }
+  const char psepchar = *os::path_separator();
+  char* inpath = (char*)NEW_C_HEAP_ARRAY(char, strlen(path) + 1);
+  if (inpath == NULL) {
+    return NULL;
+  }
+  strncpy(inpath, path, strlen(path));
+  int count = 1;
+  char* p = strchr(inpath, psepchar);
+  // Get a count of elements to allocate memory
+  while (p != NULL) {
+    count++;
+    p++;
+    p = strchr(p, psepchar);
+  }
+  char** opath = (char**) NEW_C_HEAP_ARRAY(char*, count);
+  if (opath == NULL) {
+    return NULL;
+  }
+
+  // do the actual splitting
+  p = inpath;
+  for (int i = 0 ; i < count ; i++) {
+    size_t len = strcspn(p, os::path_separator());
+    if (len > JVM_MAXPATHLEN) {
+      return NULL;
+    }
+    // allocate the string and add terminator storage
+    char* s  = (char*)NEW_C_HEAP_ARRAY(char, len + 1);
+    if (s == NULL) {
+      return NULL;
+    }
+    strncpy(s, p, len);
+    s[len] = '\0';
+    opath[i] = s;
+    p += len + 1;
+  }
+  FREE_C_HEAP_ARRAY(char, inpath);
+  *n = count;
+  return opath;
+}
+
 void os::set_memory_serialize_page(address page) {
   int count = log2_intptr(sizeof(class JavaThread)) - log2_intptr(64);
   _mem_serialize_page = (volatile int32_t *)page;
--- a/src/share/vm/runtime/os.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/os.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -607,6 +607,7 @@
                                 char fileSep,
                                 char pathSep);
   static bool set_boot_path(char fileSep, char pathSep);
+  static char** split_path(const char* path, int* n);
 };
 
 // Note that "PAUSE" is almost always used with synchronization
--- a/src/share/vm/runtime/synchronizer.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/synchronizer.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -1117,10 +1117,10 @@
 
           // Optimization: if the mark->locker stack address is associated
           // with this thread we could simply set m->_owner = Self and
-          // m->OwnerIsThread = 1.  Note that a thread can inflate an object
+          // m->OwnerIsThread = 1. Note that a thread can inflate an object
           // that it has stack-locked -- as might happen in wait() -- directly
           // with CAS.  That is, we can avoid the xchg-NULL .... ST idiom.
-          m->set_owner (mark->locker());
+          m->set_owner(mark->locker());
           m->set_object(object);
           // TODO-FIXME: assert BasicLock->dhw != 0.
 
@@ -1214,10 +1214,9 @@
       BiasedLocking::revoke_at_safepoint(obj);
     }
     assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
-  }
-
-  THREAD->update_highest_lock((address)lock);
-  slow_enter (obj, lock, THREAD) ;
+ }
+
+ slow_enter (obj, lock, THREAD) ;
 }
 
 void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
--- a/src/share/vm/runtime/thread.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/thread.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -128,7 +128,6 @@
   debug_only(_allow_allocation_count = 0;)
   NOT_PRODUCT(_allow_safepoint_count = 0;)
   CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;)
-  _highest_lock = NULL;
   _jvmti_env_iteration_count = 0;
   _vm_operation_started_count = 0;
   _vm_operation_completed_count = 0;
@@ -790,19 +789,6 @@
 }
 #endif
 
-bool Thread::lock_is_in_stack(address adr) const {
-  assert(Thread::current() == this, "lock_is_in_stack can only be called from current thread");
-  // High limit: highest_lock is set during thread execution
-  // Low  limit: address of the local variable dummy, rounded to 4K boundary.
-  // (The rounding helps finding threads in unsafe mode, even if the particular stack
-  // frame has been popped already.  Correct as long as stacks are at least 4K long and aligned.)
-  address end = os::current_stack_pointer();
-  if (_highest_lock >= adr && adr >= end) return true;
-
-  return false;
-}
-
-
 bool Thread::is_in_stack(address adr) const {
   assert(Thread::current() == this, "is_in_stack can only be called from current thread");
   address end = os::current_stack_pointer();
@@ -818,8 +804,7 @@
 // should be revisited, and they should be removed if possible.
 
 bool Thread::is_lock_owned(address adr) const {
-  if (lock_is_in_stack(adr) ) return true;
-  return false;
+  return (_stack_base >= adr && adr >= (_stack_base - _stack_size));
 }
 
 bool Thread::set_as_starting_thread() {
@@ -1664,7 +1649,7 @@
 }
 
 bool JavaThread::is_lock_owned(address adr) const {
-  if (lock_is_in_stack(adr)) return true;
+  if (Thread::is_lock_owned(adr)) return true;
 
   for (MonitorChunk* chunk = monitor_chunks(); chunk != NULL; chunk = chunk->next()) {
     if (chunk->contains(adr)) return true;
@@ -2443,7 +2428,7 @@
   if (thread_oop != NULL && java_lang_Thread::is_daemon(thread_oop))  st->print("daemon ");
   Thread::print_on(st);
   // print guess for valid stack memory region (assume 4K pages); helps lock debugging
-  st->print_cr("[" INTPTR_FORMAT ".." INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12), highest_lock());
+  st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12));
   if (thread_oop != NULL && JDK_Version::is_gte_jdk15x_version()) {
     st->print_cr("   java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop));
   }
@@ -3733,25 +3718,13 @@
   // heavyweight monitors, then the owner is the stack address of the
   // Lock Word in the owning Java thread's stack.
   //
-  // We can't use Thread::is_lock_owned() or Thread::lock_is_in_stack() because
-  // those routines rely on the "current" stack pointer. That would be our
-  // stack pointer which is not relevant to the question. Instead we use the
-  // highest lock ever entered by the thread and find the thread that is
-  // higher than and closest to our target stack address.
-  //
-  address    least_diff = 0;
-  bool       least_diff_initialized = false;
   JavaThread* the_owner = NULL;
   {
     MutexLockerEx ml(doLock ? Threads_lock : NULL);
     ALL_JAVA_THREADS(q) {
-      address addr = q->highest_lock();
-      if (addr == NULL || addr < owner) continue;  // thread has entered no monitors or is too low
-      address diff = (address)(addr - owner);
-      if (!least_diff_initialized || diff < least_diff) {
-        least_diff_initialized = true;
-        least_diff = diff;
+      if (q->is_lock_owned(owner)) {
         the_owner = q;
+        break;
       }
     }
   }
--- a/src/share/vm/runtime/thread.hpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/thread.hpp	Tue Apr 14 12:25:54 2009 -0700
@@ -200,14 +200,6 @@
   friend class ThreadLocalStorage;
   friend class GC_locker;
 
-  // In order for all threads to be able to use fast locking, we need to know the highest stack
-  // address of where a lock is on the stack (stacks normally grow towards lower addresses). This
-  // variable is initially set to NULL, indicating no locks are used by the thread. During the thread's
-  // execution, it will be set whenever locking can happen, i.e., when we call out to Java code or use
-  // an ObjectLocker. The value is never decreased, hence, it will over the lifetime of a thread
-  // approximate the real stackbase.
-  address _highest_lock;                         // Highest stack address where a JavaLock exist
-
   ThreadLocalAllocBuffer _tlab;                  // Thread-local eden
 
   int   _vm_operation_started_count;             // VM_Operation support
@@ -400,18 +392,14 @@
   // Sweeper support
   void nmethods_do();
 
-  // Fast-locking support
-  address highest_lock() const                   { return _highest_lock; }
-  void update_highest_lock(address base)         { if (base > _highest_lock) _highest_lock = base; }
-
   // Tells if adr belong to this thread. This is used
   // for checking if a lock is owned by the running thread.
-  // Warning: the method can only be used on the running thread
-  // Fast lock support uses these methods
-  virtual bool lock_is_in_stack(address adr) const;
+
+  // Used by fast lock support
   virtual bool is_lock_owned(address adr) const;
 
   // Check if address is in the stack of the thread (not just for locks).
+  // Warning: the method can only be used on the running thread
   bool is_in_stack(address adr) const;
 
   // Sets this thread as starting thread. Returns failure if thread
--- a/src/share/vm/runtime/vmStructs.cpp	Fri Apr 10 15:01:14 2009 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Tue Apr 14 12:25:54 2009 -0700
@@ -656,7 +656,6 @@
                                                                                                                                      \
    volatile_nonstatic_field(Thread,            _suspend_flags,                                uint32_t)                              \
   nonstatic_field(Thread,                      _active_handles,                               JNIHandleBlock*)                       \
-  nonstatic_field(Thread,                      _highest_lock,                                 address)                               \
   nonstatic_field(Thread,                      _tlab,                                         ThreadLocalAllocBuffer)                \
   nonstatic_field(Thread,                      _current_pending_monitor,                      ObjectMonitor*)                        \
   nonstatic_field(Thread,                      _current_pending_monitor_is_from_java,         bool)                                  \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/runtime/6819213/TestBootNativeLibraryPath.java	Tue Apr 14 12:25:54 2009 -0700
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test TestBootNativeLibraryPath.java
+ * @bug 6819213
+ * @compile -XDignore.symbol.file TestBootNativeLibraryPath.java
+ * @summary verify sun.boot.native.library.path is expandable on 32 bit systems
+ * @run main TestBootNativeLibraryPath
+ * @author ksrini
+*/
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.tools.JavaCompiler;
+import javax.tools.ToolProvider;
+
+public class TestBootNativeLibraryPath {
+
+    private static final String TESTFILE = "Test6";
+
+    static void createTestClass() throws IOException {
+        FileOutputStream fos = new FileOutputStream(TESTFILE + ".java");
+        PrintStream ps = new PrintStream(fos);
+        ps.println("public class " + TESTFILE + "{");
+        ps.println("public static void main(String[] args) {\n");
+        ps.println("System.out.println(System.getProperty(\"sun.boot.library.path\"));\n");
+        ps.println("}}\n");
+        ps.close();
+        fos.close();
+
+        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
+        String javacOpts[] = {TESTFILE + ".java"};
+        if (javac.run(null, null, null,  javacOpts) != 0) {
+            throw new RuntimeException("compilation of " + TESTFILE + ".java Failed");
+        }
+    }
+
+    static List<String> doExec(String... args) {
+        String javaCmd = System.getProperty("java.home") + "/bin/java";
+        if (!new File(javaCmd).exists()) {
+            javaCmd = System.getProperty("java.home") + "/bin/java.exe";
+        }
+
+        ArrayList<String> cmds = new ArrayList<String>();
+        cmds.add(javaCmd);
+        for (String x : args) {
+            cmds.add(x);
+        }
+        System.out.println("cmds=" + cmds);
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+
+        Map<String, String> env = pb.environment();
+        pb.directory(new File("."));
+
+        List<String> out = new ArrayList<String>();
+        try {
+            pb.redirectErrorStream(true);
+            Process p = pb.start();
+            BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream()),8192);
+            String in = rd.readLine();
+            while (in != null) {
+                out.add(in);
+                System.out.println(in);
+                in = rd.readLine();
+            }
+            int retval = p.waitFor();
+            p.destroy();
+            if (retval != 0) {
+                throw new RuntimeException("Error: test returned non-zero value");
+            }
+            return out;
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+
+    public static void main(String[] args) {
+        try {
+            if (!System.getProperty("sun.arch.data.model").equals("32")) {
+                System.out.println("Warning: test skipped for 64-bit systems\n");
+                return;
+            }
+            String osname = System.getProperty("os.name");
+            if (osname.startsWith("Windows")) {
+                osname = "Windows";
+            }
+
+            createTestClass();
+
+            // Test a simple path
+            String libpath = File.pathSeparator + "tmp" + File.pathSeparator + "foobar";
+            List<String> processOut = null;
+            String sunbootlibrarypath = "-Dsun.boot.library.path=" + libpath;
+            processOut = doExec(sunbootlibrarypath, "-cp", ".", TESTFILE);
+            if (processOut == null || !processOut.get(0).endsWith(libpath)) {
+                throw new RuntimeException("Error: did not get expected error string");
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException("Unexpected error " + ex);
+        }
+    }
+}