Mercurial > hg > graal-compiler
annotate src/share/vm/prims/jvmtiCodeBlobEvents.cpp @ 6972:bd7a7ce2e264
6830717: replay of compilations would help with debugging
Summary: When java process crashed in compiler thread, repeat the compilation process will help finding root cause. This is done with using SA dump application class data and replay data from core dump, then use debug version of jvm to recompile the problematic java method.
Reviewed-by: kvn, twisti, sspitsyn
Contributed-by: yumin.qi@oracle.com
author | minqi |
---|---|
date | Mon, 12 Nov 2012 14:03:53 -0800 |
parents | b9a9ed0f8eeb |
children | e522a00b91aa 9341a9963d36 |
rev | line source |
---|---|
0 | 1 /* |
6842
b9a9ed0f8eeb
7197424: update copyright year to match last edit in jdk8 hotspot repository
mikael
parents:
6197
diff
changeset
|
2 * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1253
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1253
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
1253
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "code/codeBlob.hpp" | |
27 #include "code/codeCache.hpp" | |
28 #include "code/scopeDesc.hpp" | |
29 #include "memory/resourceArea.hpp" | |
30 #include "oops/oop.inline.hpp" | |
31 #include "prims/jvmtiCodeBlobEvents.hpp" | |
32 #include "prims/jvmtiExport.hpp" | |
33 #include "runtime/handles.hpp" | |
34 #include "runtime/handles.inline.hpp" | |
35 #include "runtime/vmThread.hpp" | |
0 | 36 |
37 // Support class to collect a list of the non-nmethod CodeBlobs in | |
38 // the CodeCache. | |
39 // | |
40 // This class actually creates a list of JvmtiCodeBlobDesc - each JvmtiCodeBlobDesc | |
41 // describes a single CodeBlob in the CodeCache. Note that collection is | |
42 // done to a static list - this is because CodeCache::blobs_do is defined | |
43 // as void CodeCache::blobs_do(void f(CodeBlob* nm)) and hence requires | |
44 // a C or static method. | |
45 // | |
46 // Usage :- | |
47 // | |
48 // CodeBlobCollector collector; | |
49 // | |
50 // collector.collect(); | |
51 // JvmtiCodeBlobDesc* blob = collector.first(); | |
52 // while (blob != NULL) { | |
53 // : | |
54 // blob = collector.next(); | |
55 // } | |
56 // | |
57 | |
58 class CodeBlobCollector : StackObj { | |
59 private: | |
60 GrowableArray<JvmtiCodeBlobDesc*>* _code_blobs; // collected blobs | |
61 int _pos; // iterator position | |
62 | |
63 // used during a collection | |
64 static GrowableArray<JvmtiCodeBlobDesc*>* _global_code_blobs; | |
65 static void do_blob(CodeBlob* cb); | |
66 public: | |
67 CodeBlobCollector() { | |
68 _code_blobs = NULL; | |
69 _pos = -1; | |
70 } | |
71 ~CodeBlobCollector() { | |
72 if (_code_blobs != NULL) { | |
73 for (int i=0; i<_code_blobs->length(); i++) { | |
74 FreeHeap(_code_blobs->at(i)); | |
75 } | |
76 delete _code_blobs; | |
77 } | |
78 } | |
79 | |
80 // collect list of code blobs in the cache | |
81 void collect(); | |
82 | |
83 // iteration support - return first code blob | |
84 JvmtiCodeBlobDesc* first() { | |
85 assert(_code_blobs != NULL, "not collected"); | |
86 if (_code_blobs->length() == 0) { | |
87 return NULL; | |
88 } | |
89 _pos = 0; | |
90 return _code_blobs->at(0); | |
91 } | |
92 | |
93 // iteration support - return next code blob | |
94 JvmtiCodeBlobDesc* next() { | |
95 assert(_pos >= 0, "iteration not started"); | |
96 if (_pos+1 >= _code_blobs->length()) { | |
97 return NULL; | |
98 } | |
99 return _code_blobs->at(++_pos); | |
100 } | |
101 | |
102 }; | |
103 | |
104 // used during collection | |
105 GrowableArray<JvmtiCodeBlobDesc*>* CodeBlobCollector::_global_code_blobs; | |
106 | |
107 | |
108 // called for each CodeBlob in the CodeCache | |
109 // | |
110 // This function filters out nmethods as it is only interested in | |
111 // other CodeBlobs. This function also filters out CodeBlobs that have | |
112 // a duplicate starting address as previous blobs. This is needed to | |
113 // handle the case where multiple stubs are generated into a single | |
114 // BufferBlob. | |
115 | |
116 void CodeBlobCollector::do_blob(CodeBlob* cb) { | |
117 | |
118 // ignore nmethods | |
119 if (cb->is_nmethod()) { | |
120 return; | |
121 } | |
122 | |
123 // check if this starting address has been seen already - the | |
124 // assumption is that stubs are inserted into the list before the | |
125 // enclosing BufferBlobs. | |
1748 | 126 address addr = cb->code_begin(); |
0 | 127 for (int i=0; i<_global_code_blobs->length(); i++) { |
128 JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); | |
129 if (addr == scb->code_begin()) { | |
130 return; | |
131 } | |
132 } | |
133 | |
134 // record the CodeBlob details as a JvmtiCodeBlobDesc | |
1748 | 135 JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->code_begin(), cb->code_end()); |
0 | 136 _global_code_blobs->append(scb); |
137 } | |
138 | |
139 | |
140 // collects a list of CodeBlobs in the CodeCache. | |
141 // | |
142 // The created list is growable array of JvmtiCodeBlobDesc - each one describes | |
143 // a CodeBlob. Note that the list is static - this is because CodeBlob::blobs_do | |
144 // requires a a C or static function so we can't use an instance function. This | |
145 // isn't a problem as the iteration is serial anyway as we need the CodeCache_lock | |
146 // to iterate over the code cache. | |
147 // | |
148 // Note that the CodeBlobs in the CodeCache will include BufferBlobs that may | |
149 // contain multiple stubs. As a profiler is interested in the stubs rather than | |
150 // the enclosing container we first iterate over the stub code descriptors so | |
151 // that the stubs go into the list first. do_blob will then filter out the | |
152 // enclosing blobs if the starting address of the enclosing blobs matches the | |
153 // starting address of first stub generated in the enclosing blob. | |
154 | |
155 void CodeBlobCollector::collect() { | |
156 assert_locked_or_safepoint(CodeCache_lock); | |
157 assert(_global_code_blobs == NULL, "checking"); | |
158 | |
159 // create the global list | |
6197 | 160 _global_code_blobs = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<JvmtiCodeBlobDesc*>(50,true); |
0 | 161 |
162 // iterate over the stub code descriptors and put them in the list first. | |
163 int index = 0; | |
164 StubCodeDesc* desc; | |
165 while ((desc = StubCodeDesc::desc_for_index(++index)) != NULL) { | |
166 _global_code_blobs->append(new JvmtiCodeBlobDesc(desc->name(), desc->begin(), desc->end())); | |
167 } | |
168 | |
169 // next iterate over all the non-nmethod code blobs and add them to | |
170 // the list - as noted above this will filter out duplicates and | |
171 // enclosing blobs. | |
172 CodeCache::blobs_do(do_blob); | |
173 | |
174 // make the global list the instance list so that it can be used | |
175 // for other iterations. | |
176 _code_blobs = _global_code_blobs; | |
177 _global_code_blobs = NULL; | |
178 } | |
179 | |
180 | |
181 // Generate a DYNAMIC_CODE_GENERATED event for each non-nmethod code blob. | |
182 | |
183 jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { | |
184 CodeBlobCollector collector; | |
185 | |
1633
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
186 // First collect all the code blobs. This has to be done in a |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
187 // single pass over the code cache with CodeCache_lock held because |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
188 // there isn't any safe way to iterate over regular CodeBlobs since |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
189 // they can be freed at any point. |
0 | 190 { |
191 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); | |
192 collector.collect(); | |
193 } | |
194 | |
195 // iterate over the collected list and post an event for each blob | |
196 JvmtiCodeBlobDesc* blob = collector.first(); | |
197 while (blob != NULL) { | |
198 JvmtiExport::post_dynamic_code_generated(env, blob->name(), blob->code_begin(), blob->code_end()); | |
199 blob = collector.next(); | |
200 } | |
201 return JVMTI_ERROR_NONE; | |
202 } | |
203 | |
204 | |
205 // Generate a COMPILED_METHOD_LOAD event for each nnmethod | |
206 jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { | |
207 HandleMark hm; | |
208 | |
1633
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
209 // Walk the CodeCache notifying for live nmethods. The code cache |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
210 // may be changing while this is happening which is ok since newly |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
211 // created nmethod will notify normally and nmethods which are freed |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
212 // can be safely skipped. |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
213 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
214 nmethod* current = CodeCache::first_nmethod(); |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
215 while (current != NULL) { |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
216 // Only notify for live nmethods |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
217 if (current->is_alive()) { |
1649
a528509c992b
6968336: VM crash guarantee(!nm->is_zombie()) failed: cannot lock a zombie method
never
parents:
1633
diff
changeset
|
218 // Lock the nmethod so it can't be freed |
a528509c992b
6968336: VM crash guarantee(!nm->is_zombie()) failed: cannot lock a zombie method
never
parents:
1633
diff
changeset
|
219 nmethodLocker nml(current); |
a528509c992b
6968336: VM crash guarantee(!nm->is_zombie()) failed: cannot lock a zombie method
never
parents:
1633
diff
changeset
|
220 |
1633
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
221 // Don't hold the lock over the notify or jmethodID creation |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
222 MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
223 current->get_and_cache_jmethod_id(); |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
224 JvmtiExport::post_compiled_method_load(current); |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
225 } |
65b0c03b165d
6965671: fatal error: acquiring lock JNIGlobalHandle_lock/16 out of order with lock CodeCache_lock/1
never
parents:
1616
diff
changeset
|
226 current = CodeCache::next_nmethod(current); |
0 | 227 } |
228 return JVMTI_ERROR_NONE; | |
229 } | |
230 | |
231 | |
232 // create a C-heap allocated address location map for an nmethod | |
233 void JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nmethod *nm, | |
234 jvmtiAddrLocationMap** map_ptr, | |
235 jint *map_length_ptr) | |
236 { | |
237 ResourceMark rm; | |
238 jvmtiAddrLocationMap* map = NULL; | |
239 jint map_length = 0; | |
240 | |
241 | |
242 // Generate line numbers using PcDesc and ScopeDesc info | |
243 methodHandle mh(nm->method()); | |
244 | |
245 if (!mh->is_native()) { | |
246 PcDesc *pcd; | |
247 int pcds_in_method; | |
248 | |
249 pcds_in_method = (nm->scopes_pcs_end() - nm->scopes_pcs_begin()); | |
6197 | 250 map = NEW_C_HEAP_ARRAY(jvmtiAddrLocationMap, pcds_in_method, mtInternal); |
0 | 251 |
252 address scopes_data = nm->scopes_data_begin(); | |
253 for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) { | |
1253
f70b0d9ab095
6910618: C2: Error: assert(d->is_oop(),"JVM_ArrayCopy: dst not an oop")
kvn
parents:
931
diff
changeset
|
254 ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop()); |
0 | 255 ScopeDesc *sd = &sc0; |
256 while( !sd->is_top() ) { sd = sd->sender(); } | |
257 int bci = sd->bci(); | |
258 if (bci != InvocationEntryBci) { | |
259 assert(map_length < pcds_in_method, "checking"); | |
260 map[map_length].start_address = (const void*)pcd->real_pc(nm); | |
261 map[map_length].location = bci; | |
262 ++map_length; | |
263 } | |
264 } | |
265 } | |
266 | |
267 *map_ptr = map; | |
268 *map_length_ptr = map_length; | |
269 } |