8331429: [JVMCI] Cleanup JVMCIRuntime allocation routines

Reviewed-by: dlong, dnsimon
This commit is contained in:
Yudi Zheng 2024-05-15 09:35:11 +00:00 committed by Doug Simon
parent 2f10a316ff
commit 957eb611ce
4 changed files with 71 additions and 113 deletions

View File

@ -125,23 +125,17 @@ class InternalOOMEMark: public StackObj {
public: public:
explicit InternalOOMEMark(JavaThread* thread) { explicit InternalOOMEMark(JavaThread* thread) {
if (thread != nullptr) { assert(thread != nullptr, "nullptr is not supported");
_outer = thread->is_in_internal_oome_mark(); _outer = thread->is_in_internal_oome_mark();
thread->set_is_in_internal_oome_mark(true); thread->set_is_in_internal_oome_mark(true);
_thread = thread; _thread = thread;
} else {
_outer = false;
_thread = nullptr;
}
} }
~InternalOOMEMark() { ~InternalOOMEMark() {
if (_thread != nullptr) { // Check that only InternalOOMEMark sets
// Check that only InternalOOMEMark sets // JavaThread::_is_in_internal_oome_mark
// JavaThread::_is_in_internal_oome_mark assert(_thread->is_in_internal_oome_mark(), "must be");
assert(_thread->is_in_internal_oome_mark(), "must be"); _thread->set_is_in_internal_oome_mark(_outer);
_thread->set_is_in_internal_oome_mark(_outer);
}
} }
JavaThread* thread() const { return _thread; } JavaThread* thread() const { return _thread; }

View File

@ -102,7 +102,7 @@ class RetryableAllocationMark {
private: private:
InternalOOMEMark _iom; InternalOOMEMark _iom;
public: public:
RetryableAllocationMark(JavaThread* thread, bool activate) : _iom(activate ? thread : nullptr) {} RetryableAllocationMark(JavaThread* thread) : _iom(thread) {}
~RetryableAllocationMark() { ~RetryableAllocationMark() {
JavaThread* THREAD = _iom.thread(); // For exception macros. JavaThread* THREAD = _iom.thread(); // For exception macros.
if (THREAD != nullptr) { if (THREAD != nullptr) {
@ -117,34 +117,29 @@ class RetryableAllocationMark {
} }
}; };
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance_common(JavaThread* current, Klass* klass, bool null_on_fail)) JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance_or_null(JavaThread* current, Klass* klass))
JRT_BLOCK; JRT_BLOCK;
assert(klass->is_klass(), "not a class"); assert(klass->is_klass(), "not a class");
Handle holder(current, klass->klass_holder()); // keep the klass alive Handle holder(current, klass->klass_holder()); // keep the klass alive
InstanceKlass* h = InstanceKlass::cast(klass); InstanceKlass* h = InstanceKlass::cast(klass);
{ {
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
h->check_valid_for_instantiation(true, CHECK); h->check_valid_for_instantiation(true, CHECK);
oop obj; if (!h->is_initialized()) {
if (null_on_fail) { // Cannot re-execute class initialization without side effects
if (!h->is_initialized()) { // so return without attempting the initialization
// Cannot re-execute class initialization without side effects current->set_vm_result(nullptr);
// so return without attempting the initialization return;
return;
}
} else {
// make sure klass is initialized
h->initialize(CHECK);
} }
// allocate instance and return via TLS // allocate instance and return via TLS
obj = h->allocate_instance(CHECK); oop obj = h->allocate_instance(CHECK);
current->set_vm_result(obj); current->set_vm_result(obj);
} }
JRT_BLOCK_END; JRT_BLOCK_END;
SharedRuntime::on_slowpath_allocation_exit(current); SharedRuntime::on_slowpath_allocation_exit(current);
JRT_END JRT_END
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_common(JavaThread* current, Klass* array_klass, jint length, bool null_on_fail)) JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_or_null(JavaThread* current, Klass* array_klass, jint length))
JRT_BLOCK; JRT_BLOCK;
// Note: no handle for klass needed since they are not used // Note: no handle for klass needed since they are not used
// anymore after new_objArray() and no GC can happen before. // anymore after new_objArray() and no GC can happen before.
@ -153,27 +148,21 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_common(JavaThread* current, Klass*
oop obj; oop obj;
if (array_klass->is_typeArray_klass()) { if (array_klass->is_typeArray_klass()) {
BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type();
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
obj = oopFactory::new_typeArray(elt_type, length, CHECK); obj = oopFactory::new_typeArray(elt_type, length, CHECK);
} else { } else {
Handle holder(current, array_klass->klass_holder()); // keep the klass alive Handle holder(current, array_klass->klass_holder()); // keep the klass alive
Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
obj = oopFactory::new_objArray(elem_klass, length, CHECK); obj = oopFactory::new_objArray(elem_klass, length, CHECK);
} }
// This is pretty rare but this runtime patch is stressful to deoptimization // This is pretty rare but this runtime patch is stressful to deoptimization
// if we deoptimize here so force a deopt to stress the path. // if we deoptimize here so force a deopt to stress the path.
if (DeoptimizeALot) { if (DeoptimizeALot) {
static int deopts = 0; static int deopts = 0;
// Alternate between deoptimizing and raising an error (which will also cause a deopt)
if (deopts++ % 2 == 0) { if (deopts++ % 2 == 0) {
if (null_on_fail) { // Drop the allocation
// Drop the allocation obj = nullptr;
obj = nullptr;
} else {
ResourceMark rm(current);
THROW(vmSymbols::java_lang_OutOfMemoryError());
}
} else { } else {
deopt_caller(); deopt_caller();
} }
@ -183,42 +172,38 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_common(JavaThread* current, Klass*
SharedRuntime::on_slowpath_allocation_exit(current); SharedRuntime::on_slowpath_allocation_exit(current);
JRT_END JRT_END
JRT_ENTRY(void, JVMCIRuntime::new_multi_array_common(JavaThread* current, Klass* klass, int rank, jint* dims, bool null_on_fail)) JRT_ENTRY(void, JVMCIRuntime::new_multi_array_or_null(JavaThread* current, Klass* klass, int rank, jint* dims))
assert(klass->is_klass(), "not a class"); assert(klass->is_klass(), "not a class");
assert(rank >= 1, "rank must be nonzero"); assert(rank >= 1, "rank must be nonzero");
Handle holder(current, klass->klass_holder()); // keep the klass alive Handle holder(current, klass->klass_holder()); // keep the klass alive
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
current->set_vm_result(obj); current->set_vm_result(obj);
JRT_END JRT_END
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_common(JavaThread* current, oopDesc* element_mirror, jint length, bool null_on_fail)) JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_or_null(JavaThread* current, oopDesc* element_mirror, jint length))
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK);
current->set_vm_result(obj); current->set_vm_result(obj);
JRT_END JRT_END
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_common(JavaThread* current, oopDesc* type_mirror, bool null_on_fail)) JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_or_null(JavaThread* current, oopDesc* type_mirror))
InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror)); InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror));
if (klass == nullptr) { if (klass == nullptr) {
ResourceMark rm(current); ResourceMark rm(current);
THROW(vmSymbols::java_lang_InstantiationException()); THROW(vmSymbols::java_lang_InstantiationException());
} }
RetryableAllocationMark ram(current, null_on_fail); RetryableAllocationMark ram(current);
// Create new instance (the receiver) // Create new instance (the receiver)
klass->check_valid_for_instantiation(false, CHECK); klass->check_valid_for_instantiation(false, CHECK);
if (null_on_fail) { if (!klass->is_initialized()) {
if (!klass->is_initialized()) { // Cannot re-execute class initialization without side effects
// Cannot re-execute class initialization without side effects // so return without attempting the initialization
// so return without attempting the initialization current->set_vm_result(nullptr);
return; return;
}
} else {
// Make sure klass gets initialized
klass->initialize(CHECK);
} }
oop obj = klass->allocate_instance(CHECK); oop obj = klass->allocate_instance(CHECK);

