提交 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 @@ ...@@ -34,7 +34,9 @@
// ciInstanceKlass::ciInstanceKlass // ciInstanceKlass::ciInstanceKlass
// //
// Loaded instance klass. // 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"); assert(get_Klass()->oop_is_instance(), "wrong type");
instanceKlass* ik = get_instanceKlass(); instanceKlass* ik = get_instanceKlass();
...@@ -335,6 +337,37 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static) ...@@ -335,6 +337,37 @@ ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static)
return field; 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) { static int sort_field_by_offset(ciField** a, ciField** b) {
return (*a)->offset_in_bytes() - (*b)->offset_in_bytes(); return (*a)->offset_in_bytes() - (*b)->offset_in_bytes();
// (no worries about 32-bit overflow...) // (no worries about 32-bit overflow...)
......
...@@ -46,6 +46,7 @@ private: ...@@ -46,6 +46,7 @@ private:
bool _has_subklass; bool _has_subklass;
ciFlags _flags; ciFlags _flags;
jint _nonstatic_field_size; jint _nonstatic_field_size;
jint _nonstatic_oop_map_size;
// Lazy fields get filled in only upon request. // Lazy fields get filled in only upon request.
ciInstanceKlass* _super; ciInstanceKlass* _super;
...@@ -58,6 +59,8 @@ private: ...@@ -58,6 +59,8 @@ private:
ciInstanceKlass* _implementors[implementors_limit]; ciInstanceKlass* _implementors[implementors_limit];
jint _nof_implementors; jint _nof_implementors;
GrowableArray<ciField*>* _non_static_fields;
protected: protected:
ciInstanceKlass(KlassHandle h_k); ciInstanceKlass(KlassHandle h_k);
ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain); ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain);
...@@ -129,6 +132,9 @@ public: ...@@ -129,6 +132,9 @@ public:
jint nonstatic_field_size() { jint nonstatic_field_size() {
assert(is_loaded(), "must be loaded"); assert(is_loaded(), "must be loaded");
return _nonstatic_field_size; } return _nonstatic_field_size; }
jint nonstatic_oop_map_size() {
assert(is_loaded(), "must be loaded");
return _nonstatic_oop_map_size; }
ciInstanceKlass* super(); ciInstanceKlass* super();
jint nof_implementors() { jint nof_implementors() {
assert(is_loaded(), "must be loaded"); assert(is_loaded(), "must be loaded");
...@@ -138,6 +144,9 @@ public: ...@@ -138,6 +144,9 @@ public:
ciInstanceKlass* get_canonical_holder(int offset); ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static); ciField* get_field_by_offset(int field_offset, bool is_static);
GrowableArray<ciField*>* non_static_fields();
// total number of nonstatic fields (including inherited): // total number of nonstatic fields (including inherited):
int nof_nonstatic_fields() { int nof_nonstatic_fields() {
if (_nonstatic_fields == NULL) if (_nonstatic_fields == NULL)
......
...@@ -47,7 +47,8 @@ ScopeValue* DebugInfoReadStream::read_object_value() { ...@@ -47,7 +47,8 @@ ScopeValue* DebugInfoReadStream::read_object_value() {
} }
#endif #endif
ObjectValue* result = new ObjectValue(id); 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); result->read_object(this);
return result; return result;
} }
...@@ -56,9 +57,9 @@ ScopeValue* DebugInfoReadStream::get_cached_object() { ...@@ -56,9 +57,9 @@ ScopeValue* DebugInfoReadStream::get_cached_object() {
int id = read_int(); int id = read_int();
assert(_obj_pool != NULL, "object pool does not exist"); assert(_obj_pool != NULL, "object pool does not exist");
for (int i = _obj_pool->length() - 1; i >= 0; i--) { for (int i = _obj_pool->length() - 1; i >= 0; i--) {
ObjectValue* sv = (ObjectValue*) _obj_pool->at(i); ObjectValue* ov = (ObjectValue*) _obj_pool->at(i);
if (sv->id() == id) { if (ov->id() == id) {
return sv; return ov;
} }
} }
ShouldNotReachHere(); ShouldNotReachHere();
......
...@@ -91,7 +91,9 @@ GrowableArray<ScopeValue*>* ScopeDesc::decode_object_values(int decode_offset) { ...@@ -91,7 +91,9 @@ GrowableArray<ScopeValue*>* ScopeDesc::decode_object_values(int decode_offset) {
DebugInfoReadStream* stream = new DebugInfoReadStream(_code, decode_offset, result); DebugInfoReadStream* stream = new DebugInfoReadStream(_code, decode_offset, result);
int length = stream->read_int(); int length = stream->read_int();
for (int index = 0; index < length; index++) { 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"); assert(result->length() == length, "inconsistent debug information");
return result; return result;
......
...@@ -791,17 +791,39 @@ void instanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, vo ...@@ -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) { void instanceKlass::do_nonstatic_fields(FieldClosure* cl) {
fieldDescriptor fd;
instanceKlass* super = superklass(); instanceKlass* super = superklass();
if (super != NULL) { if (super != NULL) {
super->do_nonstatic_fields(cl); super->do_nonstatic_fields(cl);
} }
fieldDescriptor fd;
int length = fields()->length(); 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) { for (int i = 0; i < length; i += next_offset) {
fd.initialize(as_klassOop(), i); 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,41 +141,45 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread ...@@ -141,41 +141,45 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
#ifdef COMPILER2 #ifdef COMPILER2
// Reallocate the non-escaping objects and restore their fields. Then // Reallocate the non-escaping objects and restore their fields. Then
// relock objects if synchronization on them was eliminated. // relock objects if synchronization on them was eliminated.
if (DoEscapeAnalysis && EliminateAllocations) { if (DoEscapeAnalysis) {
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects(); if (EliminateAllocations) {
bool reallocated = false; GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
if (objects != NULL) { bool reallocated = false;
JRT_BLOCK if (objects != NULL) {
reallocated = realloc_objects(thread, &deoptee, objects, THREAD); JRT_BLOCK
JRT_END reallocated = realloc_objects(thread, &deoptee, objects, THREAD);
} JRT_END
if (reallocated) { }
reassign_fields(&deoptee, &map, objects); if (reallocated) {
reassign_fields(&deoptee, &map, objects);
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDeoptimization) { if (TraceDeoptimization) {
ttyLocker ttyl; ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
print_objects(objects); print_objects(objects);
} }
#endif #endif
}
} }
for (int i = 0; i < chunk->length(); i++) { if (EliminateLocks) {
GrowableArray<MonitorValue*>* monitors = chunk->at(i)->scope()->monitors(); for (int i = 0; i < chunk->length(); i++) {
if (monitors != NULL) { GrowableArray<MonitorValue*>* monitors = chunk->at(i)->scope()->monitors();
relock_objects(&deoptee, &map, monitors); if (monitors != NULL) {
relock_objects(&deoptee, &map, monitors);
#ifndef PRODUCT #ifndef PRODUCT
if (TraceDeoptimization) { if (TraceDeoptimization) {
ttyLocker ttyl; ttyLocker ttyl;
tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread);
for (int j = 0; i < monitors->length(); i++) { for (int j = 0; j < monitors->length(); j++) {
MonitorValue* mv = monitors->at(i); MonitorValue* mv = monitors->at(j);
if (mv->eliminated()) { if (mv->eliminated()) {
StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner()); StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner());
tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()()); tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()());
}
} }
} }
}
#endif #endif
}
} }
} }
} }
...@@ -656,6 +660,7 @@ public: ...@@ -656,6 +660,7 @@ public:
void do_field(fieldDescriptor* fd) { void do_field(fieldDescriptor* fd) {
intptr_t val;
StackValue* value = StackValue* value =
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i())); StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(i()));
int offset = fd->offset(); int offset = fd->offset();
...@@ -669,24 +674,36 @@ public: ...@@ -669,24 +674,36 @@ public:
assert(value->type() == T_INT, "Agreement."); assert(value->type() == T_INT, "Agreement.");
StackValue* low = StackValue* low =
StackValue::create_stack_value(_fr, _reg_map, _sv->field_at(++_i)); 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()); jlong res = jlong_from((jint)value->get_int(), (jint)low->get_int());
#endif //SPARC
#endif
_obj->long_field_put(offset, res); _obj->long_field_put(offset, res);
break; break;
} }
// Have to cast to INT (32 bits) pointer to avoid little/big-endian problem.
case T_INT: case T_FLOAT: // 4 bytes. case T_INT: case T_FLOAT: // 4 bytes.
assert(value->type() == T_INT, "Agreement."); 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; break;
case T_SHORT: case T_CHAR: // 2 bytes case T_SHORT: case T_CHAR: // 2 bytes
assert(value->type() == T_INT, "Agreement."); 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; break;
case T_BOOLEAN: // 1 byte case T_BOOLEAN: case T_BYTE: // 1 byte
assert(value->type() == T_INT, "Agreement."); 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; break;
default: default:
...@@ -698,25 +715,49 @@ public: ...@@ -698,25 +715,49 @@ public:
// restore elements of an eliminated type array // restore elements of an eliminated type array
void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) { void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) {
StackValue* low;
jlong lval;
int index = 0; int index = 0;
intptr_t val;
for (int i = 0; i < sv->field_size(); i++) { for (int i = 0; i < sv->field_size(); i++) {
StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i)); StackValue* value = StackValue::create_stack_value(fr, reg_map, sv->field_at(i));
switch(type) { switch(type) {
case T_BOOLEAN: obj->bool_at_put (index, (jboolean) value->get_int()); break; case T_LONG: case T_DOUBLE: {
case T_BYTE: obj->byte_at_put (index, (jbyte) value->get_int()); break; assert(value->type() == T_INT, "Agreement.");
case T_CHAR: obj->char_at_put (index, (jchar) value->get_int()); break; StackValue* low =
case T_SHORT: obj->short_at_put(index, (jshort) value->get_int()); break; StackValue::create_stack_value(fr, reg_map, sv->field_at(++i));
case T_INT: obj->int_at_put (index, (jint) value->get_int()); break; #ifdef _LP64
case T_FLOAT: obj->float_at_put(index, (jfloat) value->get_int()); break; jlong res = (jlong)low->get_int();
case T_LONG: #else
case T_DOUBLE: #ifdef SPARC
low = StackValue::create_stack_value(fr, reg_map, sv->field_at(++i)); // For SPARC we have to swap high and low words.
lval = jlong_from((jint)value->get_int(), (jint)low->get_int()); jlong res = jlong_from((jint)low->get_int(), (jint)value->get_int());
sv->value()->long_field_put(index, lval); #else
break; 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: default:
ShouldNotReachHere(); ShouldNotReachHere();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册