8156922: [ppc] Implement template interpreter stack overflow checks as on x86/sparc.
authorgoetz
Fri, 13 May 2016 15:20:06 +0200
changeset 38734 69ced2325f58
parent 38733 2b65f4db449e
child 38735 cb658958508c
child 38929 1ee62412a66f
8156922: [ppc] Implement template interpreter stack overflow checks as on x86/sparc. Reviewed-by: dlong, dholmes, simonis, coleenp
hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp
hotspot/src/share/vm/runtime/os.cpp
hotspot/src/share/vm/runtime/thread.hpp
--- a/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp	Wed Jun 01 11:14:58 2016 -0400
+++ b/hotspot/src/cpu/ppc/vm/templateInterpreterGenerator_ppc.cpp	Fri May 13 15:20:06 2016 +0200
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2015, 2016 SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -562,10 +562,16 @@
   return NULL;
 }
 
-// Actually we should never reach here since we do stack overflow checks before pushing any frame.
 address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
   address entry = __ pc();
-  __ unimplemented("generate_StackOverflowError_handler");
+
+  // Expression stack must be empty before entering the VM if an
+  // exception happened.
+  __ empty_expression_stack();
+  // Throw exception.
+  __ call_VM(noreg,
+             CAST_FROM_FN_PTR(address,
+                              InterpreterRuntime::throw_StackOverflowError));
   return entry;
 }
 
@@ -944,7 +950,7 @@
 // The top most frame needs an abi space of 112 bytes. This space is needed,
 // since we call to c. The c function may spill their arguments to the caller
 // frame. When we call to java, we don't need these spill slots. In order to save
-// space on the stack, we resize the caller. However, java local reside in
+// space on the stack, we resize the caller. However, java locals reside in
 // the caller frame and the frame has to be increased. The frame_size for the
 // current frame was calculated based on max_stack as size for the expression
 // stack. At the call, just a part of the expression stack might be used.
@@ -1007,7 +1013,7 @@
   // parent_frame_resize = (locals-parameters) - (ESP-SP-ABI48) Rounded to frame alignment size.
   // Enlarge by locals-parameters (not in case of native_call), shrink by ESP-SP-ABI48.
 
-  {
+  if (!native_call) {
     // --------------------------------------------------------------------------
     // Stack overflow check
 
@@ -1047,7 +1053,7 @@
   __ addi(R26_monitor, R1_SP, - frame::ijava_state_size);
   __ addi(R15_esp, R26_monitor, - Interpreter::stackElementSize);
 
-  // Get mirror and store it in the frame as GC root for this Method*
+  // Get mirror and store it in the frame as GC root for this Method*.
   __ load_mirror(R12_scratch2, R19_method);
 
   // Store values.
@@ -1133,6 +1139,29 @@
   return entry;
 }
 
+void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
+  // Quick & dirty stack overflow checking: bang the stack & handle trap.
+  // Note that we do the banging after the frame is setup, since the exception
+  // handling code expects to find a valid interpreter frame on the stack.
+  // Doing the banging earlier fails if the caller frame is not an interpreter
+  // frame.
+  // (Also, the exception throwing code expects to unlock any synchronized
+  // method receiever, so do the banging after locking the receiver.)
+
+  // Bang each page in the shadow zone. We can't assume it's been done for
+  // an interpreter frame with greater than a page of locals, so each page
+  // needs to be checked.  Only true for non-native.
+  if (UseStackBanging) {
+    const int page_size = os::vm_page_size();
+    const int n_shadow_pages = ((int)JavaThread::stack_shadow_zone_size()) / page_size;
+    const int start_page = native_call ? n_shadow_pages : 1;
+    BLOCK_COMMENT("bang_stack_shadow_pages:");
+    for (int pages = start_page; pages <= n_shadow_pages; pages++) {
+      __ bang_stack_with_offset(pages*page_size);
+    }
+  }
+}
+
 // Interpreter stub for calling a native method. (asm interpreter)
 // This sets up a somewhat different looking stack for calling the
 // native method than the typical interpreter frame setup.
