8172049: [s390] Implement "JEP 270: Reserved Stack Areas for Critical Sections".
Reviewed-by: mdoerr
--- a/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/c1_LIRAssembler_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -1105,16 +1105,16 @@
}
case T_FLOAT :
if (short_disp) {
- __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
+ __ z_ste(from->as_float_reg(), disp_value, disp_reg, dest);
} else {
- __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
+ __ z_stey(from->as_float_reg(), disp_value, disp_reg, dest);
}
break;
case T_DOUBLE:
if (short_disp) {
- __ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
+ __ z_std(from->as_double_reg(), disp_value, disp_reg, dest);
} else {
- __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
+ __ z_stdy(from->as_double_reg(), disp_value, disp_reg, dest);
}
break;
default: ShouldNotReachHere();
@@ -1148,6 +1148,10 @@
__ restore_return_pc();
}
+ if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) {
+ __ reserved_stack_check(Z_R14);
+ }
+
// We need to mark the code position where the load from the safepoint
// polling page was emitted as relocInfo::poll_return_type here.
__ relocate(relocInfo::poll_return_type);
--- a/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/globalDefinitions_s390.hpp Tue Dec 27 16:10:59 2016 +0100
@@ -52,4 +52,6 @@
// The expected size in bytes of a cache line, used to pad data structures.
#define DEFAULT_CACHE_LINE_SIZE 256
+#define SUPPORT_RESERVED_STACK_AREA
+
#endif // CPU_S390_VM_GLOBALDEFINITIONS_S390_HPP
--- a/hotspot/src/cpu/s390/vm/globals_s390.hpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/globals_s390.hpp Tue Dec 27 16:10:59 2016 +0100
@@ -56,7 +56,7 @@
// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the
// stack. To pass stack overflow tests we need 20 shadow pages.
#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+2))
-#define DEFAULT_STACK_RESERVED_PAGES (0)
+#define DEFAULT_STACK_RESERVED_PAGES (1)
#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES
#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES
--- a/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/interp_masm_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -860,16 +860,39 @@
bool throw_monitor_exception,
bool install_monitor_exception,
bool notify_jvmti) {
-
+ BLOCK_COMMENT("remove_activation {");
unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception);
// Save result (push state before jvmti call and pop it afterwards) and notify jvmti.
notify_method_exit(false, state, notify_jvmti ? NotifyJVMTI : SkipNotifyJVMTI);
+ if (StackReservedPages > 0) {
+ BLOCK_COMMENT("reserved_stack_check:");
+ // Test if reserved zone needs to be enabled.
+ Label no_reserved_zone_enabling;
+
+ // Compare frame pointers. There is no good stack pointer, as with stack
+ // frame compression we can get different SPs when we do calls. A subsequent
+ // call could have a smaller SP, so that this compare succeeds for an
+ // inner call of the method annotated with ReservedStack.
+ z_lg(Z_R0, Address(Z_SP, (intptr_t)_z_abi(callers_sp)));
+ z_clg(Z_R0, Address(Z_thread, JavaThread::reserved_stack_activation_offset())); // Compare with frame pointer in memory.
+ z_brl(no_reserved_zone_enabling);
+
+ // Enable reserved zone again, throw stack overflow exception.
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError));
+
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+ }
+
verify_oop(Z_tos, state);
verify_thread();
pop_interpreter_frame(return_pc, Z_ARG2, Z_ARG3);
+ BLOCK_COMMENT("} remove_activation");
}
// lock object
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -2666,6 +2666,32 @@
}
}
+void MacroAssembler::reserved_stack_check(Register return_pc) {
+ // Test if reserved zone needs to be enabled.
+ Label no_reserved_zone_enabling;
+ assert(return_pc == Z_R14, "Return pc must be in R14 before z_br() to StackOverflow stub.");
+ BLOCK_COMMENT("reserved_stack_check {");
+
+ z_clg(Z_SP, Address(Z_thread, JavaThread::reserved_stack_activation_offset()));
+ z_brl(no_reserved_zone_enabling);
+
+ // Enable reserved zone again, throw stack overflow exception.
+ save_return_pc();
+ push_frame_abi160(0);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), Z_thread);
+ pop_frame();
+ restore_return_pc();
+
+ load_const_optimized(Z_R1, StubRoutines::throw_delayed_StackOverflowError_entry());
+ // Don't use call() or z_basr(), they will invalidate Z_R14 which contains the return pc.
+ z_br(Z_R1);
+
+ should_not_reach_here();
+
+ bind(no_reserved_zone_enabling);
+ BLOCK_COMMENT("} reserved_stack_check");
+}
+
// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
void MacroAssembler::tlab_allocate(Register obj,
Register var_size_in_bytes,
--- a/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/macroAssembler_s390.hpp Tue Dec 27 16:10:59 2016 +0100
@@ -627,6 +627,11 @@
// Stack overflow checking
void bang_stack_with_offset(int offset);
+ // Check for reserved stack access in method being exited. If the reserved
+ // stack area was accessed, protect it again and throw StackOverflowError.
+ // Uses Z_R1.
+ void reserved_stack_check(Register return_pc);
+
// Atomics
// -- none?
--- a/hotspot/src/cpu/s390/vm/s390.ad Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/s390.ad Tue Dec 27 16:10:59 2016 +0100
@@ -909,15 +909,8 @@
// If this does safepoint polling, then do it here.
bool need_polling = do_polling() && C->is_method_compilation();
- // Touch the polling page.
- // Part 1: get the page's address.
- if (need_polling) {
- AddressLiteral pp(os::get_polling_page());
- __ load_const_optimized(Z_R1_scratch, pp);
- }
-
// Pop frame, restore return_pc, and all stuff needed by interpreter.
- // Pop frame by add insted of load (a penny saved is a penny got :-).
+ // Pop frame by add instead of load (a penny saved is a penny got :-).
int frame_size_in_bytes = Assembler::align((C->frame_slots() << LogBytesPerInt), frame::alignment_in_bytes);
int retPC_offset = frame_size_in_bytes + _z_abi16(return_pc);
if (Displacement::is_validDisp(retPC_offset)) {
@@ -928,9 +921,14 @@
__ restore_return_pc();
}
- // Touch the polling page,
- // part 2: touch the page now.
+ if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
+ __ reserved_stack_check(Z_R14);
+ }
+
+ // Touch the polling page.
if (need_polling) {
+ AddressLiteral pp(os::get_polling_page());
+ __ load_const_optimized(Z_R1_scratch, pp);
// We need to mark the code position where the load from the safepoint
// polling page was emitted as relocInfo::poll_return_type here.
__ relocate(relocInfo::poll_return_type);
@@ -939,7 +937,7 @@
}
uint MachEpilogNode::size(PhaseRegAlloc *ra_) const {
- // variable size. determine dynamically.
+ // Variable size. determine dynamically.
return MachNode::size(ra_);
}
--- a/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/stubGenerator_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -2433,13 +2433,12 @@
StubRoutines::_throw_StackOverflowError_entry =
generate_throw_exception("StackOverflowError throw_exception",
CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
+ StubRoutines::_throw_delayed_StackOverflowError_entry =
+ generate_throw_exception("delayed StackOverflowError throw_exception",
+ CAST_FROM_FN_PTR(address, SharedRuntime::throw_delayed_StackOverflowError), false);
//----------------------------------------------------------------------
// Entry points that are platform specific.
- // Build this early so it's available for the interpreter.
- StubRoutines::_throw_StackOverflowError_entry =
- generate_throw_exception("StackOverflowError throw_exception",
- CAST_FROM_FN_PTR(address, SharedRuntime::throw_StackOverflowError), false);
if (UseCRC32Intrinsics) {
// We have no CRC32 table on z/Architecture.
--- a/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/cpu/s390/vm/templateInterpreterGenerator_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -1112,16 +1112,21 @@
// top_frame_size = TOP_IJAVA_FRAME_ABI + max_stack + size of interpreter state
__ add2reg(top_frame_size,
frame::z_top_ijava_frame_abi_size +
- frame::z_ijava_state_size +
- frame::interpreter_frame_monitor_size() * wordSize,
+ frame::z_ijava_state_size +
+ frame::interpreter_frame_monitor_size() * wordSize,
max_stack);
- // Check if there's room for the new frame...
- Register frame_size = max_stack; // Reuse the regiser for max_stack.
- __ z_lgr(frame_size, Z_SP);
- __ z_sgr(frame_size, sp_after_resize);
- __ z_agr(frame_size, top_frame_size);
- generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+ if (!native_call) {
+ // Stack overflow check.
+ // Native calls don't need the stack size check since they have no
+ // expression stack and the arguments are already on the stack and
+ // we only add a handful of words to the stack.
+ Register frame_size = max_stack; // Reuse the regiser for max_stack.
+ __ z_lgr(frame_size, Z_SP);
+ __ z_sgr(frame_size, sp_after_resize);
+ __ z_agr(frame_size, top_frame_size);
+ generate_stack_overflow_check(frame_size, fp/*tmp1*/);
+ }
DEBUG_ONLY(__ z_cg(Z_R14, _z_abi16(return_pc), Z_SP));
__ asm_assert_eq("killed Z_R14", 0);
--- a/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/src/os_cpu/linux_s390/vm/os_linux_s390.cpp Tue Dec 27 16:10:59 2016 +0100
@@ -144,6 +144,42 @@
return frame(sp, epc.pc());
}
+bool os::Linux::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+ address pc = (address) os::Linux::ucontext_get_pc(uc);
+ if (Interpreter::contains(pc)) {
+ // Interpreter performs stack banging after the fixed frame header has
+ // been generated while the compilers perform it before. To maintain
+ // semantic consistency between interpreted and compiled frames, the
+ // method returns the Java sender of the current frame.
+ *fr = os::fetch_frame_from_context(uc);
+ if (!fr->is_first_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ *fr = fr->java_sender();
+ }
+ } else {
+ // More complex code with compiled code.
+ assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+ CodeBlob* cb = CodeCache::find_blob(pc);
+ if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+ // Not sure where the pc points to, fallback to default
+ // stack overflow handling. In compiled code, we bang before
+ // the frame is complete.
+ return false;
+ } else {
+ intptr_t* fp = os::Linux::ucontext_get_fp(uc);
+ intptr_t* sp = os::Linux::ucontext_get_sp(uc);
+ *fr = frame(sp, (address)*sp);
+ if (!fr->is_java_frame()) {
+ assert(fr->safe_for_sender(thread), "Safety check");
+ assert(!fr->is_first_frame(), "Safety check");
+ *fr = fr->java_sender();
+ }
+ }
+ }
+ assert(fr->is_java_frame(), "Safety check");
+ return true;
+}
+
frame os::get_sender_for_C_frame(frame* fr) {
if (*fr->sp() == 0) {
// fr is the last C frame.
@@ -279,13 +315,31 @@
if (thread->on_local_stack(addr)) {
// stack overflow
if (thread->in_stack_yellow_reserved_zone(addr)) {
- thread->disable_stack_yellow_reserved_zone();
if (thread->thread_state() == _thread_in_Java) {
+ if (thread->in_stack_reserved_zone(addr)) {
+ frame fr;
+ if (os::Linux::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+ assert(fr.is_java_frame(), "Must be a Javac frame");
+ frame activation =
+ SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+ if (activation.sp() != NULL) {
+ thread->disable_stack_reserved_zone();
+ if (activation.is_interpreted_frame()) {
+ thread->set_reserved_stack_activation((address)activation.fp());
+ } else {
+ thread->set_reserved_stack_activation((address)activation.unextended_sp());
+ }
+ return 1;
+ }
+ }
+ }
// Throw a stack overflow exception.
// Guard pages will be reenabled while unwinding the stack.
+ thread->disable_stack_yellow_reserved_zone();
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
} else {
// Thread was in the vm or native code. Return and try to finish.
+ thread->disable_stack_yellow_reserved_zone();
return 1;
}
} else if (thread->in_stack_red_zone(addr)) {
--- a/hotspot/test/runtime/ReservedStack/ReservedStackTest.java Tue Jan 03 11:22:37 2017 +0100
+++ b/hotspot/test/runtime/ReservedStack/ReservedStackTest.java Tue Dec 27 16:10:59 2016 +0100
@@ -199,7 +199,8 @@
// corruptions are still possible.
boolean supportedPlatform =
Platform.isAix() ||
- (Platform.isLinux() && (Platform.isPPC() || Platform.isX64() || Platform.isX86())) ||
+ (Platform.isLinux() &&
+ (Platform.isPPC() || Platform.isS390x() || Platform.isX64() || Platform.isX86())) ||
Platform.isOSX() ||
Platform.isSolaris();
if (supportedPlatform && !result.contains("PASSED")) {