View File

@ -504,34 +504,16 @@ class JVMCIRuntime: public CHeapObj<mtJVMCI> {
static BasicType kindToBasicType(const Handle& kind, TRAPS); static BasicType kindToBasicType(const Handle& kind, TRAPS);
static void new_instance_common(JavaThread* current, Klass* klass, bool null_on_fail);
static void new_array_common(JavaThread* current, Klass* klass, jint length, bool null_on_fail);
static void new_multi_array_common(JavaThread* current, Klass* klass, int rank, jint* dims, bool null_on_fail);
static void dynamic_new_array_common(JavaThread* current, oopDesc* element_mirror, jint length, bool null_on_fail);
static void dynamic_new_instance_common(JavaThread* current, oopDesc* type_mirror, bool null_on_fail);
// The following routines are called from compiled JVMCI code // The following routines are called from compiled JVMCI code
// When allocation fails, these stubs: // When allocation fails, these stubs return null and have no pending OutOfMemoryError exception.
// 1. Exercise -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError handling and also // Compiled code can use these stubs if a failed allocation will be retried (e.g., by deoptimizing
// post a JVMTI_EVENT_RESOURCE_EXHAUSTED event if the failure is an OutOfMemroyError // and re-executing in the interpreter).
// 2. Return null with a pending exception. static void new_instance_or_null(JavaThread* thread, Klass* klass);
// Compiled code must ensure these stubs are not called twice for the same allocation static void new_array_or_null(JavaThread* thread, Klass* klass, jint length);
// site due to the non-repeatable side effects in the case of OOME. static void new_multi_array_or_null(JavaThread* thread, Klass* klass, int rank, jint* dims);
static void new_instance(JavaThread* current, Klass* klass) { new_instance_common(current, klass, false); } static void dynamic_new_array_or_null(JavaThread* thread, oopDesc* element_mirror, jint length);
static void new_array(JavaThread* current, Klass* klass, jint length) { new_array_common(current, klass, length, false); } static void dynamic_new_instance_or_null(JavaThread* thread, oopDesc* type_mirror);
static void new_multi_array(JavaThread* current, Klass* klass, int rank, jint* dims) { new_multi_array_common(current, klass, rank, dims, false); }
static void dynamic_new_array(JavaThread* current, oopDesc* element_mirror, jint length) { dynamic_new_array_common(current, element_mirror, length, false); }
static void dynamic_new_instance(JavaThread* current, oopDesc* type_mirror) { dynamic_new_instance_common(current, type_mirror, false); }
// When allocation fails, these stubs return null and have no pending exception. Compiled code
// can use these stubs if a failed allocation will be retried (e.g., by deoptimizing and
// re-executing in the interpreter).
static void new_instance_or_null(JavaThread* thread, Klass* klass) { new_instance_common(thread, klass, true); }
static void new_array_or_null(JavaThread* thread, Klass* klass, jint length) { new_array_common(thread, klass, length, true); }
static void new_multi_array_or_null(JavaThread* thread, Klass* klass, int rank, jint* dims) { new_multi_array_common(thread, klass, rank, dims, true); }
static void dynamic_new_array_or_null(JavaThread* thread, oopDesc* element_mirror, jint length) { dynamic_new_array_common(thread, element_mirror, length, true); }
static void dynamic_new_instance_or_null(JavaThread* thread, oopDesc* type_mirror) { dynamic_new_instance_common(thread, type_mirror, true); }
static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3);
static jint identity_hash_code(JavaThread* current, oopDesc* obj); static jint identity_hash_code(JavaThread* current, oopDesc* obj);

