提交 23135ee9 编写于 作者: K kvn

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
上级 a37e0865
......@@ -104,7 +104,7 @@ public:
};
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 @@ void BCEscapeAnalyzer::set_returned(ArgumentMap vars) {
_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_argument(ArgumentMap vars) {
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 @@ bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){
}
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 @@ void BCEscapeAnalyzer::set_dirty(ArgumentMap vars) {
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 @@ bool BCEscapeAnalyzer::is_recursive_call(ciMethod* callee) {
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 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
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 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
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 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
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 @@ void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod*
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 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
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 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
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 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
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 @@ void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
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::iterate_one_block(ciBlock *blk, StateInfo &state, Growabl
}
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 @@ void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest,
}
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 @@ void BCEscapeAnalyzer::iterate_blocks(Arena *arena) {
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 @@ void BCEscapeAnalyzer::iterate_blocks(Arena *arena) {
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 @@ void BCEscapeAnalyzer::iterate_blocks(Arena *arena) {
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 BCEscapeAnalyzer::known_intrinsic() {
vmIntrinsics::ID iid = method()->intrinsic_id();
if (iid == vmIntrinsics::_getClass ||
iid == vmIntrinsics::_fillInStackTrace ||
iid == vmIntrinsics::_hashCode)
return iid;
else
......@@ -1060,12 +1123,16 @@ vmIntrinsics::ID BCEscapeAnalyzer::known_intrinsic() {
}
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 @@ void BCEscapeAnalyzer::initialize() {
_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 @@ void BCEscapeAnalyzer::clear_escape_info() {
_return_local = false;
_return_allocated = false;
_allocated_escapes = true;
_unknown_modified = true;
}
......@@ -1205,8 +1279,17 @@ void BCEscapeAnalyzer::compute_escape_info() {
} 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 @@ void BCEscapeAnalyzer::compute_escape_info() {
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 @@ void BCEscapeAnalyzer::read_escape_info() {
_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 @@ void BCEscapeAnalyzer::read_escape_info() {
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 @@ BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent)
, _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 @@ BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent)
_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;
......
......@@ -46,9 +46,12 @@ class BCEscapeAnalyzer : public ResourceObj {
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 @@ class BCEscapeAnalyzer : public ResourceObj {
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 @@ class BCEscapeAnalyzer : public ResourceObj {
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);
};
......@@ -42,6 +42,8 @@ ciMethodData::ciMethodData(methodDataHandle h_md) : ciObject(h_md) {
// 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 @@ ciMethodData::ciMethodData() : ciObject() {
// 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 @@ ciProfileData* ciMethodData::data_at(int data_index) {
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 @@ ciProfileData* ciMethodData::bci_to_data(int bci) {
_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 @@ int ciMethodData::trap_recompiled_at(ciProfileData* data) {
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 @@ void ciMethodData::update_escape_info() {
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 @@ void ciMethodData::set_arg_returned(int i) {
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 @@ bool ciMethodData::is_arg_returned(int i) const {
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 @@ ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_
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 @@ void ciMethodData::print_data_on(outputStream* st) {
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) {
......
......@@ -30,6 +30,7 @@ class ciRetData;
class ciBranchData;
class ciArrayData;
class ciMultiBranchData;
class ciArgInfoData;
typedef ProfileData ciProfileData;
......@@ -121,6 +122,11 @@ public:
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 @@ private:
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 @@ private:
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 @@ private:
// 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 @@ public:
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);
......
......@@ -318,6 +318,11 @@ inline bool match_F_SN(jshort flags) {
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 @@ const char* vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID id, char* buf,
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 @@ void vmIntrinsics::verify_method(ID actual_id, methodOop m) {
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();
}
}
......
......@@ -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 @@ class vmIntrinsics: AllStatic {
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:
......
......@@ -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 @@ void MultiBranchData::print_data_on(outputStream* st) {
}
#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 methodDataOopDesc::compute_allocation_size_in_bytes(methodHandle method) {
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 @@ ProfileData* methodDataOopDesc::data_at(int data_index) {
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 @@ void methodDataOopDesc::initialize(methodHandle method) {
// 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 @@ ProfileData* methodDataOopDesc::bci_to_extra_data(int bci, bool create_if_missin
// 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 @@ ProfileData* methodDataOopDesc::bci_to_extra_data(int bci, bool create_if_missin
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 @@ void methodDataOopDesc::print_data_on(outputStream* st) {
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);
......
......@@ -101,7 +101,8 @@ public:
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 JumpData;
class BranchData;
class ArrayData;
class MultiBranchData;
class ArgInfoData;
// ProfileData
......@@ -376,6 +378,8 @@ public:
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 @@ public:
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 @@ public:
#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 @@ private:
// 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 @@ public:
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; }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册