Skip to content

Commit

Permalink
Store deferred locals information in frame
Browse files Browse the repository at this point in the history
  • Loading branch information
tkrodriguez committed Nov 15, 2024
1 parent f316808 commit 4a039c6
Show file tree
Hide file tree
Showing 28 changed files with 163 additions and 229 deletions.
9 changes: 2 additions & 7 deletions src/hotspot/cpu/aarch64/frame_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,14 +457,9 @@ JavaThread** frame::saved_thread_address(const frame& f) {
// given unextended SP.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
frame fr;
assert(unextended_sp == _unextended_sp, "expected to be the same frame");

// This is ugly but it's better than to change {get,set}_original_pc
// to take an SP value as argument. And it's only a debugging
// method anyway.
fr._unextended_sp = unextended_sp;

address original_pc = nm->get_original_pc(&fr);
address original_pc = get_original_pc(nm);
assert(nm->insts_contains_inclusive(original_pc),
"original PC must be in the main code section of the compiled method (or must be immediately following it)");
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/aarch64/frame_aarch64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@

#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
#endif

public:
Expand Down
9 changes: 2 additions & 7 deletions src/hotspot/cpu/arm/frame_arm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,9 @@ JavaThread** frame::saved_thread_address(const frame& f) {
// for MethodHandle call sites.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) {
frame fr;
assert(unextended_sp == _unextended_sp, "expected to be the same frame");

// This is ugly but it's better than to change {get,set}_original_pc
// to take an SP value as argument. And it's only a debugging
// method anyway.
fr._unextended_sp = unextended_sp;

address original_pc = nm->get_original_pc(&fr);
address original_pc = get_original_pc(nm);
assert(nm->insts_contains_inclusive(original_pc),
"original PC must be in the main code section of the compiled method (or must be immediately following it)");
assert(nm->is_method_handle_return(original_pc) == is_method_handle_return, "must be");
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/cpu/arm/frame_arm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@

#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false);
void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) {
verify_deopt_original_pc(nm, unextended_sp, true);
}
#endif
Expand Down
9 changes: 2 additions & 7 deletions src/hotspot/cpu/riscv/frame_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,15 +430,10 @@ JavaThread** frame::saved_thread_address(const frame& f) {
// given unextended SP.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
frame fr;

// This is ugly but it's better than to change {get,set}_original_pc
// to take an SP value as argument. And it's only a debugging
// method anyway.
fr._unextended_sp = unextended_sp;
assert(unextended_sp == _unextended_sp, "expected to be the same frame");

assert_cond(nm != nullptr);
address original_pc = nm->get_original_pc(&fr);
address original_pc = get_original_pc(nm);
assert(nm->insts_contains_inclusive(original_pc),
"original PC must be in the main code section of the compiled method (or must be immediately following it)");
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/riscv/frame_riscv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@

#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
#endif

public:
Expand Down
9 changes: 2 additions & 7 deletions src/hotspot/cpu/x86/frame_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,9 @@ JavaThread** frame::saved_thread_address(const frame& f) {
// given unextended SP.
#ifdef ASSERT
void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) {
frame fr;
assert(unextended_sp == _unextended_sp, "expected to be the same frame");

// This is ugly but it's better than to change {get,set}_original_pc
// to take an SP value as argument. And it's only a debugging
// method anyway.
fr._unextended_sp = unextended_sp;

address original_pc = nm->get_original_pc(&fr);
address original_pc = get_original_pc(nm);
assert(nm->insts_contains_inclusive(original_pc),
"original PC must be in the main code section of the compiled method (or must be immediately following it) original_pc: " INTPTR_FORMAT " unextended_sp: " INTPTR_FORMAT " name: %s", p2i(original_pc), p2i(unextended_sp), nm->name());
}
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/x86/frame_x86.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@

#ifdef ASSERT
// Used in frame::sender_for_{interpreter,compiled}_frame
static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp);
#endif

public:
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/os/posix/signals_posix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info,
assert(deopt != nullptr, "");

frame fr = os::fetch_frame_from_context(uc);
nm->set_original_pc(&fr, pc);
fr.set_original_pc(nm, pc);

os::Posix::ucontext_set_pc(uc, deopt);
signal_was_handled = true;
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/os/windows/os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2778,7 +2778,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
nm->deopt_mh_handler_begin() :
nm->deopt_handler_begin();
assert(nm->insts_contains_inclusive(pc), "");
nm->set_original_pc(&fr, pc);
fr.set_original_pc(nm, pc);
// Set pc to handler
exceptionInfo->ContextRecord->PC_NAME = (DWORD64)deopt;
return EXCEPTION_CONTINUE_EXECUTION;
Expand Down
4 changes: 0 additions & 4 deletions src/hotspot/share/code/nmethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,10 +857,6 @@ void nmethod::cleanup_inline_caches_whitebox() {
cleanup_inline_caches_impl(false /* unloading_occurred */, true /* clean_all */);
}

address* nmethod::orig_pc_addr(const frame* fr) {
return (address*) ((address)fr->unextended_sp() + orig_pc_offset());
}

// Called to clean up after class unloading for live nmethods
void nmethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) {
assert(CompiledICLocker::is_safe(this), "mt unsafe call");
Expand Down
8 changes: 3 additions & 5 deletions src/hotspot/share/code/nmethod.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -749,9 +749,9 @@ class nmethod : public CodeBlob {
inline bool is_deopt_mh_entry(address pc);
inline bool is_deopt_entry(address pc);

// Accessor/mutator for the original pc of a frame before a frame was deopted.
address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); }
void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; }
address* orig_pc_addr(const frame* fr) const {
return (address*) ((address)fr->unextended_sp() + _orig_pc_offset);
}

