1 /*
   2  * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
   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  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include <string.h>
  25 #include "jvmti.h"
  26 #include "agent_common.h"
  27 #include "jni_tools.h"
  28 #include "jvmti_tools.h"
  29 
  30 extern "C" {
  31 
  32 /* ============================================================================= */
  33 
  34 /* scaffold objects */
  35 static JNIEnv* jni = NULL;
  36 static jvmtiEnv *jvmti = NULL;
  37 static jlong timeout = 0;
  38 
  39 /* constant names */
  40 #define DEBUGEE_CLASS_NAME      "nsk/jvmti/scenarios/events/EM05/em05t002"
  41 #define THREAD_CLASS_NAME       "nsk/jvmti/scenarios/events/EM05/em05t002Thread"
  42 #define THREAD_FIELD_NAME       "thread"
  43 #define THREAD_FIELD_SIG        "L" THREAD_CLASS_NAME ";"
  44 
  45 /* constants */
  46 #define MAX_NAME_LENGTH         64
  47 #define EVENTS_COUNT            2
  48 #define METHODS_COUNT           2
  49 #define MOMENTS_COUNT           3
  50 
  51 /* compilation moments */
  52 #define COMPILATION_MOMENT_BEFORE       0
  53 #define COMPILATION_MOMENT_RUNNING      1
  54 #define COMPILATION_MOMENT_AFTER        2
  55 
  56 /* tested events */
  57 static jvmtiEvent eventsList[EVENTS_COUNT] = {
  58     JVMTI_EVENT_COMPILED_METHOD_LOAD,
  59     JVMTI_EVENT_COMPILED_METHOD_UNLOAD
  60 };
  61 
  62 /* method description structure */
  63 typedef struct {
  64     char methodName[MAX_NAME_LENGTH];
  65     char methodSig[MAX_NAME_LENGTH];
  66     jmethodID method;
  67     int compiled;
  68     int loadEvents[MOMENTS_COUNT];
  69     int unloadEvents[MOMENTS_COUNT];
  70 } MethodDesc;
  71 
  72 /* descriptions of tested methods */
  73 static MethodDesc methodsDesc[METHODS_COUNT] = {
  74     {"javaMethod", "(I)I", NULL, 0, {}, {} },
  75     {"nativeMethod", "(I)I", NULL, 0, {}, {} }
  76 };
  77 
  78 /* current compilation moment */
  79 static volatile int moment = COMPILATION_MOMENT_BEFORE;
  80 
  81 /* ============================================================================= */
  82 
  83 /* testcase(s) */
  84 static int prepare();
  85 static int generateEvents();
  86 static int checkEvents();
  87 static int clean();
  88 
  89 /* ============================================================================= */
  90 
  91 /** Agent algorithm. */
  92 static void JNICALL
  93 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
  94     jni = agentJNI;
  95 
  96     NSK_DISPLAY0("Wait for debuggee to become ready\n");
  97     if (!nsk_jvmti_waitForSync(timeout))
  98         return;
  99 
 100     {
 101         NSK_DISPLAY0("Prepare data\n");
 102         if (!prepare()) {
 103             nsk_jvmti_setFailStatus();
 104             return;
 105         }
 106 
 107         NSK_DISPLAY0("Testcase #1: generate events before running thread\n");
 108         moment = COMPILATION_MOMENT_BEFORE;
 109         NSK_DISPLAY0("Call GenerateEvents() before running methods\n");
 110         if (!generateEvents())
 111             return;
 112         NSK_DISPLAY0("Check if events received\n");
 113         if (!checkEvents())
 114             return;
 115 
 116         NSK_DISPLAY0("Testcase #2: run methods to provoke compilation\n");
 117         moment = COMPILATION_MOMENT_RUNNING;
 118         NSK_DISPLAY0("Provoke methods compilation\n");
 119         if (!nsk_jvmti_resumeSync())
 120             return;
 121         NSK_DISPLAY0("Wait for thread to completed\n");
 122         if (!nsk_jvmti_waitForSync(timeout))
 123             return;
 124         NSK_DISPLAY0("Check if events received\n");
 125         if (!checkEvents())
 126             return;
 127 
 128         NSK_DISPLAY0("Testcase #3: generate events before running thread\n");
 129         moment = COMPILATION_MOMENT_AFTER;
 130         NSK_DISPLAY0("Call GenerateEvents() after running methods\n");
 131         if (!generateEvents())
 132             return;
 133         NSK_DISPLAY0("Check if events received\n");
 134         if (!checkEvents())
 135             return;
 136 
 137         NSK_DISPLAY0("Clean data\n");
 138         if (!clean()) {
 139             nsk_jvmti_setFailStatus();
 140             return;
 141         }
 142     }
 143 
 144     NSK_DISPLAY0("Let debuggee to finish\n");
 145     if (!nsk_jvmti_resumeSync())
 146         return;
 147 }
 148 
 149 /* ============================================================================= */
 150 
 151 /**
 152  * Generate tested events (COMPILED_METHOD_LOAD only).
 153  */
 154 static int generateEvents() {
 155     if (!NSK_JVMTI_VERIFY(jvmti->GenerateEvents(JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
 156         nsk_jvmti_setFailStatus();
 157         return NSK_FALSE;
 158     }
 159     return NSK_TRUE;
 160 }
 161 
 162 /**
 163  * Prepare data.
 164  *    - find tested thread
 165  *    - get tested methodIDs
 166  *    - enable events
 167  */
 168 static int prepare() {
 169     jclass debugeeClass = NULL;
 170     jclass threadClass = NULL;
 171     jfieldID threadFieldID = NULL;
 172     jthread thread = NULL;
 173     int i;
 174 
 175     for (i = 0; i < METHODS_COUNT; i++) {
 176         int j;
 177         methodsDesc[i].method = (jmethodID)NULL;
 178         methodsDesc[i].compiled = NSK_FALSE;
 179         for (j = 0; j < MOMENTS_COUNT; j++) {
 180             methodsDesc[i].loadEvents[j] = 0;
 181             methodsDesc[i].unloadEvents[j] = 0;
 182         }
 183     }
 184 
 185     if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL))
 186         return NSK_FALSE;
 187 
 188     if (!NSK_JNI_VERIFY(jni, (threadFieldID =
 189             jni->GetStaticFieldID(debugeeClass, THREAD_FIELD_NAME, THREAD_FIELD_SIG)) != NULL))
 190         return NSK_FALSE;
 191 
 192     if (!NSK_JNI_VERIFY(jni, (thread = (jthread)
 193             jni->GetStaticObjectField(debugeeClass, threadFieldID)) != NULL))
 194         return NSK_FALSE;
 195 
 196     if (!NSK_JNI_VERIFY(jni, (threadClass = jni->GetObjectClass(thread)) != NULL))
 197         return NSK_FALSE;
 198 
 199     NSK_DISPLAY0("Find tested methods:\n");
 200     for (i = 0; i < METHODS_COUNT; i++) {
 201         if (!NSK_JNI_VERIFY(jni, (methodsDesc[i].method =
 202                 jni->GetMethodID(threadClass, methodsDesc[i].methodName, methodsDesc[i].methodSig)) != NULL))
 203             return NSK_FALSE;
 204         NSK_DISPLAY3("    method #%d (%s): 0x%p\n",
 205                                 i, methodsDesc[i].methodName, (void*)methodsDesc[i].method);
 206     }
 207 
 208     NSK_DISPLAY0("Enable events\n");
 209     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
 210         return NSK_FALSE;
 211 
 212     return NSK_TRUE;
 213 }
 214 
 215 /**
 216  * Testcase: check tested events.
 217  *   - check if expected events received for each method
 218  *
 219  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
 220  */
 221 static int checkEvents() {
 222     int i;
 223 
 224     for (i = 0; i < METHODS_COUNT; i++) {
 225         NSK_DISPLAY2("  method #%d (%s):\n",
 226                                 i, methodsDesc[i].methodName);
 227         NSK_DISPLAY2("    COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 228                                 methodsDesc[i].loadEvents[moment],
 229                                 methodsDesc[i].unloadEvents[moment]);
 230 
 231         if (moment == COMPILATION_MOMENT_AFTER) {
 232             int loadEventsTotal = methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE]
 233                                 + methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING];
 234             int unloadEventsTotal = methodsDesc[i].unloadEvents[COMPILATION_MOMENT_BEFORE]
 235                                   + methodsDesc[i].unloadEvents[COMPILATION_MOMENT_RUNNING];
 236 
 237             /* complain if no COMPILED_METHOD_LOAD events finally generated for compiled events */
 238             if (methodsDesc[i].compiled) {
 239                 if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
 240                     NSK_COMPLAIN4("No COMPILED_METHOD_LOAD events finally generated for compiled method: %s\n"
 241                               "#   total COMPILED_METHOD_LOAD:   %d\n"
 242                               "#   total COMPILED_METHOD_UNLOAD: %d\n"
 243                               "#         final GenerateEvents(): %d\n",
 244                                 methodsDesc[i].methodName,
 245                                 loadEventsTotal,
 246                                 unloadEventsTotal,
 247                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
 248                     nsk_jvmti_setFailStatus();
 249                 }
 250             }
 251 
 252             /* complain if too many COMPILED_METHOD_LOAD events finally generated */
 253             if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
 254                 NSK_COMPLAIN5("Too many COMPILED_METHOD_LOAD events finally generated for method: %s\n"
 255                               "#   GenerateEvents() before execution: %d\n"
 256                               "#   generated during execution:        %d\n"
 257                               "#                    total:            %d\n"
 258                               "#   GenerateEvents() after execution:  %d\n",
 259                                 methodsDesc[i].methodName,
 260                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE],
 261                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING],
 262                                 loadEventsTotal,
 263                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
 264                 nsk_jvmti_setFailStatus();
 265             }
 266 
 267             /* warn if too mamy COMPILED_METHOD_UNLOAD events received */
 268             if (unloadEventsTotal > loadEventsTotal) {
 269                 NSK_DISPLAY1("# WARNING: Too many COMPILED_METHOD_UNLOAD events for method: %s\n",
 270                                     methodsDesc[i].methodName);
 271                 NSK_DISPLAY2("#   COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 272                                     loadEventsTotal, unloadEventsTotal);
 273             }
 274         }
 275     }
 276     return NSK_TRUE;
 277 }
 278 
 279 /**
 280  * Clean data.
 281  *   - disable events
 282  */
 283 static int clean() {
 284     NSK_DISPLAY0("Disable events\n");
 285     if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
 286         return NSK_FALSE;
 287 
 288     return NSK_TRUE;
 289 }
 290 
 291 /* ============================================================================= */
 292 
 293 /**
 294  * COMPILED_METHOD_LOAD callback.
 295  *   - turm on flag that method is compiled
 296  */
 297 JNIEXPORT void JNICALL
 298 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
 299                             jint code_size, const void* code_addr,
 300                             jint map_length, const jvmtiAddrLocationMap* map,
 301                             const void* compile_info) {
 302     int i;
 303 
 304     /* check if event is for tested method and count it */
 305     for (i = 0; i < METHODS_COUNT; i++) {
 306         if (methodsDesc[i].method == method) {
 307             methodsDesc[i].loadEvents[moment]++;
 308             methodsDesc[i].compiled = NSK_TRUE;
 309 
 310             NSK_DISPLAY3("  COMPILED_METHOD_LOAD for method #%d (%s): %d times\n",
 311                                 i, methodsDesc[i].methodName,
 312                                 methodsDesc[i].loadEvents[moment]);
 313             NSK_DISPLAY1("    methodID:   0x%p\n",
 314                                 (void*)methodsDesc[i].method);
 315             NSK_DISPLAY1("    code_size:  %d\n",
 316                                 (int)code_size);
 317             NSK_DISPLAY1("    map_length: %d\n",
 318                                 (int)map_length);
 319             break;
 320         }
 321     }
 322 }
 323 
 324 /**
 325  * COMPILED_METHOD_UNLOAD callback.
 326  *   - turn off flag that method is compiled
 327  */
 328 JNIEXPORT void JNICALL
 329 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
 330                              const void* code_addr) {
 331     int i;
 332 
 333     /* check if event is for tested method and count it */
 334     for (i = 0; i < METHODS_COUNT; i++) {
 335         if (methodsDesc[i].method == method) {
 336             methodsDesc[i].unloadEvents[moment]++;
 337             methodsDesc[i].compiled = NSK_FALSE;
 338 
 339             NSK_DISPLAY3("  COMPILED_METHOD_UNLOAD for method #%d (%s): %d times\n",
 340                                 i, methodsDesc[i].methodName,
 341                                 methodsDesc[i].loadEvents[moment]);
 342             NSK_DISPLAY1("    methodID:   0x%p\n",
 343                                 (void*)methodsDesc[i].method);
 344             break;
 345         }
 346     }
 347 }
 348 
 349 /* ============================================================================= */
 350 
 351 /** Native running method in tested thread. */
 352 JNIEXPORT jint JNICALL
 353 Java_nsk_jvmti_scenarios_events_EM05_em05t002Thread_nativeMethod(JNIEnv* jni,
 354                                                                     jobject obj, jint i) {
 355     jint k = 0;
 356     jint j;
 357 
 358     for (j = 0; j < i; j++) {
 359         k += (i - j);
 360     }
 361     return k;
 362 }
 363 
 364 /* ============================================================================= */
 365 
 366 /** Agent library initialization. */
 367 #ifdef STATIC_BUILD
 368 JNIEXPORT jint JNICALL Agent_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
 369     return Agent_Initialize(jvm, options, reserved);
 370 }
 371 JNIEXPORT jint JNICALL Agent_OnAttach_em05t002(JavaVM *jvm, char *options, void *reserved) {
 372     return Agent_Initialize(jvm, options, reserved);
 373 }
 374 JNIEXPORT jint JNI_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
 375     return JNI_VERSION_1_8;
 376 }
 377 #endif
 378 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 379 
 380     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 381         return JNI_ERR;
 382 
 383     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 384 
 385     if (!NSK_VERIFY((jvmti =
 386             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 387         return JNI_ERR;
 388 
 389     {
 390         jvmtiCapabilities caps;
 391         memset(&caps, 0, sizeof(caps));
 392         caps.can_generate_compiled_method_load_events = 1;
 393         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
 394             return JNI_ERR;
 395     }
 396 
 397     {
 398         jvmtiEventCallbacks eventCallbacks;
 399         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 400         eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
 401         eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
 402         if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
 403             return JNI_ERR;
 404     }
 405 
 406     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 407         return JNI_ERR;
 408 
 409     return JNI_OK;
 410 }
 411 
 412 /* ============================================================================= */
 413 
 414 }