# HG changeset patch # User kvn # Date 1228340497 28800 # Node ID 424f9bfe6b96f5ffa249d9a87a09224b0a691ed1 # Parent 3a86a8dcf27c536055055fb192a83413301fff5a 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 diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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); diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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;} diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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. diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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. diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/locknode.cpp --- a/src/share/vm/opto/locknode.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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) { diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/locknode.hpp --- a/src/share/vm/opto/locknode.hpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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; } diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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; diff -r 3a86a8dcf27c -r 424f9bfe6b96 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Tue Nov 25 13:14:07 2008 -0800 +++ b/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())); } diff -r 3a86a8dcf27c -r 424f9bfe6b96 test/compiler/6775880/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/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); + } +} + +