Fri, 13 Sep 2013 12:48:50 -0700
8024346: ~CautiouslyPreserveExceptionMark - assert(!_thread->has_pending_exception()) failed: unexpected exception generated
Summary: Pending exceptions must be handled properly after a call to the JVMTI merge_cp_and_rewrite
Reviewed-by: coleenp, dholmes
Contributed-by: serguei.spitsyn@oracle.com
duke@435 | 1 | /* |
mikael@4153 | 2 | * Copyright (c) 2003, 2012, 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 "code/codeBlob.hpp" |
stefank@2314 | 27 | #include "code/codeCache.hpp" |
stefank@2314 | 28 | #include "code/scopeDesc.hpp" |
stefank@2314 | 29 | #include "memory/resourceArea.hpp" |
stefank@2314 | 30 | #include "oops/oop.inline.hpp" |
stefank@2314 | 31 | #include "prims/jvmtiCodeBlobEvents.hpp" |
stefank@2314 | 32 | #include "prims/jvmtiExport.hpp" |
stefank@2314 | 33 | #include "runtime/handles.hpp" |
stefank@2314 | 34 | #include "runtime/handles.inline.hpp" |
stefank@2314 | 35 | #include "runtime/vmThread.hpp" |
duke@435 | 36 | |
duke@435 | 37 | // Support class to collect a list of the non-nmethod CodeBlobs in |
duke@435 | 38 | // the CodeCache. |
duke@435 | 39 | // |
duke@435 | 40 | // This class actually creates a list of JvmtiCodeBlobDesc - each JvmtiCodeBlobDesc |
duke@435 | 41 | // describes a single CodeBlob in the CodeCache. Note that collection is |
duke@435 | 42 | // done to a static list - this is because CodeCache::blobs_do is defined |
duke@435 | 43 | // as void CodeCache::blobs_do(void f(CodeBlob* nm)) and hence requires |
duke@435 | 44 | // a C or static method. |
duke@435 | 45 | // |
duke@435 | 46 | // Usage :- |
duke@435 | 47 | // |
duke@435 | 48 | // CodeBlobCollector collector; |
duke@435 | 49 | // |
duke@435 | 50 | // collector.collect(); |
duke@435 | 51 | // JvmtiCodeBlobDesc* blob = collector.first(); |
duke@435 | 52 | // while (blob != NULL) { |
duke@435 | 53 | // : |
duke@435 | 54 | // blob = collector.next(); |
duke@435 | 55 | // } |
duke@435 | 56 | // |
duke@435 | 57 | |
duke@435 | 58 | class CodeBlobCollector : StackObj { |
duke@435 | 59 | private: |
duke@435 | 60 | GrowableArray<JvmtiCodeBlobDesc*>* _code_blobs; // collected blobs |
duke@435 | 61 | int _pos; // iterator position |
duke@435 | 62 | |
duke@435 | 63 | // used during a collection |
duke@435 | 64 | static GrowableArray<JvmtiCodeBlobDesc*>* _global_code_blobs; |
duke@435 | 65 | static void do_blob(CodeBlob* cb); |
duke@435 | 66 | public: |
duke@435 | 67 | CodeBlobCollector() { |
duke@435 | 68 | _code_blobs = NULL; |
duke@435 | 69 | _pos = -1; |
duke@435 | 70 | } |
duke@435 | 71 | ~CodeBlobCollector() { |
duke@435 | 72 | if (_code_blobs != NULL) { |
duke@435 | 73 | for (int i=0; i<_code_blobs->length(); i++) { |
duke@435 | 74 | FreeHeap(_code_blobs->at(i)); |
duke@435 | 75 | } |
duke@435 | 76 | delete _code_blobs; |
duke@435 | 77 | } |
duke@435 | 78 | } |
duke@435 | 79 | |
duke@435 | 80 | // collect list of code blobs in the cache |
duke@435 | 81 | void collect(); |
duke@435 | 82 | |
duke@435 | 83 | // iteration support - return first code blob |
duke@435 | 84 | JvmtiCodeBlobDesc* first() { |
duke@435 | 85 | assert(_code_blobs != NULL, "not collected"); |
duke@435 | 86 | if (_code_blobs->length() == 0) { |
duke@435 | 87 | return NULL; |
duke@435 | 88 | } |
duke@435 | 89 | _pos = 0; |
duke@435 | 90 | return _code_blobs->at(0); |
duke@435 | 91 | } |
duke@435 | 92 | |
duke@435 | 93 | // iteration support - return next code blob |
duke@435 | 94 | JvmtiCodeBlobDesc* next() { |
duke@435 | 95 | assert(_pos >= 0, "iteration not started"); |
duke@435 | 96 | if (_pos+1 >= _code_blobs->length()) { |
duke@435 | 97 | return NULL; |
duke@435 | 98 | } |
duke@435 | 99 | return _code_blobs->at(++_pos); |
duke@435 | 100 | } |
duke@435 | 101 | |
duke@435 | 102 | }; |
duke@435 | 103 | |
duke@435 | 104 | // used during collection |
duke@435 | 105 | GrowableArray<JvmtiCodeBlobDesc*>* CodeBlobCollector::_global_code_blobs; |
duke@435 | 106 | |
duke@435 | 107 | |
duke@435 | 108 | // called for each CodeBlob in the CodeCache |
duke@435 | 109 | // |
duke@435 | 110 | // This function filters out nmethods as it is only interested in |
duke@435 | 111 | // other CodeBlobs. This function also filters out CodeBlobs that have |
duke@435 | 112 | // a duplicate starting address as previous blobs. This is needed to |
duke@435 | 113 | // handle the case where multiple stubs are generated into a single |
duke@435 | 114 | // BufferBlob. |
duke@435 | 115 | |
duke@435 | 116 | void CodeBlobCollector::do_blob(CodeBlob* cb) { |
duke@435 | 117 | |
duke@435 | 118 | // ignore nmethods |
duke@435 | 119 | if (cb->is_nmethod()) { |
duke@435 | 120 | return; |
duke@435 | 121 | } |
duke@435 | 122 | |
duke@435 | 123 | // check if this starting address has been seen already - the |
duke@435 | 124 | // assumption is that stubs are inserted into the list before the |
duke@435 | 125 | // enclosing BufferBlobs. |
twisti@2103 | 126 | address addr = cb->code_begin(); |
duke@435 | 127 | for (int i=0; i<_global_code_blobs->length(); i++) { |
duke@435 | 128 | JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); |
duke@435 | 129 | if (addr == scb->code_begin()) { |
duke@435 | 130 | return; |
duke@435 | 131 | } |
duke@435 | 132 | } |
duke@435 | 133 | |
duke@435 | 134 | // record the CodeBlob details as a JvmtiCodeBlobDesc |
twisti@2103 | 135 | JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->code_begin(), cb->code_end()); |
duke@435 | 136 | _global_code_blobs->append(scb); |
duke@435 | 137 | } |
duke@435 | 138 | |
duke@435 | 139 | |
duke@435 | 140 | // collects a list of CodeBlobs in the CodeCache. |
duke@435 | 141 | // |
duke@435 | 142 | // The created list is growable array of JvmtiCodeBlobDesc - each one describes |
duke@435 | 143 | // a CodeBlob. Note that the list is static - this is because CodeBlob::blobs_do |
duke@435 | 144 | // requires a a C or static function so we can't use an instance function. This |
duke@435 | 145 | // isn't a problem as the iteration is serial anyway as we need the CodeCache_lock |
duke@435 | 146 | // to iterate over the code cache. |
duke@435 | 147 | // |
duke@435 | 148 | // Note that the CodeBlobs in the CodeCache will include BufferBlobs that may |
duke@435 | 149 | // contain multiple stubs. As a profiler is interested in the stubs rather than |
duke@435 | 150 | // the enclosing container we first iterate over the stub code descriptors so |
duke@435 | 151 | // that the stubs go into the list first. do_blob will then filter out the |
duke@435 | 152 | // enclosing blobs if the starting address of the enclosing blobs matches the |
duke@435 | 153 | // starting address of first stub generated in the enclosing blob. |
duke@435 | 154 | |
duke@435 | 155 | void CodeBlobCollector::collect() { |
duke@435 | 156 | assert_locked_or_safepoint(CodeCache_lock); |
duke@435 | 157 | assert(_global_code_blobs == NULL, "checking"); |
duke@435 | 158 | |
duke@435 | 159 | // create the global list |
zgu@3900 | 160 | _global_code_blobs = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JvmtiCodeBlobDesc*>(50,true); |
duke@435 | 161 | |
duke@435 | 162 | // iterate over the stub code descriptors and put them in the list first. |
duke@435 | 163 | int index = 0; |
duke@435 | 164 | StubCodeDesc* desc; |
duke@435 | 165 | while ((desc = StubCodeDesc::desc_for_index(++index)) != NULL) { |
duke@435 | 166 | _global_code_blobs->append(new JvmtiCodeBlobDesc(desc->name(), desc->begin(), desc->end())); |
duke@435 | 167 | } |
duke@435 | 168 | |
duke@435 | 169 | // next iterate over all the non-nmethod code blobs and add them to |
duke@435 | 170 | // the list - as noted above this will filter out duplicates and |
duke@435 | 171 | // enclosing blobs. |
duke@435 | 172 | CodeCache::blobs_do(do_blob); |
duke@435 | 173 | |
duke@435 | 174 | // make the global list the instance list so that it can be used |
duke@435 | 175 | // for other iterations. |
duke@435 | 176 | _code_blobs = _global_code_blobs; |
duke@435 | 177 | _global_code_blobs = NULL; |
duke@435 | 178 | } |
duke@435 | 179 | |
duke@435 | 180 | |
duke@435 | 181 | // Generate a DYNAMIC_CODE_GENERATED event for each non-nmethod code blob. |
duke@435 | 182 | |
duke@435 | 183 | jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { |
duke@435 | 184 | CodeBlobCollector collector; |
duke@435 | 185 | |
never@1988 | 186 | // First collect all the code blobs. This has to be done in a |
never@1988 | 187 | // single pass over the code cache with CodeCache_lock held because |
never@1988 | 188 | // there isn't any safe way to iterate over regular CodeBlobs since |
never@1988 | 189 | // they can be freed at any point. |
duke@435 | 190 | { |
duke@435 | 191 | MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
duke@435 | 192 | collector.collect(); |
duke@435 | 193 | } |
duke@435 | 194 | |
duke@435 | 195 | // iterate over the collected list and post an event for each blob |
duke@435 | 196 | JvmtiCodeBlobDesc* blob = collector.first(); |
duke@435 | 197 | while (blob != NULL) { |
duke@435 | 198 | JvmtiExport::post_dynamic_code_generated(env, blob->name(), blob->code_begin(), blob->code_end()); |
duke@435 | 199 | blob = collector.next(); |
duke@435 | 200 | } |
duke@435 | 201 | return JVMTI_ERROR_NONE; |
duke@435 | 202 | } |
duke@435 | 203 | |
duke@435 | 204 | |
duke@435 | 205 | // Generate a COMPILED_METHOD_LOAD event for each nnmethod |
duke@435 | 206 | jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { |
duke@435 | 207 | HandleMark hm; |
duke@435 | 208 | |
never@1988 | 209 | // Walk the CodeCache notifying for live nmethods. The code cache |
never@1988 | 210 | // may be changing while this is happening which is ok since newly |
never@1988 | 211 | // created nmethod will notify normally and nmethods which are freed |
never@1988 | 212 | // can be safely skipped. |
never@1988 | 213 | MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
never@1988 | 214 | nmethod* current = CodeCache::first_nmethod(); |
never@1988 | 215 | while (current != NULL) { |
never@1988 | 216 | // Only notify for live nmethods |
never@1988 | 217 | if (current->is_alive()) { |
never@2004 | 218 | // Lock the nmethod so it can't be freed |
never@2004 | 219 | nmethodLocker nml(current); |
never@2004 | 220 | |
never@1988 | 221 | // Don't hold the lock over the notify or jmethodID creation |
never@1988 | 222 | MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
never@1988 | 223 | current->get_and_cache_jmethod_id(); |
never@1988 | 224 | JvmtiExport::post_compiled_method_load(current); |
never@1988 | 225 | } |
never@1988 | 226 | current = CodeCache::next_nmethod(current); |
duke@435 | 227 | } |
duke@435 | 228 | return JVMTI_ERROR_NONE; |
duke@435 | 229 | } |
duke@435 | 230 | |
duke@435 | 231 | |
duke@435 | 232 | // create a C-heap allocated address location map for an nmethod |
duke@435 | 233 | void JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nmethod *nm, |
duke@435 | 234 | jvmtiAddrLocationMap** map_ptr, |
duke@435 | 235 | jint *map_length_ptr) |
duke@435 | 236 | { |
duke@435 | 237 | ResourceMark rm; |
duke@435 | 238 | jvmtiAddrLocationMap* map = NULL; |
duke@435 | 239 | jint map_length = 0; |
duke@435 | 240 | |
duke@435 | 241 | |
duke@435 | 242 | // Generate line numbers using PcDesc and ScopeDesc info |
duke@435 | 243 | methodHandle mh(nm->method()); |
duke@435 | 244 | |
duke@435 | 245 | if (!mh->is_native()) { |
duke@435 | 246 | PcDesc *pcd; |
duke@435 | 247 | int pcds_in_method; |
duke@435 | 248 | |
duke@435 | 249 | pcds_in_method = (nm->scopes_pcs_end() - nm->scopes_pcs_begin()); |
zgu@3900 | 250 | map = NEW_C_HEAP_ARRAY(jvmtiAddrLocationMap, pcds_in_method, mtInternal); |
duke@435 | 251 | |
duke@435 | 252 | address scopes_data = nm->scopes_data_begin(); |
duke@435 | 253 | for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { |
kvn@1688 | 254 | ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); |
duke@435 | 255 | ScopeDesc *sd = &sc0; |
duke@435 | 256 | while( !sd->is_top() ) { sd = sd->sender(); } |
duke@435 | 257 | int bci = sd->bci(); |
duke@435 | 258 | if (bci != InvocationEntryBci) { |
duke@435 | 259 | assert(map_length < pcds_in_method, "checking"); |
duke@435 | 260 | map[map_length].start_address = (const void*)pcd->real_pc(nm); |
duke@435 | 261 | map[map_length].location = bci; |
duke@435 | 262 | ++map_length; |
duke@435 | 263 | } |
duke@435 | 264 | } |
duke@435 | 265 | } |
duke@435 | 266 | |
duke@435 | 267 | *map_ptr = map; |
duke@435 | 268 | *map_length_ptr = map_length; |
duke@435 | 269 | } |