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 StackOverflow()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. initialize(address base,address end)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 stack_end() const76 address stack_end() const { return _stack_end; } stack_base() const77 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 stack_red_zone_size()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). stack_red_zone_base() const142 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. in_stack_red_zone(address a) const147 bool in_stack_red_zone(address a) const { 148 return a < stack_red_zone_base() && a >= stack_end(); 149 } 150 stack_yellow_zone_size()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 stack_reserved_zone_size()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). stack_reserved_zone_base() const162 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. in_stack_reserved_zone(address a) const168 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 stack_yellow_reserved_zone_size()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. in_stack_yellow_reserved_zone(address a) const178 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. stack_guard_zone_size()183 static size_t stack_guard_zone_size() { 184 return stack_red_zone_size() + stack_yellow_reserved_zone_size(); 185 } 186 stack_shadow_zone_size()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 stack_guard_zone_unused() const202 bool stack_guard_zone_unused() const { return _stack_guard_state == stack_guard_unused; } 203 stack_yellow_reserved_zone_disabled() const204 bool stack_yellow_reserved_zone_disabled() const { 205 return _stack_guard_state == stack_guard_yellow_reserved_disabled; 206 } 207 stack_available(address cur_sp) const208 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 reserved_stack_activation() const221 address reserved_stack_activation() const { return _reserved_stack_activation; } set_reserved_stack_activation(address addr)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 set_stack_overflow_limit()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 248