const char* state() const;

Expand Down Expand Up @@ -871,8 +871,6 @@ class nmethod : public CodeBlob {
private:
ScopeDesc* scope_desc_in(address begin, address end);

address* orig_pc_addr(const frame* fr);

// used by jvmti to track if the load events has been reported
bool load_reported() const { return _load_reported; }
void set_load_reported() { _load_reported = true; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,6 @@ bool ReferenceToThreadRootClosure::do_thread_stack_detailed(JavaThread* jt) {
return true;
}

GrowableArrayView<jvmtiDeferredLocalVariableSet*>* const list = JvmtiDeferredUpdates::deferred_locals(jt);
if (list != nullptr) {
for (int i = 0; i < list->length(); i++) {
list->at(i)->oops_do(&rcl);
}
}

if (rcl.complete()) {
return true;
}
Expand Down
52 changes: 0 additions & 52 deletions src/hotspot/share/prims/jvmtiDeferredUpdates.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,62 +26,10 @@
#include "precompiled.hpp"
#include "prims/jvmtiDeferredUpdates.hpp"

void JvmtiDeferredUpdates::create_for(JavaThread* thread) {
assert(thread->deferred_updates() == nullptr, "already allocated");
thread->set_deferred_updates(new JvmtiDeferredUpdates());
}

JvmtiDeferredUpdates::~JvmtiDeferredUpdates() {
while (_deferred_locals_updates.length() != 0) {
jvmtiDeferredLocalVariableSet* dlv = _deferred_locals_updates.pop();
// individual jvmtiDeferredLocalVariableSet are CHeapObj's
delete dlv;
}
}

void JvmtiDeferredUpdates::inc_relock_count_after_wait(JavaThread* thread) {
if (thread->deferred_updates() == nullptr) {
create_for(thread);
}
thread->deferred_updates()->inc_relock_count_after_wait();
}

int JvmtiDeferredUpdates::get_and_reset_relock_count_after_wait(JavaThread* jt) {
JvmtiDeferredUpdates* updates = jt->deferred_updates();
int result = 0;
if (updates != nullptr) {
result = updates->get_and_reset_relock_count_after_wait();
if (updates->count() == 0) {
delete updates;
jt->set_deferred_updates(nullptr);
}
}
return result;
}

void JvmtiDeferredUpdates::delete_updates_for_frame(JavaThread* jt, intptr_t* frame_id) {
JvmtiDeferredUpdates* updates = jt->deferred_updates();
if (updates != nullptr) {
GrowableArray<jvmtiDeferredLocalVariableSet*>* list = updates->deferred_locals();
assert(list->length() > 0, "Updates holder not deleted");
int i = 0;
do {
// Because of inlining we could have multiple vframes for a single frame
// and several of the vframes could have deferred writes. Find them all.
jvmtiDeferredLocalVariableSet* dlv = list->at(i);
if (dlv->id() == frame_id) {
list->remove_at(i);
// individual jvmtiDeferredLocalVariableSet are CHeapObj's
delete dlv;
} else {
i++;
}
} while ( i < list->length() );
if (updates->count() == 0) {
jt->set_deferred_updates(nullptr);
// Free deferred updates.
// Note, the 'list' of local variable updates is embedded in 'updates'.
delete updates;
}
}
}
44 changes: 7 additions & 37 deletions src/hotspot/share/prims/jvmtiDeferredUpdates.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,51 +112,21 @@ class jvmtiDeferredLocalVariableSet : public CHeapObj<mtCompiler> {

class JvmtiDeferredUpdates : public CHeapObj<mtCompiler> {

// Relocking has to be deferred if the lock owning thread is currently waiting on the monitor.
int _relock_count_after_wait;
address _original_pc;

// Deferred updates of locals, expressions, and monitors
GrowableArray<jvmtiDeferredLocalVariableSet*> _deferred_locals_updates;

void inc_relock_count_after_wait() {
_relock_count_after_wait++;
}

int get_and_reset_relock_count_after_wait() {
int result = _relock_count_after_wait;
_relock_count_after_wait = 0;
return result;
}

GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred_locals() { return &_deferred_locals_updates; }

JvmtiDeferredUpdates() :
_relock_count_after_wait(0),
public:
JvmtiDeferredUpdates(address original_pc) :
_original_pc(original_pc),
_deferred_locals_updates((AnyObj::set_allocation_type((address) &_deferred_locals_updates,
AnyObj::C_HEAP), 1), mtCompiler) { }
AnyObj::C_HEAP), 1), mtCompiler) { }

public:
~JvmtiDeferredUpdates();

static void create_for(JavaThread* thread);

static GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred_locals(JavaThread* jt) {
return jt->deferred_updates() == nullptr ? nullptr : jt->deferred_updates()->deferred_locals();
}

// Relocking has to be deferred if the lock owning thread is currently waiting on the monitor.
static int get_and_reset_relock_count_after_wait(JavaThread* jt);
static void inc_relock_count_after_wait(JavaThread* thread);

// Delete deferred updates for the compiled frame with id 'frame_id' on the
// given thread's stack. The thread's JvmtiDeferredUpdates instance will be
// deleted too if no updates remain.
static void delete_updates_for_frame(JavaThread* jt, intptr_t* frame_id);

// Number of deferred updates
int count() const {
return _deferred_locals_updates.length() + (_relock_count_after_wait > 0 ? 1 : 0);
}
address original_pc() const { return _original_pc; }
GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred_locals() { return &_deferred_locals_updates; }
};

