# HG changeset patch # User apangin # Date 1279144338 14400 # Node ID 1e7ec26380bd57206f9fe8dfda12f7656b420af1 # Parent 0e7d2a08b6053ed595aebc39d0becc3a50208b7a# Parent 9ee05c8ab82f5ddbb46b2af9fe1024bf85f27127 Merge diff -r 9ee05c8ab82f -r 1e7ec26380bd make/linux/makefiles/sa.make --- a/make/linux/makefiles/sa.make Mon Jul 12 12:53:52 2010 -0700 +++ b/make/linux/makefiles/sa.make Wed Jul 14 17:52:18 2010 -0400 @@ -40,6 +40,9 @@ # tools.jar is needed by the JDI - SA binding SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar +# TODO: if it's a modules image, check if SA module is installed. +MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules + # gnumake 3.78.1 does not accept the *s that # are in AGENT_FILES1 and AGENT_FILES2, so use the shell to expand them AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) @@ -65,7 +68,7 @@ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) ] ; then \ + $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ echo ""; \ exit 1; \ diff -r 9ee05c8ab82f -r 1e7ec26380bd make/solaris/makefiles/sa.make --- a/make/solaris/makefiles/sa.make Mon Jul 12 12:53:52 2010 -0700 +++ b/make/solaris/makefiles/sa.make Wed Jul 14 17:52:18 2010 -0400 @@ -36,6 +36,9 @@ # tools.jar is needed by the JDI - SA binding SA_CLASSPATH = $(BOOT_JAVA_HOME)/lib/tools.jar +# TODO: if it's a modules image, check if SA module is installed. +MODULELIB_PATH= $(BOOT_JAVA_HOME)/lib/modules + # gnumake 3.78.1 does not accept the *s that # are in AGENT_FILES1 and AGENT_FILES2, so use the shell to expand them AGENT_FILES1 := $(shell /usr/bin/test -d $(AGENT_DIR) && /bin/ls $(AGENT_FILES1)) @@ -59,7 +62,7 @@ echo "ALT_BOOTDIR, BOOTDIR or JAVA_HOME needs to be defined to build SA"; \ exit 1; \ fi - $(QUIETLY) if [ ! -f $(SA_CLASSPATH) ] ; then \ + $(QUIETLY) if [ ! -f $(SA_CLASSPATH) -a ! -d $(MODULELIB_PATH) ] ; then \ echo "Missing $(SA_CLASSPATH) file. Use 1.6.0 or later version of JDK";\ echo ""; \ exit 1; \ diff -r 9ee05c8ab82f -r 1e7ec26380bd src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/os/linux/vm/os_linux.cpp Wed Jul 14 17:52:18 2010 -0400 @@ -2079,9 +2079,9 @@ static char saved_jvm_path[MAXPATHLEN] = {0}; // Find the full path to the current module, libjvm.so or libjvm_g.so -void os::jvm_path(char *buf, jint len) { +void os::jvm_path(char *buf, jint buflen) { // Error checking. - if (len < MAXPATHLEN) { + if (buflen < MAXPATHLEN) { assert(false, "must use a large-enough buffer"); buf[0] = '\0'; return; @@ -2117,6 +2117,9 @@ // Look for JAVA_HOME in the environment. char* java_home_var = ::getenv("JAVA_HOME"); if (java_home_var != NULL && java_home_var[0] != 0) { + char* jrelib_p; + int len; + // Check the current module name "libjvm.so" or "libjvm_g.so". p = strrchr(buf, '/'); assert(strstr(p, "/libjvm") == p, "invalid library name"); @@ -2124,14 +2127,24 @@ if (realpath(java_home_var, buf) == NULL) return; - sprintf(buf + strlen(buf), "/jre/lib/%s", cpu_arch); + + // determine if this is a legacy image or modules image + // modules image doesn't have "jre" subdirectory + len = strlen(buf); + jrelib_p = buf + len; + snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch); + if (0 != access(buf, F_OK)) { + snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch); + } + if (0 == access(buf, F_OK)) { // Use current module name "libjvm[_g].so" instead of // "libjvm"debug_only("_g")".so" since for fastdebug version // we should have "libjvm.so" but debug_only("_g") adds "_g"! // It is used when we are choosing the HPI library's name // "libhpi[_g].so" in hpi::initialize_get_interface(). - sprintf(buf + strlen(buf), "/hotspot/libjvm%s.so", p); + len = strlen(buf); + snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p); } else { // Go back to path of .so if (realpath(dli_fname, buf) == NULL) diff -r 9ee05c8ab82f -r 1e7ec26380bd src/os/solaris/vm/os_solaris.cpp --- a/src/os/solaris/vm/os_solaris.cpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/os/solaris/vm/os_solaris.cpp Wed Jul 14 17:52:18 2010 -0400 @@ -2435,6 +2435,8 @@ char* java_home_var = ::getenv("JAVA_HOME"); if (java_home_var != NULL && java_home_var[0] != 0) { char cpu_arch[12]; + char* jrelib_p; + int len; sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch)); #ifdef _LP64 // If we are on sparc running a 64-bit vm, look in jre/lib/sparcv9. @@ -2450,14 +2452,23 @@ p = strstr(p, "_g") ? "_g" : ""; realpath(java_home_var, buf); - sprintf(buf + strlen(buf), "/jre/lib/%s", cpu_arch); + // determine if this is a legacy image or modules image + // modules image doesn't have "jre" subdirectory + len = strlen(buf); + jrelib_p = buf + len; + snprintf(jrelib_p, buflen-len, "/jre/lib/%s", cpu_arch); + if (0 != access(buf, F_OK)) { + snprintf(jrelib_p, buflen-len, "/lib/%s", cpu_arch); + } + if (0 == access(buf, F_OK)) { // Use current module name "libjvm[_g].so" instead of // "libjvm"debug_only("_g")".so" since for fastdebug version // we should have "libjvm.so" but debug_only("_g") adds "_g"! // It is used when we are choosing the HPI library's name // "libhpi[_g].so" in hpi::initialize_get_interface(). - sprintf(buf + strlen(buf), "/hotspot/libjvm%s.so", p); + len = strlen(buf); + snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p); } else { // Go back to path of .so realpath((char *)dlinfo.dli_fname, buf); diff -r 9ee05c8ab82f -r 1e7ec26380bd src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/share/vm/runtime/os.cpp Wed Jul 14 17:52:18 2010 -0400 @@ -886,6 +886,11 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" + + // ## TEMPORARY hack to keep the legacy launcher working when + // ## only the boot module is installed (cf. j.l.ClassLoader) + "%/lib/modules/jdk.boot.jar:" + "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false; diff -r 9ee05c8ab82f -r 1e7ec26380bd src/share/vm/runtime/synchronizer.cpp --- a/src/share/vm/runtime/synchronizer.cpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/share/vm/runtime/synchronizer.cpp Wed Jul 14 17:52:18 2010 -0400 @@ -747,6 +747,8 @@ ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ; +ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ; +int ObjectSynchronizer::gOmInUseCount = 0; static volatile intptr_t ListLock = 0 ; // protects global monitor free-list cache static volatile int MonitorFreeCount = 0 ; // # on gFreeList static volatile int MonitorPopulation = 0 ; // # Extant -- in circulation @@ -826,6 +828,22 @@ } } } +/* Too slow for general assert or debug +void ObjectSynchronizer::verifyInUse (Thread *Self) { + ObjectMonitor* mid; + int inusetally = 0; + for (mid = Self->omInUseList; mid != NULL; mid = mid->FreeNext) { + inusetally ++; + } + assert(inusetally == Self->omInUseCount, "inuse count off"); + + int freetally = 0; + for (mid = Self->omFreeList; mid != NULL; mid = mid->FreeNext) { + freetally ++; + } + assert(freetally == Self->omFreeCount, "free count off"); +} +*/ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) { // A large MAXPRIVATE value reduces both list lock contention @@ -853,6 +871,9 @@ m->FreeNext = Self->omInUseList; Self->omInUseList = m; Self->omInUseCount ++; + // verifyInUse(Self); + } else { + m->FreeNext = NULL; } return m ; } @@ -874,13 +895,12 @@ guarantee (take->object() == NULL, "invariant") ; guarantee (!take->is_busy(), "invariant") ; take->Recycle() ; - omRelease (Self, take) ; + omRelease (Self, take, false) ; } Thread::muxRelease (&ListLock) ; Self->omFreeProvision += 1 + (Self->omFreeProvision/2) ; if (Self->omFreeProvision > MAXPRIVATE ) Self->omFreeProvision = MAXPRIVATE ; TEVENT (omFirst - reprovision) ; - continue ; const int mx = MonitorBound ; if (mx > 0 && (MonitorPopulation-MonitorFreeCount) > mx) { @@ -961,11 +981,34 @@ // That is, *not* one-at-a-time. -void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m) { +void ObjectSynchronizer::omRelease (Thread * Self, ObjectMonitor * m, bool fromPerThreadAlloc) { guarantee (m->object() == NULL, "invariant") ; - m->FreeNext = Self->omFreeList ; - Self->omFreeList = m ; - Self->omFreeCount ++ ; + + // Remove from omInUseList + if (MonitorInUseLists && fromPerThreadAlloc) { + ObjectMonitor* curmidinuse = NULL; + for (ObjectMonitor* mid = Self->omInUseList; mid != NULL; ) { + if (m == mid) { + // extract from per-thread in-use-list + if (mid == Self->omInUseList) { + Self->omInUseList = mid->FreeNext; + } else if (curmidinuse != NULL) { + curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } + Self->omInUseCount --; + // verifyInUse(Self); + break; + } else { + curmidinuse = mid; + mid = mid->FreeNext; + } + } + } + + // FreeNext is used for both onInUseList and omFreeList, so clear old before setting new + m->FreeNext = Self->omFreeList ; + Self->omFreeList = m ; + Self->omFreeCount ++ ; } // Return the monitors of a moribund thread's local free list to @@ -975,6 +1018,10 @@ // consecutive STW safepoints. Relatedly, we might decay // omFreeProvision at STW safepoints. // +// Also return the monitors of a moribund thread"s omInUseList to +// a global gOmInUseList under the global list lock so these +// will continue to be scanned. +// // We currently call omFlush() from the Thread:: dtor _after the thread // has been excised from the thread list and is no longer a mutator. // That means that omFlush() can run concurrently with a safepoint and @@ -987,24 +1034,50 @@ void ObjectSynchronizer::omFlush (Thread * Self) { ObjectMonitor * List = Self->omFreeList ; // Null-terminated SLL Self->omFreeList = NULL ; - if (List == NULL) return ; ObjectMonitor * Tail = NULL ; - ObjectMonitor * s ; int Tally = 0; - for (s = List ; s != NULL ; s = s->FreeNext) { - Tally ++ ; - Tail = s ; - guarantee (s->object() == NULL, "invariant") ; - guarantee (!s->is_busy(), "invariant") ; - s->set_owner (NULL) ; // redundant but good hygiene - TEVENT (omFlush - Move one) ; + if (List != NULL) { + ObjectMonitor * s ; + for (s = List ; s != NULL ; s = s->FreeNext) { + Tally ++ ; + Tail = s ; + guarantee (s->object() == NULL, "invariant") ; + guarantee (!s->is_busy(), "invariant") ; + s->set_owner (NULL) ; // redundant but good hygiene + TEVENT (omFlush - Move one) ; + } + guarantee (Tail != NULL && List != NULL, "invariant") ; } - guarantee (Tail != NULL && List != NULL, "invariant") ; + ObjectMonitor * InUseList = Self->omInUseList; + ObjectMonitor * InUseTail = NULL ; + int InUseTally = 0; + if (InUseList != NULL) { + Self->omInUseList = NULL; + ObjectMonitor *curom; + for (curom = InUseList; curom != NULL; curom = curom->FreeNext) { + InUseTail = curom; + InUseTally++; + } +// TODO debug + assert(Self->omInUseCount == InUseTally, "inuse count off"); + Self->omInUseCount = 0; + guarantee (InUseTail != NULL && InUseList != NULL, "invariant"); + } + Thread::muxAcquire (&ListLock, "omFlush") ; - Tail->FreeNext = gFreeList ; - gFreeList = List ; - MonitorFreeCount += Tally; + if (Tail != NULL) { + Tail->FreeNext = gFreeList ; + gFreeList = List ; + MonitorFreeCount += Tally; + } + + if (InUseTail != NULL) { + InUseTail->FreeNext = gOmInUseList; + gOmInUseList = InUseList; + gOmInUseCount += InUseTally; + } + Thread::muxRelease (&ListLock) ; TEVENT (omFlush) ; } @@ -1166,7 +1239,6 @@ // We do this before the CAS in order to minimize the length of time // in which INFLATING appears in the mark. m->Recycle(); - m->FreeNext = NULL ; m->_Responsible = NULL ; m->OwnerIsThread = 0 ; m->_recursions = 0 ; @@ -1174,7 +1246,7 @@ markOop cmp = (markOop) Atomic::cmpxchg_ptr (markOopDesc::INFLATING(), object->mark_addr(), mark) ; if (cmp != mark) { - omRelease (Self, m) ; + omRelease (Self, m, true) ; continue ; // Interference -- just retry } @@ -1262,7 +1334,6 @@ m->set_object(object); m->OwnerIsThread = 1 ; m->_recursions = 0 ; - m->FreeNext = NULL ; m->_Responsible = NULL ; m->_SpinDuration = Knob_SpinLimit ; // consider: keep metastats by type/class @@ -1271,7 +1342,7 @@ m->set_owner (NULL) ; m->OwnerIsThread = 0 ; m->Recycle() ; - omRelease (Self, m) ; + omRelease (Self, m, true) ; m = NULL ; continue ; // interference - the markword changed - just retry. @@ -1852,6 +1923,10 @@ // only scans the per-thread inuse lists. omAlloc() puts all // assigned monitors on the per-thread list. deflate_idle_monitors() // returns the non-busy monitors to the global free list. +// When a thread dies, omFlush() adds the list of active monitors for +// that thread to a global gOmInUseList acquiring the +// global list lock. deflate_idle_monitors() acquires the global +// list lock to scan for non-busy monitors to the global free list. // An alternative could have used a single global inuse list. The // downside would have been the additional cost of acquiring the global list lock // for every omAlloc(). @@ -1904,6 +1979,7 @@ if (*FreeHeadp == NULL) *FreeHeadp = mid; if (*FreeTailp != NULL) { ObjectMonitor * prevtail = *FreeTailp; + assert(prevtail->FreeNext == NULL, "cleaned up deflated?"); // TODO KK prevtail->FreeNext = mid; } *FreeTailp = mid; @@ -1912,6 +1988,39 @@ return deflated; } +// Caller acquires ListLock +int ObjectSynchronizer::walk_monitor_list(ObjectMonitor** listheadp, + ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp) { + ObjectMonitor* mid; + ObjectMonitor* next; + ObjectMonitor* curmidinuse = NULL; + int deflatedcount = 0; + + for (mid = *listheadp; mid != NULL; ) { + oop obj = (oop) mid->object(); + bool deflated = false; + if (obj != NULL) { + deflated = deflate_monitor(mid, obj, FreeHeadp, FreeTailp); + } + if (deflated) { + // extract from per-thread in-use-list + if (mid == *listheadp) { + *listheadp = mid->FreeNext; + } else if (curmidinuse != NULL) { + curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist + } + next = mid->FreeNext; + mid->FreeNext = NULL; // This mid is current tail in the FreeHead list + mid = next; + deflatedcount++; + } else { + curmidinuse = mid; + mid = mid->FreeNext; + } + } + return deflatedcount; +} + void ObjectSynchronizer::deflate_idle_monitors() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); int nInuse = 0 ; // currently associated with objects @@ -1929,36 +2038,25 @@ Thread::muxAcquire (&ListLock, "scavenge - return") ; if (MonitorInUseLists) { - ObjectMonitor* mid; - ObjectMonitor* next; - ObjectMonitor* curmidinuse; + int inUse = 0; for (JavaThread* cur = Threads::first(); cur != NULL; cur = cur->next()) { - curmidinuse = NULL; - for (mid = cur->omInUseList; mid != NULL; ) { - oop obj = (oop) mid->object(); - deflated = false; - if (obj != NULL) { - deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); - } - if (deflated) { - // extract from per-thread in-use-list - if (mid == cur->omInUseList) { - cur->omInUseList = mid->FreeNext; - } else if (curmidinuse != NULL) { - curmidinuse->FreeNext = mid->FreeNext; // maintain the current thread inuselist - } - next = mid->FreeNext; - mid->FreeNext = NULL; // This mid is current tail in the FreeHead list - mid = next; - cur->omInUseCount--; - nScavenged ++ ; - } else { - curmidinuse = mid; - mid = mid->FreeNext; - nInuse ++; - } + nInCirculation+= cur->omInUseCount; + int deflatedcount = walk_monitor_list(cur->omInUseList_addr(), &FreeHead, &FreeTail); + cur->omInUseCount-= deflatedcount; + // verifyInUse(cur); + nScavenged += deflatedcount; + nInuse += cur->omInUseCount; } - } + + // For moribund threads, scan gOmInUseList + if (gOmInUseList) { + nInCirculation += gOmInUseCount; + int deflatedcount = walk_monitor_list((ObjectMonitor **)&gOmInUseList, &FreeHead, &FreeTail); + gOmInUseCount-= deflatedcount; + nScavenged += deflatedcount; + nInuse += gOmInUseCount; + } + } else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { // Iterate over all extant monitors - Scavenge all idle monitors. assert(block->object() == CHAINMARKER, "must be a block header"); diff -r 9ee05c8ab82f -r 1e7ec26380bd src/share/vm/runtime/synchronizer.hpp --- a/src/share/vm/runtime/synchronizer.hpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/share/vm/runtime/synchronizer.hpp Wed Jul 14 17:52:18 2010 -0400 @@ -122,8 +122,9 @@ static void reenter (Handle obj, intptr_t recursion, TRAPS); // thread-specific and global objectMonitor free list accessors +// static void verifyInUse (Thread * Self) ; too slow for general assert/debug static ObjectMonitor * omAlloc (Thread * Self) ; - static void omRelease (Thread * Self, ObjectMonitor * m) ; + static void omRelease (Thread * Self, ObjectMonitor * m, bool FromPerThreadAlloc) ; static void omFlush (Thread * Self) ; // Inflate light weight monitor to heavy weight monitor @@ -150,6 +151,9 @@ // Basically we deflate all monitors that are not busy. // An adaptive profile-based deflation policy could be used if needed static void deflate_idle_monitors(); + static int walk_monitor_list(ObjectMonitor** listheadp, + ObjectMonitor** FreeHeadp, + ObjectMonitor** FreeTailp); static bool deflate_monitor(ObjectMonitor* mid, oop obj, ObjectMonitor** FreeHeadp, ObjectMonitor** FreeTailp); static void oops_do(OopClosure* f); @@ -163,6 +167,8 @@ enum { _BLOCKSIZE = 128 }; static ObjectMonitor* gBlockList; static ObjectMonitor * volatile gFreeList; + static ObjectMonitor * volatile gOmInUseList; // for moribund thread, so monitors they inflated still get scanned + static int gOmInUseCount; public: static void Initialize () ; diff -r 9ee05c8ab82f -r 1e7ec26380bd src/share/vm/runtime/thread.hpp --- a/src/share/vm/runtime/thread.hpp Mon Jul 12 12:53:52 2010 -0700 +++ b/src/share/vm/runtime/thread.hpp Wed Jul 14 17:52:18 2010 -0400 @@ -270,6 +270,7 @@ static void interrupt(Thread* thr); static bool is_interrupted(Thread* thr, bool clear_interrupted); + ObjectMonitor** omInUseList_addr() { return (ObjectMonitor **)&omInUseList; } Monitor* SR_lock() const { return _SR_lock; } bool has_async_exception() const { return (_suspend_flags & _has_async_exception) != 0; }