blob: e0a207701a974602fc6f8031e19b467735ae5d90 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * - Neither the name of Sun Microsystems nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/* This file contains all class, method and allocation event support functions,
33 * both JVMTI and BCI events.
34 * (See hprof_monitor.c for the monitor event handlers).
35 */
36
37#include "hprof.h"
38
39/* Private internal functions. */
40
41/* Return a TraceIndex for the given thread. */
42static TraceIndex
43get_current(TlsIndex tls_index, JNIEnv *env, jboolean skip_init)
44{
45 TraceIndex trace_index;
46
47 trace_index = tls_get_trace(tls_index, env, gdata->max_trace_depth, skip_init);
48 return trace_index;
49}
50
51/* Return a ClassIndex for the given jclass, loader supplied or looked up. */
52static ClassIndex
53find_cnum(JNIEnv *env, jclass klass, jobject loader)
54{
55 LoaderIndex loader_index;
56 ClassIndex cnum;
57 char * signature;
58
59 HPROF_ASSERT(klass!=NULL);
60
61 /* Get the loader index */
62 loader_index = loader_find_or_create(env, loader);
63
64 /* Get the signature for this class */
65 getClassSignature(klass, &signature, NULL);
66
67 /* Find the ClassIndex for this class */
68 cnum = class_find_or_create(signature, loader_index);
69
70 /* Free the signature space */
71 jvmtiDeallocate(signature);
72
73 /* Make sure we save a global reference to this class in the table */
74 HPROF_ASSERT(cnum!=0);
75 (void)class_new_classref(env, cnum, klass);
76 return cnum;
77}
78
79/* Get the ClassIndex for the superClass of this jclass. */
80static ClassIndex
81get_super(JNIEnv *env, jclass klass)
82{
83 ClassIndex super_cnum;
84
85 super_cnum = 0;
86 WITH_LOCAL_REFS(env, 1) {
87 jclass super_klass;
88
89 super_klass = getSuperclass(env, klass);
90 if ( super_klass != NULL ) {
91 super_cnum = find_cnum(env, super_klass,
92 getClassLoader(super_klass));
93 }
94 } END_WITH_LOCAL_REFS;
95 return super_cnum;
96}
97
98/* Record an allocation. Could be jobject, jclass, jarray or primitive type. */
99static void
100any_allocation(JNIEnv *env, SerialNumber thread_serial_num,
101 TraceIndex trace_index, jobject object)
102{
103 SiteIndex site_index;
104 ClassIndex cnum;
105 jint size;
106 jclass klass;
107
108 /* NOTE: Normally the getObjectClass() and getClassLoader()
109 * would require a
110 * WITH_LOCAL_REFS(env, 1) {
111 * } END_WITH_LOCAL_REFS;
112 * but for performance reasons we skip it here.
113 */
114
115 /* Get and tag the klass */
116 klass = getObjectClass(env, object);
117 cnum = find_cnum(env, klass, getClassLoader(klass));
118 site_index = site_find_or_create(cnum, trace_index);
119 tag_class(env, klass, cnum, thread_serial_num, site_index);
120
121 /* Tag the object */
122 size = (jint)getObjectSize(object);
123 tag_new_object(object, OBJECT_NORMAL, thread_serial_num, size, site_index);
124}
125
126/* Handle a java.lang.Object.<init> object allocation. */
127void
128event_object_init(JNIEnv *env, jthread thread, jobject object)
129{
130 /* Called via BCI Tracker class */
131
132 /* Be very careful what is called here, watch out for recursion. */
133
134 jint *pstatus;
135 TraceIndex trace_index;
136 SerialNumber thread_serial_num;
137
138 HPROF_ASSERT(env!=NULL);
139 HPROF_ASSERT(thread!=NULL);
140 HPROF_ASSERT(object!=NULL);
141
142 /* Prevent recursion into any BCI function for this thread (pstatus). */
143 if ( tls_get_tracker_status(env, thread, JNI_TRUE,
144 &pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) {
145 (*pstatus) = 1;
146 any_allocation(env, thread_serial_num, trace_index, object);
147 (*pstatus) = 0;
148 }
149}
150
151/* Handle any newarray opcode allocation. */
152void
153event_newarray(JNIEnv *env, jthread thread, jobject object)
154{
155 /* Called via BCI Tracker class */
156
157 /* Be very careful what is called here, watch out for recursion. */
158
159 jint *pstatus;
160 TraceIndex trace_index;
161 SerialNumber thread_serial_num;
162
163 HPROF_ASSERT(env!=NULL);
164 HPROF_ASSERT(thread!=NULL);
165 HPROF_ASSERT(object!=NULL);
166
167 /* Prevent recursion into any BCI function for this thread (pstatus). */
168 if ( tls_get_tracker_status(env, thread, JNI_FALSE,
169 &pstatus, NULL, &thread_serial_num, &trace_index) == 0 ) {
170 (*pstatus) = 1;
171 any_allocation(env, thread_serial_num, trace_index, object);
172 (*pstatus) = 0;
173 }
174}
175
176/* Handle tracking of a method call. */
177void
178event_call(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum)
179{
180 /* Called via BCI Tracker class */
181
182 /* Be very careful what is called here, watch out for recursion. */
183
184 TlsIndex tls_index;
185 jint *pstatus;
186
187 HPROF_ASSERT(env!=NULL);
188 HPROF_ASSERT(thread!=NULL);
189 HPROF_ASSERT(cnum!=0 && cnum!=gdata->tracker_cnum);
190
191 /* Prevent recursion into any BCI function for this thread (pstatus). */
192 if ( tls_get_tracker_status(env, thread, JNI_FALSE,
193 &pstatus, &tls_index, NULL, NULL) == 0 ) {
194 jmethodID method;
195
196 (*pstatus) = 1;
197 method = class_get_methodID(env, cnum, mnum);
198 HPROF_ASSERT(method!=NULL);
199 tls_push_method(tls_index, method);
200 (*pstatus) = 0;
201 }
202}
203
204/* Handle tracking of an exception catch */
205void
206event_exception_catch(JNIEnv *env, jthread thread, jmethodID method,
207 jlocation location, jobject exception)
208{
209 /* Called via JVMTI_EVENT_EXCEPTION_CATCH callback */
210
211 /* Be very careful what is called here, watch out for recursion. */
212
213 TlsIndex tls_index;
214 jint *pstatus;
215
216 HPROF_ASSERT(env!=NULL);
217 HPROF_ASSERT(thread!=NULL);
218 HPROF_ASSERT(method!=NULL);
219
220 /* Prevent recursion into any BCI function for this thread (pstatus). */
221 if ( tls_get_tracker_status(env, thread, JNI_FALSE,
222 &pstatus, &tls_index, NULL, NULL) == 0 ) {
223 (*pstatus) = 1;
224 tls_pop_exception_catch(tls_index, thread, method);
225 (*pstatus) = 0;
226 }
227}
228
229/* Handle tracking of a method return pop one (maybe more) methods. */
230void
231event_return(JNIEnv *env, jthread thread, ClassIndex cnum, MethodIndex mnum)
232{
233 /* Called via BCI Tracker class */
234
235 /* Be very careful what is called here, watch out for recursion. */
236
237 TlsIndex tls_index;
238 jint *pstatus;
239
240 HPROF_ASSERT(env!=NULL);
241 HPROF_ASSERT(thread!=NULL);
242 HPROF_ASSERT(cnum!=0 && cnum!=gdata->tracker_cnum);
243
244 /* Prevent recursion into any BCI function for this thread (pstatus). */
245 if ( tls_get_tracker_status(env, thread, JNI_FALSE,
246 &pstatus, &tls_index, NULL, NULL) == 0 ) {
247 jmethodID method;
248
249 (*pstatus) = 1;
250 method = class_get_methodID(env, cnum, mnum);
251 HPROF_ASSERT(method!=NULL);
252 tls_pop_method(tls_index, thread, method);
253 (*pstatus) = 0;
254 }
255}
256
257/* Handle a class prepare (should have been already loaded) */
258void
259event_class_prepare(JNIEnv *env, jthread thread, jclass klass, jobject loader)
260{
261 /* Called via JVMTI_EVENT_CLASS_PREPARE event */
262
263 ClassIndex cnum;
264
265 HPROF_ASSERT(env!=NULL);
266 HPROF_ASSERT(thread!=NULL);
267 HPROF_ASSERT(klass!=NULL);
268
269 /* Find the ClassIndex for this class */
270 cnum = find_cnum(env, klass, loader);
271 class_add_status(cnum, CLASS_PREPARED);
272
273}
274
275/* Handle a class load (could have been already loaded) */
276void
277event_class_load(JNIEnv *env, jthread thread, jclass klass, jobject loader)
278{
279 /* Called via JVMTI_EVENT_CLASS_LOAD event or reset_class_load_status() */
280
281 ClassIndex cnum;
282
283 HPROF_ASSERT(env!=NULL);
284 HPROF_ASSERT(klass!=NULL);
285
286 /* Find the ClassIndex for this class */
287 cnum = find_cnum(env, klass, loader);
288
289 /* Always mark it as being in the load list */
290 class_add_status(cnum, CLASS_IN_LOAD_LIST);
291
292 /* If we are seeing this as a new loaded class, extra work */
293 if ( ! ( class_get_status(cnum) & CLASS_LOADED ) ) {
294 TraceIndex trace_index;
295 SiteIndex site_index;
296 ClassIndex super;
297 SerialNumber class_serial_num;
298 SerialNumber trace_serial_num;
299 SerialNumber thread_serial_num;
300 ObjectIndex class_object_index;
301 char *signature;
302
303 /* Get the TlsIndex and a TraceIndex for this location */
304 if ( thread == NULL ) {
305 /* This should be very rare, but if this class load was simulated
306 * from hprof_init.c due to a reset of the class load status,
307 * and it originated from a pre-VM_INIT event, the jthread
308 * would be NULL, or it was a jclass created that didn't get
309 * reported to us, like an array class or a primitive class?
310 */
311 trace_index = gdata->system_trace_index;
312 thread_serial_num = gdata->unknown_thread_serial_num;
313 } else {
314 TlsIndex tls_index;
315
316 tls_index = tls_find_or_create(env, thread);
317 trace_index = get_current(tls_index, env, JNI_FALSE);
318 thread_serial_num = tls_get_thread_serial_number(tls_index);
319 }
320
321 /* Get the SiteIndex for this location and a java.lang.Class object */
322 /* Note that the target cnum, not the cnum for java.lang.Class. */
323 site_index = site_find_or_create(cnum, trace_index);
324
325 /* Tag this java.lang.Class object */
326 tag_class(env, klass, cnum, thread_serial_num, site_index);
327
328 class_add_status(cnum, CLASS_LOADED);
329
330 class_serial_num = class_get_serial_number(cnum);
331 class_object_index = class_get_object_index(cnum);
332 trace_serial_num = trace_get_serial_number(trace_index);
333 signature = string_get(class_get_signature(cnum));
334
335 rawMonitorEnter(gdata->data_access_lock); {
336 io_write_class_load(class_serial_num, class_object_index,
337 trace_serial_num, signature);
338 } rawMonitorExit(gdata->data_access_lock);
339
340 super = get_super(env, klass);
341 class_set_super(cnum, super);
342 }
343
344}
345
346/* Handle a thread start event */
347void
348event_thread_start(JNIEnv *env, jthread thread)
349{
350 /* Called via JVMTI_EVENT_THREAD_START event */
351
352 TlsIndex tls_index;
353 ObjectIndex object_index;
354 TraceIndex trace_index;
355 jlong tag;
356 SerialNumber thread_serial_num;
357
358 HPROF_ASSERT(env!=NULL);
359 HPROF_ASSERT(thread!=NULL);
360
361 tls_index = tls_find_or_create(env, thread);
362 thread_serial_num = tls_get_thread_serial_number(tls_index);
363 trace_index = get_current(tls_index, env, JNI_FALSE);
364
365 tag = getTag(thread);
366 if ( tag == (jlong)0 ) {
367 SiteIndex site_index;
368 jint size;
369
370 size = (jint)getObjectSize(thread);
371 site_index = site_find_or_create(gdata->thread_cnum, trace_index);
372 /* We create a new object with this thread's serial number */
373 object_index = object_new(site_index, size, OBJECT_NORMAL,
374 thread_serial_num);
375 } else {
376 object_index = tag_extract(tag);
377 /* Normally the Thread object is created and tagged before we get
378 * here, but the thread_serial_number on this object isn't what
379 * we want. So we update it to the serial number of this thread.
380 */
381 object_set_thread_serial_number(object_index, thread_serial_num);
382 }
383 tls_set_thread_object_index(tls_index, object_index);
384
385 WITH_LOCAL_REFS(env, 1) {
386 jvmtiThreadInfo threadInfo;
387 jvmtiThreadGroupInfo threadGroupInfo;
388 jvmtiThreadGroupInfo parentGroupInfo;
389
390 getThreadInfo(thread, &threadInfo);
391 getThreadGroupInfo(threadInfo.thread_group, &threadGroupInfo);
392 if ( threadGroupInfo.parent != NULL ) {
393 getThreadGroupInfo(threadGroupInfo.parent, &parentGroupInfo);
394 } else {
395 (void)memset(&parentGroupInfo, 0, sizeof(parentGroupInfo));
396 }
397
398 rawMonitorEnter(gdata->data_access_lock); {
399 io_write_thread_start(thread_serial_num,
400 object_index, trace_get_serial_number(trace_index),
401 threadInfo.name, threadGroupInfo.name, parentGroupInfo.name);
402 } rawMonitorExit(gdata->data_access_lock);
403
404 jvmtiDeallocate(threadInfo.name);
405 jvmtiDeallocate(threadGroupInfo.name);
406 jvmtiDeallocate(parentGroupInfo.name);
407
408 } END_WITH_LOCAL_REFS;
409}
410
411void
412event_thread_end(JNIEnv *env, jthread thread)
413{
414 /* Called via JVMTI_EVENT_THREAD_END event */
415 TlsIndex tls_index;
416
417 HPROF_ASSERT(env!=NULL);
418 HPROF_ASSERT(thread!=NULL);
419
420 tls_index = tls_find_or_create(env, thread);
421 rawMonitorEnter(gdata->data_access_lock); {
422 io_write_thread_end(tls_get_thread_serial_number(tls_index));
423 } rawMonitorExit(gdata->data_access_lock);
424 tls_thread_ended(env, tls_index);
425 setThreadLocalStorage(thread, (void*)NULL);
426}