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