blob: fe0637ec7d52e0b574495c68905fc38b8a675152 [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/* Tracker class support functions. */
33
34/*
35 * This file contains the native support calls for the Tracker
36 * class. These native methods are registered and not made extern.
37 * Tracking is engaged by using JNI to assign to a static field in the
38 * Tracker class.
39 *
40 * Just like JVMTI callbacks, it's best that we keep track of these so that
41 * when the VM_DEATH happens we know to wait for them to complete.
42 *
43 * This file also contains the functions that will initialize the Tracker
44 * interface for BCI and identify the Tracker methods to make sure
45 * they are not included in any stack traces obtained from JVMTI.
46 *
47 * RFE: The performance of the java injected code calling native methods
48 * could be an issue here, cpu=times seems to be the worst where
49 * a native call is made for entry and exit, even on the smallest
50 * Java method. The alternative would be to cache the data on
51 * the Java side, and either push it out to the native side, or
52 * use some kind of pull from the native side, or even using
53 * shared memory or a socket. However having said that, the
54 * current performance issues are more around sheer memory needed,
55 * and repeated calls to GetThreadCpuTime(), which is being investigated.
56 *
57 */
58
59#include "hprof.h"
60
61/* Macros to surround tracker based callback code.
62 * Also see BEGIN_CALLBACK and END_CALLBACK in hprof_init.c.
63 * If the VM_DEATH callback is active in the begining, then this callback
64 * just blocks (it is assumed we don't want to return to the VM).
65 * If the VM_DEATH callback is active at the end, then this callback
66 * will notify the VM_DEATH callback if it's the last one.
67 *
68 * WARNING: No not 'return' or 'goto' out of the BEGIN_TRACKER_CALLBACK/END_TRACKER_CALLBACK
69 * block, this will mess up the count.
70 */
71
72#define BEGIN_TRACKER_CALLBACK() \
73{ /* BEGIN OF TRACKER_CALLBACK */ \
74 jboolean bypass = JNI_TRUE; \
75 rawMonitorEnter(gdata->callbackLock); { \
76 if ( gdata->tracking_engaged != 0 ) { \
77 if (!gdata->vm_death_callback_active) { \
78 gdata->active_callbacks++; \
79 bypass = JNI_FALSE; \
80 } \
81 } \
82 } rawMonitorExit(gdata->callbackLock); \
83 if ( !bypass ) { \
84 /* BODY OF TRACKER_CALLBACK CODE */
85
86#define END_TRACKER_CALLBACK() /* Part of bypass if body */ \
87 rawMonitorEnter(gdata->callbackLock); { \
88 gdata->active_callbacks--; \
89 if (gdata->active_callbacks < 0) { \
90 HPROF_ERROR(JNI_TRUE, "Problems tracking callbacks"); \
91 } \
92 if (gdata->vm_death_callback_active) { \
93 if (gdata->active_callbacks == 0) { \
94 rawMonitorNotifyAll(gdata->callbackLock); \
95 } \
96 } \
97 } rawMonitorExit(gdata->callbackLock); \
98 } \
99} /* END OF TRACKER_CALLBACK */
100
101
102/*
103 * Class: Tracker
104 * Method: nativeNewArray
105 * Signature: (Ljava/lang/Object;Ljava/lang/Object;)V
106 */
107static void JNICALL
108Tracker_nativeNewArray
109 (JNIEnv *env, jclass clazz, jobject thread, jobject obj)
110{
111 BEGIN_TRACKER_CALLBACK() {
112 event_newarray(env, thread, obj);
113 } END_TRACKER_CALLBACK();
114}
115
116/*
117 * Class: Tracker
118 * Method: nativeObjectInit
119 * Signature: (Ljava/lang/Object;Ljava/lang/Object;)V
120 */
121static void JNICALL
122Tracker_nativeObjectInit
123 (JNIEnv *env, jclass clazz, jobject thread, jobject obj)
124{
125 BEGIN_TRACKER_CALLBACK() {
126 event_object_init(env, thread, obj);
127 } END_TRACKER_CALLBACK();
128}
129
130/*
131 * Class: Tracker
132 * Method: nativeCallSite
133 * Signature: (Ljava/lang/Object;II)V
134 */
135static void JNICALL
136Tracker_nativeCallSite
137 (JNIEnv *env, jclass clazz, jobject thread, jint cnum, jint mnum)
138{
139 BEGIN_TRACKER_CALLBACK() {
140 event_call(env, thread, cnum, mnum);
141 } END_TRACKER_CALLBACK();
142}
143
144/*
145 * Class: Tracker
146 * Method: nativeReturnSite
147 * Signature: (Ljava/lang/Object;II)V
148 */
149static void JNICALL
150Tracker_nativeReturnSite
151 (JNIEnv *env, jclass clazz, jobject thread, jint cnum, jint mnum)
152{
153 BEGIN_TRACKER_CALLBACK() {
154 event_return(env, thread, cnum, mnum);
155 } END_TRACKER_CALLBACK();
156}
157
158
159/* ------------------------------------------------------------------- */
160/* Set Java static field to turn on native code calls in Tracker. */
161
162static void
163set_engaged(JNIEnv *env, jint engaged)
164{
165 LOG3("set_engaged()", "engaging tracking", engaged);
166
167 if ( ! gdata->bci ) {
168 return;
169 }
170 rawMonitorEnter(gdata->callbackLock); {
171 if ( gdata->tracking_engaged != engaged ) {
172 jfieldID field;
173 jclass tracker_class;
174
175 tracker_class = class_get_class(env, gdata->tracker_cnum);
176 gdata->tracking_engaged = 0;
177 /* Activate or deactivate the injection code on the Java side */
178 HPROF_ASSERT(tracker_class!=NULL);
179 exceptionClear(env);
180 field = getStaticFieldID(env, tracker_class,
181 TRACKER_ENGAGED_NAME, TRACKER_ENGAGED_SIG);
182 setStaticIntField(env, tracker_class, field, engaged);
183 exceptionClear(env);
184
185 LOG3("set_engaged()", "tracking engaged", engaged);
186
187 gdata->tracking_engaged = engaged;
188 }
189 } rawMonitorExit(gdata->callbackLock);
190}
191
192void
193tracker_engage(JNIEnv *env)
194{
195 set_engaged(env, 0xFFFF);
196}
197
198void
199tracker_disengage(JNIEnv *env)
200{
201 set_engaged(env, 0);
202}
203
204jboolean
205tracker_method(jmethodID method)
206{
207 int i;
208
209 if ( ! gdata->bci ) {
210 return JNI_FALSE;
211 }
212
213 HPROF_ASSERT(method!=NULL);
214 HPROF_ASSERT(gdata->tracker_method_count > 0);
215 for ( i = 0 ; i < gdata->tracker_method_count ; i++ ) {
216 HPROF_ASSERT(gdata->tracker_methods[i].method!=NULL);
217 if ( method == gdata->tracker_methods[i].method ) {
218 return JNI_TRUE;
219 }
220 }
221 return JNI_FALSE;
222}
223
224static JNINativeMethod registry[4] =
225{
226 { TRACKER_NEWARRAY_NATIVE_NAME, TRACKER_NEWARRAY_NATIVE_SIG,
227 (void*)&Tracker_nativeNewArray },
228 { TRACKER_OBJECT_INIT_NATIVE_NAME, TRACKER_OBJECT_INIT_NATIVE_SIG,
229 (void*)&Tracker_nativeObjectInit },
230 { TRACKER_CALL_NATIVE_NAME, TRACKER_CALL_NATIVE_SIG,
231 (void*)&Tracker_nativeCallSite },
232 { TRACKER_RETURN_NATIVE_NAME, TRACKER_RETURN_NATIVE_SIG,
233 (void*)&Tracker_nativeReturnSite }
234};
235
236static struct {
237 char *name;
238 char *sig;
239} tracker_methods[] =
240 {
241 { TRACKER_NEWARRAY_NAME, TRACKER_NEWARRAY_SIG },
242 { TRACKER_OBJECT_INIT_NAME, TRACKER_OBJECT_INIT_SIG },
243 { TRACKER_CALL_NAME, TRACKER_CALL_SIG },
244 { TRACKER_RETURN_NAME, TRACKER_RETURN_SIG },
245 { TRACKER_NEWARRAY_NATIVE_NAME, TRACKER_NEWARRAY_NATIVE_SIG },
246 { TRACKER_OBJECT_INIT_NATIVE_NAME, TRACKER_OBJECT_INIT_NATIVE_SIG },
247 { TRACKER_CALL_NATIVE_NAME, TRACKER_CALL_NATIVE_SIG },
248 { TRACKER_RETURN_NATIVE_NAME, TRACKER_RETURN_NATIVE_SIG }
249 };
250
251void
252tracker_setup_class(void)
253{
254 ClassIndex cnum;
255 LoaderIndex loader_index;
256
257 HPROF_ASSERT(gdata->tracker_cnum==0);
258 loader_index = loader_find_or_create(NULL,NULL);
259 cnum = class_find_or_create(TRACKER_CLASS_SIG, loader_index);
260 gdata->tracker_cnum = cnum;
261 HPROF_ASSERT(cnum!=0);
262 class_add_status(cnum, CLASS_SPECIAL);
263}
264
265void
266tracker_setup_methods(JNIEnv *env)
267{
268 ClassIndex cnum;
269 LoaderIndex loader_index;
270 int i;
271 jclass object_class;
272 jclass tracker_class;
273
274 if ( ! gdata->bci ) {
275 return;
276 }
277
278 loader_index = loader_find_or_create(NULL,NULL);
279 cnum = class_find_or_create(OBJECT_CLASS_SIG, loader_index);
280 object_class = class_get_class(env, cnum);
281 tracker_class = class_get_class(env, gdata->tracker_cnum);
282
283 CHECK_EXCEPTIONS(env) {
284 registerNatives(env, tracker_class, registry,
285 (int)sizeof(registry)/(int)sizeof(registry[0]));
286 } END_CHECK_EXCEPTIONS;
287
288 HPROF_ASSERT(tracker_class!=NULL);
289
290 gdata->tracker_method_count =
291 (int)sizeof(tracker_methods)/(int)sizeof(tracker_methods[0]);
292
293 HPROF_ASSERT(gdata->tracker_method_count <=
294 (int)(sizeof(gdata->tracker_methods)/sizeof(gdata->tracker_methods[0])));
295
296 CHECK_EXCEPTIONS(env) {
297 gdata->object_init_method = getMethodID(env, object_class,
298 OBJECT_INIT_NAME, OBJECT_INIT_SIG);
299 for ( i=0 ; i < gdata->tracker_method_count ; i++ ) {
300 gdata->tracker_methods[i].name =
301 string_find_or_create(tracker_methods[i].name);
302 gdata->tracker_methods[i].sig =
303 string_find_or_create(tracker_methods[i].sig);
304 gdata->tracker_methods[i].method =
305 getStaticMethodID(env, tracker_class,
306 tracker_methods[i].name, tracker_methods[i].sig);
307 HPROF_ASSERT(gdata->tracker_methods[i].method!=NULL);
308 LOG2("tracker_setup_methods(): Found", tracker_methods[i].name);
309 }
310 } END_CHECK_EXCEPTIONS;
311}