8338745: Intrinsify Continuation.pin() and Continuation.unpin()

Reviewed-by: kvn
This commit is contained in:
Markus Grönlund 2024-08-23 09:26:00 +00:00
parent a5e28005fa
commit fead3cf541
9 changed files with 109 additions and 4 deletions

View File

@ -242,6 +242,8 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
case vmIntrinsics::_Reference_get:
case vmIntrinsics::_Continuation_doYield:
case vmIntrinsics::_Continuation_enterSpecial:
case vmIntrinsics::_Continuation_pin:
case vmIntrinsics::_Continuation_unpin:
break;
default:
return true;

View File

@ -600,6 +600,8 @@ class methodHandle;
do_alias(continuationOnPinned_signature, int_void_signature) \
do_intrinsic(_Continuation_doYield, jdk_internal_vm_Continuation, doYield_name, continuationDoYield_signature, F_SN) \
do_alias( continuationDoYield_signature, void_int_signature) \
do_intrinsic(_Continuation_pin, jdk_internal_vm_Continuation, pin_name, void_method_signature, F_SN) \
do_intrinsic(_Continuation_unpin, jdk_internal_vm_Continuation, unpin_name, void_method_signature, F_SN) \
\
/* java/lang/VirtualThread */ \
do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -406,6 +406,8 @@ class SerializeClosure;
template(onContinue_name, "onContinue0") \
template(scope_name, "scope") \
template(yieldInfo_name, "yieldInfo") \
template(pin_name, "pin") \
template(unpin_name, "unpin") \
template(tail_name, "tail") \
template(size_name, "size") \
template(bottom_name, "bottom") \

View File

@ -35,6 +35,7 @@
#include "oops/methodCounters.hpp"
#include "oops/objArrayKlass.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/continuationEntry.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/flags/jvmFlag.hpp"
#include "runtime/osThread.hpp"
@ -244,10 +245,12 @@
nonstatic_field(JavaThread, _held_monitor_count, intx) \
nonstatic_field(JavaThread, _lock_stack, LockStack) \
nonstatic_field(JavaThread, _om_cache, OMCache) \
nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \
JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \
JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \
JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \
\
nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \
nonstatic_field(LockStack, _top, uint32_t) \
\
JVMTI_ONLY(static_field(JvmtiVTMSTransitionDisabler, _VTMS_notify_jvmti_events, bool)) \

View File

@ -731,6 +731,8 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
case vmIntrinsics::_setCurrentThread:
case vmIntrinsics::_scopedValueCache:
case vmIntrinsics::_setScopedValueCache:
case vmIntrinsics::_Continuation_pin:
case vmIntrinsics::_Continuation_unpin:
#ifdef JFR_HAVE_INTRINSICS
case vmIntrinsics::_counterTime:
case vmIntrinsics::_getEventWriter:

View File

