hotspot/src/share/vm/opto/callnode.cpp
Print this page
rev 611 : Merge
@@ -1,10 +1,10 @@
#ifdef USE_PRAGMA_IDENT_SRC
#pragma ident "@(#)callnode.cpp 1.238 07/10/04 14:36:00 JVM"
#endif
/*
- * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-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.
@@ -231,10 +231,11 @@
_caller = caller;
_depth = 1 + (caller == NULL ? 0 : caller->depth());
_locoff = TypeFunc::Parms;
_stkoff = _locoff + _method->max_locals();
_monoff = _stkoff + _method->max_stack();
+ _scloff = _monoff;
_endoff = _monoff;
_sp = 0;
}
JVMState::JVMState(int stack_size) {
_method = NULL;
@@ -243,10 +244,11 @@
_caller = NULL;
_depth = 1;
_locoff = TypeFunc::Parms;
_stkoff = _locoff;
_monoff = _stkoff + stack_size;
+ _scloff = _monoff;
_endoff = _monoff;
_sp = 0;
}
//--------------------------------of_depth-------------------------------------
@@ -298,16 +300,26 @@
total += jvmp->debug_size();
}
return total;
}
+#ifndef PRODUCT
+
//------------------------------format_helper----------------------------------
// Given an allocation (a Chaitin object) and a Node decide if the Node carries
// any defined value or not. If it does, print out the register or constant.
-#ifndef PRODUCT
-static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i ) {
+static void format_helper( PhaseRegAlloc *regalloc, outputStream* st, Node *n, const char *msg, uint i, GrowableArray<SafePointScalarObjectNode*> *scobjs ) {
if (n == NULL) { st->print(" NULL"); return; }
+ if (n->is_SafePointScalarObject()) {
+ // Scalar replacement.
+ SafePointScalarObjectNode* spobj = n->as_SafePointScalarObject();
+ scobjs->append_if_missing(spobj);
+ int sco_n = scobjs->find(spobj);
+ assert(sco_n >= 0, "");
+ st->print(" %s%d]=#ScObj" INT32_FORMAT, msg, i, sco_n);
+ return;
+ }
if( OptoReg::is_valid(regalloc->get_reg_first(n))) { // Check for undefined
char buf[50];
regalloc->dump_register(n,buf);
st->print(" %s%d]=%s",msg,i,buf);
} else { // No register, but might be constant
@@ -323,10 +335,13 @@
case Type::AryPtr:
case Type::KlassPtr:
case Type::InstPtr:
st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->isa_oopptr()->const_oop());
break;
+ case Type::NarrowOop:
+ st->print(" %s%d]=#Ptr" INTPTR_FORMAT,msg,i,t->make_ptr()->isa_oopptr()->const_oop());
+ break;
case Type::RawPtr:
st->print(" %s%d]=#Raw" INTPTR_FORMAT,msg,i,t->is_rawptr());
break;
case Type::DoubleCon:
st->print(" %s%d]=#%fD",msg,i,t->is_double_constant()->_d);
@@ -343,58 +358,119 @@
break;
default: ShouldNotReachHere();
}
}
}
-#endif
//------------------------------format-----------------------------------------
-#ifndef PRODUCT
void JVMState::format(PhaseRegAlloc *regalloc, const Node *n, outputStream* st) const {
st->print(" #");
if( _method ) {
_method->print_short_name(st);
st->print(" @ bci:%d ",_bci);
} else {
st->print_cr(" runtime stub ");
return;
}
if (n->is_MachSafePoint()) {
+ GrowableArray<SafePointScalarObjectNode*> scobjs;
MachSafePointNode *mcall = n->as_MachSafePoint();
uint i;
// Print locals
for( i = 0; i < (uint)loc_size(); i++ )
- format_helper( regalloc, st, mcall->local(this, i), "L[", i );
+ format_helper( regalloc, st, mcall->local(this, i), "L[", i, &scobjs );
// Print stack
for (i = 0; i < (uint)stk_size(); i++) {
if ((uint)(_stkoff + i) >= mcall->len())
st->print(" oob ");
else
- format_helper( regalloc, st, mcall->stack(this, i), "STK[", i );
+ format_helper( regalloc, st, mcall->stack(this, i), "STK[", i, &scobjs );
}
for (i = 0; (int)i < nof_monitors(); i++) {
Node *box = mcall->monitor_box(this, i);
Node *obj = mcall->monitor_obj(this, i);
if ( OptoReg::is_valid(regalloc->get_reg_first(box)) ) {
while( !box->is_BoxLock() ) box = box->in(1);
- format_helper( regalloc, st, box, "MON-BOX[", i );
+ format_helper( regalloc, st, box, "MON-BOX[", i, &scobjs );
} else {
OptoReg::Name box_reg = BoxLockNode::stack_slot(box);
st->print(" MON-BOX%d=%s+%d",
i,
OptoReg::regname(OptoReg::c_frame_pointer),
regalloc->reg2offset(box_reg));
}
- format_helper( regalloc, st, obj, "MON-OBJ[", i );
+ 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++) {
+ // Scalar replaced objects.
+ st->print_cr("");
+ st->print(" # ScObj" INT32_FORMAT " ", i);
+ SafePointScalarObjectNode* spobj = scobjs.at(i);
+ ciKlass* cik = spobj->bottom_type()->is_oopptr()->klass();
+ assert(cik->is_instance_klass() ||
+ cik->is_array_klass(), "Not supported allocation.");
+ ciInstanceKlass *iklass = NULL;
+ if (cik->is_instance_klass()) {
+ cik->print_name_on(st);
+ iklass = cik->as_instance_klass();
+ } else if (cik->is_type_array_klass()) {
+ cik->as_array_klass()->base_element_type()->print_name_on(st);
+ st->print("[%d]=", spobj->n_fields());
+ } else if (cik->is_obj_array_klass()) {
+ ciType* cie = cik->as_array_klass()->base_element_type();
+ int ndim = 1;
+ while (cie->is_obj_array_klass()) {
+ ndim += 1;
+ cie = cie->as_array_klass()->base_element_type();
+ }
+ cie->print_name_on(st);
+ while (ndim-- > 0) {
+ st->print("[]");
+ }
+ st->print("[%d]=", spobj->n_fields());
+ }
+ st->print("{");
+ uint nf = spobj->n_fields();
+ if (nf > 0) {
+ uint first_ind = spobj->first_index();
+ Node* fld_node = mcall->in(first_ind);
+ ciField* cifield;
+ if (iklass != NULL) {
+ st->print(" [");
+ cifield = iklass->nonstatic_field_at(0);
+ cifield->print_name_on(st);
+ format_helper( regalloc, st, fld_node, ":", 0, &scobjs );
+ } else {
+ format_helper( regalloc, st, fld_node, "[", 0, &scobjs );
+ }
+ for (uint j = 1; j < nf; j++) {
+ fld_node = mcall->in(first_ind+j);
+ if (iklass != NULL) {
+ st->print(", [");
+ cifield = iklass->nonstatic_field_at(j);
+ cifield->print_name_on(st);
+ format_helper( regalloc, st, fld_node, ":", j, &scobjs );
+ } else {
+ format_helper( regalloc, st, fld_node, ", [", j, &scobjs );
+ }
+ }
+ }
+ st->print(" }");
}
}
st->print_cr("");
if (caller() != NULL) caller()->format(regalloc, n, st);
}
-#endif
-#ifndef PRODUCT
+
void JVMState::dump_spec(outputStream *st) const {
if (_method != NULL) {
bool printed = false;
if (!Verbose) {
// The JVMS dumps make really, really long lines.
@@ -420,13 +496,12 @@
} else {
st->print(" runtime stub");
}
if (caller() != NULL) caller()->dump_spec(st);
}
-#endif
-#ifndef PRODUCT
+
void JVMState::dump_on(outputStream* st) const {
if (_map && !((uintptr_t)_map & 1)) {
if (_map->len() > _map->req()) { // _map->has_exceptions()
Node* ex = _map->in(_map->req()); // _map->next_exception()
// skip the first one; it's already being printed
@@ -435,12 +510,12 @@
ex->dump(1);
}
}
_map->dump(2);
}
- st->print("JVMS depth=%d loc=%d stk=%d mon=%d end=%d mondepth=%d sp=%d bci=%d method=",
- depth(), locoff(), stkoff(), monoff(), endoff(), monitor_depth(), sp(), bci());
+ st->print("JVMS depth=%d loc=%d stk=%d mon=%d scalar=%d end=%d mondepth=%d sp=%d bci=%d method=",
+ depth(), locoff(), stkoff(), monoff(), scloff(), endoff(), monitor_depth(), sp(), bci());
if (_method == NULL) {
st->print_cr("(none)");
} else {
_method->print_name(st);
st->cr();
@@ -466,10 +541,11 @@
JVMState* n = has_method() ? new (C) JVMState(_method, _caller) : new (C) JVMState(0);
n->set_bci(_bci);
n->set_locoff(_locoff);
n->set_stkoff(_stkoff);
n->set_monoff(_monoff);
+ n->set_scloff(_scloff);
n->set_endoff(_endoff);
n->set_sp(_sp);
n->set_map(_map);
return n;
}
@@ -558,10 +634,62 @@
// Do we Match on this edge index or not? Match no edges
uint CallNode::match_edge(uint idx) const {
return 0;
}
+//
+// Determine whether the call could modify the field of the specified
+// instance at the specified offset.
+//
+bool CallNode::may_modify(const TypePtr *addr_t, PhaseTransform *phase) {
+ const TypeOopPtr *adrInst_t = addr_t->isa_oopptr();
+
+ // If not an OopPtr or not an instance type, assume the worst.
+ // Note: currently this method is called only for instance types.
+ if (adrInst_t == NULL || !adrInst_t->is_known_instance()) {
+ return true;
+ }
+ // The instance_id is set only for scalar-replaceable allocations which
+ // are not passed as arguments according to Escape Analysis.
+ return false;
+}
+
+// Does this call have a direct reference to n other than debug information?
+bool CallNode::has_non_debug_use(Node *n) {
+ const TypeTuple * d = tf()->domain();
+ for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
+ Node *arg = in(i);
+ if (arg == n) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Returns the unique CheckCastPP of a call
+// or 'this' if there are several CheckCastPP
+// or returns NULL if there is no one.
+Node *CallNode::result_cast() {
+ Node *cast = NULL;
+
+ Node *p = proj_out(TypeFunc::Parms);
+ if (p == NULL)
+ return NULL;
+
+ for (DUIterator_Fast imax, i = p->fast_outs(imax); i < imax; i++) {
+ Node *use = p->fast_out(i);
+ if (use->is_CheckCastPP()) {
+ if (cast != NULL) {
+ return this; // more than 1 CheckCastPP
+ }
+ cast = use;
+ }
+ }
+ return cast;
+}
+
+
//=============================================================================
uint CallJavaNode::size_of() const { return sizeof(*this); }
uint CallJavaNode::cmp( const Node &n ) const {
CallJavaNode &call = (CallJavaNode&)n;
return CallNode::cmp(call) && _method == call._method;
@@ -711,13 +839,11 @@
//------------------------------Ideal------------------------------------------
// Skip over any collapsed Regions
Node *SafePointNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- if (remove_dead_region(phase, can_reshape)) return this;
-
- return NULL;
+ return remove_dead_region(phase, can_reshape) ? this : NULL;
}
//------------------------------Identity---------------------------------------
// Remove obviously duplicate safepoints
Node *SafePointNode::Identity( PhaseTransform *phase ) {
@@ -766,44 +892,52 @@
void SafePointNode::grow_stack(JVMState* jvms, uint grow_by) {
assert((int)grow_by > 0, "sanity");
int monoff = jvms->monoff();
+ int scloff = jvms->scloff();
int endoff = jvms->endoff();
assert(endoff == (int)req(), "no other states or debug info after me");
Node* top = Compile::current()->top();
for (uint i = 0; i < grow_by; i++) {
ins_req(monoff, top);
}
jvms->set_monoff(monoff + grow_by);
+ jvms->set_scloff(scloff + grow_by);
jvms->set_endoff(endoff + grow_by);
}
void SafePointNode::push_monitor(const FastLockNode *lock) {
// Add a LockNode, which points to both the original BoxLockNode (the
// stack space for the monitor) and the Object being locked.
const int MonitorEdges = 2;
assert(JVMState::logMonitorEdges == exact_log2(MonitorEdges), "correct MonitorEdges");
assert(req() == jvms()->endoff(), "correct sizing");
+ int nextmon = jvms()->scloff();
if (GenerateSynchronizationCode) {
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());
}
void SafePointNode::pop_monitor() {
// Delete last monitor from debug info
debug_only(int num_before_pop = jvms()->nof_monitors());
const int MonitorEdges = (1<<JVMState::logMonitorEdges);
+ int scloff = jvms()->scloff();
int endoff = jvms()->endoff();
+ int new_scloff = scloff - MonitorEdges;
int new_endoff = endoff - MonitorEdges;
+ jvms()->set_scloff(new_scloff);
jvms()->set_endoff(new_endoff);
- while (endoff > new_endoff) del_req(--endoff);
+ while (scloff > new_scloff) del_req(--scloff);
assert(jvms()->nof_monitors() == num_before_pop-1, "");
}
Node *SafePointNode::peek_monitor_box() const {
int mon = jvms()->nof_monitors() - 1;
@@ -823,20 +957,79 @@
return 0;
return (TypeFunc::Parms == idx);
}
+//============== SafePointScalarObjectNode ==============
+
+SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
+#ifdef ASSERT
+ AllocateNode* alloc,
+#endif
+ uint first_index,
+ uint n_fields) :
+ TypeNode(tp, 1), // 1 control input -- seems required. Get from root.
+#ifdef ASSERT
+ _alloc(alloc),
+#endif
+ _first_index(first_index),
+ _n_fields(n_fields)
+{
+ init_class_id(Class_SafePointScalarObject);
+}
+
+bool SafePointScalarObjectNode::pinned() const { return true; }
+
+uint SafePointScalarObjectNode::ideal_reg() const {
+ return 0; // No matching to machine instruction
+}
+
+const RegMask &SafePointScalarObjectNode::in_RegMask(uint idx) const {
+ return *(Compile::current()->matcher()->idealreg2debugmask[in(idx)->ideal_reg()]);
+}
+
+const RegMask &SafePointScalarObjectNode::out_RegMask() const {
+ return RegMask::Empty;
+}
+
+uint SafePointScalarObjectNode::match_edge(uint idx) const {
+ return 0;
+}
+
+SafePointScalarObjectNode*
+SafePointScalarObjectNode::clone(int jvms_adj, Dict* sosn_map) const {
+ void* cached = (*sosn_map)[(void*)this];
+ if (cached != NULL) {
+ return (SafePointScalarObjectNode*)cached;
+ }
+ Compile* C = Compile::current();
+ SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone();
+ res->_first_index += jvms_adj;
+ sosn_map->Insert((void*)this, (void*)res);
+ return res;
+}
+
+
+#ifndef PRODUCT
+void SafePointScalarObjectNode::dump_spec(outputStream *st) const {
+ st->print(" # fields@[%d..%d]", first_index(),
+ first_index() + n_fields() - 1);
+}
+
+#endif
+
//=============================================================================
uint AllocateNode::size_of() const { return sizeof(*this); }
AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype,
Node *ctrl, Node *mem, Node *abio,
Node *size, Node *klass_node, Node *initial_test)
: CallNode(atype, NULL, TypeRawPtr::BOTTOM)
{
init_class_id(Class_Allocate);
init_flags(Flag_is_macro);
+ _is_scalar_replaceable = false;
Node *topnode = C->top();
init_req( TypeFunc::Control , ctrl );
init_req( TypeFunc::I_O , abio );
init_req( TypeFunc::Memory , mem );
@@ -850,10 +1043,43 @@
}
//=============================================================================
uint AllocateArrayNode::size_of() const { return sizeof(*this); }
+// Retrieve the length from the AllocateArrayNode. Narrow the type with a
+// CastII, if appropriate. If we are not allowed to create new nodes, and
+// a CastII is appropriate, return NULL.
+Node *AllocateArrayNode::make_ideal_length(const TypeOopPtr* oop_type, PhaseTransform *phase, bool allow_new_nodes) {
+ Node *length = in(AllocateNode::ALength);
+ assert(length != NULL, "length is not null");
+
+ const TypeInt* length_type = phase->find_int_type(length);
+ const TypeAryPtr* ary_type = oop_type->isa_aryptr();
+
+ if (ary_type != NULL && length_type != NULL) {
+ const TypeInt* narrow_length_type = ary_type->narrow_size_type(length_type);
+ if (narrow_length_type != length_type) {
+ // Assert one of:
+ // - the narrow_length is 0
+ // - the narrow_length is not wider than length
+ assert(narrow_length_type == TypeInt::ZERO ||
+ (narrow_length_type->_hi <= length_type->_hi &&
+ narrow_length_type->_lo >= length_type->_lo),
+ "narrow type must be narrower than length type");
+
+ // Return NULL if new nodes are not allowed
+ if (!allow_new_nodes) return NULL;
+ // Create a cast which is control dependent on the initialization to
+ // propagate the fact that the array length must be positive.
+ length = new (phase->C, 2) CastIINode(length, narrow_length_type);
+ length->set_req(0, initialization()->proj_out(0));
+ }
+ }
+
+ return length;
+}
+
//=============================================================================
uint LockNode::size_of() const { return sizeof(*this); }
// Redundant lock elimination
//
@@ -1152,19 +1378,32 @@
}
//=============================================================================
Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- // perform any generic optimizations first
+ // perform any generic optimizations first (returns 'this' or NULL)
Node *result = SafePointNode::Ideal(phase, can_reshape);
// Now see if we can optimize away this lock. We don't actually
// remove the locking here, we simply set the _eliminate flag which
// prevents macro expansion from expanding the lock. Since we don't
// modify the graph, the value returned from this function is the
// one computed above.
- if (EliminateLocks && !is_eliminated()) {
+ if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) {
+ //
+ // If we are locking an unescaped object, the lock/unlock is unnecessary
+ //
+ ConnectionGraph *cgr = phase->C->congraph();
+ PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
+ if (cgr != NULL)
+ es = cgr->escape_state(obj_node(), phase);
+ if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
+ // Mark it eliminated to update any counters
+ this->set_eliminated();
+ return result;
+ }
+
//
// Try lock coarsening
//
PhaseIterGVN* iter = phase->is_IterGVN();
if (iter != NULL) {
@@ -1200,12 +1439,14 @@
if (PrintEliminateLocks) {
int locks = 0;
int unlocks = 0;
for (int i = 0; i < lock_ops.length(); i++) {
AbstractLockNode* lock = lock_ops.at(i);
- if (lock->Opcode() == Op_Lock) locks++;
- else unlocks++;
+ if (lock->Opcode() == Op_Lock)
+ locks++;
+ else
+ unlocks++;
if (Verbose) {
lock->dump(1);
}
}
tty->print_cr("***Eliminated %d unlocks and %d locks", unlocks, locks);
@@ -1217,10 +1458,11 @@
for (int i = 0; i < lock_ops.length(); i++) {
AbstractLockNode* lock = lock_ops.at(i);
// Mark it eliminated to update any counters
lock->set_eliminated();
+ lock->set_coarsened();
}
} else if (result != NULL && ctrl->is_Region() &&
iter->_worklist.member(ctrl)) {
// We weren't able to find any opportunities but the region this
// lock is control dependent on hasn't been processed yet so put
@@ -1238,77 +1480,29 @@
uint UnlockNode::size_of() const { return sizeof(*this); }
//=============================================================================
Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
- // perform any generic optimizations first
+ // perform any generic optimizations first (returns 'this' or NULL)
Node * result = SafePointNode::Ideal(phase, can_reshape);
// Now see if we can optimize away this unlock. We don't actually
// remove the unlocking here, we simply set the _eliminate flag which
// prevents macro expansion from expanding the unlock. Since we don't
// modify the graph, the value returned from this function is the
// one computed above.
- if (EliminateLocks && !is_eliminated()) {
+ // Escape state is defined after Parse phase.
+ if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) {
//
- // If we are unlocking an unescaped object, the lock/unlock is unnecessary
- // We can eliminate them if there are no safepoints in the locked region.
+ // If we are unlocking an unescaped object, the lock/unlock is unnecessary.
//
- ConnectionGraph *cgr = Compile::current()->congraph();
- if (cgr != NULL && cgr->escape_state(obj_node(), phase) == PointsToNode::NoEscape) {
- GrowableArray<AbstractLockNode*> lock_ops;
- LockNode *lock = find_matching_lock(this);
- if (lock != NULL) {
- lock_ops.append(this);
- lock_ops.append(lock);
- // find other unlocks which pair with the lock we found and add them
- // to the list
- Node * box = box_node();
-
- for (DUIterator_Fast imax, i = box->fast_outs(imax); i < imax; i++) {
- Node *use = box->fast_out(i);
- if (use->is_Unlock() && use != this) {
- UnlockNode *unlock1 = use->as_Unlock();
- if (!unlock1->is_eliminated()) {
- LockNode *lock1 = find_matching_lock(unlock1);
- if (lock == lock1)
- lock_ops.append(unlock1);
- else if (lock1 == NULL) {
- // we can't find a matching lock, we must assume the worst
- lock_ops.trunc_to(0);
- break;
- }
- }
- }
- }
- if (lock_ops.length() > 0) {
-
- #ifndef PRODUCT
- if (PrintEliminateLocks) {
- int locks = 0;
- int unlocks = 0;
- for (int i = 0; i < lock_ops.length(); i++) {
- AbstractLockNode* lock = lock_ops.at(i);
- if (lock->Opcode() == Op_Lock) locks++;
- else unlocks++;
- if (Verbose) {
- lock->dump(1);
- }
- }
- tty->print_cr("***Eliminated %d unescaped unlocks and %d unescaped locks", unlocks, locks);
- }
- #endif
-
- // for each of the identified locks, mark them
- // as eliminatable
- for (int i = 0; i < lock_ops.length(); i++) {
- AbstractLockNode* lock = lock_ops.at(i);
-
+ ConnectionGraph *cgr = phase->C->congraph();
+ PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
+ if (cgr != NULL)
+ es = cgr->escape_state(obj_node(), phase);
+ if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters
- lock->set_eliminated();
- }
- }
- }
+ this->set_eliminated();
}
}
return result;
}