@@ -1156,7 +1185,7 @@
   // This is not a full-blown interpreter frame, but in particular, the
   // following registers are valid after this:
   // - R19_method
-  // - R18_local (points to start of argumuments to native function)
+  // - R18_local (points to start of arguments to native function)
   //
   //   abstract stack (grows up)
   //     [  IJava (caller of JNI callee)  ]  <-- ASP
@@ -1207,6 +1236,11 @@
     generate_counter_incr(&invocation_counter_overflow, NULL, NULL);
 
     BIND(continue_after_compile);
+  }
+
+  bang_stack_shadow_pages(true);
+
+  if (inc_counter) {
     // Reset the _do_not_unlock_if_synchronized flag.
     if (synchronized) {
       __ li(R0, 0);
@@ -1595,6 +1629,7 @@
   Register Rsize_of_parameters = R4_ARG2, // Written by generate_fixed_frame.
            Rsize_of_locals     = R5_ARG3; // Written by generate_fixed_frame.
 
+  // Does also a stack check to assure this frame fits on the stack.
   generate_fixed_frame(false, Rsize_of_parameters, Rsize_of_locals);
 
   // --------------------------------------------------------------------------
@@ -1651,7 +1686,11 @@
     }
 
     __ bind(profile_method_continue);
+  }
 
+  bang_stack_shadow_pages(false);
+
+  if (inc_counter || ProfileInterpreter) {
     // Reset the _do_not_unlock_if_synchronized flag.
     if (synchronized) {
       __ li(R0, 0);
--- a/hotspot/src/share/vm/runtime/os.cpp	Wed Jun 01 11:14:58 2016 -0400
+++ b/hotspot/src/share/vm/runtime/os.cpp	Fri May 13 15:20:06 2016 +0200
@@ -1336,12 +1336,10 @@
   const int framesize_in_bytes =
     Interpreter::size_top_interpreter_activation(method()) * wordSize;
 
-  assert((thread->stack_base() - thread->stack_size()) +
-         (JavaThread::stack_guard_zone_size() +
-          JavaThread::stack_shadow_zone_size() + framesize_in_bytes) ==
-         ((JavaThread*)thread)->stack_overflow_limit() + framesize_in_bytes, "sanity");
+  address limit = ((JavaThread*)thread)->stack_end() +
+                  (JavaThread::stack_guard_zone_size() + JavaThread::stack_shadow_zone_size());
 
-  return (sp > ((JavaThread*)thread)->stack_overflow_limit() + framesize_in_bytes);
+  return sp > (limit + framesize_in_bytes);
 }
 
 size_t os::page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned) {
--- a/hotspot/src/share/vm/runtime/thread.hpp	Wed Jun 01 11:14:58 2016 -0400
+++ b/hotspot/src/share/vm/runtime/thread.hpp	Fri May 13 15:20:06 2016 +0200
@@ -1371,10 +1371,10 @@
   //  |  reserved pages                      |
   //  |                                      |
   //  --  <-- stack_reserved_zone_base()    ---      ---
-  //                                                 /|\  shadow
+  //                                                 /|\  shadow     <--  stack_overflow_limit() (somewhere in here)
   //                                                  |   zone
   //                                                 \|/  size
-  //  some untouched memory                          ---         <--  stack_overflow_limit()
+  //  some untouched memory                          ---
   //
   //
   //  --
@@ -1522,9 +1522,8 @@
 
   address stack_overflow_limit() { return _stack_overflow_limit; }
   void set_stack_overflow_limit() {
-    _stack_overflow_limit = stack_end() +
-                            (JavaThread::stack_guard_zone_size() +
-                             JavaThread::stack_shadow_zone_size());
+    _stack_overflow_limit =
+      stack_end() + MAX2(JavaThread::stack_guard_zone_size(), JavaThread::stack_shadow_zone_size());
   }
 
   // Misc. accessors/mutators