7125896: Eliminate nested locks

Nested locks elimination done before lock nodes expansion by looking for outer locks of the same object.

Reviewed-by: never, twisti
This commit is contained in:
Vladimir Kozlov 2012-01-07 13:26:43 -08:00
parent f99fb50071
commit 94927c382b
17 changed files with 366 additions and 145 deletions

View file

@ -1789,7 +1789,8 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) {
slow_call_address);
}
//-----------------------mark_eliminated_locking_nodes-----------------------
//-------------------mark_eliminated_box----------------------------------
//
// During EA obj may point to several objects but after few ideal graph
// transformations (CCP) it may point to only one non escaping object
// (but still using phi), corresponding locks and unlocks will be marked
@ -1800,62 +1801,145 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) {
// marked for elimination since new obj has no escape information.
// Mark all associated (same box and obj) lock and unlock nodes for
// elimination if some of them marked already.
void PhaseMacroExpand::mark_eliminated_locking_nodes(AbstractLockNode *alock) {
if (!alock->is_eliminated()) {
void PhaseMacroExpand::mark_eliminated_box(Node* oldbox, Node* obj) {
if (oldbox->is_BoxLock() && oldbox->as_BoxLock()->is_eliminated())
return;
if (oldbox->is_BoxLock() &&
oldbox->as_BoxLock()->is_simple_lock_region(NULL, obj)) {
// Box is used only in one lock region. Mark this box as eliminated.
_igvn.hash_delete(oldbox);
oldbox->as_BoxLock()->set_eliminated(); // This changes box's hash value
_igvn.hash_insert(oldbox);
for (uint i = 0; i < oldbox->outcnt(); i++) {
Node* u = oldbox->raw_out(i);
if (u->is_AbstractLock() && !u->as_AbstractLock()->is_non_esc_obj()) {
AbstractLockNode* alock = u->as_AbstractLock();
// Check lock's box since box could be referenced by Lock's debug info.
if (alock->box_node() == oldbox) {
assert(alock->obj_node() == obj, "");
// Mark eliminated all related locks and unlocks.
alock->set_non_esc_obj();
}
}
}
return;
}
if (!alock->is_coarsened()) { // Eliminated by EA
// Create new "eliminated" BoxLock node and use it
// in monitor debug info for the same object.
BoxLockNode* oldbox = alock->box_node()->as_BoxLock();
Node* obj = alock->obj_node();
if (!oldbox->is_eliminated()) {
BoxLockNode* newbox = oldbox->clone()->as_BoxLock();
// Create new "eliminated" BoxLock node and use it in monitor debug info
// instead of oldbox for the same object.
BoxLockNode* box = BoxLockNode::box_node(oldbox);
BoxLockNode* newbox = box->clone()->as_BoxLock();
// Note: BoxLock node is marked eliminated only here and it is used
// to indicate that all associated lock and unlock nodes are marked
// for elimination.
newbox->set_eliminated();
transform_later(newbox);
// Replace old box node with new box for all users of the same object.
for (uint i = 0; i < oldbox->outcnt();) {
bool next_edge = true;
Node* u = oldbox->raw_out(i);
if (u->is_AbstractLock()) {
AbstractLockNode* alock = u->as_AbstractLock();
if (alock->obj_node() == obj && alock->box_node() == oldbox) {
// Replace Box and mark eliminated all related locks and unlocks.
alock->set_non_esc_obj();
_igvn.hash_delete(alock);
alock->set_box_node(newbox);
_igvn._worklist.push(alock);
next_edge = false;
}
}
if (u->is_FastLock() && u->as_FastLock()->obj_node() == obj) {
FastLockNode* flock = u->as_FastLock();
assert(flock->box_node() == oldbox, "sanity");
_igvn.hash_delete(flock);
flock->set_box_node(newbox);
_igvn._worklist.push(flock);
next_edge = false;
}
// Replace old box in monitor debug info.
if (u->is_SafePoint() && u->as_SafePoint()->jvms()) {
SafePointNode* sfn = u->as_SafePoint();
JVMState* youngest_jvms = sfn->jvms();
int max_depth = youngest_jvms->depth();
for (int depth = 1; depth <= max_depth; depth++) {
JVMState* jvms = youngest_jvms->of_depth(depth);
int num_mon = jvms->nof_monitors();
// Loop over monitors
for (int idx = 0; idx < num_mon; idx++) {
Node* obj_node = sfn->monitor_obj(jvms, idx);
Node* box_node = sfn->monitor_box(jvms, idx);
if (box_node == oldbox && obj_node == obj) {
int j = jvms->monitor_box_offset(idx);
_igvn.hash_delete(u);
u->set_req(j, newbox);
_igvn._worklist.push(u);
next_edge = false;
}
}
}
}
if (next_edge) i++;
}
}
//-----------------------mark_eliminated_locking_nodes-----------------------
void PhaseMacroExpand::mark_eliminated_locking_nodes(AbstractLockNode *alock) {
if (EliminateNestedLocks) {
if (alock->is_nested()) {
assert(alock->box_node()->as_BoxLock()->is_eliminated(), "sanity");
return;
} else if (!alock->is_non_esc_obj()) { // Not eliminated or coarsened
// Only Lock node has JVMState needed here.
if (alock->jvms() != NULL && alock->as_Lock()->is_nested_lock_region()) {
// Mark eliminated related nested locks and unlocks.
Node* obj = alock->obj_node();
BoxLockNode* box_node = alock->box_node()->as_BoxLock();
assert(!box_node->is_eliminated(), "should not be marked yet");
// Note: BoxLock node is marked eliminated only here
// and it is used to indicate that all associated lock
// and unlock nodes are marked for elimination.
newbox->set_eliminated();
transform_later(newbox);
// Replace old box node with new box for all users
// of the same object.
for (uint i = 0; i < oldbox->outcnt();) {
bool next_edge = true;
Node* u = oldbox->raw_out(i);
if (u->is_AbstractLock() &&
u->as_AbstractLock()->obj_node() == obj &&
u->as_AbstractLock()->box_node() == oldbox) {
// Mark all associated locks and unlocks.
u->as_AbstractLock()->set_eliminated();
_igvn.hash_delete(u);
u->set_req(TypeFunc::Parms + 1, newbox);
next_edge = false;
box_node->set_eliminated(); // Box's hash is always NO_HASH here
for (uint i = 0; i < box_node->outcnt(); i++) {
Node* u = box_node->raw_out(i);
if (u->is_AbstractLock()) {
alock = u->as_AbstractLock();
if (alock->box_node() == box_node) {
// Verify that this Box is referenced only by related locks.
assert(alock->obj_node() == obj, "");
// Mark all related locks and unlocks.
alock->set_nested();
}
}
// Replace old box in monitor debug info.
if (u->is_SafePoint() && u->as_SafePoint()->jvms()) {
SafePointNode* sfn = u->as_SafePoint();
JVMState* youngest_jvms = sfn->jvms();
int max_depth = youngest_jvms->depth();
for (int depth = 1; depth <= max_depth; depth++) {
JVMState* jvms = youngest_jvms->of_depth(depth);
int num_mon = jvms->nof_monitors();
// Loop over monitors
for (int idx = 0; idx < num_mon; idx++) {
Node* obj_node = sfn->monitor_obj(jvms, idx);
Node* box_node = sfn->monitor_box(jvms, idx);
if (box_node == oldbox && obj_node == obj) {
int j = jvms->monitor_box_offset(idx);
_igvn.hash_delete(u);
u->set_req(j, newbox);
next_edge = false;
}
} // for (int idx = 0;
} // for (int depth = 1;
} // if (u->is_SafePoint()
if (next_edge) i++;
} // for (uint i = 0; i < oldbox->outcnt();)
} // if (!oldbox->is_eliminated())
} // if (!alock->is_coarsened())
}
}
return;
}
// Process locks for non escaping object
assert(alock->is_non_esc_obj(), "");
} // EliminateNestedLocks
if (alock->is_non_esc_obj()) { // Lock is used for non escaping object
// Look for all locks of this object and mark them and
// corresponding BoxLock nodes as eliminated.
Node* obj = alock->obj_node();
for (uint j = 0; j < obj->outcnt(); j++) {
Node* o = obj->raw_out(j);
if (o->is_AbstractLock() && o->as_AbstractLock()->obj_node() == obj) {
alock = o->as_AbstractLock();
Node* box = alock->box_node();
// Replace old box node with new eliminated box for all users
// of the same object and mark related locks as eliminated.
mark_eliminated_box(box, obj);
}
}
}
}
// we have determined that this lock/unlock can be eliminated, we simply
@ -1870,7 +1954,7 @@ bool PhaseMacroExpand::eliminate_locking_node(AbstractLockNode *alock) {
return false;
}
#ifdef ASSERT
if (alock->is_Lock() && !alock->is_coarsened()) {
if (!alock->is_coarsened()) {
// Check that new "eliminated" BoxLock node is created.
BoxLockNode* oldbox = alock->box_node()->as_BoxLock();
assert(oldbox->is_eliminated(), "should be done already");
@ -1962,6 +2046,8 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) {
Node* box = lock->box_node();
Node* flock = lock->fastlock_node();
assert(!BoxLockNode::box_node(box)->is_eliminated(), "sanity");
// Make the merge point
Node *region;
Node *mem_phi;
@ -2196,6 +2282,8 @@ void PhaseMacroExpand::expand_unlock_node(UnlockNode *unlock) {
Node* obj = unlock->obj_node();
Node* box = unlock->box_node();
assert(!BoxLockNode::box_node(box)->is_eliminated(), "sanity");
// No need for a null check on unlock
// Make the merge point