6667615: (Escape Analysis) extend MDO to cache arguments escape state
Use MDO to cache arguments escape state determined by the byte code escape analyzer. Reviewed-by: never
This commit is contained in:
parent
96e8bcb6aa
commit
b64d5e4209
hotspot/src/share/vm
@ -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; }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user