6667620: (Escape Analysis) fix deoptimization for scalar replaced objects
Deoptimization code for reallocation and relocking scalar replaced objects has to be fixed. Reviewed-by: rasbold, never
This commit is contained in:
parent
50708126d4
commit
96e8bcb6aa
@ -34,7 +34,9 @@
|
||||
// ciInstanceKlass::ciInstanceKlass
|
||||
//
|
||||
// Loaded instance klass.
|
||||
ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) : ciKlass(h_k) {
|
||||
ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
|
||||
ciKlass(h_k), _non_static_fields(NULL)
|
||||
{
|
||||
assert(get_Klass()->oop_is_instance(), "wrong type");
|
||||
instanceKlass* ik = get_instanceKlass();
|
||||
|
||||
@ -335,6 +337,37 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static)
|
||||
return field;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciInstanceKlass::non_static_fields.
|
||||
|
||||
class NonStaticFieldFiller: public FieldClosure {
|
||||
GrowableArray<ciField*>* _arr;
|
||||
ciEnv* _curEnv;
|
||||
public:
|
||||
NonStaticFieldFiller(ciEnv* curEnv, GrowableArray<ciField*>* arr) :
|
||||
_curEnv(curEnv), _arr(arr)
|
||||
{}
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
ciField* field = new (_curEnv->arena()) ciField(fd);
|
||||
_arr->append(field);
|
||||
}
|
||||
};
|
||||
|
||||
GrowableArray<ciField*>* ciInstanceKlass::non_static_fields() {
|
||||
if (_non_static_fields == NULL) {
|
||||
VM_ENTRY_MARK;
|
||||
ciEnv* curEnv = ciEnv::current();
|
||||
instanceKlass* ik = get_instanceKlass();
|
||||
int max_n_fields = ik->fields()->length()/instanceKlass::next_offset;
|
||||
|
||||
_non_static_fields =
|
||||
new (curEnv->arena()) GrowableArray<ciField*>(max_n_fields);
|
||||
NonStaticFieldFiller filler(curEnv, _non_static_fields);
|
||||
ik->do_nonstatic_fields(&filler);
|
||||
}
|
||||
return _non_static_fields;
|
||||
}
|
||||
|
||||
static int sort_field_by_offset(ciField** a, ciField** b) {
|
||||
return (*a)->offset_in_bytes() - (*b)->offset_in_bytes();
|
||||
// (no worries about 32-bit overflow...)
|
||||
|
@ -46,6 +46,7 @@ private:
|
||||
bool _has_subklass;
|
||||
ciFlags _flags;
|
||||
jint _nonstatic_field_size;
|
||||
jint _nonstatic_oop_map_size;
|
||||
|
||||
// Lazy fields get filled in only upon request.
|
||||
ciInstanceKlass* _super;
|
||||
@ -58,6 +59,8 @@ private:
|
||||
ciInstanceKlass* _implementors[implementors_limit];
|
||||
jint _nof_implementors;
|
||||
|
||||
GrowableArray<ciField*>* _non_static_fields;
|
||||
|
||||
protected:
|
||||
ciInstanceKlass(KlassHandle h_k);
|
||||
ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain);
|
||||
@ -129,6 +132,9 @@ public:
|
||||
jint nonstatic_field_size() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
return _nonstatic_field_size; }
|
||||
jint nonstatic_oop_map_size() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
return _nonstatic_oop_map_size; }
|
||||
ciInstanceKlass* super();
|
||||
jint nof_implementors() {
|
||||
assert(is_loaded(), "must be loaded");
|
||||
@ -138,6 +144,9 @@ public:
|
||||
|
||||
ciInstanceKlass* get_canonical_holder(int offset);
|
||||
ciField* get_field_by_offset(int field_offset, bool is_static);
|
||||
|
||||
GrowableArray<ciField*>* non_static_fields();
|
||||
|
||||
// total number of nonstatic fields (including inherited):
|
||||
int nof_nonstatic_fields() {
|
||||
if (_nonstatic_fields == NULL)
|
||||
|
@ -47,7 +47,8 @@ ScopeValue* DebugInfoReadStream::read_object_value() {
|
||||
}
|
||||
#endif
|
||||
ObjectValue* result = new ObjectValue(id);
|
||||
_obj_pool->append(result);
|
||||
// Cache the object since an object field could reference it.
|
||||
_obj_pool->push(result);
|
||||
result->read_object(this);
|
||||
return result;
|
||||
}
|
||||
@ -56,9 +57,9 @@ ScopeValue* DebugInfoReadStream::get_cached_object() {
|
||||
int id = read_int();
|
||||
assert(_obj_pool != NULL, "object pool does not exist");
|
||||
for (int i = _obj_pool->length() - 1; i >= 0; i--) {
|
||||
ObjectValue* sv = (ObjectValue*) _obj_pool->at(i);
|
||||
if (sv->id() == id) {
|
||||
return sv;
|
||||
ObjectValue* ov = (ObjectValue*) _obj_pool->at(i);
|
||||
if (ov->id() == id) {
|
||||
return ov;
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
|
@ -91,7 +91,9 @@ GrowableArray<ScopeValue*>* ScopeDesc::decode_object_values(int decode_offset) {
|
||||
DebugInfoReadStream* stream = new DebugInfoReadStream(_code, decode_offset, result);
|
||||
int length = stream->read_int();
|
||||
for (int index = 0; index < length; index++) {
|
||||
result->push(ScopeValue::read_from(stream));
|
||||
// Objects values are pushed to 'result' array during read so that
|
||||
// object's fields could reference it (OBJECT_ID_CODE).
|
||||
(void)ScopeValue::read_from(stream);
|
||||
}
|
||||
assert(result->length() == length, "inconsistent debug information");
|
||||
return result;
|
||||
|
@ -791,18 +791,40 @@ void instanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, vo
|
||||
}
|
||||
|
||||
|
||||
static int compare_fields_by_offset(int* a, int* b) {
|
||||
return a[0] - b[0];
|
||||
}
|
||||
|
||||
void instanceKlass::do_nonstatic_fields(FieldClosure* cl) {
|
||||
fieldDescriptor fd;
|
||||
instanceKlass* super = superklass();
|
||||
if (super != NULL) {
|
||||
super->do_nonstatic_fields(cl);
|
||||
}
|
||||
fieldDescriptor fd;
|
||||
int length = fields()->length();
|
||||
// In DebugInfo nonstatic fields are sorted by offset.
|
||||
int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1));
|
||||
int j = 0;
|
||||
for (int i = 0; i < length; i += next_offset) {
|
||||
fd.initialize(as_klassOop(), i);
|
||||
if (!(fd.is_static())) cl->do_field(&fd);
|
||||
if (!fd.is_static()) {
|
||||
fields_sorted[j + 0] = fd.offset();
|
||||
fields_sorted[j + 1] = i;
|
||||
j += 2;
|
||||
}
|
||||
}
|
||||
if (j > 0) {
|
||||
length = j;
|
||||
// _sort_Fn is defined in growableArray.hpp.
|
||||
qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset);
|
||||
for (int i = 0; i < length; i += 2) {
|
||||
fd.initialize(as_klassOop(), fields_sorted[i + 1]);
|
||||
assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields");
|
||||
cl->do_field(&fd);
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(int, fields_sorted);
|
||||
}
|
||||
|
||||
|
||||
void instanceKlass::array_klasses_do(void f(klassOop k)) {
|
||||
|
@ -141,7 +141,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
||||
#ifdef COMPILER2
|
||||
// Reallocate the non-escaping objects and restore their fields. Then
|
||||
// relock objects if synchronization on them was eliminated.
|
||||
if (DoEscapeAnalysis && EliminateAllocations) {
|
||||
if (DoEscapeAnalysis) {
|
||||
if (EliminateAllocations) {
|
||||
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
|
||||
bool reallocated = false;
|
||||
if (objects != NULL) {
|
||||
@ -159,6 +160,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (EliminateLocks) {
|
||||
for (int i = 0; i < chunk->length(); i++) {
|
||||
GrowableArray<MonitorValue*>* monitors = chunk->at(i)->scope()->monitors();
|
||||
if (monitors != NULL) {
|
||||
@ -167,8 +170,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
||||
if (TraceDeoptimization) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread);
|
||||
for (int j = 0; i < monitors->length(); i++) {
|
||||
MonitorValue* mv = monitors->at(i);
|
||||
for (int j = 0; j < monitors->length(); j++) {
|
||||
MonitorValue* mv = monitors->at(j);
|
||||
if (mv->eliminated()) {
|
||||
StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner());
|
||||
tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()());
|
||||
@ -179,6 +182,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // COMPILER2
|
||||
// Ensure that no safepoint is taken after pointers have been stored
|
||||
// in fields of rematerialized objects. If a safepoint occurs from here on
|
||||
@ -656,6 +660,7 @@ public:
|
||||
|
||||
|
||||
void do_field(fieldDescriptor* fd) {
|
||||
intptr_t val;
|
||||
StackValue* value =
|
||||
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i()));
|
||||
int offset = fd->offset();
|
||||
@ -669,24 +674,36 @@ public:
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
StackValue* low =
|
||||
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i));
|
||||
#ifdef _LP64
|
||||
jlong res = (jlong)low->get_int();
|
||||
#else
|
||||
#ifdef SPARC
|
||||
// For SPARC we have to swap high and low words.
|
||||
jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int());
|
||||
#else
|
||||
jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int());
|
||||
#endif //SPARC
|
||||
#endif
|
||||
_obj->long_field_put(offset, res);
|
||||
break;
|
||||
}
|
||||
|
||||
// Have to cast to INT (32 bits) pointer to avoid little/big-endian problem.
|
||||
case T_INT: case T_FLOAT: // 4 bytes.
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
_obj->int_field_put(offset, (jint)value->get_int());
|
||||
val = value->get_int();
|
||||
_obj->int_field_put(offset, (jint)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_SHORT: case T_CHAR: // 2 bytes
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
_obj->short_field_put(offset, (jshort)value->get_int());
|
||||
val = value->get_int();
|
||||
_obj->short_field_put(offset, (jshort)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_BOOLEAN: // 1 byte
|
||||
case T_BOOLEAN: case T_BYTE: // 1 byte
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
_obj->bool_field_put(offset, (jboolean)value->get_int());
|
||||
val = value->get_int();
|
||||
_obj->bool_field_put(offset, (jboolean)*((jint*)&val));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -698,25 +715,49 @@ public:
|
||||
|
||||
// restore elements of an eliminated type array
|
||||
void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) {
|
||||
StackValue* low;
|
||||
jlong lval;
|
||||
int index = 0;
|
||||
intptr_t val;
|
||||
|
||||
for (int i = 0; i < sv->field_size(); i++) {
|
||||
StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i));
|
||||
switch(type) {
|
||||
case T_BOOLEAN: obj->bool_at_put (index, (jboolean) value->get_int()); break;
|
||||
case T_BYTE: obj->byte_at_put (index, (jbyte) value->get_int()); break;
|
||||
case T_CHAR: obj->char_at_put (index, (jchar) value->get_int()); break;
|
||||
case T_SHORT: obj->short_at_put(index, (jshort) value->get_int()); break;
|
||||
case T_INT: obj->int_at_put (index, (jint) value->get_int()); break;
|
||||
case T_FLOAT: obj->float_at_put(index, (jfloat) value->get_int()); break;
|
||||
case T_LONG:
|
||||
case T_DOUBLE:
|
||||
low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i));
|
||||
lval = jlong_from((jint)value->get_int(), (jint)low->get_int());
|
||||
sv->value()->long_field_put(index, lval);
|
||||
case T_LONG: case T_DOUBLE: {
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
StackValue* low =
|
||||
StackValue::create_stack_value(fr, reg_map, sv->field_at(++i));
|
||||
#ifdef _LP64
|
||||
jlong res = (jlong)low->get_int();
|
||||
#else
|
||||
#ifdef SPARC
|
||||
// For SPARC we have to swap high and low words.
|
||||
jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int());
|
||||
#else
|
||||
jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int());
|
||||
#endif //SPARC
|
||||
#endif
|
||||
obj->long_at_put(index, res);
|
||||
break;
|
||||
}
|
||||
|
||||
// Have to cast to INT (32 bits) pointer to avoid little/big-endian problem.
|
||||
case T_INT: case T_FLOAT: // 4 bytes.
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
obj->int_at_put(index, (jint)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_SHORT: case T_CHAR: // 2 bytes
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
obj->short_at_put(index, (jshort)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_BOOLEAN: case T_BYTE: // 1 byte
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
obj->bool_at_put(index, (jboolean)*((jint*)&val));
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user