1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/prims/jvmtiCodeBlobEvents.cpp Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,286 @@ 1.4 +/* 1.5 + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "code/codeBlob.hpp" 1.30 +#include "code/codeCache.hpp" 1.31 +#include "code/scopeDesc.hpp" 1.32 +#include "code/vtableStubs.hpp" 1.33 +#include "memory/resourceArea.hpp" 1.34 +#include "oops/oop.inline.hpp" 1.35 +#include "prims/jvmtiCodeBlobEvents.hpp" 1.36 +#include "prims/jvmtiExport.hpp" 1.37 +#include "runtime/handles.hpp" 1.38 +#include "runtime/handles.inline.hpp" 1.39 +#include "runtime/vmThread.hpp" 1.40 + 1.41 +// Support class to collect a list of the non-nmethod CodeBlobs in 1.42 +// the CodeCache. 1.43 +// 1.44 +// This class actually creates a list of JvmtiCodeBlobDesc - each JvmtiCodeBlobDesc 1.45 +// describes a single CodeBlob in the CodeCache. Note that collection is 1.46 +// done to a static list - this is because CodeCache::blobs_do is defined 1.47 +// as void CodeCache::blobs_do(void f(CodeBlob* nm)) and hence requires 1.48 +// a C or static method. 1.49 +// 1.50 +// Usage :- 1.51 +// 1.52 +// CodeBlobCollector collector; 1.53 +// 1.54 +// collector.collect(); 1.55 +// JvmtiCodeBlobDesc* blob = collector.first(); 1.56 +// while (blob != NULL) { 1.57 +// : 1.58 +// blob = collector.next(); 1.59 +// } 1.60 +// 1.61 + 1.62 +class CodeBlobCollector : StackObj { 1.63 + private: 1.64 + GrowableArray<JvmtiCodeBlobDesc*>* _code_blobs; // collected blobs 1.65 + int _pos; // iterator position 1.66 + 1.67 + // used during a collection 1.68 + static GrowableArray<JvmtiCodeBlobDesc*>* _global_code_blobs; 1.69 + static void do_blob(CodeBlob* cb); 1.70 + static void do_vtable_stub(VtableStub* vs); 1.71 + public: 1.72 + CodeBlobCollector() { 1.73 + _code_blobs = NULL; 1.74 + _pos = -1; 1.75 + } 1.76 + ~CodeBlobCollector() { 1.77 + if (_code_blobs != NULL) { 1.78 + for (int i=0; i<_code_blobs->length(); i++) { 1.79 + FreeHeap(_code_blobs->at(i)); 1.80 + } 1.81 + delete _code_blobs; 1.82 + } 1.83 + } 1.84 + 1.85 + // collect list of code blobs in the cache 1.86 + void collect(); 1.87 + 1.88 + // iteration support - return first code blob 1.89 + JvmtiCodeBlobDesc* first() { 1.90 + assert(_code_blobs != NULL, "not collected"); 1.91 + if (_code_blobs->length() == 0) { 1.92 + return NULL; 1.93 + } 1.94 + _pos = 0; 1.95 + return _code_blobs->at(0); 1.96 + } 1.97 + 1.98 + // iteration support - return next code blob 1.99 + JvmtiCodeBlobDesc* next() { 1.100 + assert(_pos >= 0, "iteration not started"); 1.101 + if (_pos+1 >= _code_blobs->length()) { 1.102 + return NULL; 1.103 + } 1.104 + return _code_blobs->at(++_pos); 1.105 + } 1.106 + 1.107 +}; 1.108 + 1.109 +// used during collection 1.110 +GrowableArray<JvmtiCodeBlobDesc*>* CodeBlobCollector::_global_code_blobs; 1.111 + 1.112 + 1.113 +// called for each CodeBlob in the CodeCache 1.114 +// 1.115 +// This function filters out nmethods as it is only interested in 1.116 +// other CodeBlobs. This function also filters out CodeBlobs that have 1.117 +// a duplicate starting address as previous blobs. This is needed to 1.118 +// handle the case where multiple stubs are generated into a single 1.119 +// BufferBlob. 1.120 + 1.121 +void CodeBlobCollector::do_blob(CodeBlob* cb) { 1.122 + 1.123 + // ignore nmethods 1.124 + if (cb->is_nmethod()) { 1.125 + return; 1.126 + } 1.127 + // exclude VtableStubs, which are processed separately 1.128 + if (cb->is_buffer_blob() && strcmp(cb->name(), "vtable chunks") == 0) { 1.129 + return; 1.130 + } 1.131 + 1.132 + // check if this starting address has been seen already - the 1.133 + // assumption is that stubs are inserted into the list before the 1.134 + // enclosing BufferBlobs. 1.135 + address addr = cb->code_begin(); 1.136 + for (int i=0; i<_global_code_blobs->length(); i++) { 1.137 + JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); 1.138 + if (addr == scb->code_begin()) { 1.139 + return; 1.140 + } 1.141 + } 1.142 + 1.143 + // record the CodeBlob details as a JvmtiCodeBlobDesc 1.144 + JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->code_begin(), cb->code_end()); 1.145 + _global_code_blobs->append(scb); 1.146 +} 1.147 + 1.148 +// called for each VtableStub in VtableStubs 1.149 + 1.150 +void CodeBlobCollector::do_vtable_stub(VtableStub* vs) { 1.151 + JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(vs->is_vtable_stub() ? "vtable stub" : "itable stub", 1.152 + vs->code_begin(), vs->code_end()); 1.153 + _global_code_blobs->append(scb); 1.154 +} 1.155 + 1.156 +// collects a list of CodeBlobs in the CodeCache. 1.157 +// 1.158 +// The created list is growable array of JvmtiCodeBlobDesc - each one describes 1.159 +// a CodeBlob. Note that the list is static - this is because CodeBlob::blobs_do 1.160 +// requires a a C or static function so we can't use an instance function. This 1.161 +// isn't a problem as the iteration is serial anyway as we need the CodeCache_lock 1.162 +// to iterate over the code cache. 1.163 +// 1.164 +// Note that the CodeBlobs in the CodeCache will include BufferBlobs that may 1.165 +// contain multiple stubs. As a profiler is interested in the stubs rather than 1.166 +// the enclosing container we first iterate over the stub code descriptors so 1.167 +// that the stubs go into the list first. do_blob will then filter out the 1.168 +// enclosing blobs if the starting address of the enclosing blobs matches the 1.169 +// starting address of first stub generated in the enclosing blob. 1.170 + 1.171 +void CodeBlobCollector::collect() { 1.172 + assert_locked_or_safepoint(CodeCache_lock); 1.173 + assert(_global_code_blobs == NULL, "checking"); 1.174 + 1.175 + // create the global list 1.176 + _global_code_blobs = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JvmtiCodeBlobDesc*>(50,true); 1.177 + 1.178 + // iterate over the stub code descriptors and put them in the list first. 1.179 + int index = 0; 1.180 + StubCodeDesc* desc; 1.181 + while ((desc = StubCodeDesc::desc_for_index(++index)) != NULL) { 1.182 + _global_code_blobs->append(new JvmtiCodeBlobDesc(desc->name(), desc->begin(), desc->end())); 1.183 + } 1.184 + 1.185 + // Vtable stubs are not described with StubCodeDesc, 1.186 + // process them separately 1.187 + VtableStubs::vtable_stub_do(do_vtable_stub); 1.188 + 1.189 + // next iterate over all the non-nmethod code blobs and add them to 1.190 + // the list - as noted above this will filter out duplicates and 1.191 + // enclosing blobs. 1.192 + CodeCache::blobs_do(do_blob); 1.193 + 1.194 + // make the global list the instance list so that it can be used 1.195 + // for other iterations. 1.196 + _code_blobs = _global_code_blobs; 1.197 + _global_code_blobs = NULL; 1.198 +} 1.199 + 1.200 + 1.201 +// Generate a DYNAMIC_CODE_GENERATED event for each non-nmethod code blob. 1.202 + 1.203 +jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { 1.204 + CodeBlobCollector collector; 1.205 + 1.206 + // First collect all the code blobs. This has to be done in a 1.207 + // single pass over the code cache with CodeCache_lock held because 1.208 + // there isn't any safe way to iterate over regular CodeBlobs since 1.209 + // they can be freed at any point. 1.210 + { 1.211 + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); 1.212 + collector.collect(); 1.213 + } 1.214 + 1.215 + // iterate over the collected list and post an event for each blob 1.216 + JvmtiCodeBlobDesc* blob = collector.first(); 1.217 + while (blob != NULL) { 1.218 + JvmtiExport::post_dynamic_code_generated(env, blob->name(), blob->code_begin(), blob->code_end()); 1.219 + blob = collector.next(); 1.220 + } 1.221 + return JVMTI_ERROR_NONE; 1.222 +} 1.223 + 1.224 + 1.225 +// Generate a COMPILED_METHOD_LOAD event for each nnmethod 1.226 +jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { 1.227 + HandleMark hm; 1.228 + 1.229 + // Walk the CodeCache notifying for live nmethods. The code cache 1.230 + // may be changing while this is happening which is ok since newly 1.231 + // created nmethod will notify normally and nmethods which are freed 1.232 + // can be safely skipped. 1.233 + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); 1.234 + nmethod* current = CodeCache::first_nmethod(); 1.235 + while (current != NULL) { 1.236 + // Only notify for live nmethods 1.237 + if (current->is_alive()) { 1.238 + // Lock the nmethod so it can't be freed 1.239 + nmethodLocker nml(current); 1.240 + 1.241 + // Don't hold the lock over the notify or jmethodID creation 1.242 + MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); 1.243 + current->get_and_cache_jmethod_id(); 1.244 + JvmtiExport::post_compiled_method_load(current); 1.245 + } 1.246 + current = CodeCache::next_nmethod(current); 1.247 + } 1.248 + return JVMTI_ERROR_NONE; 1.249 +} 1.250 + 1.251 + 1.252 +// create a C-heap allocated address location map for an nmethod 1.253 +void JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nmethod *nm, 1.254 + jvmtiAddrLocationMap** map_ptr, 1.255 + jint *map_length_ptr) 1.256 +{ 1.257 + ResourceMark rm; 1.258 + jvmtiAddrLocationMap* map = NULL; 1.259 + jint map_length = 0; 1.260 + 1.261 + 1.262 + // Generate line numbers using PcDesc and ScopeDesc info 1.263 + methodHandle mh(nm->method()); 1.264 + 1.265 + if (!mh->is_native()) { 1.266 + PcDesc *pcd; 1.267 + int pcds_in_method; 1.268 + 1.269 + pcds_in_method = (nm->scopes_pcs_end() - nm->scopes_pcs_begin()); 1.270 + map = NEW_C_HEAP_ARRAY(jvmtiAddrLocationMap, pcds_in_method, mtInternal); 1.271 + 1.272 + address scopes_data = nm->scopes_data_begin(); 1.273 + for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { 1.274 + ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); 1.275 + ScopeDesc *sd = &sc0; 1.276 + while( !sd->is_top() ) { sd = sd->sender(); } 1.277 + int bci = sd->bci(); 1.278 + if (bci != InvocationEntryBci) { 1.279 + assert(map_length < pcds_in_method, "checking"); 1.280 + map[map_length].start_address = (const void*)pcd->real_pc(nm); 1.281 + map[map_length].location = bci; 1.282 + ++map_length; 1.283 + } 1.284 + } 1.285 + } 1.286 + 1.287 + *map_ptr = map; 1.288 + *map_length_ptr = map_length; 1.289 +}