mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
Merge
This commit is contained in:
commit
344a9becee
539 changed files with 51665 additions and 1091 deletions
|
@ -37,6 +37,7 @@
|
|||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/fieldStreams.hpp"
|
||||
#include "oops/verifyOopClosure.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
#include "runtime/biasedLocking.hpp"
|
||||
|
@ -53,6 +54,12 @@
|
|||
#include "utilities/events.hpp"
|
||||
#include "utilities/xmlstream.hpp"
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
#include "jvmci/jvmciRuntime.hpp"
|
||||
#include "jvmci/jvmciJavaClasses.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
bool DeoptimizationMarker::_is_active = false;
|
||||
|
||||
Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame,
|
||||
|
@ -130,6 +137,9 @@ JRT_BLOCK_ENTRY(Deoptimization::UnrollBlock*, Deoptimization::fetch_unroll_info(
|
|||
// handler. Note this fact before we start generating temporary frames
|
||||
// that can confuse an asynchronous stack walker. This counter is
|
||||
// decremented at the end of unpack_frames().
|
||||
if (TraceDeoptimization) {
|
||||
tty->print_cr("Deoptimizing thread " INTPTR_FORMAT, p2i(thread));
|
||||
}
|
||||
thread->inc_in_deopt_handler();
|
||||
|
||||
return fetch_unroll_info_helper(thread);
|
||||
|
@ -157,6 +167,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
// Set the deoptee nmethod
|
||||
assert(thread->deopt_nmethod() == NULL, "Pending deopt!");
|
||||
thread->set_deopt_nmethod(deoptee.cb()->as_nmethod_or_null());
|
||||
bool skip_internal = thread->deopt_nmethod() != NULL && !thread->deopt_nmethod()->compiler()->is_jvmci();
|
||||
|
||||
if (VerifyStack) {
|
||||
thread->validate_frame_layout();
|
||||
|
@ -177,11 +188,13 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
|
||||
bool realloc_failures = false;
|
||||
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
// Reallocate the non-escaping objects and restore their fields. Then
|
||||
// relock objects if synchronization on them was eliminated.
|
||||
#ifndef INCLUDE_JVMCI
|
||||
if (DoEscapeAnalysis || EliminateNestedLocks) {
|
||||
if (EliminateAllocations) {
|
||||
#endif // INCLUDE_JVMCI
|
||||
assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
|
||||
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
|
||||
|
||||
|
@ -211,7 +224,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
JRT_BLOCK
|
||||
realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
|
||||
JRT_END
|
||||
reassign_fields(&deoptee, &map, objects, realloc_failures);
|
||||
reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
|
||||
#ifndef PRODUCT
|
||||
if (TraceDeoptimization) {
|
||||
ttyLocker ttyl;
|
||||
|
@ -224,8 +237,10 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
// Restore result.
|
||||
deoptee.set_saved_oop_result(&map, return_value());
|
||||
}
|
||||
#ifndef INCLUDE_JVMCI
|
||||
}
|
||||
if (EliminateLocks) {
|
||||
#endif // INCLUDE_JVMCI
|
||||
#ifndef PRODUCT
|
||||
bool first = true;
|
||||
#endif
|
||||
|
@ -236,7 +251,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
if (monitors->is_nonempty()) {
|
||||
relock_objects(monitors, thread, realloc_failures);
|
||||
#ifndef PRODUCT
|
||||
if (TraceDeoptimization) {
|
||||
if (PrintDeoptimizationDetails) {
|
||||
ttyLocker ttyl;
|
||||
for (int j = 0; j < monitors->length(); j++) {
|
||||
MonitorInfo* mi = monitors->at(j);
|
||||
|
@ -254,19 +269,22 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // !PRODUCT
|
||||
}
|
||||
}
|
||||
#ifndef INCLUDE_JVMCI
|
||||
}
|
||||
}
|
||||
#endif // COMPILER2
|
||||
#endif // INCLUDE_JVMCI
|
||||
#endif // COMPILER2 || INCLUDE_JVMCI
|
||||
|
||||
// Ensure that no safepoint is taken after pointers have been stored
|
||||
// in fields of rematerialized objects. If a safepoint occurs from here on
|
||||
// out the java state residing in the vframeArray will be missed.
|
||||
No_Safepoint_Verifier no_safepoint;
|
||||
|
||||
vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
if (realloc_failures) {
|
||||
pop_frames_failed_reallocs(thread, array);
|
||||
}
|
||||
|
@ -316,7 +334,11 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||
unpack_sp = deoptee.unextended_sp();
|
||||
|
||||
#ifdef ASSERT
|
||||
assert(cb->is_deoptimization_stub() || cb->is_uncommon_trap_stub(), "just checking");
|
||||
assert(cb->is_deoptimization_stub() ||
|
||||
cb->is_uncommon_trap_stub() ||
|
||||
strcmp("Stub<DeoptimizationStub.deoptimizationHandler>", cb->name()) == 0 ||
|
||||
strcmp("Stub<UncommonTrapStub.uncommonTrapHandler>", cb->name()) == 0,
|
||||
"unexpected code blob: %s", cb->name());
|
||||
#endif
|
||||
#else
|
||||
intptr_t* unpack_sp = stub_frame.sender(&dummy_map).unextended_sp();
|
||||
|
@ -720,7 +742,7 @@ int Deoptimization::deoptimize_dependents() {
|
|||
Deoptimization::DeoptAction Deoptimization::_unloaded_action
|
||||
= Deoptimization::Action_reinterpret;
|
||||
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS) {
|
||||
Handle pending_exception(thread->pending_exception());
|
||||
const char* exception_file = thread->exception_file();
|
||||
|
@ -768,77 +790,6 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArra
|
|||
return failures;
|
||||
}
|
||||
|
||||
// This assumes that the fields are stored in ObjectValue in the same order
|
||||
// they are yielded by do_nonstatic_fields.
|
||||
class FieldReassigner: public FieldClosure {
|
||||
frame* _fr;
|
||||
RegisterMap* _reg_map;
|
||||
ObjectValue* _sv;
|
||||
InstanceKlass* _ik;
|
||||
oop _obj;
|
||||
|
||||
int _i;
|
||||
public:
|
||||
FieldReassigner(frame* fr, RegisterMap* reg_map, ObjectValue* sv, oop obj) :
|
||||
_fr(fr), _reg_map(reg_map), _sv(sv), _obj(obj), _i(0) {}
|
||||
|
||||
int i() const { return _i; }
|
||||
|
||||
|
||||
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();
|
||||
switch (fd->field_type()) {
|
||||
case T_OBJECT: case T_ARRAY:
|
||||
assert(value->type() == T_OBJECT, "Agreement.");
|
||||
_obj->obj_field_put(offset, value->get_obj()());
|
||||
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_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.");
|
||||
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.");
|
||||
val = value->get_int();
|
||||
_obj->short_field_put(offset, (jshort)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_BOOLEAN: case T_BYTE: // 1 byte
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
_obj->bool_field_put(offset, (jboolean)*((jint*)&val));
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
_i++;
|
||||
}
|
||||
};
|
||||
|
||||
// restore elements of an eliminated type array
|
||||
void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type) {
|
||||
int index = 0;
|
||||
|
@ -866,11 +817,43 @@ void Deoptimization::reassign_type_array_elements(frame* fr, RegisterMap* reg_ma
|
|||
}
|
||||
|
||||
// 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.");
|
||||
val = value->get_int();
|
||||
obj->int_at_put(index, (jint)*((jint*)&val));
|
||||
bool big_value = false;
|
||||
if (i + 1 < sv->field_size() && type == T_INT) {
|
||||
if (sv->field_at(i)->is_location()) {
|
||||
Location::Type type = ((LocationValue*) sv->field_at(i))->location().type();
|
||||
if (type == Location::dbl || type == Location::lng) {
|
||||
big_value = true;
|
||||
}
|
||||
} else if (sv->field_at(i)->is_constant_int()) {
|
||||
ScopeValue* next_scope_field = sv->field_at(i + 1);
|
||||
if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) {
|
||||
big_value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (big_value) {
|
||||
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->int_at_put(index, (jint)*((jint*)&res));
|
||||
obj->int_at_put(++index, (jint)*(((jint*)&res) + 1));
|
||||
} else {
|
||||
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.");
|
||||
|
@ -901,22 +884,135 @@ void Deoptimization::reassign_object_array_elements(frame* fr, RegisterMap* reg_
|
|||
}
|
||||
}
|
||||
|
||||
class ReassignedField {
|
||||
public:
|
||||
int _offset;
|
||||
BasicType _type;
|
||||
public:
|
||||
ReassignedField() {
|
||||
_offset = 0;
|
||||
_type = T_ILLEGAL;
|
||||
}
|
||||
};
|
||||
|
||||
int compare(ReassignedField* left, ReassignedField* right) {
|
||||
return left->_offset - right->_offset;
|
||||
}
|
||||
|
||||
// Restore fields of an eliminated instance object using the same field order
|
||||
// returned by HotSpotResolvedObjectTypeImpl.getInstanceFields(true)
|
||||
static int reassign_fields_by_klass(InstanceKlass* klass, frame* fr, RegisterMap* reg_map, ObjectValue* sv, int svIndex, oop obj, bool skip_internal) {
|
||||
if (klass->superklass() != NULL) {
|
||||
svIndex = reassign_fields_by_klass(klass->superklass(), fr, reg_map, sv, svIndex, obj, skip_internal);
|
||||
}
|
||||
|
||||
GrowableArray<ReassignedField>* fields = new GrowableArray<ReassignedField>();
|
||||
for (AllFieldStream fs(klass); !fs.done(); fs.next()) {
|
||||
if (!fs.access_flags().is_static() && (!skip_internal || !fs.access_flags().is_internal())) {
|
||||
ReassignedField field;
|
||||
field._offset = fs.offset();
|
||||
field._type = FieldType::basic_type(fs.signature());
|
||||
fields->append(field);
|
||||
}
|
||||
}
|
||||
fields->sort(compare);
|
||||
for (int i = 0; i < fields->length(); i++) {
|
||||
intptr_t val;
|
||||
ScopeValue* scope_field = sv->field_at(svIndex);
|
||||
StackValue* value = StackValue::create_stack_value(fr, reg_map, scope_field);
|
||||
int offset = fields->at(i)._offset;
|
||||
BasicType type = fields->at(i)._type;
|
||||
switch (type) {
|
||||
case T_OBJECT: case T_ARRAY:
|
||||
assert(value->type() == T_OBJECT, "Agreement.");
|
||||
obj->obj_field_put(offset, value->get_obj()());
|
||||
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.");
|
||||
bool big_value = false;
|
||||
if (i+1 < fields->length() && fields->at(i+1)._type == T_INT) {
|
||||
if (scope_field->is_location()) {
|
||||
Location::Type type = ((LocationValue*) scope_field)->location().type();
|
||||
if (type == Location::dbl || type == Location::lng) {
|
||||
big_value = true;
|
||||
}
|
||||
}
|
||||
if (scope_field->is_constant_int()) {
|
||||
ScopeValue* next_scope_field = sv->field_at(svIndex + 1);
|
||||
if (next_scope_field->is_constant_long() || next_scope_field->is_constant_double()) {
|
||||
big_value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (big_value) {
|
||||
i++;
|
||||
assert(i < fields->length(), "second T_INT field needed");
|
||||
assert(fields->at(i)._type == T_INT, "T_INT field needed");
|
||||
} else {
|
||||
val = value->get_int();
|
||||
obj->int_field_put(offset, (jint)*((jint*)&val));
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* no 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(++svIndex));
|
||||
#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;
|
||||
}
|
||||
|
||||
case T_SHORT: case T_CHAR: // 2 bytes
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
obj->short_field_put(offset, (jshort)*((jint*)&val));
|
||||
break;
|
||||
|
||||
case T_BOOLEAN: case T_BYTE: // 1 byte
|
||||
assert(value->type() == T_INT, "Agreement.");
|
||||
val = value->get_int();
|
||||
obj->bool_field_put(offset, (jboolean)*((jint*)&val));
|
||||
break;
|
||||
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
svIndex++;
|
||||
}
|
||||
return svIndex;
|
||||
}
|
||||
|
||||
// restore fields of all eliminated objects and arrays
|
||||
void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
|
||||
void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures, bool skip_internal) {
|
||||
for (int i = 0; i < objects->length(); i++) {
|
||||
ObjectValue* sv = (ObjectValue*) objects->at(i);
|
||||
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
|
||||
Handle obj = sv->value();
|
||||
assert(obj.not_null() || realloc_failures, "reallocation was missed");
|
||||
if (PrintDeoptimizationDetails) {
|
||||
tty->print_cr("reassign fields for object of type %s!", k->name()->as_C_string());
|
||||
}
|
||||
if (obj.is_null()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (k->oop_is_instance()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k());
|
||||
FieldReassigner reassign(fr, reg_map, sv, obj());
|
||||
ik->do_nonstatic_fields(&reassign);
|
||||
reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal);
|
||||
} else if (k->oop_is_typeArray()) {
|
||||
TypeArrayKlass* ak = TypeArrayKlass::cast(k());
|
||||
reassign_type_array_elements(fr, reg_map, sv, (typeArrayOop) obj(), ak->element_type());
|
||||
|
@ -981,13 +1077,13 @@ void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects, bool rea
|
|||
}
|
||||
}
|
||||
#endif
|
||||
#endif // COMPILER2
|
||||
#endif // COMPILER2 || INCLUDE_JVMCI
|
||||
|
||||
vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
|
||||
Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, p2i(fr.pc()), p2i(fr.sp()));
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDeoptimization) {
|
||||
if (PrintDeoptimizationDetails) {
|
||||
ttyLocker ttyl;
|
||||
tty->print("DEOPT PACKING thread " INTPTR_FORMAT " ", p2i(thread));
|
||||
fr.print_on(tty);
|
||||
|
@ -1032,7 +1128,7 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re
|
|||
assert(array->structural_compare(thread, chunk), "just checking");
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceDeoptimization) {
|
||||
if (PrintDeoptimizationDetails) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr(" Created vframeArray " INTPTR_FORMAT, p2i(array));
|
||||
}
|
||||
|
@ -1041,7 +1137,7 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re
|
|||
return array;
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
#if defined(COMPILER2) || INCLUDE_JVMCI
|
||||
void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) {
|
||||
// Reallocation of some scalar replaced objects failed. Record
|
||||
// that we need to pop all the interpreter frames for the
|
||||
|
@ -1149,17 +1245,38 @@ void Deoptimization::revoke_biases_of_monitors(CodeBlob* cb) {
|
|||
}
|
||||
|
||||
|
||||
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr) {
|
||||
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
|
||||
assert(fr.can_be_deoptimized(), "checking frame type");
|
||||
|
||||
gather_statistics(Reason_constraint, Action_none, Bytecodes::_illegal);
|
||||
gather_statistics(reason, Action_none, Bytecodes::_illegal);
|
||||
|
||||
// Patch the nmethod so that when execution returns to it we will
|
||||
if (LogCompilation && xtty != NULL) {
|
||||
nmethod* nm = fr.cb()->as_nmethod_or_null();
|
||||
assert(nm != NULL, "only compiled methods can deopt");
|
||||
|
||||
ttyLocker ttyl;
|
||||
xtty->begin_head("deoptimized thread='" UINTX_FORMAT "'", (uintx)thread->osthread()->thread_id());
|
||||
nm->log_identity(xtty);
|
||||
xtty->end_head();
|
||||
for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) {
|
||||
xtty->begin_elem("jvms bci='%d'", sd->bci());
|
||||
xtty->method(sd->method());
|
||||
xtty->end_elem();
|
||||
if (sd->is_top()) break;
|
||||
}
|
||||
xtty->tail("deoptimized");
|
||||
}
|
||||
|
||||
// Patch the compiled method so that when execution returns to it we will
|
||||
// deopt the execution state and return to the interpreter.
|
||||
fr.deoptimize(thread);
|
||||
}
|
||||
|
||||
void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) {
|
||||
deoptimize(thread, fr, map, Reason_constraint);
|
||||
}
|
||||
|
||||
void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) {
|
||||
// Deoptimize only if the frame comes from compile code.
|
||||
// Do not deoptimize the frame which is already patched
|
||||
// during the execution of the loops below.
|
||||
|
@ -1171,12 +1288,12 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map)
|
|||
if (UseBiasedLocking) {
|
||||
revoke_biases_of_monitors(thread, fr, map);
|
||||
}
|
||||
deoptimize_single_frame(thread, fr);
|
||||
deoptimize_single_frame(thread, fr, reason);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id) {
|
||||
void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id, DeoptReason reason) {
|
||||
assert(thread == Thread::current() || SafepointSynchronize::is_at_safepoint(),
|
||||
"can only deoptimize other thread at a safepoint");
|
||||
// Compute frame and register map based on thread and sp.
|
||||
|
@ -1185,19 +1302,22 @@ void Deoptimization::deoptimize_frame_internal(JavaThread* thread, intptr_t* id)
|
|||
while (fr.id() != id) {
|
||||
fr = fr.sender(®_map);
|
||||
}
|
||||
deoptimize(thread, fr, ®_map);
|
||||
deoptimize(thread, fr, ®_map, reason);
|
||||
}
|
||||
|
||||
|
||||
void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
|
||||
void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id, DeoptReason reason) {
|
||||
if (thread == Thread::current()) {
|
||||
Deoptimization::deoptimize_frame_internal(thread, id);
|
||||
Deoptimization::deoptimize_frame_internal(thread, id, reason);
|
||||
} else {
|
||||
VM_DeoptimizeFrame deopt(thread, id);
|
||||
VM_DeoptimizeFrame deopt(thread, id, reason);
|
||||
VMThread::execute(&deopt);
|
||||
}
|
||||
}
|
||||
|
||||
void Deoptimization::deoptimize_frame(JavaThread* thread, intptr_t* id) {
|
||||
deoptimize_frame(thread, id, Reason_constraint);
|
||||
}
|
||||
|
||||
// JVMTI PopFrame support
|
||||
JRT_LEAF(void, Deoptimization::popframe_preserve_args(JavaThread* thread, int bytes_to_save, void* start_address))
|
||||
|
@ -1224,7 +1344,7 @@ Deoptimization::get_method_data(JavaThread* thread, methodHandle m,
|
|||
return mdo;
|
||||
}
|
||||
|
||||
#if defined(COMPILER2) || defined(SHARK)
|
||||
#if defined(COMPILER2) || defined(SHARK) || INCLUDE_JVMCI
|
||||
void Deoptimization::load_class_by_index(constantPoolHandle constant_pool, int index, TRAPS) {
|
||||
// in case of an unresolved klass entry, load the class.
|
||||
if (constant_pool->tag_at(index).is_unresolved_klass()) {
|
||||
|
@ -1287,7 +1407,12 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
thread->inc_in_deopt_handler();
|
||||
|
||||
// We need to update the map if we have biased locking.
|
||||
#if INCLUDE_JVMCI
|
||||
// JVMCI might need to get an exception from the stack, which in turn requires the register map to be valid
|
||||
RegisterMap reg_map(thread, true);
|
||||
#else
|
||||
RegisterMap reg_map(thread, UseBiasedLocking);
|
||||
#endif
|
||||
frame stub_frame = thread->last_frame();
|
||||
frame fr = stub_frame.sender(®_map);
|
||||
// Make sure the calling nmethod is not getting deoptimized and removed
|
||||
|
@ -1295,8 +1420,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
nmethodLocker nl(fr.pc());
|
||||
|
||||
// Log a message
|
||||
Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT,
|
||||
trap_request, p2i(fr.pc()));
|
||||
Events::log(thread, "Uncommon trap: trap_request=" PTR32_FORMAT " fr.pc=" INTPTR_FORMAT " relative=" INTPTR_FORMAT,
|
||||
trap_request, p2i(fr.pc()), fr.pc() - fr.cb()->code_begin());
|
||||
|
||||
{
|
||||
ResourceMark rm;
|
||||
|
@ -1306,6 +1431,9 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
|
||||
DeoptReason reason = trap_request_reason(trap_request);
|
||||
DeoptAction action = trap_request_action(trap_request);
|
||||
#if INCLUDE_JVMCI
|
||||
int debug_id = trap_request_debug_id(trap_request);
|
||||
#endif
|
||||
jint unloaded_class_index = trap_request_index(trap_request); // CP idx or -1
|
||||
|
||||
vframe* vf = vframe::new_vframe(&fr, ®_map, thread);
|
||||
|
@ -1314,10 +1442,71 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
nmethod* nm = cvf->code();
|
||||
|
||||
ScopeDesc* trap_scope = cvf->scope();
|
||||
|
||||
if (TraceDeoptimization) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr(" bci=%d pc=" INTPTR_FORMAT ", relative_pc=" INTPTR_FORMAT ", method=%s" JVMCI_ONLY(", debug_id=%d"), trap_scope->bci(), p2i(fr.pc()), fr.pc() - nm->code_begin(), trap_scope->method()->name_and_sig_as_C_string()
|
||||
#if INCLUDE_JVMCI
|
||||
, debug_id
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
methodHandle trap_method = trap_scope->method();
|
||||
int trap_bci = trap_scope->bci();
|
||||
#if INCLUDE_JVMCI
|
||||
oop speculation = thread->pending_failed_speculation();
|
||||
if (nm->is_compiled_by_jvmci()) {
|
||||
if (speculation != NULL) {
|
||||
oop speculation_log = nm->speculation_log();
|
||||
if (speculation_log != NULL) {
|
||||
if (TraceDeoptimization || TraceUncollectedSpeculations) {
|
||||
if (SpeculationLog::lastFailed(speculation_log) != NULL) {
|
||||
tty->print_cr("A speculation that was not collected by the compiler is being overwritten");
|
||||
}
|
||||
}
|
||||
if (TraceDeoptimization) {
|
||||
tty->print_cr("Saving speculation to speculation log");
|
||||
}
|
||||
SpeculationLog::set_lastFailed(speculation_log, speculation);
|
||||
} else {
|
||||
if (TraceDeoptimization) {
|
||||
tty->print_cr("Speculation present but no speculation log");
|
||||
}
|
||||
}
|
||||
thread->set_pending_failed_speculation(NULL);
|
||||
} else {
|
||||
if (TraceDeoptimization) {
|
||||
tty->print_cr("No speculation");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert(speculation == NULL, "There should not be a speculation for method compiled by non-JVMCI compilers");
|
||||
}
|
||||
|
||||
if (trap_bci == SynchronizationEntryBCI) {
|
||||
trap_bci = 0;
|
||||
thread->set_pending_monitorenter(true);
|
||||
}
|
||||
|
||||
if (reason == Deoptimization::Reason_transfer_to_interpreter) {
|
||||
thread->set_pending_transfer_to_interpreter(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
Bytecodes::Code trap_bc = trap_method->java_code_at(trap_bci);
|
||||
|
||||
if (trap_scope->rethrow_exception()) {
|
||||
if (PrintDeoptimizationDetails) {
|
||||
tty->print_cr("Exception to be rethrown in the interpreter for method %s::%s at bci %d", trap_method->method_holder()->name()->as_C_string(), trap_method->name()->as_C_string(), trap_bci);
|
||||
}
|
||||
GrowableArray<ScopeValue*>* expressions = trap_scope->expressions();
|
||||
guarantee(expressions != NULL, "must have exception to throw");
|
||||
ScopeValue* topOfStack = expressions->top();
|
||||
Handle topOfStackObj = StackValue::create_stack_value(&fr, ®_map, topOfStack)->get_obj();
|
||||
THREAD->set_pending_exception(topOfStackObj(), NULL, 0);
|
||||
}
|
||||
|
||||
// Record this event in the histogram.
|
||||
gather_statistics(reason, action, trap_bc);
|
||||
|
||||
|
@ -1325,8 +1514,19 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
// Need MDO to record RTM code generation state.
|
||||
bool create_if_missing = ProfileTraps || UseCodeAging RTM_OPT_ONLY( || UseRTMLocking );
|
||||
|
||||
methodHandle profiled_method;
|
||||
#if INCLUDE_JVMCI
|
||||
if (nm->is_compiled_by_jvmci()) {
|
||||
profiled_method = nm->method();
|
||||
} else {
|
||||
profiled_method = trap_method;
|
||||
}
|
||||
#else
|
||||
profiled_method = trap_method;
|
||||
#endif
|
||||
|
||||
MethodData* trap_mdo =
|
||||
get_method_data(thread, trap_method, create_if_missing);
|
||||
get_method_data(thread, profiled_method, create_if_missing);
|
||||
|
||||
// Log a message
|
||||
Events::log_deopt_message(thread, "Uncommon trap: reason=%s action=%s pc=" INTPTR_FORMAT " method=%s @ %d",
|
||||
|
@ -1384,12 +1584,33 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
if (TraceDeoptimization) { // make noise on the tty
|
||||
tty->print("Uncommon trap occurred in");
|
||||
nm->method()->print_short_name(tty);
|
||||
tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d",
|
||||
tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id());
|
||||
#if INCLUDE_JVMCI
|
||||
oop installedCode = nm->jvmci_installed_code();
|
||||
if (installedCode != NULL) {
|
||||
oop installedCodeName = NULL;
|
||||
if (installedCode->is_a(InstalledCode::klass())) {
|
||||
installedCodeName = InstalledCode::name(installedCode);
|
||||
}
|
||||
if (installedCodeName != NULL) {
|
||||
tty->print(" (JVMCI: installedCodeName=%s) ", java_lang_String::as_utf8_string(installedCodeName));
|
||||
} else {
|
||||
tty->print(" (JVMCI: installed code has no name) ");
|
||||
}
|
||||
} else if (nm->is_compiled_by_jvmci()) {
|
||||
tty->print(" (JVMCI: no installed code) ");
|
||||
}
|
||||
#endif
|
||||
tty->print(" (@" INTPTR_FORMAT ") thread=" UINTX_FORMAT " reason=%s action=%s unloaded_class_index=%d" JVMCI_ONLY(" debug_id=%d"),
|
||||
p2i(fr.pc()),
|
||||
os::current_thread_id(),
|
||||
trap_reason_name(reason),
|
||||
trap_action_name(action),
|
||||
unloaded_class_index);
|
||||
unloaded_class_index
|
||||
#if INCLUDE_JVMCI
|
||||
, debug_id
|
||||
#endif
|
||||
);
|
||||
if (class_name != NULL) {
|
||||
tty->print(unresolved ? " unresolved class: " : " symbol: ");
|
||||
class_name->print_symbol_on(tty);
|
||||
|
@ -1523,11 +1744,14 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
|||
bool inc_recompile_count = false;
|
||||
ProfileData* pdata = NULL;
|
||||
if (ProfileTraps && update_trap_state && trap_mdo != NULL) {
|
||||
assert(trap_mdo == get_method_data(thread, trap_method, false), "sanity");
|
||||
assert(trap_mdo == get_method_data(thread, profiled_method, false), "sanity");
|
||||
uint this_trap_count = 0;
|
||||
bool maybe_prior_trap = false;
|
||||
bool maybe_prior_recompile = false;
|
||||
pdata = query_update_method_data(trap_mdo, trap_bci, reason,
|
||||
pdata = query_update_method_data(trap_mdo, trap_bci, reason, true,
|
||||
#if INCLUDE_JVMCI
|
||||
nm->is_compiled_by_jvmci() && nm->is_osr_method(),
|
||||
#endif
|
||||
nm->method(),
|
||||
//outputs:
|
||||
this_trap_count,
|
||||
|
@ -1659,26 +1883,42 @@ ProfileData*
|
|||
Deoptimization::query_update_method_data(MethodData* trap_mdo,
|
||||
int trap_bci,
|
||||
Deoptimization::DeoptReason reason,
|
||||
bool update_total_trap_count,
|
||||
#if INCLUDE_JVMCI
|
||||
bool is_osr,
|
||||
#endif
|
||||
Method* compiled_method,
|
||||
//outputs:
|
||||
uint& ret_this_trap_count,
|
||||
bool& ret_maybe_prior_trap,
|
||||
bool& ret_maybe_prior_recompile) {
|
||||
uint prior_trap_count = trap_mdo->trap_count(reason);
|
||||
uint this_trap_count = trap_mdo->inc_trap_count(reason);
|
||||
bool maybe_prior_trap = false;
|
||||
bool maybe_prior_recompile = false;
|
||||
uint this_trap_count = 0;
|
||||
if (update_total_trap_count) {
|
||||
uint idx = reason;
|
||||
#if INCLUDE_JVMCI
|
||||
if (is_osr) {
|
||||
idx += Reason_LIMIT;
|
||||
}
|
||||
#endif
|
||||
uint prior_trap_count = trap_mdo->trap_count(idx);
|
||||
this_trap_count = trap_mdo->inc_trap_count(idx);
|
||||
|
||||
// If the runtime cannot find a place to store trap history,
|
||||
// it is estimated based on the general condition of the method.
|
||||
// If the method has ever been recompiled, or has ever incurred
|
||||
// a trap with the present reason , then this BCI is assumed
|
||||
// (pessimistically) to be the culprit.
|
||||
bool maybe_prior_trap = (prior_trap_count != 0);
|
||||
bool maybe_prior_recompile = (trap_mdo->decompile_count() != 0);
|
||||
// If the runtime cannot find a place to store trap history,
|
||||
// it is estimated based on the general condition of the method.
|
||||
// If the method has ever been recompiled, or has ever incurred
|
||||
// a trap with the present reason , then this BCI is assumed
|
||||
// (pessimistically) to be the culprit.
|
||||
maybe_prior_trap = (prior_trap_count != 0);
|
||||
maybe_prior_recompile = (trap_mdo->decompile_count() != 0);
|
||||
}
|
||||
ProfileData* pdata = NULL;
|
||||
|
||||
|
||||
// For reasons which are recorded per bytecode, we check per-BCI data.
|
||||
DeoptReason per_bc_reason = reason_recorded_per_bytecode_if_any(reason);
|
||||
assert(per_bc_reason != Reason_none || update_total_trap_count, "must be");
|
||||
if (per_bc_reason != Reason_none) {
|
||||
// Find the profile data for this BCI. If there isn't one,
|
||||
// try to allocate one from the MDO's set of spares.
|
||||
|
@ -1731,8 +1971,14 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr
|
|||
bool ignore_maybe_prior_trap;
|
||||
bool ignore_maybe_prior_recompile;
|
||||
assert(!reason_is_speculate(reason), "reason speculate only used by compiler");
|
||||
// JVMCI uses the total counts to determine if deoptimizations are happening too frequently -> do not adjust total counts
|
||||
bool update_total_counts = JVMCI_ONLY(false) NOT_JVMCI(true);
|
||||
query_update_method_data(trap_mdo, trap_bci,
|
||||
(DeoptReason)reason,
|
||||
update_total_counts,
|
||||
#if INCLUDE_JVMCI
|
||||
false,
|
||||
#endif
|
||||
NULL,
|
||||
ignore_this_trap_count,
|
||||
ignore_maybe_prior_trap,
|
||||
|
@ -1740,7 +1986,9 @@ Deoptimization::update_method_data_from_interpreter(MethodData* trap_mdo, int tr
|
|||
}
|
||||
|
||||
Deoptimization::UnrollBlock* Deoptimization::uncommon_trap(JavaThread* thread, jint trap_request) {
|
||||
|
||||
if (TraceDeoptimization) {
|
||||
tty->print("Uncommon trap ");
|
||||
}
|
||||
// Still in Java no safepoints
|
||||
{
|
||||
// This enters VM and may safepoint
|
||||
|
@ -1845,12 +2093,12 @@ const char* Deoptimization::_trap_reason_name[] = {
|
|||
// Note: Keep this in sync. with enum DeoptReason.
|
||||
"none",
|
||||
"null_check",
|
||||
"null_assert",
|
||||
"null_assert" JVMCI_ONLY("_or_unreached0"),
|
||||
"range_check",
|
||||
"class_check",
|
||||
"array_check",
|
||||
"intrinsic",
|
||||
"bimorphic",
|
||||
"intrinsic" JVMCI_ONLY("_or_type_checked_inlining"),
|
||||
"bimorphic" JVMCI_ONLY("_or_optimized_type_check"),
|
||||
"unloaded",
|
||||
"uninitialized",
|
||||
"unreached",
|
||||
|
@ -1865,6 +2113,13 @@ const char* Deoptimization::_trap_reason_name[] = {
|
|||
"rtm_state_change",
|
||||
"unstable_if",
|
||||
"unstable_fused_if",
|
||||
#if INCLUDE_JVMCI
|
||||
"aliasing",
|
||||
"transfer_to_interpreter",
|
||||
"not_compiled_exception_handler",
|
||||
"unresolved",
|
||||
"jsr_mismatch",
|
||||
#endif
|
||||
"tenured"
|
||||
};
|
||||
const char* Deoptimization::_trap_action_name[] = {
|
||||
|
@ -1904,13 +2159,24 @@ const char* Deoptimization::format_trap_request(char* buf, size_t buflen,
|
|||
jint unloaded_class_index = trap_request_index(trap_request);
|
||||
const char* reason = trap_reason_name(trap_request_reason(trap_request));
|
||||
const char* action = trap_action_name(trap_request_action(trap_request));
|
||||
#if INCLUDE_JVMCI
|
||||
int debug_id = trap_request_debug_id(trap_request);
|
||||
#endif
|
||||
size_t len;
|
||||
if (unloaded_class_index < 0) {
|
||||
len = jio_snprintf(buf, buflen, "reason='%s' action='%s'",
|
||||
reason, action);
|
||||
len = jio_snprintf(buf, buflen, "reason='%s' action='%s'" JVMCI_ONLY(" debug_id='%d'"),
|
||||
reason, action
|
||||
#if INCLUDE_JVMCI
|
||||
,debug_id
|
||||
#endif
|
||||
);
|
||||
} else {
|
||||
len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'",
|
||||
reason, action, unloaded_class_index);
|
||||
len = jio_snprintf(buf, buflen, "reason='%s' action='%s' index='%d'" JVMCI_ONLY(" debug_id='%d'"),
|
||||
reason, action, unloaded_class_index
|
||||
#if INCLUDE_JVMCI
|
||||
,debug_id
|
||||
#endif
|
||||
);
|
||||
}
|
||||
if (len >= buflen)
|
||||
buf[buflen-1] = '\0';
|
||||
|
@ -2007,7 +2273,7 @@ void Deoptimization::print_statistics() {
|
|||
if (xtty != NULL) xtty->tail("statistics");
|
||||
}
|
||||
}
|
||||
#else // COMPILER2 || SHARK
|
||||
#else // COMPILER2 || SHARK || INCLUDE_JVMCI
|
||||
|
||||
|
||||
// Stubs for C1 only system.
|
||||
|
@ -2043,4 +2309,4 @@ const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
|
|||
return buf;
|
||||
}
|
||||
|
||||
#endif // COMPILER2 || SHARK
|
||||
#endif // COMPILER2 || SHARK || INCLUDE_JVMCI
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue