提交 e61bcd09 编写于 作者: F fyang

8047212: runtime/ParallelClassLoading/bootstrap/random/inner-complex...

8047212: runtime/ParallelClassLoading/bootstrap/random/inner-complex assert(ObjectSynchronizer::verify_objmon_isinpool(inf)) failed: monitor is invalid
Summary: Fix race between ObjectMonitor alloc and verification code; teach SA about "static pointer volatile" fields.
Reviewed-by: andrew
上级 c6836afa
...@@ -149,7 +149,7 @@ int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) { ...@@ -149,7 +149,7 @@ int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) {
#define NINFLATIONLOCKS 256 #define NINFLATIONLOCKS 256
static volatile intptr_t InflationLocks [NINFLATIONLOCKS] ; static volatile intptr_t InflationLocks [NINFLATIONLOCKS] ;
ObjectMonitor * ObjectSynchronizer::gBlockList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gBlockList = NULL;
ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gFreeList = NULL ;
ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ; ObjectMonitor * volatile ObjectSynchronizer::gOmInUseList = NULL ;
int ObjectSynchronizer::gOmInUseCount = 0; int ObjectSynchronizer::gOmInUseCount = 0;
...@@ -830,18 +830,18 @@ JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) { ...@@ -830,18 +830,18 @@ JavaThread* ObjectSynchronizer::get_lock_owner(Handle h_obj, bool doLock) {
// Visitors ... // Visitors ...
void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) { void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) {
ObjectMonitor* block = gBlockList; ObjectMonitor* block =
ObjectMonitor* mid; (ObjectMonitor*)OrderAccess::load_ptr_acquire(&gBlockList);
while (block) { while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header"); assert(block->object() == CHAINMARKER, "must be a block header");
for (int i = _BLOCKSIZE - 1; i > 0; i--) { for (int i = _BLOCKSIZE - 1; i > 0; i--) {
mid = block + i; ObjectMonitor* mid = (ObjectMonitor *)(block + i);
oop object = (oop) mid->object(); oop object = (oop)mid->object();
if (object != NULL) { if (object != NULL) {
closure->do_monitor(mid); closure->do_monitor(mid);
} }
} }
block = (ObjectMonitor*) block->FreeNext; block = (ObjectMonitor*)block->FreeNext;
} }
} }
...@@ -856,7 +856,9 @@ static inline ObjectMonitor* next(ObjectMonitor* block) { ...@@ -856,7 +856,9 @@ static inline ObjectMonitor* next(ObjectMonitor* block) {
void ObjectSynchronizer::oops_do(OopClosure* f) { void ObjectSynchronizer::oops_do(OopClosure* f) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { ObjectMonitor* block =
(ObjectMonitor*)OrderAccess::load_ptr_acquire(&gBlockList);
for (; block != NULL; block = (ObjectMonitor *)next(block)) {
assert(block->object() == CHAINMARKER, "must be a block header"); assert(block->object() == CHAINMARKER, "must be a block header");
for (int i = 1; i < _BLOCKSIZE; i++) { for (int i = 1; i < _BLOCKSIZE; i++) {
ObjectMonitor* mid = &block[i]; ObjectMonitor* mid = &block[i];
...@@ -1059,7 +1061,9 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) { ...@@ -1059,7 +1061,9 @@ ObjectMonitor * ATTR ObjectSynchronizer::omAlloc (Thread * Self) {
// The very first objectMonitor in a block is reserved and dedicated. // The very first objectMonitor in a block is reserved and dedicated.
// It serves as blocklist "next" linkage. // It serves as blocklist "next" linkage.
temp[0].FreeNext = gBlockList; temp[0].FreeNext = gBlockList;
gBlockList = temp; // There are lock-free uses of gBlockList so make sure that
// the previous stores happen before we update gBlockList.
OrderAccess::release_store_ptr(&gBlockList, temp);
// Add the new string of objectMonitors to the global free list // Add the new string of objectMonitors to the global free list
temp[_BLOCKSIZE - 1].FreeNext = gFreeList ; temp[_BLOCKSIZE - 1].FreeNext = gFreeList ;
...@@ -1536,29 +1540,33 @@ void ObjectSynchronizer::deflate_idle_monitors() { ...@@ -1536,29 +1540,33 @@ void ObjectSynchronizer::deflate_idle_monitors() {
nInuse += gOmInUseCount; nInuse += gOmInUseCount;
} }
} else for (ObjectMonitor* block = gBlockList; block != NULL; block = next(block)) { } else {
// Iterate over all extant monitors - Scavenge all idle monitors. ObjectMonitor* block =
assert(block->object() == CHAINMARKER, "must be a block header"); (ObjectMonitor*)OrderAccess::load_ptr_acquire(&gBlockList);
nInCirculation += _BLOCKSIZE ; for (; block != NULL; block = (ObjectMonitor*)next(block)) {
for (int i = 1 ; i < _BLOCKSIZE; i++) { // Iterate over all extant monitors - Scavenge all idle monitors.
ObjectMonitor* mid = &block[i]; assert(block->object() == CHAINMARKER, "must be a block header");
oop obj = (oop) mid->object(); nInCirculation += _BLOCKSIZE;
for (int i = 1; i < _BLOCKSIZE; i++) {
if (obj == NULL) { ObjectMonitor* mid = (ObjectMonitor*)&block[i];
// The monitor is not associated with an object. oop obj = (oop)mid->object();
// The monitor should either be a thread-specific private
// free list or the global free list. if (obj == NULL) {
// obj == NULL IMPLIES mid->is_busy() == 0 // The monitor is not associated with an object.
guarantee (!mid->is_busy(), "invariant") ; // The monitor should either be a thread-specific private
continue ; // free list or the global free list.
} // obj == NULL IMPLIES mid->is_busy() == 0
deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail); guarantee(!mid->is_busy(), "invariant");
continue;
}
deflated = deflate_monitor(mid, obj, &FreeHead, &FreeTail);
if (deflated) { if (deflated) {
mid->FreeNext = NULL ; mid->FreeNext = NULL;
nScavenged ++ ; nScavenged++;
} else { } else {
nInuse ++; nInuse++;
}
} }
} }
} }
...@@ -1693,13 +1701,13 @@ void ObjectSynchronizer::sanity_checks(const bool verbose, ...@@ -1693,13 +1701,13 @@ void ObjectSynchronizer::sanity_checks(const bool verbose,
// Verify all monitors in the monitor cache, the verification is weak. // Verify all monitors in the monitor cache, the verification is weak.
void ObjectSynchronizer::verify() { void ObjectSynchronizer::verify() {
ObjectMonitor* block = gBlockList; ObjectMonitor* block =
ObjectMonitor* mid; (ObjectMonitor *)OrderAccess::load_ptr_acquire(&gBlockList);
while (block) { while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header"); assert(block->object() == CHAINMARKER, "must be a block header");
for (int i = 1; i < _BLOCKSIZE; i++) { for (int i = 1; i < _BLOCKSIZE; i++) {
mid = block + i; ObjectMonitor* mid = (ObjectMonitor *)(block + i);
oop object = (oop) mid->object(); oop object = (oop)mid->object();
if (object != NULL) { if (object != NULL) {
mid->verify(); mid->verify();
} }
...@@ -1713,18 +1721,18 @@ void ObjectSynchronizer::verify() { ...@@ -1713,18 +1721,18 @@ void ObjectSynchronizer::verify() {
// the list of extant blocks without taking a lock. // the list of extant blocks without taking a lock.
int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) { int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) {
ObjectMonitor* block = gBlockList; ObjectMonitor* block =
(ObjectMonitor*)OrderAccess::load_ptr_acquire(&gBlockList);
while (block) { while (block != NULL) {
assert(block->object() == CHAINMARKER, "must be a block header"); assert(block->object() == CHAINMARKER, "must be a block header");
if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) { if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) {
address mon = (address) monitor; address mon = (address)monitor;
address blk = (address) block; address blk = (address)block;
size_t diff = mon - blk; size_t diff = mon - blk;
assert((diff % sizeof(ObjectMonitor)) == 0, "check"); assert((diff % sizeof(ObjectMonitor)) == 0, "must be aligned");
return 1; return 1;
} }
block = (ObjectMonitor*) block->FreeNext; block = (ObjectMonitor*)block->FreeNext;
} }
return 0; return 0;
} }
......
...@@ -131,7 +131,7 @@ class ObjectSynchronizer : AllStatic { ...@@ -131,7 +131,7 @@ class ObjectSynchronizer : AllStatic {
private: private:
enum { _BLOCKSIZE = 128 }; enum { _BLOCKSIZE = 128 };
static ObjectMonitor* gBlockList; static ObjectMonitor * volatile gBlockList;
static ObjectMonitor * volatile gFreeList; static ObjectMonitor * volatile gFreeList;
static ObjectMonitor * volatile gOmInUseList; // for moribund thread, so monitors they inflated still get scanned static ObjectMonitor * volatile gOmInUseList; // for moribund thread, so monitors they inflated still get scanned
static int gOmInUseCount; static int gOmInUseCount;
......
...@@ -257,6 +257,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -257,6 +257,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
#define VM_STRUCTS(nonstatic_field, \ #define VM_STRUCTS(nonstatic_field, \
static_field, \ static_field, \
static_ptr_volatile_field, \
unchecked_nonstatic_field, \ unchecked_nonstatic_field, \
volatile_nonstatic_field, \ volatile_nonstatic_field, \
nonproduct_nonstatic_field, \ nonproduct_nonstatic_field, \
...@@ -1082,7 +1083,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -1082,7 +1083,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
volatile_nonstatic_field(BasicLock, _displaced_header, markOop) \ volatile_nonstatic_field(BasicLock, _displaced_header, markOop) \
nonstatic_field(BasicObjectLock, _lock, BasicLock) \ nonstatic_field(BasicObjectLock, _lock, BasicLock) \
nonstatic_field(BasicObjectLock, _obj, oop) \ nonstatic_field(BasicObjectLock, _obj, oop) \
static_field(ObjectSynchronizer, gBlockList, ObjectMonitor*) \ static_ptr_volatile_field(ObjectSynchronizer,gBlockList, ObjectMonitor*) \
\ \
/*********************/ \ /*********************/ \
/* Matcher (C2 only) */ \ /* Matcher (C2 only) */ \
...@@ -2667,6 +2668,11 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -2667,6 +2668,11 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
#define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ #define GENERATE_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \
{ QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName }, { QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, &typeName::fieldName },
// This macro generates a VMStructEntry line for a static pointer volatile field,
// e.g.: "static ObjectMonitor * volatile gBlockList;"
#define GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \
{ QUOTE(typeName), QUOTE(fieldName), QUOTE(type), 1, 0, (void*)&typeName::fieldName },
// This macro generates a VMStructEntry line for an unchecked // This macro generates a VMStructEntry line for an unchecked
// nonstatic field, in which the size of the type is also specified. // nonstatic field, in which the size of the type is also specified.
// The type string is given as NULL, indicating an "opaque" type. // The type string is given as NULL, indicating an "opaque" type.
...@@ -2692,10 +2698,15 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable; ...@@ -2692,10 +2698,15 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
#define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ #define CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \
{typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; } {typedef type dummyvtype; typeName *dummyObj = NULL; volatile dummyvtype* dummy = &dummyObj->fieldName; }
// This macro checks the type of a VMStructEntry by comparing pointer types // This macro checks the type of a static VMStructEntry by comparing pointer types
#define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \ #define CHECK_STATIC_VM_STRUCT_ENTRY(typeName, fieldName, type) \
{type* dummy = &typeName::fieldName; } {type* dummy = &typeName::fieldName; }
// This macro checks the type of a static pointer volatile VMStructEntry by comparing pointer types,
// e.g.: "static ObjectMonitor * volatile gBlockList;"
#define CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY(typeName, fieldName, type) \
{type volatile * dummy = &typeName::fieldName; }
// This macro ensures the type of a field and its containing type are // This macro ensures the type of a field and its containing type are
// present in the type table. The assertion string is shorter than // present in the type table. The assertion string is shorter than
// preferable because (incredibly) of a bug in Solstice NFS client // preferable because (incredibly) of a bug in Solstice NFS client
...@@ -2889,6 +2900,7 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = { ...@@ -2889,6 +2900,7 @@ VMStructEntry VMStructs::localHotSpotVMStructs[] = {
VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY, VM_STRUCTS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
GENERATE_STATIC_VM_STRUCT_ENTRY, GENERATE_STATIC_VM_STRUCT_ENTRY,
GENERATE_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY,
GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_UNCHECKED_NONSTATIC_VM_STRUCT_ENTRY,
GENERATE_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, GENERATE_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY,
...@@ -3047,6 +3059,7 @@ void ...@@ -3047,6 +3059,7 @@ void
VMStructs::init() { VMStructs::init() {
VM_STRUCTS(CHECK_NONSTATIC_VM_STRUCT_ENTRY, VM_STRUCTS(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
CHECK_STATIC_VM_STRUCT_ENTRY, CHECK_STATIC_VM_STRUCT_ENTRY,
CHECK_STATIC_PTR_VOLATILE_VM_STRUCT_ENTRY,
CHECK_NO_OP, CHECK_NO_OP,
CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY, CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY,
CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY, CHECK_NONPRODUCT_NONSTATIC_VM_STRUCT_ENTRY,
...@@ -3162,8 +3175,10 @@ VMStructs::init() { ...@@ -3162,8 +3175,10 @@ VMStructs::init() {
CHECK_NO_OP, CHECK_NO_OP,
CHECK_NO_OP, CHECK_NO_OP,
CHECK_NO_OP, CHECK_NO_OP,
CHECK_NO_OP,
CHECK_NO_OP)); CHECK_NO_OP));
debug_only(VM_STRUCTS(CHECK_NO_OP, debug_only(VM_STRUCTS(CHECK_NO_OP,
ENSURE_FIELD_TYPE_PRESENT,
ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT,
CHECK_NO_OP, CHECK_NO_OP,
ENSURE_FIELD_TYPE_PRESENT, ENSURE_FIELD_TYPE_PRESENT,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册