Thu, 16 Feb 2012 17:12:49 -0800
7145346: VerifyStackAtCalls is broken
Summary: Replace call_epilog() encoding with macroassembler use. Moved duplicated code to x86.ad. Fixed return_addr() definition.
Reviewed-by: never
duke@435 | 1 | /* |
stefank@2314 | 2 | * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. |
duke@435 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
duke@435 | 4 | * |
duke@435 | 5 | * This code is free software; you can redistribute it and/or modify it |
duke@435 | 6 | * under the terms of the GNU General Public License version 2 only, as |
duke@435 | 7 | * published by the Free Software Foundation. |
duke@435 | 8 | * |
duke@435 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
duke@435 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
duke@435 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
duke@435 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
duke@435 | 13 | * accompanied this code). |
duke@435 | 14 | * |
duke@435 | 15 | * You should have received a copy of the GNU General Public License version |
duke@435 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
duke@435 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
duke@435 | 18 | * |
trims@1907 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
trims@1907 | 20 | * or visit www.oracle.com if you need additional information or have any |
trims@1907 | 21 | * questions. |
duke@435 | 22 | * |
duke@435 | 23 | */ |
duke@435 | 24 | |
stefank@2314 | 25 | #include "precompiled.hpp" |
stefank@2314 | 26 | #include "runtime/threadLocalStorage.hpp" |
stefank@2314 | 27 | #include "thread_solaris.inline.hpp" |
duke@435 | 28 | |
duke@435 | 29 | #ifdef AMD64 |
duke@435 | 30 | extern "C" Thread* fs_load(ptrdiff_t tlsOffset); |
duke@435 | 31 | extern "C" intptr_t fs_thread(); |
duke@435 | 32 | #else |
duke@435 | 33 | // From solaris_i486.s |
duke@435 | 34 | extern "C" Thread* gs_load(ptrdiff_t tlsOffset); |
duke@435 | 35 | extern "C" intptr_t gs_thread(); |
duke@435 | 36 | #endif // AMD64 |
duke@435 | 37 | |
duke@435 | 38 | // tlsMode encoding: |
duke@435 | 39 | // |
duke@435 | 40 | // pd_tlsAccessUndefined : uninitialized |
duke@435 | 41 | // pd_tlsAccessSlow : not available |
duke@435 | 42 | // pd_tlsAccessIndirect : |
duke@435 | 43 | // old-style indirect access - present in "T1" libthread. |
duke@435 | 44 | // use thr_slot_sync_allocate() to attempt to allocate a slot. |
duke@435 | 45 | // pd_tlsAccessDirect : |
duke@435 | 46 | // new-style direct access - present in late-model "T2" libthread. |
duke@435 | 47 | // Allocate the offset (slot) via _thr_slot_offset() or by |
duke@435 | 48 | // defining an IE- or LE-mode TLS/TSD slot in the launcher and then passing |
duke@435 | 49 | // that offset into libjvm.so. |
duke@435 | 50 | // See http://sac.eng/Archives/CaseLog/arc/PSARC/2003/159/. |
duke@435 | 51 | // |
duke@435 | 52 | // Note that we have a capability gap - some early model T2 forms |
duke@435 | 53 | // (e.g., unpatched S9) have neither _thr_slot_sync_allocate() nor |
duke@435 | 54 | // _thr_slot_offset(). In that case we revert to the usual |
duke@435 | 55 | // thr_getspecific accessor. |
duke@435 | 56 | // |
duke@435 | 57 | |
duke@435 | 58 | static ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_tlsAccessUndefined ; |
duke@435 | 59 | static ptrdiff_t tlsOffset = 0 ; |
duke@435 | 60 | static thread_key_t tlsKey ; |
duke@435 | 61 | |
duke@435 | 62 | typedef int (*TSSA_Entry) (ptrdiff_t *, int, int) ; |
duke@435 | 63 | typedef ptrdiff_t (*TSO_Entry) (int) ; |
duke@435 | 64 | |
duke@435 | 65 | ThreadLocalStorage::pd_tlsAccessMode ThreadLocalStorage::pd_getTlsAccessMode () |
duke@435 | 66 | { |
duke@435 | 67 | guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; |
duke@435 | 68 | return tlsMode ; |
duke@435 | 69 | } |
duke@435 | 70 | |
duke@435 | 71 | ptrdiff_t ThreadLocalStorage::pd_getTlsOffset () { |
duke@435 | 72 | guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; |
duke@435 | 73 | return tlsOffset ; |
duke@435 | 74 | } |
duke@435 | 75 | |
duke@435 | 76 | // TODO: Consider the following improvements: |
duke@435 | 77 | // |
duke@435 | 78 | // 1. Convert from thr_*specific* to pthread_*specific*. |
duke@435 | 79 | // The pthread_ forms are slightly faster. Also, the |
duke@435 | 80 | // pthread_ forms have a pthread_key_delete() API which |
duke@435 | 81 | // would aid in clean JVM shutdown and the eventual goal |
duke@435 | 82 | // of permitting a JVM to reinstantiate itself withing a process. |
duke@435 | 83 | // |
duke@435 | 84 | // 2. See ThreadLocalStorage::init(). We end up allocating |
duke@435 | 85 | // two TLS keys during VM startup. That's benign, but we could collapse |
duke@435 | 86 | // down to one key without too much trouble. |
duke@435 | 87 | // |
duke@435 | 88 | // 3. MacroAssembler::get_thread() currently emits calls to thr_getspecific(). |
duke@435 | 89 | // Modify get_thread() to call Thread::current() instead. |
duke@435 | 90 | // |
duke@435 | 91 | // 4. Thread::current() currently uses a cache keyed by %gs:[0]. |
duke@435 | 92 | // (The JVM has PSARC permission to use %g7/%gs:[0] |
duke@435 | 93 | // as an opaque temporally unique thread identifier). |
duke@435 | 94 | // For C++ access to a thread's reflexive "self" pointer we |
duke@435 | 95 | // should consider using one of the following: |
duke@435 | 96 | // a. a radix tree keyed by %esp - as in EVM. |
duke@435 | 97 | // This requires two loads (the 2nd dependent on the 1st), but |
duke@435 | 98 | // is easily inlined and doesn't require a "miss" slow path. |
duke@435 | 99 | // b. a fast TLS/TSD slot allocated by _thr_slot_offset |
duke@435 | 100 | // or _thr_slot_sync_allocate. |
duke@435 | 101 | // |
duke@435 | 102 | // 5. 'generate_code_for_get_thread' is a misnomer. |
duke@435 | 103 | // We should change it to something more general like |
duke@435 | 104 | // pd_ThreadSelf_Init(), for instance. |
duke@435 | 105 | // |
duke@435 | 106 | |
duke@435 | 107 | static void AllocateTLSOffset () |
duke@435 | 108 | { |
duke@435 | 109 | int rslt ; |
duke@435 | 110 | TSSA_Entry tssa ; |
duke@435 | 111 | TSO_Entry tso ; |
duke@435 | 112 | ptrdiff_t off ; |
duke@435 | 113 | |
duke@435 | 114 | guarantee (tlsMode == ThreadLocalStorage::pd_tlsAccessUndefined, "tlsMode not set") ; |
duke@435 | 115 | tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; |
duke@435 | 116 | tlsOffset = 0 ; |
duke@435 | 117 | #ifndef AMD64 |
duke@435 | 118 | |
duke@435 | 119 | tssa = (TSSA_Entry) dlsym (RTLD_DEFAULT, "thr_slot_sync_allocate") ; |
duke@435 | 120 | if (tssa != NULL) { |
duke@435 | 121 | off = -1 ; |
duke@435 | 122 | rslt = (*tssa)(&off, NULL, NULL) ; // (off,dtor,darg) |
duke@435 | 123 | if (off != -1) { |
duke@435 | 124 | tlsOffset = off ; |
duke@435 | 125 | tlsMode = ThreadLocalStorage::pd_tlsAccessIndirect ; |
duke@435 | 126 | return ; |
duke@435 | 127 | } |
duke@435 | 128 | } |
duke@435 | 129 | |
duke@435 | 130 | rslt = thr_keycreate (&tlsKey, NULL) ; |
duke@435 | 131 | if (rslt != 0) { |
duke@435 | 132 | tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; // revert to slow mode |
duke@435 | 133 | return ; |
duke@435 | 134 | } |
duke@435 | 135 | |
duke@435 | 136 | tso = (TSO_Entry) dlsym (RTLD_DEFAULT, "_thr_slot_offset") ; |
duke@435 | 137 | if (tso != NULL) { |
duke@435 | 138 | off = (*tso)(tlsKey) ; |
duke@435 | 139 | if (off >= 0) { |
duke@435 | 140 | tlsOffset = off ; |
duke@435 | 141 | tlsMode = ThreadLocalStorage::pd_tlsAccessDirect ; |
duke@435 | 142 | return ; |
duke@435 | 143 | } |
duke@435 | 144 | } |
duke@435 | 145 | |
duke@435 | 146 | // Failure: Too bad ... we've allocated a TLS slot we don't need and there's |
duke@435 | 147 | // no provision in the ABI for returning the slot. |
duke@435 | 148 | // |
duke@435 | 149 | // If we didn't find a slot then then: |
duke@435 | 150 | // 1. We might be on liblwp. |
duke@435 | 151 | // 2. We might be on T2 libthread, but all "fast" slots are already |
duke@435 | 152 | // consumed |
duke@435 | 153 | // 3. We might be on T1, and all TSD (thr_slot_sync_allocate) slots are |
duke@435 | 154 | // consumed. |
duke@435 | 155 | // 4. We might be on T2 libthread, but it's be re-architected |
duke@435 | 156 | // so that fast slots are no longer g7-relative. |
duke@435 | 157 | // |
duke@435 | 158 | |
duke@435 | 159 | tlsMode = ThreadLocalStorage::pd_tlsAccessSlow ; |
duke@435 | 160 | return ; |
duke@435 | 161 | #endif // AMD64 |
duke@435 | 162 | } |
duke@435 | 163 | |
duke@435 | 164 | void ThreadLocalStorage::generate_code_for_get_thread() { |
duke@435 | 165 | AllocateTLSOffset() ; |
duke@435 | 166 | } |
duke@435 | 167 | |
duke@435 | 168 | void ThreadLocalStorage::set_thread_in_slot(Thread *thread) { |
duke@435 | 169 | guarantee (tlsMode != pd_tlsAccessUndefined, "tlsMode not set") ; |
duke@435 | 170 | if (tlsMode == pd_tlsAccessIndirect) { |
duke@435 | 171 | #ifdef AMD64 |
duke@435 | 172 | intptr_t tbase = fs_thread(); |
duke@435 | 173 | #else |
duke@435 | 174 | intptr_t tbase = gs_thread(); |
duke@435 | 175 | #endif // AMD64 |
duke@435 | 176 | *((Thread**) (tbase + tlsOffset)) = thread ; |
duke@435 | 177 | } else |
duke@435 | 178 | if (tlsMode == pd_tlsAccessDirect) { |
duke@435 | 179 | thr_setspecific (tlsKey, (void *) thread) ; |
duke@435 | 180 | // set with thr_setspecific and then readback with gs_load to validate. |
duke@435 | 181 | #ifdef AMD64 |
duke@435 | 182 | guarantee (thread == fs_load(tlsOffset), "tls readback failure") ; |
duke@435 | 183 | #else |
duke@435 | 184 | guarantee (thread == gs_load(tlsOffset), "tls readback failure") ; |
duke@435 | 185 | #endif // AMD64 |
duke@435 | 186 | } |
duke@435 | 187 | } |
duke@435 | 188 | |
duke@435 | 189 | |
duke@435 | 190 | extern "C" Thread* get_thread() { |
duke@435 | 191 | return ThreadLocalStorage::thread(); |
duke@435 | 192 | } |