Skip to content

Commit

Permalink
[Wisp] Port jstack related changes to JDK11
Browse files Browse the repository at this point in the history
Summary:
Port jstack related changes to JDK11:
[Wisp] jstack enhancement for Wisp
[Wisp] Some minor code adjustment for object monitor
[Wisp] Coroutine support of cross-thread stacktrace dumping

Test Plan: test/runtime/coroutine/JStackTest.java

Reviewers: 梁希,三红,云矅

Issue: https://aone.alibaba-inc.com/task/22742140

CR: https://code.aone.alibaba-inc.com/xcode/jdk11/codereview/1905054
  • Loading branch information
shiyue.xw authored and Sere-Fu committed Aug 19, 2021
1 parent 48bd148 commit d600293
Show file tree
Hide file tree
Showing 24 changed files with 389 additions and 196 deletions.
7 changes: 6 additions & 1 deletion src/hotspot/cpu/x86/c1_Runtime1_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1445,7 +1445,12 @@ OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) {
// Called with store_parameter and not C abi
f.load_argument(0, rax); // rax,: lock address
int call_offset;
call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit_wisp_proxy), rax);
if (UseWispMonitor) {
call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit_wisp_proxy), rax);
} else {
call_offset = 0;
__ should_not_reach_here();
}
oop_maps = new OopMapSet();
oop_maps->add_gc_map(call_offset, map);
restore_live_registers(sasm, save_fpu_registers);
Expand Down
12 changes: 11 additions & 1 deletion src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4462,6 +4462,7 @@ bool com_alibaba_wisp_engine_WispEngine::in_critical(oop obj) {
}

