Thu, 15 Apr 2010 02:40:12 -0700
6941224: Improved stack overflow handling for Zero
Summary: Adding stack overflow checking to Shark brought to light a bunch of deficiencies in Zero's stack overflow code.
Reviewed-by: twisti
Contributed-by: Gary Benson <gbenson@redhat.com>
never@1445 | 1 | /* |
never@1445 | 2 | * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. |
twisti@1814 | 3 | * Copyright 2007, 2008, 2010 Red Hat, Inc. |
never@1445 | 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
never@1445 | 5 | * |
never@1445 | 6 | * This code is free software; you can redistribute it and/or modify it |
never@1445 | 7 | * under the terms of the GNU General Public License version 2 only, as |
never@1445 | 8 | * published by the Free Software Foundation. |
never@1445 | 9 | * |
never@1445 | 10 | * This code is distributed in the hope that it will be useful, but WITHOUT |
never@1445 | 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
never@1445 | 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
never@1445 | 13 | * version 2 for more details (a copy is included in the LICENSE file that |
never@1445 | 14 | * accompanied this code). |
never@1445 | 15 | * |
never@1445 | 16 | * You should have received a copy of the GNU General Public License version |
never@1445 | 17 | * 2 along with this work; if not, write to the Free Software Foundation, |
never@1445 | 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
never@1445 | 19 | * |
never@1445 | 20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
never@1445 | 21 | * CA 95054 USA or visit www.sun.com if you need additional information or |
never@1445 | 22 | * have any questions. |
never@1445 | 23 | * |
never@1445 | 24 | */ |
never@1445 | 25 | |
never@1445 | 26 | #include "incls/_precompiled.incl" |
never@1445 | 27 | #include "incls/_stubGenerator_zero.cpp.incl" |
never@1445 | 28 | |
never@1445 | 29 | // Declaration and definition of StubGenerator (no .hpp file). |
never@1445 | 30 | // For a more detailed description of the stub routine structure |
never@1445 | 31 | // see the comment in stubRoutines.hpp |
never@1445 | 32 | |
never@1445 | 33 | class StubGenerator: public StubCodeGenerator { |
never@1445 | 34 | private: |
never@1445 | 35 | // The call stub is used to call Java from C |
never@1445 | 36 | static void call_stub( |
never@1445 | 37 | JavaCallWrapper *call_wrapper, |
never@1445 | 38 | intptr_t* result, |
never@1445 | 39 | BasicType result_type, |
never@1445 | 40 | methodOop method, |
never@1445 | 41 | address entry_point, |
never@1445 | 42 | intptr_t* parameters, |
never@1445 | 43 | int parameter_words, |
never@1445 | 44 | TRAPS) { |
never@1445 | 45 | JavaThread *thread = (JavaThread *) THREAD; |
never@1445 | 46 | ZeroStack *stack = thread->zero_stack(); |
never@1445 | 47 | |
never@1445 | 48 | // Make sure we have no pending exceptions |
never@1445 | 49 | assert(!HAS_PENDING_EXCEPTION, "call_stub called with pending exception"); |
never@1445 | 50 | |
never@1445 | 51 | // Set up the stack if necessary |
never@1445 | 52 | bool stack_needs_teardown = false; |
never@1445 | 53 | if (stack->needs_setup()) { |
never@1445 | 54 | size_t stack_used = thread->stack_base() - (address) &stack_used; |
never@1445 | 55 | size_t stack_free = thread->stack_size() - stack_used; |
never@1445 | 56 | size_t zero_stack_size = align_size_down(stack_free / 2, wordSize); |
never@1445 | 57 | |
never@1445 | 58 | stack->setup(alloca(zero_stack_size), zero_stack_size); |
never@1445 | 59 | stack_needs_teardown = true; |
never@1445 | 60 | } |
never@1445 | 61 | |
never@1445 | 62 | // Allocate and initialize our frame |
twisti@1814 | 63 | EntryFrame *frame = |
twisti@1814 | 64 | EntryFrame::build(parameters, parameter_words, call_wrapper, THREAD); |
never@1445 | 65 | |
twisti@1814 | 66 | if (!HAS_PENDING_EXCEPTION) { |
twisti@1814 | 67 | // Push the frame |
twisti@1814 | 68 | thread->push_zero_frame(frame); |
never@1445 | 69 | |
twisti@1814 | 70 | // Make the call |
twisti@1814 | 71 | Interpreter::invoke_method(method, entry_point, THREAD); |
twisti@1814 | 72 | |
twisti@1814 | 73 | // Store the result |
twisti@1814 | 74 | if (!HAS_PENDING_EXCEPTION) { |
twisti@1814 | 75 | switch (result_type) { |
twisti@1814 | 76 | case T_INT: |
twisti@1814 | 77 | *(jint *) result = *(jint *) stack->sp(); |
twisti@1814 | 78 | break; |
twisti@1814 | 79 | case T_LONG: |
twisti@1814 | 80 | *(jlong *) result = *(jlong *) stack->sp(); |
twisti@1814 | 81 | break; |
twisti@1814 | 82 | case T_FLOAT: |
twisti@1814 | 83 | *(jfloat *) result = *(jfloat *) stack->sp(); |
twisti@1814 | 84 | break; |
twisti@1814 | 85 | case T_DOUBLE: |
twisti@1814 | 86 | *(jdouble *) result = *(jdouble *) stack->sp(); |
twisti@1814 | 87 | break; |
twisti@1814 | 88 | case T_OBJECT: |
twisti@1814 | 89 | *(oop *) result = *(oop *) stack->sp(); |
twisti@1814 | 90 | break; |
twisti@1814 | 91 | default: |
twisti@1814 | 92 | ShouldNotReachHere(); |
twisti@1814 | 93 | } |
never@1445 | 94 | } |
twisti@1814 | 95 | |
twisti@1814 | 96 | // Unwind the frame |
twisti@1814 | 97 | thread->pop_zero_frame(); |
never@1445 | 98 | } |
never@1445 | 99 | |
never@1445 | 100 | // Tear down the stack if necessary |
never@1445 | 101 | if (stack_needs_teardown) |
never@1445 | 102 | stack->teardown(); |
never@1445 | 103 | } |
never@1445 | 104 | |
never@1445 | 105 | // These stubs get called from some dumb test routine. |
never@1445 | 106 | // I'll write them properly when they're called from |
never@1445 | 107 | // something that's actually doing something. |
never@1445 | 108 | static void fake_arraycopy_stub(address src, address dst, int count) { |
never@1445 | 109 | assert(count == 0, "huh?"); |
never@1445 | 110 | } |
never@1445 | 111 | |
never@1445 | 112 | void generate_arraycopy_stubs() { |
never@1445 | 113 | // Call the conjoint generation methods immediately after |
never@1445 | 114 | // the disjoint ones so that short branches from the former |
never@1445 | 115 | // to the latter can be generated. |
never@1445 | 116 | StubRoutines::_jbyte_disjoint_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 117 | StubRoutines::_jbyte_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 118 | |
never@1445 | 119 | StubRoutines::_jshort_disjoint_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 120 | StubRoutines::_jshort_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 121 | |
never@1445 | 122 | StubRoutines::_jint_disjoint_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 123 | StubRoutines::_jint_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 124 | |
never@1445 | 125 | StubRoutines::_jlong_disjoint_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 126 | StubRoutines::_jlong_arraycopy = (address) fake_arraycopy_stub; |
never@1445 | 127 | |
never@1445 | 128 | StubRoutines::_oop_disjoint_arraycopy = ShouldNotCallThisStub(); |
never@1445 | 129 | StubRoutines::_oop_arraycopy = ShouldNotCallThisStub(); |
never@1445 | 130 | |
never@1445 | 131 | StubRoutines::_checkcast_arraycopy = ShouldNotCallThisStub(); |
never@1445 | 132 | StubRoutines::_unsafe_arraycopy = ShouldNotCallThisStub(); |
never@1445 | 133 | StubRoutines::_generic_arraycopy = ShouldNotCallThisStub(); |
never@1445 | 134 | |
never@1445 | 135 | // We don't generate specialized code for HeapWord-aligned source |
never@1445 | 136 | // arrays, so just use the code we've already generated |
never@1445 | 137 | StubRoutines::_arrayof_jbyte_disjoint_arraycopy = |
never@1445 | 138 | StubRoutines::_jbyte_disjoint_arraycopy; |
never@1445 | 139 | StubRoutines::_arrayof_jbyte_arraycopy = |
never@1445 | 140 | StubRoutines::_jbyte_arraycopy; |
never@1445 | 141 | |
never@1445 | 142 | StubRoutines::_arrayof_jshort_disjoint_arraycopy = |
never@1445 | 143 | StubRoutines::_jshort_disjoint_arraycopy; |
never@1445 | 144 | StubRoutines::_arrayof_jshort_arraycopy = |
never@1445 | 145 | StubRoutines::_jshort_arraycopy; |
never@1445 | 146 | |
never@1445 | 147 | StubRoutines::_arrayof_jint_disjoint_arraycopy = |
never@1445 | 148 | StubRoutines::_jint_disjoint_arraycopy; |
never@1445 | 149 | StubRoutines::_arrayof_jint_arraycopy = |
never@1445 | 150 | StubRoutines::_jint_arraycopy; |
never@1445 | 151 | |
never@1445 | 152 | StubRoutines::_arrayof_jlong_disjoint_arraycopy = |
never@1445 | 153 | StubRoutines::_jlong_disjoint_arraycopy; |
never@1445 | 154 | StubRoutines::_arrayof_jlong_arraycopy = |
never@1445 | 155 | StubRoutines::_jlong_arraycopy; |
never@1445 | 156 | |
never@1445 | 157 | StubRoutines::_arrayof_oop_disjoint_arraycopy = |
never@1445 | 158 | StubRoutines::_oop_disjoint_arraycopy; |
never@1445 | 159 | StubRoutines::_arrayof_oop_arraycopy = |
never@1445 | 160 | StubRoutines::_oop_arraycopy; |
never@1445 | 161 | } |
never@1445 | 162 | |
never@1445 | 163 | void generate_initial() { |
never@1445 | 164 | // Generates all stubs and initializes the entry points |
never@1445 | 165 | |
never@1445 | 166 | // entry points that exist in all platforms Note: This is code |
never@1445 | 167 | // that could be shared among different platforms - however the |
never@1445 | 168 | // benefit seems to be smaller than the disadvantage of having a |
never@1445 | 169 | // much more complicated generator structure. See also comment in |
never@1445 | 170 | // stubRoutines.hpp. |
never@1445 | 171 | |
never@1445 | 172 | StubRoutines::_forward_exception_entry = ShouldNotCallThisStub(); |
never@1445 | 173 | StubRoutines::_call_stub_entry = (address) call_stub; |
never@1445 | 174 | StubRoutines::_catch_exception_entry = ShouldNotCallThisStub(); |
never@1445 | 175 | |
never@1445 | 176 | // atomic calls |
never@1445 | 177 | StubRoutines::_atomic_xchg_entry = ShouldNotCallThisStub(); |
never@1445 | 178 | StubRoutines::_atomic_xchg_ptr_entry = ShouldNotCallThisStub(); |
never@1445 | 179 | StubRoutines::_atomic_cmpxchg_entry = ShouldNotCallThisStub(); |
never@1445 | 180 | StubRoutines::_atomic_cmpxchg_ptr_entry = ShouldNotCallThisStub(); |
never@1445 | 181 | StubRoutines::_atomic_cmpxchg_long_entry = ShouldNotCallThisStub(); |
never@1445 | 182 | StubRoutines::_atomic_add_entry = ShouldNotCallThisStub(); |
never@1445 | 183 | StubRoutines::_atomic_add_ptr_entry = ShouldNotCallThisStub(); |
never@1445 | 184 | StubRoutines::_fence_entry = ShouldNotCallThisStub(); |
never@1445 | 185 | |
never@1445 | 186 | // amd64 does this here, sparc does it in generate_all() |
never@1445 | 187 | StubRoutines::_handler_for_unsafe_access_entry = |
never@1445 | 188 | ShouldNotCallThisStub(); |
never@1445 | 189 | } |
never@1445 | 190 | |
never@1445 | 191 | void generate_all() { |
never@1445 | 192 | // Generates all stubs and initializes the entry points |
never@1445 | 193 | |
never@1445 | 194 | // These entry points require SharedInfo::stack0 to be set up in |
never@1445 | 195 | // non-core builds and need to be relocatable, so they each |
never@1445 | 196 | // fabricate a RuntimeStub internally. |
never@1445 | 197 | StubRoutines::_throw_AbstractMethodError_entry = |
never@1445 | 198 | ShouldNotCallThisStub(); |
never@1445 | 199 | |
never@1445 | 200 | StubRoutines::_throw_ArithmeticException_entry = |
never@1445 | 201 | ShouldNotCallThisStub(); |
never@1445 | 202 | |
never@1445 | 203 | StubRoutines::_throw_NullPointerException_entry = |
never@1445 | 204 | ShouldNotCallThisStub(); |
never@1445 | 205 | |
never@1445 | 206 | StubRoutines::_throw_NullPointerException_at_call_entry = |
never@1445 | 207 | ShouldNotCallThisStub(); |
never@1445 | 208 | |
never@1445 | 209 | StubRoutines::_throw_StackOverflowError_entry = |
never@1445 | 210 | ShouldNotCallThisStub(); |
never@1445 | 211 | |
never@1445 | 212 | // support for verify_oop (must happen after universe_init) |
never@1445 | 213 | StubRoutines::_verify_oop_subroutine_entry = |
never@1445 | 214 | ShouldNotCallThisStub(); |
never@1445 | 215 | |
never@1445 | 216 | // arraycopy stubs used by compilers |
never@1445 | 217 | generate_arraycopy_stubs(); |
never@1445 | 218 | } |
never@1445 | 219 | |
never@1445 | 220 | public: |
never@1445 | 221 | StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { |
never@1445 | 222 | if (all) { |
never@1445 | 223 | generate_all(); |
never@1445 | 224 | } else { |
never@1445 | 225 | generate_initial(); |
never@1445 | 226 | } |
never@1445 | 227 | } |
never@1445 | 228 | }; |
never@1445 | 229 | |
never@1445 | 230 | void StubGenerator_generate(CodeBuffer* code, bool all) { |
never@1445 | 231 | StubGenerator g(code, all); |
never@1445 | 232 | } |
never@1445 | 233 | |
twisti@1814 | 234 | EntryFrame *EntryFrame::build(const intptr_t* parameters, |
never@1445 | 235 | int parameter_words, |
twisti@1814 | 236 | JavaCallWrapper* call_wrapper, |
twisti@1814 | 237 | TRAPS) { |
twisti@1814 | 238 | |
twisti@1814 | 239 | ZeroStack *stack = ((JavaThread *) THREAD)->zero_stack(); |
twisti@1814 | 240 | stack->overflow_check(header_words + parameter_words, CHECK_NULL); |
never@1445 | 241 | |
never@1445 | 242 | stack->push(0); // next_frame, filled in later |
never@1445 | 243 | intptr_t *fp = stack->sp(); |
never@1445 | 244 | assert(fp - stack->sp() == next_frame_off, "should be"); |
never@1445 | 245 | |
never@1445 | 246 | stack->push(ENTRY_FRAME); |
never@1445 | 247 | assert(fp - stack->sp() == frame_type_off, "should be"); |
never@1445 | 248 | |
never@1445 | 249 | stack->push((intptr_t) call_wrapper); |
never@1445 | 250 | assert(fp - stack->sp() == call_wrapper_off, "should be"); |
never@1445 | 251 | |
never@1445 | 252 | for (int i = 0; i < parameter_words; i++) |
never@1445 | 253 | stack->push(parameters[i]); |
never@1445 | 254 | |
never@1445 | 255 | return (EntryFrame *) fp; |
never@1445 | 256 | } |