#endif // SHARE_PRIMS_JVMTIDEFERREDUPDATES_HPP
9 changes: 4 additions & 5 deletions src/hotspot/share/runtime/deoptimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ static bool rematerialize_objects(JavaThread* thread, int exec_mode, nmethod* co
static void restore_eliminated_locks(JavaThread* thread, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures,
frame& deoptee, int exec_mode, bool& deoptimized_objects) {
JavaThread* deoptee_thread = chunk->at(0)->thread();
assert(!EscapeBarrier::objs_are_deoptimized(deoptee_thread, deoptee.id()), "must relock just once");
assert(!EscapeBarrier::objs_are_deoptimized(deoptee_thread, deoptee), "must relock just once");
assert(thread == Thread::current(), "should be");
HandleMark hm(thread);
#ifndef PRODUCT
Expand Down Expand Up @@ -542,7 +542,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread

#if COMPILER2_OR_JVMCI
if ((jvmci_enabled COMPILER2_PRESENT( || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks) ))
&& !EscapeBarrier::objs_are_deoptimized(current, deoptee.id())) {
&& !EscapeBarrier::objs_are_deoptimized(current, deoptee)) {
bool unused = false;
restore_eliminated_locks(current, chunk, realloc_failures, deoptee, exec_mode, unused);
}
Expand Down Expand Up @@ -579,8 +579,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
// Now that the vframeArray has been created if we have any deferred local writes
// added by jvmti then we can free up that structure as the data is now in the
// vframeArray

JvmtiDeferredUpdates::delete_updates_for_frame(current, array->original().id());
deoptee.clear_deferred_locals();

// Compute the caller frame based on the sender sp of stub_frame and stored frame sizes info.
CodeBlob* cb = stub_frame.cb();
Expand Down Expand Up @@ -1652,7 +1651,7 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArray<MonitorInf
mon_info->lock()->set_bad_metadata_deopt();
}
#endif
JvmtiDeferredUpdates::inc_relock_count_after_wait(deoptee_thread);
deoptee_thread->inc_relock_count_after_wait();
continue;
}
}
Expand Down
Loading

0 comments on commit 4a039c6

Please sign in to comment.