int com_alibaba_wisp_engine_WispTask::_jvmParkStatus_offset = 0;
int com_alibaba_wisp_engine_WispTask::_jdkParkStatus_offset = 0;
int com_alibaba_wisp_engine_WispTask::_id_offset = 0;
int com_alibaba_wisp_engine_WispTask::_threadWrapper_offset = 0;
int com_alibaba_wisp_engine_WispTask::_interrupted_offset = 0;
Expand All @@ -4475,6 +4476,7 @@ void com_alibaba_wisp_engine_WispTask::compute_offsets() {
assert(k != NULL, "WispTask_klass is null");
InstanceKlass *ik = InstanceKlass::cast(k);
compute_offset(_jvmParkStatus_offset, ik, vmSymbols::jvmParkStatus_name(), vmSymbols::int_signature());
compute_offset(_jdkParkStatus_offset, ik, vmSymbols::jdkParkStatus_name(), vmSymbols::int_signature());
compute_offset(_id_offset, ik, vmSymbols::id_name(), vmSymbols::int_signature());
compute_offset(_threadWrapper_offset, ik, vmSymbols::threadWrapper_name(), vmSymbols::thread_signature());
compute_offset(_interrupted_offset, ik, vmSymbols::interrupted_name(), vmSymbols::int_signature());
Expand All @@ -4485,7 +4487,15 @@ void com_alibaba_wisp_engine_WispTask::compute_offsets() {
}

void com_alibaba_wisp_engine_WispTask::set_jvmParkStatus(oop obj, jint status) {
return obj->int_field_put(_jvmParkStatus_offset, status);
obj->int_field_put(_jvmParkStatus_offset, status);
}

int com_alibaba_wisp_engine_WispTask::get_jvmParkStatus(oop obj) {
return obj->int_field(_jvmParkStatus_offset);
}

int com_alibaba_wisp_engine_WispTask::get_jdkParkStatus(oop obj) {
return obj->int_field(_jdkParkStatus_offset);
}

int com_alibaba_wisp_engine_WispTask::get_preemptCount(oop obj) {
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,6 +1610,7 @@ class com_alibaba_wisp_engine_WispEngine: AllStatic {
class com_alibaba_wisp_engine_WispTask: AllStatic {
private:
static int _jvmParkStatus_offset;
static int _jdkParkStatus_offset;
static int _id_offset;
static int _threadWrapper_offset;
static int _interrupted_offset;
Expand All @@ -1619,6 +1620,8 @@ class com_alibaba_wisp_engine_WispTask: AllStatic {
static int _preemptCount_offset;
public:
static void set_jvmParkStatus(oop obj, jint status);
static int get_jvmParkStatus(oop obj);
static int get_jdkParkStatus(oop obj);
static int get_id(oop obj);
static oop get_threadWrapper(oop obj);
static int get_interrupted(oop obj);
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,6 +655,7 @@
template(com_alibaba_wisp_engine_WispTask, "com/alibaba/wisp/engine/WispTask") \
template(com_alibaba_wisp_engine_WispEngine, "com/alibaba/wisp/engine/WispEngine") \
template(isInCritical_name, "isInCritical") \
template(jdkParkStatus_name, "jdkParkStatus") \
template(jvmParkStatus_name, "jvmParkStatus") \
template(id_name, "id") \
template(threadWrapper_name, "threadWrapper") \
Expand Down
150 changes: 4 additions & 146 deletions src/hotspot/share/opto/graphKit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -839,156 +839,14 @@ static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarr
return false;
}

void GraphKit::add_safepoint_edges_wisp(SafePointNode* call) {
assert(UseWispMonitor, "UseWispMonitor is off");
// Add the safepoint edges to the call (or other safepoint).

// Walk the inline list to fill in the correct set of JVMState's
// Also fill in the associated edges for each JVMState.

// If the bytecode needs to be reexecuted we need to put
// the arguments back on the stack.
const bool should_reexecute = jvms()->should_reexecute();
JVMState* youngest_jvms = should_reexecute ? sync_jvms_for_reexecute() : sync_jvms();

// NOTE: set_bci (called from sync_jvms) might reset the reexecute bit to
// undefined if the bci is different. This is normal for Parse but it
// should not happen for LibraryCallKit because only one bci is processed.
assert(!is_LibraryCallKit() || (jvms()->should_reexecute() == should_reexecute),
"in LibraryCallKit the reexecute bit should not change");

// If we are guaranteed to throw, we can prune everything but the
// input to the current bytecode.
bool can_prune_locals = false;
uint stack_slots_not_pruned = 0;
int inputs = 0, depth = 0;

if (env()->should_retain_local_variables()) {
// At any safepoint, this method can get breakpointed, which would
// then require an immediate deoptimization.
can_prune_locals = false; // do not prune locals
stack_slots_not_pruned = 0;
}

// do not scribble on the input jvms
JVMState* out_jvms = youngest_jvms->clone_deep(C);
call->set_jvms(out_jvms); // Start jvms list for call node

// Presize the call:
DEBUG_ONLY(uint non_debug_edges = call->req());
call->add_req_batch(top(), youngest_jvms->debug_depth());
assert(call->req() == non_debug_edges + youngest_jvms->debug_depth(), "");

// Set up edges so that the call looks like this:
// Call [state:] ctl io mem fptr retadr
// [parms:] parm0 ... parmN
// [root:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN
// [...mid:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN [...]
// [young:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN
// Note that caller debug info precedes callee debug info.

// Fill pointer walks backwards from "young:" to "root:" in the diagram above:
uint debug_ptr = call->req();

// Loop over the map input edges associated with jvms, add them
// to the call node, & reset all offsets to match call node array.
for (JVMState* in_jvms = youngest_jvms; in_jvms != NULL; ) {
uint debug_end = debug_ptr;
uint debug_start = debug_ptr - in_jvms->debug_size();
debug_ptr = debug_start; // back up the ptr

uint p = debug_start; // walks forward in [debug_start, debug_end)
uint j, k, l;
SafePointNode* in_map = in_jvms->map();
out_jvms->set_map(call);

if (can_prune_locals) {
assert(in_jvms->method() == out_jvms->method(), "sanity");
// If the current throw can reach an exception handler in this JVMS,
// then we must keep everything live that can reach that handler.
// As a quick and dirty approximation, we look for any handlers at all.
if (in_jvms->method()->has_exception_handlers()) {
can_prune_locals = false;
}
}

// Add the Locals
k = in_jvms->locoff();
l = in_jvms->loc_size();
out_jvms->set_locoff(p);
if (!can_prune_locals) {
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else {
p += l; // already set to top above by add_req_batch
}

// Add the Expression Stack
k = in_jvms->stkoff();
l = in_jvms->sp();
out_jvms->set_stkoff(p);
if (!can_prune_locals) {
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else if (can_prune_locals && stack_slots_not_pruned != 0) {
// Divide stack into {S0,...,S1}, where S0 is set to top.
uint s1 = stack_slots_not_pruned;
stack_slots_not_pruned = 0; // for next iteration
if (s1 > l) s1 = l;
uint s0 = l - s1;
p += s0; // skip the tops preinstalled by add_req_batch
for (j = s0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else {
p += l; // already set to top above by add_req_batch
}

// Add the Monitors
k = in_jvms->monoff();
l = in_jvms->mon_size();
out_jvms->set_monoff(p);
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));

// Copy any scalar object fields.
k = in_jvms->scloff();
l = in_jvms->scl_size();
out_jvms->set_scloff(p);
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));

// Finish the new jvms.
out_jvms->set_endoff(p);

assert(out_jvms->endoff() == debug_end, "fill ptr must match");
assert(out_jvms->depth() == in_jvms->depth(), "depth must match");
assert(out_jvms->loc_size() == in_jvms->loc_size(), "size must match");
assert(out_jvms->mon_size() == in_jvms->mon_size(), "size must match");
assert(out_jvms->scl_size() == in_jvms->scl_size(), "size must match");
assert(out_jvms->debug_size() == in_jvms->debug_size(), "size must match");

// Update the two tail pointers in parallel.
out_jvms = out_jvms->caller();
in_jvms = in_jvms->caller();
}

assert(debug_ptr == non_debug_edges, "debug info must fit exactly");

// Test the correctness of JVMState::debug_xxx accessors:
assert(call->jvms()->debug_start() == non_debug_edges, "");
assert(call->jvms()->debug_end() == call->req(), "");
assert(call->jvms()->debug_depth() == call->req() - non_debug_edges, "");
}


// Helper function for adding JVMState and debug information to node
void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw, bool is_wisp) {
// Add the safepoint edges to the call (or other safepoint).

// Make sure dead locals are set to top. This
// should help register allocation time and cut down on the size
// of the deoptimization information.
assert(dead_locals_are_killed(), "garbage in debug info before safepoint");
assert(is_wisp || dead_locals_are_killed(), "garbage in debug info before safepoint");

// Walk the inline list to fill in the correct set of JVMState's
// Also fill in the associated edges for each JVMState.
Expand Down Expand Up @@ -1030,7 +888,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {

// For a known set of bytecodes, the interpreter should reexecute them if
// deoptimization happens. We set the reexecute state for them here
if (out_jvms->is_reexecute_undefined() && //don't change if already specified
if (!is_wisp && out_jvms->is_reexecute_undefined() && //don't change if already specified
should_reexecute_implied_by_bytecode(out_jvms, call->is_AllocateArray())) {
out_jvms->set_should_reexecute(true); //NOTE: youngest_jvms not changed
}
Expand Down Expand Up @@ -3482,7 +3340,7 @@ void GraphKit::shared_unlock(Node* box, Node* obj) {
unlock = _gvn.transform(unlock)->as_Unlock();

if (UseWispMonitor && jvms()->has_method()) {
add_safepoint_edges_wisp(unlock);
add_safepoint_edges(unlock, false, true);
}
Node* mem = reset_memory();

Expand Down
3 changes: 1 addition & 2 deletions src/hotspot/share/opto/graphKit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,8 @@ class GraphKit : public Phase {
// The call may deoptimize. Supply required JVM state as debug info.
// If must_throw is true, the call is guaranteed not to return normally.
void add_safepoint_edges(SafePointNode* call,
bool must_throw = false);
bool must_throw = false, bool is_wisp = false);

void add_safepoint_edges_wisp(SafePointNode* call);
// How many stack inputs does the current BC consume?
// And, how does the stack change after the bytecode?
// Returns false if unknown.
Expand Down
13 changes: 13 additions & 0 deletions src/hotspot/share/prims/unsafe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1146,6 +1146,17 @@ JVM_ENTRY(jboolean, CoroutineSupport_stealCoroutine(JNIEnv* env, jclass klass, j
return true;
JVM_END

JVM_ENTRY (jobjectArray, CoroutineSupport_getCoroutineStack(JNIEnv* env, jclass klass, jlong coroPtr))
assert(EnableCoroutine, "pre-condition");

JvmtiVMObjectAllocEventCollector oam;

Coroutine* coro = (Coroutine*)coroPtr;

Handle stacktraces = ThreadService::dump_coroutine_stack_trace(coro, CHECK_NULL);
return (jobjectArray)JNIHandles::make_local(env, stacktraces());
JVM_END

/// JVM_RegisterUnsafeMethods

#define ADR "J"
Expand Down Expand Up @@ -1234,6 +1245,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {

#define COBA "Ljava/dyn/CoroutineBase;"
#define COR "Ljava/dyn/Coroutine;"
#define STE "Ljava/lang/StackTraceElement;"

JNINativeMethod coroutine_support_methods[] = {
{CC"switchTo", CC"("COBA COBA")V", FN_PTR(CoroutineSupport_switchTo)},
Expand All @@ -1249,6 +1261,7 @@ JNINativeMethod coroutine_support_methods[] = {
{CC"getNextCoroutine", CC"(J)"COR, FN_PTR(CoroutineSupport_getNextCoroutine)},
{CC"moveCoroutine", CC"(JJ)V", FN_PTR(CoroutineSupport_moveCoroutine)},
{CC"markThreadCoroutine", CC"(J"COBA")V", FN_PTR(CoroutineSupport_markThreadCoroutine)},
{CC"getCoroutineStack", CC"(J)["STE, FN_PTR(CoroutineSupport_getCoroutineStack)},
};

#define COMPILE_CORO_METHODS_BEFORE (3)
Expand Down
Loading

0 comments on commit d600293

Please sign in to comment.