@ -482,6 +482,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
case vmIntrinsics::_scopedValueCache: return inline_native_scopedValueCache();
case vmIntrinsics::_setScopedValueCache: return inline_native_setScopedValueCache();
case vmIntrinsics::_Continuation_pin: return inline_native_Continuation_pinning(false);
case vmIntrinsics::_Continuation_unpin: return inline_native_Continuation_pinning(true);
#if INCLUDE_JVMTI
case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()),
"notifyJvmtiStart", true, false);
@ -3715,6 +3718,93 @@ bool LibraryCallKit::inline_native_setScopedValueCache() {
return true;
}
//------------------------inline_native_Continuation_pin and unpin-----------
// Shared implementation routine for both pin and unpin.
bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) {
enum { _true_path = 1, _false_path = 2, PATH_LIMIT };
// Save input memory.
Node* input_memory_state = reset_memory();
set_all_memory(input_memory_state);
// TLS
Node* tls_ptr = _gvn.transform(new ThreadLocalNode());
Node* last_continuation_offset = basic_plus_adr(top(), tls_ptr, in_bytes(JavaThread::cont_entry_offset()));
Node* last_continuation = make_load(control(), last_continuation_offset, last_continuation_offset->get_ptr_type(), T_ADDRESS, MemNode::unordered);
// Null check the last continuation object.
Node* continuation_cmp_null = _gvn.transform(new CmpPNode(last_continuation, null()));
Node* test_continuation_not_equal_null = _gvn.transform(new BoolNode(continuation_cmp_null, BoolTest::ne));
IfNode* iff_continuation_not_equal_null = create_and_map_if(control(), test_continuation_not_equal_null, PROB_MAX, COUNT_UNKNOWN);
// False path, last continuation is null.
Node* continuation_is_null = _gvn.transform(new IfFalseNode(iff_continuation_not_equal_null));
// True path, last continuation is not null.
Node* continuation_is_not_null = _gvn.transform(new IfTrueNode(iff_continuation_not_equal_null));
set_control(continuation_is_not_null);
// Load the pin count from the last continuation.
Node* pin_count_offset = basic_plus_adr(top(), last_continuation, in_bytes(ContinuationEntry::pin_count_offset()));
Node* pin_count = make_load(control(), pin_count_offset, TypeInt::INT, T_INT, MemNode::unordered);
// The loaded pin count is compared against a context specific rhs for over/underflow detection.
Node* pin_count_rhs;
if (unpin) {
pin_count_rhs = _gvn.intcon(0);
} else {
pin_count_rhs = _gvn.intcon(UINT32_MAX);
}
Node* pin_count_cmp = _gvn.transform(new CmpUNode(_gvn.transform(pin_count), pin_count_rhs));
Node* test_pin_count_over_underflow = _gvn.transform(new BoolNode(pin_count_cmp, BoolTest::eq));
IfNode* iff_pin_count_over_underflow = create_and_map_if(control(), test_pin_count_over_underflow, PROB_MIN, COUNT_UNKNOWN);
// False branch, no pin count over/underflow. Increment or decrement pin count and store back.
Node* valid_pin_count = _gvn.transform(new IfFalseNode(iff_pin_count_over_underflow));
set_control(valid_pin_count);
Node* next_pin_count;
if (unpin) {
next_pin_count = _gvn.transform(new SubINode(pin_count, _gvn.intcon(1)));
} else {
next_pin_count = _gvn.transform(new AddINode(pin_count, _gvn.intcon(1)));
}
Node* updated_pin_count_memory = store_to_memory(control(), pin_count_offset, next_pin_count, T_INT, Compile::AliasIdxRaw, MemNode::unordered);
// True branch, pin count over/underflow.
Node* pin_count_over_underflow = _gvn.transform(new IfTrueNode(iff_pin_count_over_underflow));
{
// Trap (but not deoptimize (Action_none)) and continue in the interpreter
// which will throw IllegalStateException for pin count over/underflow.
PreserveJVMState pjvms(this);
set_control(pin_count_over_underflow);
set_all_memory(input_memory_state);
uncommon_trap_exact(Deoptimization::Reason_intrinsic,
Deoptimization::Action_none);
assert(stopped(), "invariant");
}
// Result of top level CFG and Memory.
RegionNode* result_rgn = new RegionNode(PATH_LIMIT);
record_for_igvn(result_rgn);
PhiNode* result_mem = new PhiNode(result_rgn, Type::MEMORY, TypePtr::BOTTOM);
record_for_igvn(result_mem);
result_rgn->init_req(_true_path, _gvn.transform(valid_pin_count));
result_rgn->init_req(_false_path, _gvn.transform(continuation_is_null));
result_mem->init_req(_true_path, _gvn.transform(updated_pin_count_memory));
result_mem->init_req(_false_path, _gvn.transform(input_memory_state));
// Set output state.
set_control(_gvn.transform(result_rgn));
set_all_memory(_gvn.transform(result_mem));
return true;
}
//---------------------------load_mirror_from_klass----------------------------
// Given a klass oop, load its java mirror (a java.lang.Class oop).
Node* LibraryCallKit::load_mirror_from_klass(Node* klass) {

View File

@ -241,6 +241,7 @@ class LibraryCallKit : public GraphKit {
const Type* scopedValueCache_type();
Node* scopedValueCache_helper();
bool inline_native_setScopedValueCache();
bool inline_native_Continuation_pinning(bool unpin);
bool inline_native_time_funcs(address method, const char* funcName);
#if INCLUDE_JVMTI

View File

@ -39,6 +39,7 @@ class RegisterMap;
// Metadata stored in the continuation entry frame
class ContinuationEntry {
friend class JVMCIVMStructs;
ContinuationEntryPD _pd;
#ifdef ASSERT
private:
@ -78,7 +79,7 @@ private:
#else
int32_t _parent_held_monitor_count;
#endif
uint _pin_count;
uint32_t _pin_count;
public:
static ByteSize parent_offset() { return byte_offset_of(ContinuationEntry, _parent); }
@ -108,7 +109,7 @@ public:
bool is_pinned() { return _pin_count > 0; }
bool pin() {
if (_pin_count == UINT_MAX) return false;
if (_pin_count == UINT32_MAX) return false;
_pin_count++;
return true;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -427,6 +427,7 @@ public class Continuation {
* Pins the current continuation (enters a critical section).
* This increments an internal semaphore that, when greater than 0, pins the continuation.
*/
@IntrinsicCandidate
public static native void pin();
/**
@ -434,6 +435,7 @@ public class Continuation {
* This decrements an internal semaphore that, when equal 0, unpins the current continuation
* if pinned with {@link #pin()}.
*/
@IntrinsicCandidate
public static native void unpin();
/**