< prev index next >
src/hotspot/share/runtime/deoptimization.cpp
Print this page
rev 56205 : imported patch 8226705-v1
*** 155,215 ****
thread->inc_in_deopt_handler();
return fetch_unroll_info_helper(thread, exec_mode);
JRT_END
-
- // This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap)
- Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) {
-
- // Note: there is a safepoint safety issue here. No matter whether we enter
- // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once
- // the vframeArray is created.
- //
-
- // Allocate our special deoptimization ResourceMark
- DeoptResourceMark* dmark = new DeoptResourceMark(thread);
- assert(thread->deopt_mark() == NULL, "Pending deopt!");
- thread->set_deopt_mark(dmark);
-
- frame stub_frame = thread->last_frame(); // Makes stack walkable as side effect
- RegisterMap map(thread, true);
- RegisterMap dummy_map(thread, false);
- // Now get the deoptee with a valid map
- frame deoptee = stub_frame.sender(&map);
- // Set the deoptee nmethod
- assert(thread->deopt_compiled_method() == NULL, "Pending deopt!");
- CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
- thread->set_deopt_compiled_method(cm);
-
- if (VerifyStack) {
- thread->validate_frame_layout();
- }
-
- // Create a growable array of VFrames where each VFrame represents an inlined
- // Java frame. This storage is allocated with the usual system arena.
- assert(deoptee.is_compiled_frame(), "Wrong frame type");
- GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
- vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
- while (!vf->is_top()) {
- assert(vf->is_compiled_frame(), "Wrong frame type");
- chunk->push(compiledVFrame::cast(vf));
- vf = vf->sender();
- }
- assert(vf->is_compiled_frame(), "Wrong frame type");
- chunk->push(compiledVFrame::cast(vf));
-
- bool realloc_failures = false;
-
#if COMPILER2_OR_JVMCI
! // Reallocate the non-escaping objects and restore their fields. Then
! // relock objects if synchronization on them was eliminated.
! #if !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();
// The flag return_oop() indicates call sites which return oop
// in compiled code. Such sites include java method calls,
// runtime calls (for example, used to allocate new objects/arrays
--- 155,170 ----
thread->inc_in_deopt_handler();
return fetch_unroll_info_helper(thread, exec_mode);
JRT_END
#if COMPILER2_OR_JVMCI
! static bool eliminate_allocations(JavaThread* thread, int exec_mode, CompiledMethod* compiled_method,
! frame& deoptee, RegisterMap& map, GrowableArray<compiledVFrame*>* chunk) {
! bool realloc_failures = false;
assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
+
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
// The flag return_oop() indicates call sites which return oop
// in compiled code. Such sites include java method calls,
// runtime calls (for example, used to allocate new objects/arrays
*** 217,227 ****
// It is not guaranteed that we can get such information here only
// by analyzing bytecode in deoptimized frames. This is why this flag
// is set during method compilation (see Compile::Process_OopMap_Node()).
// If the previous frame was popped or if we are dispatching an exception,
// we don't have an oop result.
! bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Unpack_deopt);
Handle return_value;
if (save_oop_result) {
// Reallocation may trigger GC. If deoptimization happened on return from
// call which returns oop we need to save it since it is not in oopmap.
oop result = deoptee.saved_oop_result(&map);
--- 172,182 ----
// It is not guaranteed that we can get such information here only
// by analyzing bytecode in deoptimized frames. This is why this flag
// is set during method compilation (see Compile::Process_OopMap_Node()).
// If the previous frame was popped or if we are dispatching an exception,
// we don't have an oop result.
! bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Deoptimization::Unpack_deopt);
Handle return_value;
if (save_oop_result) {
// Reallocation may trigger GC. If deoptimization happened on return from
// call which returns oop we need to save it since it is not in oopmap.
oop result = deoptee.saved_oop_result(&map);
*** 233,271 ****
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread));
}
}
if (objects != NULL) {
JRT_BLOCK
! realloc_failures = realloc_objects(thread, &deoptee, &map, objects, THREAD);
JRT_END
! bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
! reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread));
! print_objects(objects, realloc_failures);
}
#endif
}
if (save_oop_result) {
// Restore result.
deoptee.set_saved_oop_result(&map, return_value());
}
! #if !INCLUDE_JVMCI
! }
! if (EliminateLocks) {
! #endif // INCLUDE_JVMCI
#ifndef PRODUCT
bool first = true;
#endif
for (int i = 0; i < chunk->length(); i++) {
compiledVFrame* cvf = chunk->at(i);
assert (cvf->scope() != NULL,"expect only compiled java frames");
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors->is_nonempty()) {
! relock_objects(monitors, thread, realloc_failures);
#ifndef PRODUCT
if (PrintDeoptimizationDetails) {
ttyLocker ttyl;
for (int j = 0; j < monitors->length(); j++) {
MonitorInfo* mi = monitors->at(j);
--- 188,226 ----
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread));
}
}
if (objects != NULL) {
JRT_BLOCK
! realloc_failures = Deoptimization::realloc_objects(thread, &deoptee, &map, objects, THREAD);
JRT_END
! bool skip_internal = (compiled_method != NULL) && !compiled_method->is_compiled_by_jvmci();
! Deoptimization::reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread));
! Deoptimization::print_objects(objects, realloc_failures);
}
#endif
}
if (save_oop_result) {
// Restore result.
deoptee.set_saved_oop_result(&map, return_value());
}
! return realloc_failures;
! }
!
! static void eliminate_locks(JavaThread* thread, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
#ifndef PRODUCT
bool first = true;
#endif
for (int i = 0; i < chunk->length(); i++) {
compiledVFrame* cvf = chunk->at(i);
assert (cvf->scope() != NULL,"expect only compiled java frames");
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors->is_nonempty()) {
! Deoptimization::relock_objects(monitors, thread, realloc_failures);
#ifndef PRODUCT
if (PrintDeoptimizationDetails) {
ttyLocker ttyl;
for (int j = 0; j < monitors->length(); j++) {
MonitorInfo* mi = monitors->at(j);
*** 284,297 ****
}
}
#endif // !PRODUCT
}
}
! #if !INCLUDE_JVMCI
}
}
- #endif // INCLUDE_JVMCI
#endif // COMPILER2_OR_JVMCI
ScopeDesc* trap_scope = chunk->at(0)->scope();
Handle exceptionObject;
if (trap_scope->rethrow_exception()) {
--- 239,319 ----
}
}
#endif // !PRODUCT
}
}
! }
! #endif // COMPILER2_OR_JVMCI
!
! // This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap)
! Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) {
!
! // Note: there is a safepoint safety issue here. No matter whether we enter
! // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once
! // the vframeArray is created.
! //
!
! // Allocate our special deoptimization ResourceMark
! DeoptResourceMark* dmark = new DeoptResourceMark(thread);
! assert(thread->deopt_mark() == NULL, "Pending deopt!");
! thread->set_deopt_mark(dmark);
!
! frame stub_frame = thread->last_frame(); // Makes stack walkable as side effect
! RegisterMap map(thread, true);
! RegisterMap dummy_map(thread, false);
! // Now get the deoptee with a valid map
! frame deoptee = stub_frame.sender(&map);
! // Set the deoptee nmethod
! assert(thread->deopt_compiled_method() == NULL, "Pending deopt!");
! CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
! thread->set_deopt_compiled_method(cm);
!
! if (VerifyStack) {
! thread->validate_frame_layout();
! }
!
! // Create a growable array of VFrames where each VFrame represents an inlined
! // Java frame. This storage is allocated with the usual system arena.
! assert(deoptee.is_compiled_frame(), "Wrong frame type");
! GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
! vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
! while (!vf->is_top()) {
! assert(vf->is_compiled_frame(), "Wrong frame type");
! chunk->push(compiledVFrame::cast(vf));
! vf = vf->sender();
! }
! assert(vf->is_compiled_frame(), "Wrong frame type");
! chunk->push(compiledVFrame::cast(vf));
!
! bool realloc_failures = false;
!
! #if COMPILER2_OR_JVMCI
! #if INCLUDE_JVMCI
! bool jvmci_enabled = true;
! #else
! bool jvmci_enabled = false;
! #endif
!
! // Reallocate the non-escaping objects and restore their fields. Then
! // relock objects if synchronization on them was eliminated.
! if (jvmci_enabled || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateAllocations)) {
! realloc_failures = eliminate_allocations(thread, exec_mode, cm, deoptee, map, chunk);
}
+
+ // Revoke biases, done with in java state.
+ // No safepoints allowed after this
+ revoke_from_deopt_handler(thread, deoptee, &map);
+
+ // 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.
+ // Locks may be rebaised in a safepoint.
+ NoSafepointVerifier no_safepoint;
+
+ if (jvmci_enabled || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks)) {
+ eliminate_locks(thread, chunk, realloc_failures);
}
#endif // COMPILER2_OR_JVMCI
ScopeDesc* trap_scope = chunk->at(0)->scope();
Handle exceptionObject;
if (trap_scope->rethrow_exception()) {
*** 303,317 ****
ScopeValue* topOfStack = expressions->top();
exceptionObject = StackValue::create_stack_value(&deoptee, &map, topOfStack)->get_obj();
guarantee(exceptionObject() != NULL, "exception oop can not be null");
}
- // 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.
- NoSafepointVerifier no_safepoint;
-
vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
#if COMPILER2_OR_JVMCI
if (realloc_failures) {
pop_frames_failed_reallocs(thread, array);
}
--- 325,334 ----
*** 777,790 ****
return bt;
JRT_END
! int Deoptimization::deoptimize_dependents() {
! Threads::deoptimized_wrt_marked_nmethods();
! return 0;
}
Deoptimization::DeoptAction Deoptimization::_unloaded_action
= Deoptimization::Action_reinterpret;
--- 794,830 ----
return bt;
JRT_END
+ class DeoptimizeMarkedTC : public ThreadClosure {
+ public:
+ virtual void do_thread(Thread* thread) {
+ assert(thread->is_Java_thread(), "must be");
+ JavaThread* jt = (JavaThread*)thread;
+ jt->deoptimize_marked_methods();
+ }
+ };
+
+ void Deoptimization::deoptimize_all_marked() {
+ ResourceMark rm;
+ DeoptimizationMarker dm;
! if (SafepointSynchronize::is_at_safepoint()) {
! DeoptimizeMarkedTC deopt;
! // Make the dependent methods not entrant
! CodeCache::make_marked_nmethods_not_entrant();
! Threads::java_threads_do(&deopt);
! } else {
! // Make the dependent methods not entrant
! {
! MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
! CodeCache::make_marked_nmethods_not_entrant();
! }
! DeoptimizeMarkedTC deopt;
! Handshake::execute(&deopt);
! }
}
Deoptimization::DeoptAction Deoptimization::_unloaded_action
= Deoptimization::Action_reinterpret;
*** 1395,1412 ****
objects_to_revoke->append(Handle(thread, mon_info->owner()));
}
}
}
!
! void Deoptimization::revoke_biases_of_monitors(JavaThread* thread, frame fr, RegisterMap* map) {
! if (!UseBiasedLocking) {
! return;
! }
!
! GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
!
// Unfortunately we don't have a RegisterMap available in most of
// the places we want to call this routine so we need to walk the
// stack again to update the register map.
if (map == NULL || !map->update_map()) {
StackFrameStream sfs(thread, true);
--- 1435,1445 ----
objects_to_revoke->append(Handle(thread, mon_info->owner()));
}
}
}
! static void get_monitors_from_stack(GrowableArray<Handle>* objects_to_revoke, JavaThread* thread, frame fr, RegisterMap* map) {
// Unfortunately we don't have a RegisterMap available in most of
// the places we want to call this routine so we need to walk the
// stack again to update the register map.
if (map == NULL || !map->update_map()) {
StackFrameStream sfs(thread, true);
*** 1426,1440 ****
while (!cvf->is_top()) {
collect_monitors(cvf, objects_to_revoke);
cvf = compiledVFrame::cast(cvf->sender());
}
collect_monitors(cvf, objects_to_revoke);
! if (SafepointSynchronize::is_at_safepoint()) {
! BiasedLocking::revoke_at_safepoint(objects_to_revoke);
! } else {
! BiasedLocking::revoke(objects_to_revoke, thread);
}
}
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
--- 1459,1482 ----
while (!cvf->is_top()) {
collect_monitors(cvf, objects_to_revoke);
cvf = compiledVFrame::cast(cvf->sender());
}
collect_monitors(cvf, objects_to_revoke);
+ }
! void Deoptimization::revoke_from_deopt_handler(JavaThread* thread, frame fr, RegisterMap* map) {
! if (!UseBiasedLocking) {
! return;
! }
! GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
! get_monitors_from_stack(objects_to_revoke, thread, fr, map);
!
! int len = objects_to_revoke->length();
! for (int i = 0; i < len; i++) {
! oop obj = (objects_to_revoke->at(i))();
! BiasedLocking::revoke_own_locks(objects_to_revoke->at(i), thread);
! assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
}
}
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
*** 1462,1489 ****
// 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.
if (!fr.is_compiled_frame() || fr.is_deoptimized_frame()) {
return;
}
ResourceMark rm;
DeoptimizationMarker dm;
- if (UseBiasedLocking) {
- revoke_biases_of_monitors(thread, fr, map);
- }
deoptimize_single_frame(thread, fr, reason);
-
}
#if INCLUDE_JVMCI
address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* cm) {
// there is no exception handler for this pc => deoptimize
--- 1504,1523 ----
*** 1640,1652 ****
trap_request, p2i(fr.pc()), fr.pc() - fr.cb()->code_begin());
{
ResourceMark rm;
- // Revoke biases of any monitors in the frame to ensure we can migrate them
- revoke_biases_of_monitors(thread, fr, ®_map);
-
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
--- 1674,1683 ----
< prev index next >