View File

@ -251,6 +251,8 @@
nonstatic_field(Klass, _modifier_flags, jint) \ nonstatic_field(Klass, _modifier_flags, jint) \
nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _access_flags, AccessFlags) \
nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \
nonstatic_field(Klass, _bitmap, uintx) \
nonstatic_field(Klass, _hash_slot, uint8_t) \
\ \
nonstatic_field(LocalVariableTableElement, start_bci, u2) \ nonstatic_field(LocalVariableTableElement, start_bci, u2) \
nonstatic_field(LocalVariableTableElement, length, u2) \ nonstatic_field(LocalVariableTableElement, length, u2) \
@ -381,6 +383,7 @@
static_field(StubRoutines, _bigIntegerRightShiftWorker, address) \ static_field(StubRoutines, _bigIntegerRightShiftWorker, address) \
static_field(StubRoutines, _bigIntegerLeftShiftWorker, address) \ static_field(StubRoutines, _bigIntegerLeftShiftWorker, address) \
static_field(StubRoutines, _cont_thaw, address) \ static_field(StubRoutines, _cont_thaw, address) \
static_field(StubRoutines, _lookup_secondary_supers_table_slow_path_stub, address) \
\ \
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \ nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
nonstatic_field(Thread, _allocated_bytes, jlong) \ nonstatic_field(Thread, _allocated_bytes, jlong) \
@ -800,39 +803,33 @@
declare_function(Deoptimization::uncommon_trap) \ declare_function(Deoptimization::uncommon_trap) \
declare_function(Deoptimization::unpack_frames) \ declare_function(Deoptimization::unpack_frames) \
\ \
declare_function(JVMCIRuntime::new_instance) \ declare_function(JVMCIRuntime::new_instance_or_null) \
declare_function(JVMCIRuntime::new_array) \ declare_function(JVMCIRuntime::new_array_or_null) \
declare_function(JVMCIRuntime::new_multi_array) \ declare_function(JVMCIRuntime::new_multi_array_or_null) \
declare_function(JVMCIRuntime::dynamic_new_array) \ declare_function(JVMCIRuntime::dynamic_new_array_or_null) \
declare_function(JVMCIRuntime::dynamic_new_instance) \ declare_function(JVMCIRuntime::dynamic_new_instance_or_null) \
\ \
declare_function(JVMCIRuntime::new_instance_or_null) \ declare_function(JVMCIRuntime::invoke_static_method_one_arg) \
declare_function(JVMCIRuntime::new_array_or_null) \ \
declare_function(JVMCIRuntime::new_multi_array_or_null) \ declare_function(JVMCIRuntime::vm_message) \
declare_function(JVMCIRuntime::dynamic_new_array_or_null) \ declare_function(JVMCIRuntime::identity_hash_code) \
declare_function(JVMCIRuntime::dynamic_new_instance_or_null) \ declare_function(JVMCIRuntime::exception_handler_for_pc) \
\ declare_function(JVMCIRuntime::monitorenter) \
declare_function(JVMCIRuntime::invoke_static_method_one_arg) \ declare_function(JVMCIRuntime::monitorexit) \
\ declare_function(JVMCIRuntime::object_notify) \
declare_function(JVMCIRuntime::vm_message) \ declare_function(JVMCIRuntime::object_notifyAll) \
declare_function(JVMCIRuntime::identity_hash_code) \ declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \
declare_function(JVMCIRuntime::exception_handler_for_pc) \ declare_function(JVMCIRuntime::throw_klass_external_name_exception) \
declare_function(JVMCIRuntime::monitorenter) \ declare_function(JVMCIRuntime::throw_class_cast_exception) \
declare_function(JVMCIRuntime::monitorexit) \ declare_function(JVMCIRuntime::log_primitive) \
declare_function(JVMCIRuntime::object_notify) \ declare_function(JVMCIRuntime::log_object) \
declare_function(JVMCIRuntime::object_notifyAll) \ declare_function(JVMCIRuntime::log_printf) \
declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \ declare_function(JVMCIRuntime::vm_error) \
declare_function(JVMCIRuntime::throw_klass_external_name_exception) \ declare_function(JVMCIRuntime::load_and_clear_exception) \
declare_function(JVMCIRuntime::throw_class_cast_exception) \ G1GC_ONLY(declare_function(JVMCIRuntime::write_barrier_pre)) \
declare_function(JVMCIRuntime::log_primitive) \ G1GC_ONLY(declare_function(JVMCIRuntime::write_barrier_post)) \
declare_function(JVMCIRuntime::log_object) \ declare_function(JVMCIRuntime::validate_object) \
declare_function(JVMCIRuntime::log_printf) \ \
declare_function(JVMCIRuntime::vm_error) \
declare_function(JVMCIRuntime::load_and_clear_exception) \
G1GC_ONLY(declare_function(JVMCIRuntime::write_barrier_pre)) \
G1GC_ONLY(declare_function(JVMCIRuntime::write_barrier_post)) \
declare_function(JVMCIRuntime::validate_object) \
\
declare_function(JVMCIRuntime::test_deoptimize_call_int) declare_function(JVMCIRuntime::test_deoptimize_call_int)