1 /*
  2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  *
 23  */
 24 
 25 #ifndef SHARE_RUNTIME_STACKOVERFLOW_HPP
 26 #define SHARE_RUNTIME_STACKOVERFLOW_HPP
 27 
 28 #include "utilities/align.hpp"
 29 #include "utilities/debug.hpp"
 30 
 31 class JavaThread;
 32 
 33 // StackOverflow handling is encapsulated in this class.  This class contains state variables
 34 // for each JavaThread that are used to detect stack overflow though explicit checks or through
 35 // checks in the signal handler when stack banging into guard pages causes a trap.
 36 // The state variables also record whether guard pages are enabled or disabled.
 37 
 38 class StackOverflow {
 39   friend class JVMCIVMStructs;
 40   friend class JavaThread;
 41  public:
 42   // State of the stack guard pages for the containing thread.
 43   enum StackGuardState {
 44     stack_guard_unused,         // not needed
 45     stack_guard_reserved_disabled,
 46     stack_guard_yellow_reserved_disabled,// disabled (temporarily) after stack overflow
 47     stack_guard_enabled         // enabled
 48   };
 49 
 50   StackOverflow() :
 51     _stack_guard_state(stack_guard_unused),
 52     _stack_overflow_limit(nullptr),
 53     _reserved_stack_activation(nullptr),  // stack base not known yet
 54     _stack_base(nullptr), _stack_end(nullptr) {}
 55 
 56   // Initialization after thread is started.
 57   void initialize(address base, address end) {
 58      _stack_base = base;
 59      _stack_end = end;
 60     set_stack_overflow_limit();
 61     set_reserved_stack_activation(base);
 62   }
 63  private:
 64 
 65   StackGuardState  _stack_guard_state;
 66 
 67   // Precompute the limit of the stack as used in stack overflow checks.
 68   // We load it from here to simplify the stack overflow check in assembly.
 69   address          _stack_overflow_limit;
 70   address          _reserved_stack_activation;
 71 
 72   // Support for stack overflow handling, copied down from thread.
 73   address          _stack_base;
 74   address          _stack_end;
 75 
 76   address stack_end()  const           { return _stack_end; }
 77   address stack_base() const           { assert(_stack_base != nullptr, "Sanity check"); return _stack_base; }
 78 
 79   // Stack overflow support
 80   //
 81   //  (low addresses)
 82   //
 83   //  --  <-- stack_end()                   ---
 84   //  |                                      |
 85   //  |  red zone                            |
 86   //  |                                      |
 87   //  --  <-- stack_red_zone_base()          |
 88   //  |                                      |
 89   //  |                                     guard
 90   //  |  yellow zone                        zone
 91   //  |                                      |
 92   //  |                                      |
 93   //  --  <-- stack_yellow_zone_base()       |
 94   //  |                                      |
 95   //  |                                      |
 96   //  |  reserved zone                       |
 97   //  |                                      |
 98   //  --  <-- stack_reserved_zone_base()    ---      ---
 99   //                                                 /|\  shadow     <--  stack_overflow_limit() (somewhere in here)
100   //                                                  |   zone
101   //                                                 \|/  size
102   //  some untouched memory                          ---
103   //
104   //
105   //  --
106   //  |
107   //  |  shadow zone
108   //  |
109   //  --
110   //  x    frame n
111   //  --
112   //  x    frame n-1
113   //  x
114   //  --
115   //  ...
116   //
117   //  --
118   //  x    frame 0
119   //  --  <-- stack_base()
120   //
121   //  (high addresses)
122   //
123 
124  private:
125   // These values are derived from flags StackRedPages, StackYellowPages,
126   // StackReservedPages and StackShadowPages.
127   static size_t _stack_red_zone_size;
128   static size_t _stack_yellow_zone_size;
129   static size_t _stack_reserved_zone_size;
130   static size_t _stack_shadow_zone_size;
131 
132  public:
133   static void initialize_stack_zone_sizes();
134 
135   static size_t stack_red_zone_size() {
136     assert(_stack_red_zone_size > 0, "Don't call this before the field is initialized.");
137     return _stack_red_zone_size;
138   }
139 
140   // Returns base of red zone (one-beyond the highest red zone address, so
141   //  itself outside red zone and the highest address of the yellow zone).
142   address stack_red_zone_base() const {
143     return (address)(stack_end() + stack_red_zone_size());
144   }
145 
146   // Returns true if address points into the red zone.
147   bool in_stack_red_zone(address a) const {
148     return a < stack_red_zone_base() && a >= stack_end();
149   }
150 
151   static size_t stack_yellow_zone_size() {
152     assert(_stack_yellow_zone_size > 0, "Don't call this before the field is initialized.");
153     return _stack_yellow_zone_size;
154   }
155 
156   static size_t stack_reserved_zone_size() {
157     // _stack_reserved_zone_size may be 0. This indicates the feature is off.
158     return _stack_reserved_zone_size;
159   }
160 
161   // Returns base of the reserved zone (one-beyond the highest reserved zone address).
162   address stack_reserved_zone_base() const {
163     return (address)(stack_end() +
164                      (stack_red_zone_size() + stack_yellow_zone_size() + stack_reserved_zone_size()));
165   }
166 
167   // Returns true if address points into the reserved zone.
168   bool in_stack_reserved_zone(address a) const {
169     return (a < stack_reserved_zone_base()) &&
170            (a >= (address)((intptr_t)stack_reserved_zone_base() - stack_reserved_zone_size()));
171   }
172 
173   static size_t stack_yellow_reserved_zone_size() {
174     return _stack_yellow_zone_size + _stack_reserved_zone_size;
175   }
176 
177   // Returns true if a points into either yellow or reserved zone.
178   bool in_stack_yellow_reserved_zone(address a) const {
179     return (a < stack_reserved_zone_base()) && (a >= stack_red_zone_base());
180   }
181 
182   // Size of red + yellow + reserved zones.
183   static size_t stack_guard_zone_size() {
184     return stack_red_zone_size() + stack_yellow_reserved_zone_size();
185   }
186 
187   static size_t stack_shadow_zone_size() {
188     assert(_stack_shadow_zone_size > 0, "Don't call this before the field is initialized.");
189     return _stack_shadow_zone_size;
190   }
191 
192   void create_stack_guard_pages();
193   void remove_stack_guard_pages();
194 
195   void enable_stack_reserved_zone(bool check_if_disabled = false);
196   void disable_stack_reserved_zone();
197   void enable_stack_yellow_reserved_zone();
198   void disable_stack_yellow_reserved_zone();
199   void enable_stack_red_zone();
200   void disable_stack_red_zone();
201 
202   bool stack_guard_zone_unused() const { return _stack_guard_state == stack_guard_unused; }
203 
204   bool stack_yellow_reserved_zone_disabled() const {
205     return _stack_guard_state == stack_guard_yellow_reserved_disabled;
206   }
207 
208   size_t stack_available(address cur_sp) const {
209     // This code assumes java stacks grow down
210     address low_addr; // Limit on the address for deepest stack depth
211     if (_stack_guard_state == stack_guard_unused) {
212       low_addr = stack_end();
213     } else {
214       low_addr = stack_reserved_zone_base();
215     }
216     return cur_sp > low_addr ? cur_sp - low_addr : 0;
217   }
218 
219   bool stack_guards_enabled() const;
220 
221   address reserved_stack_activation() const { return _reserved_stack_activation; }
222   void set_reserved_stack_activation(address addr) {
223     assert(_reserved_stack_activation == stack_base()
224             || _reserved_stack_activation == nullptr
225             || addr == stack_base(), "Must not be set twice");
226     _reserved_stack_activation = addr;
227   }
228 
229   // Attempt to reguard the stack after a stack overflow may have occurred.
230   // Returns true if (a) guard pages are not needed on this thread, (b) the
231   // pages are already guarded, or (c) the pages were successfully reguarded.
232   // Returns false if there is not enough stack space to reguard the pages, in
233   // which case the caller should unwind a frame and try again.  The argument
234   // should be the caller's (approximate) sp.
235   bool reguard_stack(address cur_sp);
236   // Similar to above but see if current stackpoint is out of the guard area
237   // and reguard if possible.
238   bool reguard_stack(void);
239   bool reguard_stack_if_needed(void);
240 
241   void set_stack_overflow_limit() {
242     _stack_overflow_limit =
243       stack_end() + MAX2(stack_guard_zone_size(), stack_shadow_zone_size());
244   }
245 };
246 
247 #endif // SHARE_RUNTIME_STACKOVERFLOW_HPP