6775880: EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now")
Summary: Create new "eliminated" BoxLock node for monitor debug info when corresponding locks are eliminated.
Reviewed-by: never
--- a/hotspot/src/share/vm/opto/callnode.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/callnode.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -395,7 +395,13 @@
OptoReg::regname(OptoReg::c_frame_pointer),
regalloc->reg2offset(box_reg));
}
- format_helper( regalloc, st, obj, "MON-OBJ[", i, &scobjs );
+ const char* obj_msg = "MON-OBJ[";
+ if (EliminateLocks) {
+ while( !box->is_BoxLock() ) box = box->in(1);
+ if (box->as_BoxLock()->is_eliminated())
+ obj_msg = "MON-OBJ(LOCK ELIMINATED)[";
+ }
+ format_helper( regalloc, st, obj, obj_msg, i, &scobjs );
}
for (i = 0; i < (uint)scobjs.length(); i++) {
@@ -908,8 +914,9 @@
add_req(lock->box_node());
add_req(lock->obj_node());
} else {
- add_req(NULL);
- add_req(NULL);
+ Node* top = Compile::current()->top();
+ add_req(top);
+ add_req(top);
}
jvms()->set_scloff(nextmon+MonitorEdges);
jvms()->set_endoff(req());
@@ -1382,7 +1389,7 @@
//
// If we are locking an unescaped object, the lock/unlock is unnecessary
//
- ConnectionGraph *cgr = Compile::current()->congraph();
+ ConnectionGraph *cgr = phase->C->congraph();
PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
if (cgr != NULL)
es = cgr->escape_state(obj_node(), phase);
@@ -1450,6 +1457,7 @@
// Mark it eliminated to update any counters
lock->set_eliminated();
+ lock->set_coarsened();
}
} else if (result != NULL && ctrl->is_Region() &&
iter->_worklist.member(ctrl)) {
@@ -1484,7 +1492,7 @@
//
// If we are unlocking an unescaped object, the lock/unlock is unnecessary.
//
- ConnectionGraph *cgr = Compile::current()->congraph();
+ ConnectionGraph *cgr = phase->C->congraph();
PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
if (cgr != NULL)
es = cgr->escape_state(obj_node(), phase);
--- a/hotspot/src/share/vm/opto/callnode.hpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/callnode.hpp Wed Dec 03 13:41:37 2008 -0800
@@ -780,7 +780,8 @@
//------------------------------AbstractLockNode-----------------------------------
class AbstractLockNode: public CallNode {
private:
- bool _eliminate; // indicates this lock can be safely eliminated
+ bool _eliminate; // indicates this lock can be safely eliminated
+ bool _coarsened; // indicates this lock was coarsened
#ifndef PRODUCT
NamedCounter* _counter;
#endif
@@ -801,6 +802,7 @@
public:
AbstractLockNode(const TypeFunc *tf)
: CallNode(tf, NULL, TypeRawPtr::BOTTOM),
+ _coarsened(false),
_eliminate(false)
{
#ifndef PRODUCT
@@ -819,6 +821,9 @@
// mark node as eliminated and update the counter if there is one
void set_eliminated();
+ bool is_coarsened() { return _coarsened; }
+ void set_coarsened() { _coarsened = true; }
+
// locking does not modify its arguments
virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;}
--- a/hotspot/src/share/vm/opto/compile.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -1532,11 +1532,6 @@
if (failing()) return;
- // get rid of the connection graph since it's information is not
- // updated by optimizations
- _congraph = NULL;
-
-
// Loop transforms on the ideal graph. Range Check Elimination,
// peeling, unrolling, etc.
--- a/hotspot/src/share/vm/opto/escape.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/escape.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -199,7 +199,8 @@
es = ptnode_adr(idx)->escape_state();
// if we have already computed a value, return it
- if (es != PointsToNode::UnknownEscape)
+ if (es != PointsToNode::UnknownEscape &&
+ ptnode_adr(idx)->node_type() == PointsToNode::JavaObject)
return es;
// PointsTo() calls n->uncast() which can return a new ideal node.
--- a/hotspot/src/share/vm/opto/locknode.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/locknode.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -44,10 +44,15 @@
_inmask.Insert(reg);
}
+//-----------------------------hash--------------------------------------------
+uint BoxLockNode::hash() const {
+ return Node::hash() + _slot + (_is_eliminated ? Compile::current()->fixed_slots() : 0);
+}
+
//------------------------------cmp--------------------------------------------
uint BoxLockNode::cmp( const Node &n ) const {
const BoxLockNode &bn = (const BoxLockNode &)n;
- return bn._slot == _slot;
+ return bn._slot == _slot && bn._is_eliminated == _is_eliminated;
}
OptoReg::Name BoxLockNode::stack_slot(Node* box_node) {
--- a/hotspot/src/share/vm/opto/locknode.hpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/locknode.hpp Wed Dec 03 13:41:37 2008 -0800
@@ -36,7 +36,7 @@
virtual const RegMask &in_RegMask(uint) const;
virtual const RegMask &out_RegMask() const;
virtual uint size_of() const;
- virtual uint hash() const { return Node::hash() + _slot; }
+ virtual uint hash() const;
virtual uint cmp( const Node &n ) const;
virtual const class Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
virtual uint ideal_reg() const { return Op_RegP; }
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/macro.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -59,7 +59,7 @@
for (uint i = old_dbg_start; i < oldcall->req(); i++) {
Node* old_in = oldcall->in(i);
// Clone old SafePointScalarObjectNodes, adjusting their field contents.
- if (old_in->is_SafePointScalarObject()) {
+ if (old_in != NULL && old_in->is_SafePointScalarObject()) {
SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
uint old_unique = C->unique();
Node* new_in = old_sosn->clone(jvms_adj, sosn_map);
@@ -1509,21 +1509,63 @@
if (!alock->is_eliminated()) {
return false;
}
- // Mark the box lock as eliminated if all correspondent locks are eliminated
- // to construct correct debug info.
- BoxLockNode* box = alock->box_node()->as_BoxLock();
- if (!box->is_eliminated()) {
- bool eliminate = true;
- for (DUIterator_Fast imax, i = box->fast_outs(imax); i < imax; i++) {
- Node *lck = box->fast_out(i);
- if (lck->is_Lock() && !lck->as_AbstractLock()->is_eliminated()) {
- eliminate = false;
- break;
- }
- }
- if (eliminate)
- box->set_eliminated();
- }
+ if (alock->is_Lock() && !alock->is_coarsened()) {
+ // 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();
+ 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 == alock) {
+ i++;
+ continue; // It will be removed below
+ }
+ if (u->is_Lock() &&
+ u->as_Lock()->obj_node() == obj &&
+ // oldbox could be referenced in debug info also
+ u->as_Lock()->box_node() == oldbox) {
+ assert(u->as_Lock()->is_eliminated(), "sanity");
+ _igvn.hash_delete(u);
+ u->set_req(TypeFunc::Parms + 1, newbox);
+ next_edge = false;
+#ifdef ASSERT
+ } else if (u->is_Unlock() && u->as_Unlock()->obj_node() == obj) {
+ assert(u->as_Unlock()->is_eliminated(), "sanity");
+#endif
+ }
+ // 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_Lock() && !lock->is_coarsened())
#ifndef PRODUCT
if (PrintEliminateLocks) {
@@ -1562,6 +1604,15 @@
_igvn.subsume_node(ctrlproj, fallthroughproj);
_igvn.hash_delete(memproj);
_igvn.subsume_node(memproj, memproj_fallthrough);
+
+ // Delete FastLock node also if this Lock node is unique user
+ // (a loop peeling may clone a Lock node).
+ Node* flock = alock->as_Lock()->fastlock_node();
+ if (flock->outcnt() == 1) {
+ assert(flock->unique_out() == alock, "sanity");
+ _igvn.hash_delete(flock);
+ _igvn.subsume_node(flock, top());
+ }
}
// Seach for MemBarRelease node and delete it also.
@@ -1887,7 +1938,7 @@
bool PhaseMacroExpand::expand_macro_nodes() {
if (C->macro_count() == 0)
return false;
- // attempt to eliminate allocations
+ // First, attempt to eliminate locks
bool progress = true;
while (progress) {
progress = false;
@@ -1895,6 +1946,26 @@
Node * n = C->macro_node(i-1);
bool success = false;
debug_only(int old_macro_count = C->macro_count(););
+ if (n->is_AbstractLock()) {
+ success = eliminate_locking_node(n->as_AbstractLock());
+ } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
+ _igvn.add_users_to_worklist(n);
+ _igvn.hash_delete(n);
+ _igvn.subsume_node(n, n->in(1));
+ success = true;
+ }
+ assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
+ progress = progress || success;
+ }
+ }
+ // Next, attempt to eliminate allocations
+ progress = true;
+ while (progress) {
+ progress = false;
+ for (int i = C->macro_count(); i > 0; i--) {
+ Node * n = C->macro_node(i-1);
+ bool success = false;
+ debug_only(int old_macro_count = C->macro_count(););
switch (n->class_id()) {
case Node::Class_Allocate:
case Node::Class_AllocateArray:
@@ -1902,17 +1973,10 @@
break;
case Node::Class_Lock:
case Node::Class_Unlock:
- success = eliminate_locking_node(n->as_AbstractLock());
+ assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
break;
default:
- if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
- _igvn.add_users_to_worklist(n);
- _igvn.hash_delete(n);
- _igvn.subsume_node(n, n->in(1));
- success = true;
- } else {
- assert(false, "unknown node type in macro list");
- }
+ assert(false, "unknown node type in macro list");
}
assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
progress = progress || success;
--- a/hotspot/src/share/vm/opto/output.cpp Tue Nov 25 13:14:07 2008 -0800
+++ b/hotspot/src/share/vm/opto/output.cpp Wed Dec 03 13:41:37 2008 -0800
@@ -849,10 +849,8 @@
// Loop over monitors and insert into array
for(idx = 0; idx < num_mon; idx++) {
// Grab the node that defines this monitor
- Node* box_node;
- Node* obj_node;
- box_node = sfn->monitor_box(jvms, idx);
- obj_node = sfn->monitor_obj(jvms, idx);
+ Node* box_node = sfn->monitor_box(jvms, idx);
+ Node* obj_node = sfn->monitor_obj(jvms, idx);
// Create ScopeValue for object
ScopeValue *scval = NULL;
@@ -890,6 +888,7 @@
OptoReg::Name box_reg = BoxLockNode::stack_slot(box_node);
Location basic_lock = Location::new_stk_loc(Location::normal,_regalloc->reg2offset(box_reg));
+ while( !box_node->is_BoxLock() ) box_node = box_node->in(1);
monarray->append(new MonitorValue(scval, basic_lock, box_node->as_BoxLock()->is_eliminated()));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6775880/Test.java Wed Dec 03 13:41:37 2008 -0800
@@ -0,0 +1,67 @@
+/*
+ * 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
+ * @bug 6775880
+ * @summary EA +DeoptimizeALot: assert(mon_info->owner()->is_locked(),"object must be locked now")
+ * @compile -source 1.4 -target 1.4 Test.java
+ * @run main/othervm -server -Xbatch -XX:+DoEscapeAnalysis -XX:+DeoptimizeALot -XX:CompileCommand=exclude,java.lang.AbstractStringBuilder::append Test
+ */
+
+public class Test {
+
+ int cnt;
+ int b[];
+ String s;
+
+ String test() {
+ String res="";
+ for (int i=0; i < cnt; i++) {
+ if (i != 0) {
+ res = res +".";
+ }
+ res = res + b[i];
+ }
+ return res;
+ }
+
+ public static void main(String[] args) {
+ Test t = new Test();
+ t.cnt = 3;
+ t.b = new int[3];
+ t.b[0] = 0;
+ t.b[1] = 1;
+ t.b[2] = 2;
+ int j=0;
+ t.s = "";
+ for (int i=0; i<10001; i++) {
+ t.s = "c";
+ t.s = t.test();
+ }
+ System.out.println("After s=" + t.s);
+ }
+}
+
+