6667615: (Escape Analysis) extend MDO to cache arguments escape state
Summary: Use MDO to cache arguments escape state determined by the byte code escape analyzer.
Reviewed-by: never
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.cpp Tue Mar 11 19:00:38 2008 -0700
@@ -104,7 +104,7 @@
};
void BCEscapeAnalyzer::set_returned(ArgumentMap vars) {
- for (int i = 0; i <= _arg_size; i++) {
+ for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i))
_arg_returned.set_bit(i);
}
@@ -112,10 +112,9 @@
_return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars());
}
-
// return true if any element of vars is an argument
bool BCEscapeAnalyzer::is_argument(ArgumentMap vars) {
- for (int i = 0; i <= _arg_size; i++) {
+ for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i))
return true;
}
@@ -126,7 +125,7 @@
bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){
if (_conservative)
return true;
- for (int i = 0; i <= _arg_size; i++) {
+ for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i) && _arg_stack.at(i))
return true;
}
@@ -134,12 +133,13 @@
}
void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, BitMap &bm) {
- for (int i = 0; i <= _arg_size; i++) {
+ for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i)) {
bm.clear_bit(i);
}
}
}
+
void BCEscapeAnalyzer::set_method_escape(ArgumentMap vars) {
clear_bits(vars, _arg_local);
}
@@ -155,6 +155,17 @@
clear_bits(vars, _dirty);
}
+void BCEscapeAnalyzer::set_modified(ArgumentMap vars, int offs, int size) {
+
+ for (int i = 0; i < _arg_size; i++) {
+ if (vars.contains(i)) {
+ set_arg_modified(i, offs, size);
+ }
+ }
+ if (vars.contains_unknown())
+ _unknown_modified = true;
+}
+
bool BCEscapeAnalyzer::is_recursive_call(ciMethod* callee) {
for (BCEscapeAnalyzer* scope = this; scope != NULL; scope = scope->_parent) {
if (scope->method() == callee) {
@@ -164,6 +175,40 @@
return false;
}
+bool BCEscapeAnalyzer::is_arg_modified(int arg, int offset, int size_in_bytes) {
+ if (offset == OFFSET_ANY)
+ return _arg_modified[arg] != 0;
+ assert(arg >= 0 && arg < _arg_size, "must be an argument.");
+ bool modified = false;
+ int l = offset / HeapWordSize;
+ int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize;
+ if (l > ARG_OFFSET_MAX)
+ l = ARG_OFFSET_MAX;
+ if (h > ARG_OFFSET_MAX+1)
+ h = ARG_OFFSET_MAX + 1;
+ for (int i = l; i < h; i++) {
+ modified = modified || (_arg_modified[arg] & (1 << i)) != 0;
+ }
+ return modified;
+}
+
+void BCEscapeAnalyzer::set_arg_modified(int arg, int offset, int size_in_bytes) {
+ if (offset == OFFSET_ANY) {
+ _arg_modified[arg] = (uint) -1;
+ return;
+ }
+ assert(arg >= 0 && arg < _arg_size, "must be an argument.");
+ int l = offset / HeapWordSize;
+ int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize;
+ if (l > ARG_OFFSET_MAX)
+ l = ARG_OFFSET_MAX;
+ if (h > ARG_OFFSET_MAX+1)
+ h = ARG_OFFSET_MAX + 1;
+ for (int i = l; i < h; i++) {
+ _arg_modified[arg] |= (1 << i);
+ }
+}
+
void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder) {
int i;
@@ -197,6 +242,7 @@
for (i = 0; i < arg_size; i++) {
set_method_escape(state.raw_pop());
}
+ _unknown_modified = true; // assume the worst since we don't analyze the called method
return;
}
@@ -224,6 +270,11 @@
ArgumentMap arg = state.raw_pop();
if (!is_argument(arg))
continue;
+ for (int j = 0; j < _arg_size; j++) {
+ if (arg.contains(j)) {
+ _arg_modified[j] |= analyzer._arg_modified[i];
+ }
+ }
if (!is_arg_stack(arg)) {
// arguments have already been recognized as escaping
} else if (analyzer.is_arg_stack(i) && !analyzer.is_arg_returned(i)) {
@@ -233,6 +284,7 @@
set_global_escape(arg);
}
}
+ _unknown_modified = _unknown_modified || analyzer.has_non_arg_side_affects();
// record dependencies if at least one parameter retained stack-allocatable
if (must_record_dependencies) {
@@ -250,8 +302,10 @@
ArgumentMap arg = state.raw_pop();
if (!is_argument(arg))
continue;
+ set_modified(arg, OFFSET_ANY, type2size[T_INT]*HeapWordSize);
set_global_escape(arg);
}
+ _unknown_modified = true; // assume the worst since we don't know the called method
}
}
@@ -421,6 +475,7 @@
state.spop();
ArgumentMap arr = state.apop();
set_method_escape(arr);
+ set_modified(arr, OFFSET_ANY, type2size[T_INT]*HeapWordSize);
break;
}
case Bytecodes::_lastore:
@@ -430,6 +485,7 @@
state.spop();
ArgumentMap arr = state.apop();
set_method_escape(arr);
+ set_modified(arr, OFFSET_ANY, type2size[T_LONG]*HeapWordSize);
break;
}
case Bytecodes::_aastore:
@@ -437,6 +493,7 @@
set_global_escape(state.apop());
state.spop();
ArgumentMap arr = state.apop();
+ set_modified(arr, OFFSET_ANY, type2size[T_OBJECT]*HeapWordSize);
break;
}
case Bytecodes::_pop:
@@ -762,6 +819,7 @@
if (s.cur_bc() != Bytecodes::_putstatic) {
ArgumentMap p = state.apop();
set_method_escape(p);
+ set_modified(p, will_link ? field->offset() : OFFSET_ANY, type2size[field_type]*HeapWordSize);
}
}
break;
@@ -872,7 +930,7 @@
}
void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state) {
- StateInfo *d_state = blockstates+dest->index();
+ StateInfo *d_state = blockstates + dest->index();
int nlocals = _method->max_locals();
// exceptions may cause transfer of control to handlers in the middle of a
@@ -916,6 +974,7 @@
}
for (int i = 0; i < s_state->_stack_height; i++) {
ArgumentMap t;
+ //extra_vars |= !d_state->_vars[i] & s_state->_vars[i];
t.clear();
t = s_state->_stack[i];
t.set_difference(d_state->_stack[i]);
@@ -933,7 +992,7 @@
int datacount = (numblocks + 1) * (stkSize + numLocals);
int datasize = datacount * sizeof(ArgumentMap);
- StateInfo *blockstates = (StateInfo *) arena->Amalloc(_methodBlocks->num_blocks() * sizeof(StateInfo));
+ StateInfo *blockstates = (StateInfo *) arena->Amalloc(numblocks * sizeof(StateInfo));
ArgumentMap *statedata = (ArgumentMap *) arena->Amalloc(datasize);
for (int i = 0; i < datacount; i++) ::new ((void*)&statedata[i]) ArgumentMap();
ArgumentMap *dp = statedata;
@@ -961,33 +1020,35 @@
ArgumentMap allVars; // all oop arguments to method
ciSignature* sig = method()->signature();
int j = 0;
+ ciBlock* first_blk = _methodBlocks->block_containing(0);
+ int fb_i = first_blk->index();
if (!method()->is_static()) {
// record information for "this"
- blockstates[0]._vars[j].set(j);
+ blockstates[fb_i]._vars[j].set(j);
allVars.add(j);
j++;
}
for (int i = 0; i < sig->count(); i++) {
ciType* t = sig->type_at(i);
if (!t->is_primitive_type()) {
- blockstates[0]._vars[j].set(j);
+ blockstates[fb_i]._vars[j].set(j);
allVars.add(j);
}
j += t->size();
}
- blockstates[0]._initialized = true;
+ blockstates[fb_i]._initialized = true;
assert(j == _arg_size, "just checking");
ArgumentMap unknown_map;
unknown_map.add_unknown();
- worklist.push(_methodBlocks->block_containing(0));
+ worklist.push(first_blk);
while(worklist.length() > 0) {
ciBlock *blk = worklist.pop();
- StateInfo *blkState = blockstates+blk->index();
+ StateInfo *blkState = blockstates + blk->index();
if (blk->is_handler() || blk->is_ret_target()) {
// for an exception handler or a target of a ret instruction, we assume the worst case,
- // that any variable or stack slot could contain any argument
+ // that any variable could contain any argument
for (int i = 0; i < numLocals; i++) {
state._vars[i] = allVars;
}
@@ -997,6 +1058,7 @@
state._stack_height = blkState->_stack_height;
}
for (int i = 0; i < state._stack_height; i++) {
+// ??? should this be unknown_map ???
state._stack[i] = allVars;
}
} else {
@@ -1053,6 +1115,7 @@
vmIntrinsics::ID iid = method()->intrinsic_id();
if (iid == vmIntrinsics::_getClass ||
+ iid == vmIntrinsics::_fillInStackTrace ||
iid == vmIntrinsics::_hashCode)
return iid;
else
@@ -1060,12 +1123,16 @@
}
bool BCEscapeAnalyzer::compute_escape_for_intrinsic(vmIntrinsics::ID iid) {
- ArgumentMap empty;
- empty.clear();
+ ArgumentMap arg;
+ arg.clear();
switch (iid) {
case vmIntrinsics::_getClass:
_return_local = false;
break;
+ case vmIntrinsics::_fillInStackTrace:
+ arg.set(0); // 'this'
+ set_returned(arg);
+ break;
case vmIntrinsics::_hashCode:
// initialized state is correct
break;
@@ -1109,15 +1176,21 @@
_return_allocated = true;
}
_allocated_escapes = false;
+ _unknown_modified = false;
}
void BCEscapeAnalyzer::clear_escape_info() {
ciSignature* sig = method()->signature();
int arg_count = sig->count();
ArgumentMap var;
+ if (!method()->is_static()) {
+ arg_count++; // allow for "this"
+ }
for (int i = 0; i < arg_count; i++) {
+ set_arg_modified(i, OFFSET_ANY, 4);
var.clear();
var.set(i);
+ set_modified(var, OFFSET_ANY, 4);
set_global_escape(var);
}
_arg_local.clear();
@@ -1126,6 +1199,7 @@
_return_local = false;
_return_allocated = false;
_allocated_escapes = true;
+ _unknown_modified = true;
}
@@ -1205,8 +1279,17 @@
} else {
tty->print_cr(" non-local return values");
}
+ tty->print(" modified args: ");
+ for (int i = 0; i < _arg_size; i++) {
+ if (_arg_modified[i] == 0)
+ tty->print(" 0");
+ else
+ tty->print(" 0x%x", _arg_modified[i]);
+ }
tty->cr();
tty->print(" flags: ");
+ if (_unknown_modified)
+ tty->print(" unknown_modified");
if (_return_allocated)
tty->print(" return_allocated");
tty->cr();
@@ -1228,6 +1311,7 @@
if (_arg_returned.at(i)) {
methodData()->set_arg_returned(i);
}
+ methodData()->set_arg_modified(i, _arg_modified[i]);
}
if (_return_local) {
methodData()->set_eflag(methodDataOopDesc::return_local);
@@ -1244,6 +1328,7 @@
_arg_local.at_put(i, methodData()->is_arg_local(i));
_arg_stack.at_put(i, methodData()->is_arg_stack(i));
_arg_returned.at_put(i, methodData()->is_arg_returned(i));
+ _arg_modified[i] = methodData()->arg_modified(i);
}
_return_local = methodData()->eflag_set(methodDataOopDesc::return_local);
@@ -1261,6 +1346,12 @@
tty->print_cr(" non-local return values");
}
tty->print(" modified args: ");
+ for (int i = 0; i < _arg_size; i++) {
+ if (_arg_modified[i] == 0)
+ tty->print(" 0");
+ else
+ tty->print(" 0x%x", _arg_modified[i]);
+ }
tty->cr();
}
#endif
@@ -1281,6 +1372,7 @@
, _return_local(false)
, _return_allocated(false)
, _allocated_escapes(false)
+ , _unknown_modified(false)
, _dependencies()
, _parent(parent)
, _level(parent == NULL ? 0 : parent->level() + 1) {
@@ -1290,6 +1382,8 @@
_arg_returned.clear();
_dirty.clear();
Arena* arena = CURRENT_ENV->arena();
+ _arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint));
+ Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint));
if (methodData() == NULL)
return;
--- a/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/ci/bcEscapeAnalyzer.hpp Tue Mar 11 19:00:38 2008 -0700
@@ -46,9 +46,12 @@
BitMap _arg_stack;
BitMap _arg_returned;
BitMap _dirty;
+ enum{ ARG_OFFSET_MAX = 31};
+ uint *_arg_modified;
bool _return_local;
bool _allocated_escapes;
+ bool _unknown_modified;
bool _return_allocated;
ciObjectList _dependencies;
@@ -80,6 +83,7 @@
void set_method_escape(ArgumentMap vars);
void set_global_escape(ArgumentMap vars);
void set_dirty(ArgumentMap vars);
+ void set_modified(ArgumentMap vars, int offs, int size);
bool is_recursive_call(ciMethod* callee);
void add_dependence(ciKlass *klass, ciMethod *meth);
@@ -140,6 +144,13 @@
return !_conservative && _return_allocated && !_allocated_escapes;
}
+ // Tracking of argument modification
+
+ enum {OFFSET_ANY = -1};
+ bool is_arg_modified(int arg, int offset, int size_in_bytes);
+ void set_arg_modified(int arg, int offset, int size_in_bytes);
+ bool has_non_arg_side_affects() { return _unknown_modified; }
+
// Copy dependencies from this analysis into "deps"
void copy_dependencies(Dependencies *deps);
};
--- a/hotspot/src/share/vm/ci/ciMethodData.cpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodData.cpp Tue Mar 11 19:00:38 2008 -0700
@@ -42,6 +42,8 @@
// Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0.
_hint_di = first_di();
+ // Initialize the escape information (to "don't know.");
+ _eflags = _arg_local = _arg_stack = _arg_returned = 0;
}
// ------------------------------------------------------------------
@@ -59,6 +61,8 @@
// Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0.
_hint_di = first_di();
+ // Initialize the escape information (to "don't know.");
+ _eflags = _arg_local = _arg_stack = _arg_returned = 0;
}
void ciMethodData::load_data() {
@@ -142,6 +146,8 @@
return new ciBranchData(data_layout);
case DataLayout::multi_branch_data_tag:
return new ciMultiBranchData(data_layout);
+ case DataLayout::arg_info_data_tag:
+ return new ciArgInfoData(data_layout);
};
}
@@ -172,6 +178,9 @@
_saw_free_extra_data = true; // observed an empty slot (common case)
return NULL;
}
+ if (dp->tag() == DataLayout::arg_info_data_tag) {
+ break; // ArgInfoData is at the end of extra data section.
+ }
if (dp->bci() == bci) {
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
return new ciBitData(dp);
@@ -217,8 +226,14 @@
void ciMethodData::clear_escape_info() {
VM_ENTRY_MARK;
methodDataOop mdo = get_methodDataOop();
- if (mdo != NULL)
+ if (mdo != NULL) {
mdo->clear_escape_info();
+ ArgInfoData *aid = arg_info();
+ int arg_count = (aid == NULL) ? 0 : aid->number_of_args();
+ for (int i = 0; i < arg_count; i++) {
+ set_arg_modified(i, 0);
+ }
+ }
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
}
@@ -231,6 +246,10 @@
mdo->set_arg_local(_arg_local);
mdo->set_arg_stack(_arg_stack);
mdo->set_arg_returned(_arg_returned);
+ int arg_count = mdo->method()->size_of_parameters();
+ for (int i = 0; i < arg_count; i++) {
+ mdo->set_arg_modified(i, arg_modified(i));
+ }
}
}
@@ -262,6 +281,14 @@
set_nth_bit(_arg_returned, i);
}
+void ciMethodData::set_arg_modified(int arg, uint val) {
+ ArgInfoData *aid = arg_info();
+ if (aid == NULL)
+ return;
+ assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number");
+ aid->set_arg_modified(arg, val);
+}
+
bool ciMethodData::is_arg_local(int i) const {
return is_set_nth_bit(_arg_local, i);
}
@@ -274,6 +301,14 @@
return is_set_nth_bit(_arg_returned, i);
}
+uint ciMethodData::arg_modified(int arg) const {
+ ArgInfoData *aid = arg_info();
+ if (aid == NULL)
+ return 0;
+ assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number");
+ return aid->arg_modified(arg);
+}
+
ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) {
// Get offset within methodDataOop of the data array
ByteSize data_offset = methodDataOopDesc::data_offset();
@@ -287,6 +322,18 @@
return in_ByteSize(offset);
}
+ciArgInfoData *ciMethodData::arg_info() const {
+ // Should be last, have to skip all traps.
+ DataLayout* dp = data_layout_at(data_size());
+ DataLayout* end = data_layout_at(data_size() + extra_data_size());
+ for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) {
+ if (dp->tag() == DataLayout::arg_info_data_tag)
+ return new ciArgInfoData(dp);
+ }
+ return NULL;
+}
+
+
// Implementation of the print method.
void ciMethodData::print_impl(outputStream* st) {
ciObject::print_impl(st);
@@ -305,6 +352,22 @@
st->fill_to(6);
data->print_data_on(st);
}
+ st->print_cr("--- Extra data:");
+ DataLayout* dp = data_layout_at(data_size());
+ DataLayout* end = data_layout_at(data_size() + extra_data_size());
+ for (; dp < end; dp = methodDataOopDesc::next_extra(dp)) {
+ if (dp->tag() == DataLayout::no_tag) continue;
+ if (dp->tag() == DataLayout::bit_data_tag) {
+ data = new BitData(dp);
+ } else {
+ assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo");
+ data = new ciArgInfoData(dp);
+ dp = end; // ArgInfoData is at the end of extra data section.
+ }
+ st->print("%d", dp_to_di(data->dp()));
+ st->fill_to(6);
+ data->print_data_on(st);
+ }
}
void ciReceiverTypeData::print_receiver_data_on(outputStream* st) {
--- a/hotspot/src/share/vm/ci/ciMethodData.hpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/ci/ciMethodData.hpp Tue Mar 11 19:00:38 2008 -0700
@@ -30,6 +30,7 @@
class ciBranchData;
class ciArrayData;
class ciMultiBranchData;
+class ciArgInfoData;
typedef ProfileData ciProfileData;
@@ -121,6 +122,11 @@
ciMultiBranchData(DataLayout* layout) : MultiBranchData(layout) {};
};
+class ciArgInfoData : public ArgInfoData {
+public:
+ ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {};
+};
+
// ciMethodData
//
// This class represents a methodDataOop in the HotSpot virtual
@@ -163,9 +169,9 @@
ciMethodData();
// Accessors
- int data_size() { return _data_size; }
- int extra_data_size() { return _extra_data_size; }
- intptr_t * data() { return _data; }
+ int data_size() const { return _data_size; }
+ int extra_data_size() const { return _extra_data_size; }
+ intptr_t * data() const { return _data; }
methodDataOop get_methodDataOop() const {
if (handle() == NULL) return NULL;
@@ -178,7 +184,7 @@
void print_impl(outputStream* st);
- DataLayout* data_layout_at(int data_index) {
+ DataLayout* data_layout_at(int data_index) const {
assert(data_index % sizeof(intptr_t) == 0, "unaligned");
return (DataLayout*) (((address)_data) + data_index);
}
@@ -207,6 +213,8 @@
// What is the index of the first data entry?
int first_di() { return 0; }
+ ciArgInfoData *arg_info() const;
+
public:
bool is_method_data() { return true; }
bool is_empty() { return _state == empty_state; }
@@ -270,10 +278,12 @@
void set_arg_local(int i);
void set_arg_stack(int i);
void set_arg_returned(int i);
+ void set_arg_modified(int arg, uint val);
bool is_arg_local(int i) const;
bool is_arg_stack(int i) const;
bool is_arg_returned(int i) const;
+ uint arg_modified(int arg) const;
// Code generation helper
ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data);
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Tue Mar 11 19:00:38 2008 -0700
@@ -318,6 +318,11 @@
const int neg = JVM_ACC_SYNCHRONIZED;
return (flags & (req | neg)) == req;
}
+inline bool match_F_RNY(jshort flags) {
+ const int req = JVM_ACC_NATIVE | JVM_ACC_SYNCHRONIZED;
+ const int neg = JVM_ACC_STATIC;
+ return (flags & (req | neg)) == req;
+}
// These are for forming case labels:
#define ID3(x, y, z) (( jint)(z) + \
@@ -359,6 +364,7 @@
case F_RN: fname = "native "; break;
case F_SN: fname = "native static "; break;
case F_S: fname = "static "; break;
+ case F_RNY:fname = "native synchronized "; break;
}
const char* kptr = strrchr(kname, '/');
if (kptr != NULL) kname = kptr + 1;
@@ -485,7 +491,7 @@
if (PrintMiscellaneous && (WizardMode || Verbose)) {
tty->print_cr("*** misidentified method; %s(%d) should be %s(%d):",
declared_name, declared_id, actual_name, actual_id);
- m->print_short_name(tty);
+ mh()->print_short_name(tty);
tty->cr();
}
}
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Tue Mar 11 19:00:38 2008 -0700
@@ -584,6 +584,8 @@
do_name( attemptUpdate_name, "attemptUpdate") \
do_signature(attemptUpdate_signature, "(JJ)Z") \
\
+ do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \
+ \
/* support for sun.misc.Unsafe */ \
do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \
\
@@ -871,7 +873,8 @@
F_R, // !static !synchronized (R="regular")
F_S, // static !synchronized
F_RN, // !static native !synchronized
- F_SN // static native !synchronized
+ F_SN, // static native !synchronized
+ F_RNY // !static native synchronized
};
public:
--- a/hotspot/src/share/vm/oops/methodDataOop.cpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/oops/methodDataOop.cpp Tue Mar 11 19:00:38 2008 -0700
@@ -32,7 +32,7 @@
// Some types of data layouts need a length field.
bool DataLayout::needs_array_len(u1 tag) {
- return (tag == multi_branch_data_tag);
+ return (tag == multi_branch_data_tag) || (tag == arg_info_data_tag);
}
// Perform generic initialization of the data. More specific
@@ -404,6 +404,17 @@
}
#endif
+#ifndef PRODUCT
+void ArgInfoData::print_data_on(outputStream* st) {
+ print_shared(st, "ArgInfoData");
+ int nargs = number_of_args();
+ for (int i = 0; i < nargs; i++) {
+ st->print(" 0x%x", arg_modified(i));
+ }
+ st->cr();
+}
+
+#endif
// ==================================================================
// methodDataOop
//
@@ -508,6 +519,9 @@
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
object_size += extra_data_count * DataLayout::compute_size_in_bytes(0);
+ // Add a cell to record information about modified arguments.
+ int arg_size = method->size_of_parameters();
+ object_size += DataLayout::compute_size_in_bytes(arg_size+1);
return object_size;
}
@@ -626,6 +640,8 @@
return new BranchData(data_layout);
case DataLayout::multi_branch_data_tag:
return new MultiBranchData(data_layout);
+ case DataLayout::arg_info_data_tag:
+ return new ArgInfoData(data_layout);
};
}
@@ -681,7 +697,17 @@
// Add some extra DataLayout cells (at least one) to track stray traps.
int extra_data_count = compute_extra_data_count(data_size, empty_bc_count);
- object_size += extra_data_count * DataLayout::compute_size_in_bytes(0);
+ int extra_size = extra_data_count * DataLayout::compute_size_in_bytes(0);
+
+ // Add a cell to record information about modified arguments.
+ // Set up _args_modified array after traps cells so that
+ // the code for traps cells works.
+ DataLayout *dp = data_layout_at(data_size + extra_size);
+
+ int arg_size = method->size_of_parameters();
+ dp->initialize(DataLayout::arg_info_data_tag, 0, arg_size+1);
+
+ object_size += extra_size + DataLayout::compute_size_in_bytes(arg_size+1);
// Set an initial hint. Don't use set_hint_di() because
// first_di() may be out of bounds if data_size is 0.
@@ -764,6 +790,10 @@
// No need for "OrderAccess::load_acquire" ops,
// since the data structure is monotonic.
if (dp->tag() == DataLayout::no_tag) break;
+ if (dp->tag() == DataLayout::arg_info_data_tag) {
+ dp = end; // ArgInfoData is at the end of extra data section.
+ break;
+ }
if (dp->bci() == bci) {
assert(dp->tag() == DataLayout::bit_data_tag, "sane");
return new BitData(dp);
@@ -785,6 +815,16 @@
return NULL;
}
+ArgInfoData *methodDataOopDesc::arg_info() {
+ DataLayout* dp = extra_data_base();
+ DataLayout* end = extra_data_limit();
+ for (; dp < end; dp = next_extra(dp)) {
+ if (dp->tag() == DataLayout::arg_info_data_tag)
+ return new ArgInfoData(dp);
+ }
+ return NULL;
+}
+
#ifndef PRODUCT
void methodDataOopDesc::print_data_on(outputStream* st) {
ResourceMark rm;
@@ -794,15 +834,20 @@
st->fill_to(6);
data->print_data_on(st);
}
+ st->print_cr("--- Extra data:");
DataLayout* dp = extra_data_base();
DataLayout* end = extra_data_limit();
for (; dp < end; dp = next_extra(dp)) {
// No need for "OrderAccess::load_acquire" ops,
// since the data structure is monotonic.
- if (dp->tag() == DataLayout::no_tag) break;
- if (dp == extra_data_base())
- st->print_cr("--- Extra data:");
- data = new BitData(dp);
+ if (dp->tag() == DataLayout::no_tag) continue;
+ if (dp->tag() == DataLayout::bit_data_tag) {
+ data = new BitData(dp);
+ } else {
+ assert(dp->tag() == DataLayout::arg_info_data_tag, "must be BitData or ArgInfo");
+ data = new ArgInfoData(dp);
+ dp = end; // ArgInfoData is at the end of extra data section.
+ }
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
--- a/hotspot/src/share/vm/oops/methodDataOop.hpp Tue Mar 11 11:25:13 2008 -0700
+++ b/hotspot/src/share/vm/oops/methodDataOop.hpp Tue Mar 11 19:00:38 2008 -0700
@@ -101,7 +101,8 @@
virtual_call_data_tag,
ret_data_tag,
branch_data_tag,
- multi_branch_data_tag
+ multi_branch_data_tag,
+ arg_info_data_tag
};
enum {
@@ -245,6 +246,7 @@
class BranchData;
class ArrayData;
class MultiBranchData;
+class ArgInfoData;
// ProfileData
@@ -376,6 +378,8 @@
virtual bool is_BranchData() { return false; }
virtual bool is_ArrayData() { return false; }
virtual bool is_MultiBranchData() { return false; }
+ virtual bool is_ArgInfoData() { return false; }
+
BitData* as_BitData() {
assert(is_BitData(), "wrong type");
@@ -413,6 +417,10 @@
assert(is_MultiBranchData(), "wrong type");
return is_MultiBranchData() ? (MultiBranchData*)this : NULL;
}
+ ArgInfoData* as_ArgInfoData() {
+ assert(is_ArgInfoData(), "wrong type");
+ return is_ArgInfoData() ? (ArgInfoData*)this : NULL;
+ }
// Subclass specific initialization
@@ -1047,6 +1055,33 @@
#endif
};
+class ArgInfoData : public ArrayData {
+
+public:
+ ArgInfoData(DataLayout* layout) : ArrayData(layout) {
+ assert(layout->tag() == DataLayout::arg_info_data_tag, "wrong type");
+ }
+
+ virtual bool is_ArgInfoData() { return true; }
+
+
+ int number_of_args() {
+ return array_len();
+ }
+
+ uint arg_modified(int arg) {
+ return array_uint_at(arg);
+ }
+
+ void set_arg_modified(int arg, uint val) {
+ array_set_int_at(arg, val);
+ }
+
+#ifndef PRODUCT
+ void print_data_on(outputStream* st);
+#endif
+};
+
// methodDataOop
//
// A methodDataOop holds information which has been collected about
@@ -1183,6 +1218,9 @@
// Find or create an extra ProfileData:
ProfileData* bci_to_extra_data(int bci, bool create_if_missing);
+ // return the argument info cell
+ ArgInfoData *arg_info();
+
public:
static int header_size() {
return sizeof(methodDataOopDesc)/wordSize;
@@ -1222,11 +1260,18 @@
intx arg_local() { return _arg_local; }
intx arg_stack() { return _arg_stack; }
intx arg_returned() { return _arg_returned; }
+ uint arg_modified(int a) { ArgInfoData *aid = arg_info();
+ assert(a >= 0 && a < aid->number_of_args(), "valid argument number");
+ return aid->arg_modified(a); }
void set_eflags(intx v) { _eflags = v; }
void set_arg_local(intx v) { _arg_local = v; }
void set_arg_stack(intx v) { _arg_stack = v; }
void set_arg_returned(intx v) { _arg_returned = v; }
+ void set_arg_modified(int a, uint v) { ArgInfoData *aid = arg_info();
+ assert(a >= 0 && a < aid->number_of_args(), "valid argument number");
+
+ aid->set_arg_modified(a, v); }
void clear_escape_info() { _eflags = _arg_local = _arg_stack = _arg_returned = 0; }