mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8208686: [AOT] JVMTI ResourceExhausted event repeated for same allocation
Reviewed-by: never, kvn, sspitsyn
This commit is contained in:
parent
2223e083ba
commit
548eb6860a
20 changed files with 348 additions and 141 deletions
|
@ -109,22 +109,72 @@ static void deopt_caller() {
|
|||
}
|
||||
}
|
||||
|
||||
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass))
|
||||
// Manages a scope for a JVMCI runtime call that attempts a heap allocation.
|
||||
// If there is a pending exception upon closing the scope and the runtime
|
||||
// call is of the variety where allocation failure returns NULL without an
|
||||
// exception, the following action is taken:
|
||||
// 1. The pending exception is cleared
|
||||
// 2. NULL is written to JavaThread::_vm_result
|
||||
// 3. Checks that an OutOfMemoryError is Universe::out_of_memory_error_retry().
|
||||
class RetryableAllocationMark: public StackObj {
|
||||
private:
|
||||
JavaThread* _thread;
|
||||
public:
|
||||
RetryableAllocationMark(JavaThread* thread, bool activate) {
|
||||
if (activate) {
|
||||
assert(!thread->in_retryable_allocation(), "retryable allocation scope is non-reentrant");
|
||||
_thread = thread;
|
||||
_thread->set_in_retryable_allocation(true);
|
||||
} else {
|
||||
_thread = NULL;
|
||||
}
|
||||
}
|
||||
~RetryableAllocationMark() {
|
||||
if (_thread != NULL) {
|
||||
_thread->set_in_retryable_allocation(false);
|
||||
JavaThread* THREAD = _thread;
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
oop ex = PENDING_EXCEPTION;
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
oop retry_oome = Universe::out_of_memory_error_retry();
|
||||
if (ex->is_a(retry_oome->klass()) && retry_oome != ex) {
|
||||
ResourceMark rm;
|
||||
fatal("Unexpected exception in scope of retryable allocation: " INTPTR_FORMAT " of type %s", p2i(ex), ex->klass()->external_name());
|
||||
}
|
||||
_thread->set_vm_result(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance_common(JavaThread* thread, Klass* klass, bool null_on_fail))
|
||||
JRT_BLOCK;
|
||||
assert(klass->is_klass(), "not a class");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
ik->check_valid_for_instantiation(true, CHECK);
|
||||
// make sure klass is initialized
|
||||
ik->initialize(CHECK);
|
||||
// allocate instance and return via TLS
|
||||
oop obj = ik->allocate_instance(CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
{
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
ik->check_valid_for_instantiation(true, CHECK);
|
||||
oop obj;
|
||||
if (null_on_fail) {
|
||||
if (!ik->is_initialized()) {
|
||||
// Cannot re-execute class initialization without side effects
|
||||
// so return without attempting the initialization
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// make sure klass is initialized
|
||||
ik->initialize(CHECK);
|
||||
}
|
||||
// allocate instance and return via TLS
|
||||
obj = ik->allocate_instance(CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
}
|
||||
JRT_BLOCK_END;
|
||||
SharedRuntime::on_slowpath_allocation_exit(thread);
|
||||
JRT_END
|
||||
|
||||
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length))
|
||||
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array_common(JavaThread* thread, Klass* array_klass, jint length, bool null_on_fail))
|
||||
JRT_BLOCK;
|
||||
// Note: no handle for klass needed since they are not used
|
||||
// anymore after new_objArray() and no GC can happen before.
|
||||
|
@ -133,10 +183,12 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_k
|
|||
oop obj;
|
||||
if (array_klass->is_typeArray_klass()) {
|
||||
BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type();
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
obj = oopFactory::new_typeArray(elt_type, length, CHECK);
|
||||
} else {
|
||||
Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
|
||||
Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
obj = oopFactory::new_objArray(elem_klass, length, CHECK);
|
||||
}
|
||||
thread->set_vm_result(obj);
|
||||
|
@ -146,8 +198,12 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_k
|
|||
static int deopts = 0;
|
||||
// Alternate between deoptimizing and raising an error (which will also cause a deopt)
|
||||
if (deopts++ % 2 == 0) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW(vmSymbols::java_lang_OutOfMemoryError());
|
||||
if (null_on_fail) {
|
||||
return;
|
||||
} else {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW(vmSymbols::java_lang_OutOfMemoryError());
|
||||
}
|
||||
} else {
|
||||
deopt_caller();
|
||||
}
|
||||
|
@ -156,32 +212,43 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_k
|
|||
SharedRuntime::on_slowpath_allocation_exit(thread);
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
|
||||
JRT_ENTRY(void, JVMCIRuntime::new_multi_array_common(JavaThread* thread, Klass* klass, int rank, jint* dims, bool null_on_fail))
|
||||
assert(klass->is_klass(), "not a class");
|
||||
assert(rank >= 1, "rank must be nonzero");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length))
|
||||
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array_common(JavaThread* thread, oopDesc* element_mirror, jint length, bool null_on_fail))
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
JRT_END
|
||||
|
||||
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror))
|
||||
JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance_common(JavaThread* thread, oopDesc* type_mirror, bool null_on_fail))
|
||||
InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(type_mirror));
|
||||
|
||||
if (klass == NULL) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW(vmSymbols::java_lang_InstantiationException());
|
||||
}
|
||||
RetryableAllocationMark ram(thread, null_on_fail);
|
||||
|
||||
// Create new instance (the receiver)
|
||||
klass->check_valid_for_instantiation(false, CHECK);
|
||||
|
||||
// Make sure klass gets initialized
|
||||
klass->initialize(CHECK);
|
||||
if (null_on_fail) {
|
||||
if (!klass->is_initialized()) {
|
||||
// Cannot re-execute class initialization without side effects
|
||||
// so return without attempting the initialization
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Make sure klass gets initialized
|
||||
klass->initialize(CHECK);
|
||||
}
|
||||
|
||||
oop obj = klass->allocate_instance(CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue