Skip to content

Commit aafa15f

Browse files
author
Doug Simon
committed
8331208: Memory stress test that checks OutOfMemoryError stack trace fails
Reviewed-by: dholmes, never
1 parent edd47c1 commit aafa15f

File tree

11 files changed

+68
-54
lines changed

11 files changed

+68
-54
lines changed

src/hotspot/share/compiler/compileBroker.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "compiler/compilerEvent.hpp"
3939
#include "compiler/compilerOracle.hpp"
4040
#include "compiler/directivesParser.hpp"
41+
#include "gc/shared/memAllocator.hpp"
4142
#include "interpreter/linkResolver.hpp"
4243
#include "jvm.h"
4344
#include "jfr/jfrEvents.hpp"
@@ -1396,6 +1397,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
13961397
assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
13971398
// some prerequisites that are compiler specific
13981399
if (comp->is_c2() || comp->is_jvmci()) {
1400+
InternalOOMEMark iom(THREAD);
13991401
method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NONASYNC_NULL);
14001402
// Resolve all classes seen in the signature of the method
14011403
// we are compiling.

src/hotspot/share/gc/shared/memAllocator.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,21 @@ bool MemAllocator::Allocation::check_out_of_memory() {
123123
}
124124

125125
const char* message = _overhead_limit_exceeded ? "GC overhead limit exceeded" : "Java heap space";
126-
if (!_thread->in_retryable_allocation()) {
126+
if (!_thread->is_in_internal_oome_mark()) {
127127
// -XX:+HeapDumpOnOutOfMemoryError and -XX:OnOutOfMemoryError support
128128
report_java_out_of_memory(message);
129-
130129
if (JvmtiExport::should_post_resource_exhausted()) {
131130
JvmtiExport::post_resource_exhausted(
132131
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP,
133132
message);
134133
}
134+
135135
oop exception = _overhead_limit_exceeded ?
136136
Universe::out_of_memory_error_gc_overhead_limit() :
137137
Universe::out_of_memory_error_java_heap();
138138
THROW_OOP_(exception, true);
139139
} else {
140-
THROW_OOP_(Universe::out_of_memory_error_retry(), true);
140+
THROW_OOP_(Universe::out_of_memory_error_java_heap_without_backtrace(), true);
141141
}
142142
}
143143

src/hotspot/share/gc/shared/memAllocator.hpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,37 @@ class ClassAllocator: public MemAllocator {
114114
virtual oop initialize(HeapWord* mem) const;
115115
};
116116

117+
// Manages a scope where a failed heap allocation results in
118+
// suppression of JVMTI "resource exhausted" events and
119+
// throwing a shared, backtrace-less OOME instance.
120+
// Used for OOMEs that will not be propagated to user code.
121+
class InternalOOMEMark: public StackObj {
122+
private:
123+
bool _outer;
124+
JavaThread* _thread;
125+
126+
public:
127+
explicit InternalOOMEMark(JavaThread* thread) {
128+
if (thread != nullptr) {
129+
_outer = thread->is_in_internal_oome_mark();
130+
thread->set_is_in_internal_oome_mark(true);
131+
_thread = thread;
132+
} else {
133+
_outer = false;
134+
_thread = nullptr;
135+
}
136+
}
137+
138+
~InternalOOMEMark() {
139+
if (_thread != nullptr) {
140+
// Check that only InternalOOMEMark sets
141+
// JavaThread::_is_in_internal_oome_mark
142+
assert(_thread->is_in_internal_oome_mark(), "must be");
143+
_thread->set_is_in_internal_oome_mark(_outer);
144+
}
145+
}
146+
147+
JavaThread* thread() const { return _thread; }
148+
};
149+
117150
#endif // SHARE_GC_SHARED_MEMALLOCATOR_HPP

