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