# HG changeset patch # User kvn # Date 1205259913 25200 # Node ID c646ef2f5d587d428049512d0961de5285f7ed9b # Parent 9d2d32d9828fc0a616a4cba131165aca511bf671 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 diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/ci/ciInstanceKlass.cpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Tue Mar 11 11:25:13 2008 -0700 @@ -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 @@ return field; } +// ------------------------------------------------------------------ +// ciInstanceKlass::non_static_fields. + +class NonStaticFieldFiller: public FieldClosure { + GrowableArray* _arr; + ciEnv* _curEnv; +public: + NonStaticFieldFiller(ciEnv* curEnv, GrowableArray* arr) : + _curEnv(curEnv), _arr(arr) + {} + void do_field(fieldDescriptor* fd) { + ciField* field = new (_curEnv->arena()) ciField(fd); + _arr->append(field); + } +}; + +GrowableArray* 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(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...) diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/ci/ciInstanceKlass.hpp --- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Tue Mar 11 11:25:13 2008 -0700 @@ -46,6 +46,7 @@ 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 @@ ciInstanceKlass* _implementors[implementors_limit]; jint _nof_implementors; + GrowableArray* _non_static_fields; + protected: ciInstanceKlass(KlassHandle h_k); ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain); @@ -129,6 +132,9 @@ 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 @@ ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); + + GrowableArray* non_static_fields(); + // total number of nonstatic fields (including inherited): int nof_nonstatic_fields() { if (_nonstatic_fields == NULL) diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/code/debugInfo.cpp --- a/hotspot/src/share/vm/code/debugInfo.cpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/code/debugInfo.cpp Tue Mar 11 11:25:13 2008 -0700 @@ -47,7 +47,8 @@ } #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 @@ 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(); diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/code/scopeDesc.cpp --- a/hotspot/src/share/vm/code/scopeDesc.cpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/code/scopeDesc.cpp Tue Mar 11 11:25:13 2008 -0700 @@ -91,7 +91,9 @@ 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; diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/oops/instanceKlass.cpp --- a/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Tue Mar 11 11:25:13 2008 -0700 @@ -791,17 +791,39 @@ } +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); } diff -r 9d2d32d9828f -r c646ef2f5d58 hotspot/src/share/vm/runtime/deoptimization.cpp --- a/hotspot/src/share/vm/runtime/deoptimization.cpp Tue Mar 11 11:04:40 2008 -0700 +++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Tue Mar 11 11:25:13 2008 -0700 @@ -141,41 +141,45 @@ #ifdef COMPILER2 // Reallocate the non-escaping objects and restore their fields. Then // relock objects if synchronization on them was eliminated. - if (DoEscapeAnalysis && EliminateAllocations) { - GrowableArray* objects = chunk->at(0)->scope()->objects(); - bool reallocated = false; - if (objects != NULL) { - JRT_BLOCK - reallocated = realloc_objects(thread, &deoptee, objects, THREAD); - JRT_END - } - if (reallocated) { - reassign_fields(&deoptee, &map, objects); -#ifndef PRODUCT - if (TraceDeoptimization) { - ttyLocker ttyl; - tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); - print_objects(objects); + if (DoEscapeAnalysis) { + if (EliminateAllocations) { + GrowableArray* objects = chunk->at(0)->scope()->objects(); + bool reallocated = false; + if (objects != NULL) { + JRT_BLOCK + reallocated = realloc_objects(thread, &deoptee, objects, THREAD); + JRT_END } -#endif - } - for (int i = 0; i < chunk->length(); i++) { - GrowableArray* monitors = chunk->at(i)->scope()->monitors(); - if (monitors != NULL) { - relock_objects(&deoptee, &map, monitors); + if (reallocated) { + reassign_fields(&deoptee, &map, objects); #ifndef PRODUCT 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); - if (mv->eliminated()) { - StackValue* owner = StackValue::create_stack_value(&deoptee, &map, mv->owner()); - tty->print_cr(" object <" INTPTR_FORMAT "> locked", owner->get_obj()()); + tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread); + print_objects(objects); + } +#endif + } + } + if (EliminateLocks) { + for (int i = 0; i < chunk->length(); i++) { + GrowableArray* monitors = chunk->at(i)->scope()->monitors(); + if (monitors != NULL) { + relock_objects(&deoptee, &map, monitors); +#ifndef PRODUCT + if (TraceDeoptimization) { + ttyLocker ttyl; + tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread); + 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()()); + } } } +#endif } -#endif } } } @@ -656,6 +660,7 @@ 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 @@ 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 @@ // 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); - break; + 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(); }