src/hotspot/share/jvmci/jvmciRuntime.cpp

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "classfile/vmClasses.hpp"
2929
#include "compiler/compileBroker.hpp"
3030
#include "gc/shared/collectedHeap.hpp"
31+
#include "gc/shared/memAllocator.hpp"
3132
#include "gc/shared/oopStorage.inline.hpp"
3233
#include "jvmci/jniAccessMark.inline.hpp"
3334
#include "jvmci/jvmciCompilerToVM.hpp"
@@ -92,39 +93,25 @@ static void deopt_caller() {
9293
}
9394

9495
// Manages a scope for a JVMCI runtime call that attempts a heap allocation.
95-
// If there is a pending nonasync exception upon closing the scope and the runtime
96+
// If there is a pending OutOfMemoryError upon closing the scope and the runtime
9697
// call is of the variety where allocation failure returns null without an
9798
// exception, the following action is taken:
98-
// 1. The pending nonasync exception is cleared
99+
// 1. The pending OutOfMemoryError is cleared
99100
// 2. null is written to JavaThread::_vm_result
100-
// 3. Checks that an OutOfMemoryError is Universe::out_of_memory_error_retry().
101-
class RetryableAllocationMark: public StackObj {
101+
class RetryableAllocationMark {
102102
private:
103-
JavaThread* _thread;
103+
InternalOOMEMark _iom;
104104
public:
105-
RetryableAllocationMark(JavaThread* thread, bool activate) {
106-
if (activate) {
107-
assert(!thread->in_retryable_allocation(), "retryable allocation scope is non-reentrant");
108-
_thread = thread;
109-
_thread->set_in_retryable_allocation(true);
110-
} else {
111-
_thread = nullptr;
112-
}
113-
}
105+
RetryableAllocationMark(JavaThread* thread, bool activate) : _iom(activate ? thread : nullptr) {}
114106
~RetryableAllocationMark() {
115-
if (_thread != nullptr) {
116-
_thread->set_in_retryable_allocation(false);
117-
JavaThread* THREAD = _thread; // For exception macros.
107+
JavaThread* THREAD = _iom.thread(); // For exception macros.
108+
if (THREAD != nullptr) {
118109
if (HAS_PENDING_EXCEPTION) {
119110
oop ex = PENDING_EXCEPTION;
120-
// Do not clear probable async exceptions.
121-
CLEAR_PENDING_NONASYNC_EXCEPTION;
122-
oop retry_oome = Universe::out_of_memory_error_retry();
123-
if (ex->is_a(retry_oome->klass()) && retry_oome != ex) {
124-
ResourceMark rm;
125-
fatal("Unexpected exception in scope of retryable allocation: " INTPTR_FORMAT " of type %s", p2i(ex), ex->klass()->external_name());
111+
THREAD->set_vm_result(nullptr);
112+
if (ex->is_a(vmClasses::OutOfMemoryError_klass())) {
113+
CLEAR_PENDING_EXCEPTION;
126114
}
127-
_thread->set_vm_result(nullptr);
128115
}
129116
}
130117
}

src/hotspot/share/memory/universe.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ enum OutOfMemoryInstance { _oom_java_heap,
135135
_oom_array_size,
136136
_oom_gc_overhead_limit,
137137
_oom_realloc_objects,
138-
_oom_retry,
139138
_oom_count };
140139

141140
OopHandle Universe::_out_of_memory_errors;
@@ -655,6 +654,10 @@ oop Universe::out_of_memory_error_java_heap() {
655654
return gen_out_of_memory_error(out_of_memory_errors()->obj_at(_oom_java_heap));
656655
}
657656

657+
oop Universe::out_of_memory_error_java_heap_without_backtrace() {
658+
return out_of_memory_errors()->obj_at(_oom_java_heap);
659+
}
660+
658661
oop Universe::out_of_memory_error_c_heap() {
659662
return gen_out_of_memory_error(out_of_memory_errors()->obj_at(_oom_c_heap));
660663
}
@@ -679,9 +682,6 @@ oop Universe::out_of_memory_error_realloc_objects() {
679682
return gen_out_of_memory_error(out_of_memory_errors()->obj_at(_oom_realloc_objects));
680683
}
681684

682-
// Throw default _out_of_memory_error_retry object as it will never propagate out of the VM
683-
oop Universe::out_of_memory_error_retry() { return out_of_memory_errors()->obj_at(_oom_retry); }
684-
685685
oop Universe::class_init_out_of_memory_error() { return out_of_memory_errors()->obj_at(_oom_java_heap); }
686686
oop Universe::class_init_stack_overflow_error() { return _class_init_stack_overflow_error.resolve(); }
687687
oop Universe::delayed_stack_overflow_error_message() { return _delayed_stack_overflow_error_message.resolve(); }
@@ -785,9 +785,6 @@ void Universe::create_preallocated_out_of_memory_errors(TRAPS) {
785785
msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK);
786786
java_lang_Throwable::set_message(oom_array->obj_at(_oom_realloc_objects), msg());
787787

788-
msg = java_lang_String::create_from_str("Java heap space: failed retryable allocation", CHECK);
789-
java_lang_Throwable::set_message(oom_array->obj_at(_oom_retry), msg());
790-
791788
// Setup the array of errors that have preallocated backtrace
792789
int len = (StackTraceInThrowable) ? (int)PreallocatedOutOfMemoryErrorCount : 0;
793790
objArrayOop instance = oopFactory::new_objArray(ik, len, CHECK);

src/hotspot/share/memory/universe.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,15 +272,14 @@ class Universe: AllStatic {
272272
// may or may not have a backtrace. If error has a backtrace then the stack trace is already
273273
// filled in.
274274
static oop out_of_memory_error_java_heap();
275+
static oop out_of_memory_error_java_heap_without_backtrace();
275276
static oop out_of_memory_error_c_heap();
276277
static oop out_of_memory_error_metaspace();
277278
static oop out_of_memory_error_class_metaspace();
278279
static oop out_of_memory_error_array_size();
279280
static oop out_of_memory_error_gc_overhead_limit();
280281
static oop out_of_memory_error_realloc_objects();
281282

282-
// Throw default _out_of_memory_error_retry object as it will never propagate out of the VM
283-
static oop out_of_memory_error_retry();
284283
static oop delayed_stack_overflow_error_message();
285284

286285
// Saved StackOverflowError and OutOfMemoryError for use when

src/hotspot/share/oops/klass.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,12 +873,12 @@ void Klass::set_archived_java_mirror(int mirror_index) {
873873

874874
void Klass::check_array_allocation_length(int length, int max_length, TRAPS) {
875875
if (length > max_length) {
876-
if (!THREAD->in_retryable_allocation()) {
876+
if (!THREAD->is_in_internal_oome_mark()) {
877877
report_java_out_of_memory("Requested array size exceeds VM limit");
878878
JvmtiExport::post_array_size_exhausted();
879879
THROW_OOP(Universe::out_of_memory_error_array_size());
880880
} else {
881-
THROW_OOP(Universe::out_of_memory_error_retry());
881+
THROW_OOP(Universe::out_of_memory_error_java_heap_without_backtrace());
882882
}
883883
} else if (length < 0) {
884884
THROW_MSG(vmSymbols::java_lang_NegativeArraySizeException(), err_msg("%d", length));

src/hotspot/share/runtime/deoptimization.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "compiler/compilationPolicy.hpp"
3636
#include "compiler/compilerDefinitions.inline.hpp"
3737
#include "gc/shared/collectedHeap.hpp"
38+
#include "gc/shared/memAllocator.hpp"
3839
#include "interpreter/bytecode.hpp"
3940
#include "interpreter/bytecodeStream.hpp"
4041
#include "interpreter/interpreter.hpp"
@@ -1237,6 +1238,7 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
12371238

12381239
InstanceKlass* ik = InstanceKlass::cast(k);
12391240
if (obj == nullptr && !cache_init_error) {
1241+
InternalOOMEMark iom(THREAD);
12401242
#if COMPILER2_OR_JVMCI
12411243
if (EnableVectorSupport && VectorSupport::is_vector(ik)) {
12421244
obj = VectorSupport::allocate_vector(ik, fr, reg_map, sv, THREAD);
@@ -1251,9 +1253,11 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap*
12511253
TypeArrayKlass* ak = TypeArrayKlass::cast(k);
12521254
assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
12531255
int len = sv->field_size() / type2size[ak->element_type()];
1256+
InternalOOMEMark iom(THREAD);
12541257
obj = ak->allocate(len, THREAD);
12551258
} else if (k->is_objArray_klass()) {
12561259
ObjArrayKlass* ak = ObjArrayKlass::cast(k);
1260+
InternalOOMEMark iom(THREAD);
12571261
obj = ak->allocate(sv->field_size(), THREAD);
12581262
}
12591263

src/hotspot/share/runtime/javaThread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,11 @@ JavaThread::JavaThread() :
456456
#endif
457457
#endif
458458
_jni_attach_state(_not_attaching_via_jni),
459+
_is_in_internal_oome_mark(false),
459460
#if INCLUDE_JVMCI
460461
_pending_deoptimization(-1),
461462
_pending_monitorenter(false),
462463
_pending_transfer_to_interpreter(false),
463-
_in_retryable_allocation(false),
464464
_pending_failed_speculation(0),
465465
_jvmci{nullptr},
466466
_libjvmci_runtime(nullptr),

src/hotspot/share/runtime/javaThread.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
class AsyncExceptionHandshake;
5353
class ContinuationEntry;
5454
class DeoptResourceMark;
55+
class InternalOOMEMark;
5556
class JNIHandleBlock;
5657
class JVMCIRuntime;
5758

@@ -335,6 +336,8 @@ class JavaThread: public Thread {
335336
// of _attaching_via_jni and transitions to _attached_via_jni.
336337
volatile JNIAttachStates _jni_attach_state;
337338

339+
// In scope of an InternalOOMEMark?
340+
bool _is_in_internal_oome_mark;
338341

339342
#if INCLUDE_JVMCI
340343
// The _pending_* fields below are used to communicate extra information
@@ -350,10 +353,6 @@ class JavaThread: public Thread {
350353
// Specifies if the DeoptReason for the last uncommon trap was Reason_transfer_to_interpreter
351354
bool _pending_transfer_to_interpreter;
352355

353-
// True if in a runtime call from compiled code that will deoptimize
354-
// and re-execute a failed heap allocation in the interpreter.
355-
bool _in_retryable_allocation;
356-
357356
// An id of a speculation that JVMCI compiled code can use to further describe and
358357
// uniquely identify the speculative optimization guarded by an uncommon trap.
359358
// See JVMCINMethodData::SPECULATION_LENGTH_BITS for further details.
@@ -718,6 +717,10 @@ class JavaThread: public Thread {
718717
MemRegion deferred_card_mark() const { return _deferred_card_mark; }
719718
void set_deferred_card_mark(MemRegion mr) { _deferred_card_mark = mr; }
720719

720+
// Is thread in scope of an InternalOOMEMark?
721+
bool is_in_internal_oome_mark() const { return _is_in_internal_oome_mark; }
722+
void set_is_in_internal_oome_mark(bool b) { _is_in_internal_oome_mark = b; }
723+
721724
#if INCLUDE_JVMCI
722725
jlong pending_failed_speculation() const { return _pending_failed_speculation; }
723726
void set_pending_monitorenter(bool b) { _pending_monitorenter = b; }
@@ -727,9 +730,6 @@ class JavaThread: public Thread {
727730
void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == nullptr, "must be"); _jvmci._alternate_call_target = a; }
728731
void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == nullptr, "must be"); _jvmci._implicit_exception_pc = a; }
729732

730-
virtual bool in_retryable_allocation() const { return _in_retryable_allocation; }
731-
void set_in_retryable_allocation(bool b) { _in_retryable_allocation = b; }
732-
733733
JVMCIRuntime* libjvmci_runtime() const { return _libjvmci_runtime; }
734734
void set_libjvmci_runtime(JVMCIRuntime* rt) {
735735
assert((_libjvmci_runtime == nullptr && rt != nullptr) || (_libjvmci_runtime != nullptr && rt == nullptr), "must be");

0 commit comments

Comments
 (0)