Symptom
=======
Failing assertion on aarch64 when running the test MovingCompWindow.java
(attached) either using jtreg or directely as in continuation_trace_aarch64.log
(attached).
assert(f.sp() - frame::metadata_words >= _top_stack_address) failed: overwrote past thawing space to: 0x0000fffff5a13f30 top_address: 0x0000fffff5a13f38
at continuationFreezeThaw.cpp:2233
Issue
=====
Thawing multiple frames slowly consumes more space than calculated because it is
done without caller/callee overlap.
The size required for continuation frames is calculated assuming that caller and
callee frames overlap the stack space for passing the the call parameters if
they are both interpreted. See the usage of
ContinuationHelper::InterpretedFrame::frame_top() in
recurse_freeze_interpreted_frame(). Also
new_heap_frame<ContinuationHelper::InterpretedFrame>() does overlap the new
frame with the caller iff it is interpreted (see overlap between MARK2 and MARK3
in continuation_trace_aarch64.log)
On the other side when thawing frames slowly they are allocated on the stack
without overlap even if both are interpreted. See new_stack_frame(). In
continuation_trace_aarch64.log at MARK4 you can see that the locals start below
the callers unextended_sp at MARK5, the 3 words space for the parameters in the
caller at MARK6 are not used. This causes the overwrite error.
The above holds for aarch64 but also for x86_64.
Prerequisites and Explanation of the Reproducer Test
====================================================
All frames of a stack chunk need to be thawed slowly at once to consume all of
the precalculated size. There should be overlapping interpreter frames.
At most 3 frames are thawed slowly:
C1: 2 frames are thawed if the kind is Continuation::thaw_top (see
Thaw<ConfigT>::thaw() and ThawBase::thaw_slow())
C2: One more frame is thawed if necessary to avoid having a compiled caller as top
frame in the chunk and its interpreted callee on stack (see ThawBase::recurse_thaw_java_frame())
C1 implies that Continuation.yield() and Continuation.yield0() have to be on top in the StackChunk.
C2 requires that the caller of Continuation.yield() is compiled. In the test
this is ContinuationRunYieldRunTest.run(). Compilation is controlled with the class CompilationPolicy.
So the top of the continuation should be this:
MovingCompWindow$ContinuationRunYieldRunTest.run() (compiled, see C2)
Continuation.yield()
Continuation.yield0()
We want these 3 frames in a dedicated StackChunk to thaw them all at once and
then trigger the assertion. This is achieved by calling System.gc() after the
first yield because this will set FLAG_GC_MODE on the existing StackChunk and a
new one will be allocated for the subsequent yield (see
FreezeBase::finalize_freeze(), "gc_mode: 1" at MARK0 in continuation_trace_aarch64log).
At MARK1 in continuation_trace_aarch64.log we see that all conditions are fulfilled and
the assertion is triggered.
Why does the test succeed on x86_64?
====================================
FreezeBase::recurse_freeze_interpreted_frame() adds alignment padding that is not needed on x86_64.
Without that redundant padding the assertion fails also on x86_64 (see reproduce_without_redundant_padding_on_x86_64.patch).
The issue can also be reproduced by adding more parameters to the method
Continuation.yield0() thereby increasing the overlap.
=======
Failing assertion on aarch64 when running the test MovingCompWindow.java
(attached) either using jtreg or directely as in continuation_trace_aarch64.log
(attached).
assert(f.sp() - frame::metadata_words >= _top_stack_address) failed: overwrote past thawing space to: 0x0000fffff5a13f30 top_address: 0x0000fffff5a13f38
at continuationFreezeThaw.cpp:2233
Issue
=====
Thawing multiple frames slowly consumes more space than calculated because it is
done without caller/callee overlap.
The size required for continuation frames is calculated assuming that caller and
callee frames overlap the stack space for passing the the call parameters if
they are both interpreted. See the usage of
ContinuationHelper::InterpretedFrame::frame_top() in
recurse_freeze_interpreted_frame(). Also
new_heap_frame<ContinuationHelper::InterpretedFrame>() does overlap the new
frame with the caller iff it is interpreted (see overlap between MARK2 and MARK3
in continuation_trace_aarch64.log)
On the other side when thawing frames slowly they are allocated on the stack
without overlap even if both are interpreted. See new_stack_frame(). In
continuation_trace_aarch64.log at MARK4 you can see that the locals start below
the callers unextended_sp at MARK5, the 3 words space for the parameters in the
caller at MARK6 are not used. This causes the overwrite error.
The above holds for aarch64 but also for x86_64.
Prerequisites and Explanation of the Reproducer Test
====================================================
All frames of a stack chunk need to be thawed slowly at once to consume all of
the precalculated size. There should be overlapping interpreter frames.
At most 3 frames are thawed slowly:
C1: 2 frames are thawed if the kind is Continuation::thaw_top (see
Thaw<ConfigT>::thaw() and ThawBase::thaw_slow())
C2: One more frame is thawed if necessary to avoid having a compiled caller as top
frame in the chunk and its interpreted callee on stack (see ThawBase::recurse_thaw_java_frame())
C1 implies that Continuation.yield() and Continuation.yield0() have to be on top in the StackChunk.
C2 requires that the caller of Continuation.yield() is compiled. In the test
this is ContinuationRunYieldRunTest.run(). Compilation is controlled with the class CompilationPolicy.
So the top of the continuation should be this:
MovingCompWindow$ContinuationRunYieldRunTest.run() (compiled, see C2)
Continuation.yield()
Continuation.yield0()
We want these 3 frames in a dedicated StackChunk to thaw them all at once and
then trigger the assertion. This is achieved by calling System.gc() after the
first yield because this will set FLAG_GC_MODE on the existing StackChunk and a
new one will be allocated for the subsequent yield (see
FreezeBase::finalize_freeze(), "gc_mode: 1" at MARK0 in continuation_trace_aarch64log).
At MARK1 in continuation_trace_aarch64.log we see that all conditions are fulfilled and
the assertion is triggered.
Why does the test succeed on x86_64?
====================================
FreezeBase::recurse_freeze_interpreted_frame() adds alignment padding that is not needed on x86_64.
Without that redundant padding the assertion fails also on x86_64 (see reproduce_without_redundant_padding_on_x86_64.patch).
The issue can also be reproduced by adding more parameters to the method
Continuation.yield0() thereby increasing the overlap.
- duplicates
-
JDK-8291972 Fix double copy of arguments when thawing two interpreted frames
-
- Resolved
-