提交 a37e0865 编写于 作者: K kvn

6667620: (Escape Analysis) fix deoptimization for scalar replaced objects

Summary: Deoptimization code for reallocation and relocking scalar replaced objects has to be fixed.
Reviewed-by: rasbold, never
上级 1113d94f
......@@ -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,17 +791,39 @@ 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);
}
......
......@@ -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();
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册