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(
 156             NSK_CPP_STUB2(GenerateEvents, jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD))) {
 157         nsk_jvmti_setFailStatus();
 158         return NSK_FALSE;
 159     }
 160     return NSK_TRUE;
 161 }
 162 
 163 /**
 164  * Prepare data.
 165  *    - find tested thread
 166  *    - get tested methodIDs
 167  *    - enable events
 168  */
 169 static int prepare() {
 170     jclass debugeeClass = NULL;
 171     jclass threadClass = NULL;
 172     jfieldID threadFieldID = NULL;
 173     jthread thread = NULL;
 174     int i;
 175 
 176     for (i = 0; i < METHODS_COUNT; i++) {
 177         int j;
 178         methodsDesc[i].method = (jmethodID)NULL;
 179         methodsDesc[i].compiled = NSK_FALSE;
 180         for (j = 0; j < MOMENTS_COUNT; j++) {
 181             methodsDesc[i].loadEvents[j] = 0;
 182             methodsDesc[i].unloadEvents[j] = 0;
 183         }
 184     }
 185 
 186     if (!NSK_JNI_VERIFY(jni, (debugeeClass =
 187             NSK_CPP_STUB2(FindClass, jni, DEBUGEE_CLASS_NAME)) != NULL))
 188         return NSK_FALSE;
 189 
 190     if (!NSK_JNI_VERIFY(jni, (threadFieldID =
 191             NSK_CPP_STUB4(GetStaticFieldID, jni, debugeeClass,
 192                                     THREAD_FIELD_NAME, THREAD_FIELD_SIG)) != NULL))
 193         return NSK_FALSE;
 194 
 195     if (!NSK_JNI_VERIFY(jni, (thread = (jthread)
 196             NSK_CPP_STUB3(GetStaticObjectField, jni, debugeeClass, threadFieldID)) != NULL))
 197         return NSK_FALSE;
 198 
 199     if (!NSK_JNI_VERIFY(jni, (threadClass =
 200             NSK_CPP_STUB2(GetObjectClass, jni, thread)) != NULL))
 201         return NSK_FALSE;
 202 
 203     NSK_DISPLAY0("Find tested methods:\n");
 204     for (i = 0; i < METHODS_COUNT; i++) {
 205         if (!NSK_JNI_VERIFY(jni, (methodsDesc[i].method =
 206                 NSK_CPP_STUB4(GetMethodID, jni, threadClass,
 207                             methodsDesc[i].methodName, methodsDesc[i].methodSig)) != NULL))
 208             return NSK_FALSE;
 209         NSK_DISPLAY3("    method #%d (%s): 0x%p\n",
 210                                 i, methodsDesc[i].methodName, (void*)methodsDesc[i].method);
 211     }
 212 
 213     NSK_DISPLAY0("Enable events\n");
 214     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
 215         return NSK_FALSE;
 216 
 217     return NSK_TRUE;
 218 }
 219 
 220 /**
 221  * Testcase: check tested events.
 222  *   - check if expected events received for each method
 223  *
 224  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
 225  */
 226 static int checkEvents() {
 227     int i;
 228 
 229     for (i = 0; i < METHODS_COUNT; i++) {
 230         NSK_DISPLAY2("  method #%d (%s):\n",
 231                                 i, methodsDesc[i].methodName);
 232         NSK_DISPLAY2("    COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 233                                 methodsDesc[i].loadEvents[moment],
 234                                 methodsDesc[i].unloadEvents[moment]);
 235 
 236         if (moment == COMPILATION_MOMENT_AFTER) {
 237             int loadEventsTotal = methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE]
 238                                 + methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING];
 239             int unloadEventsTotal = methodsDesc[i].unloadEvents[COMPILATION_MOMENT_BEFORE]
 240                                   + methodsDesc[i].unloadEvents[COMPILATION_MOMENT_RUNNING];
 241 
 242             /* complain if no COMPILED_METHOD_LOAD events finally generated for compiled events */
 243             if (methodsDesc[i].compiled) {
 244                 if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
 245                     NSK_COMPLAIN4("No COMPILED_METHOD_LOAD events finally generated for compiled method: %s\n"
 246                               "#   total COMPILED_METHOD_LOAD:   %d\n"
 247                               "#   total COMPILED_METHOD_UNLOAD: %d\n"
 248                               "#         final GenerateEvents(): %d\n",
 249                                 methodsDesc[i].methodName,
 250                                 loadEventsTotal,
 251                                 unloadEventsTotal,
 252                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
 253                     nsk_jvmti_setFailStatus();
 254                 }
 255             }
 256 
 257             /* complain if too many COMPILED_METHOD_LOAD events finally generated */
 258             if (methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER] > loadEventsTotal) {
 259                 NSK_COMPLAIN5("Too many COMPILED_METHOD_LOAD events finally generated for method: %s\n"
 260                               "#   GenerateEvents() before execution: %d\n"
 261                               "#   generated during execution:        %d\n"
 262                               "#                    total:            %d\n"
 263                               "#   GenerateEvents() after execution:  %d\n",
 264                                 methodsDesc[i].methodName,
 265                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_BEFORE],
 266                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_RUNNING],
 267                                 loadEventsTotal,
 268                                 methodsDesc[i].loadEvents[COMPILATION_MOMENT_AFTER]);
 269                 nsk_jvmti_setFailStatus();
 270             }
 271 
 272             /* warn if too mamy COMPILED_METHOD_UNLOAD events received */
 273             if (unloadEventsTotal > loadEventsTotal) {
 274                 NSK_DISPLAY1("# WARNING: Too many COMPILED_METHOD_UNLOAD events for method: %s\n",
 275                                     methodsDesc[i].methodName);
 276                 NSK_DISPLAY2("#   COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 277                                     loadEventsTotal, unloadEventsTotal);
 278             }
 279         }
 280     }
 281     return NSK_TRUE;
 282 }
 283 
 284 /**
 285  * Clean data.
 286  *   - disable events
 287  */
 288 static int clean() {
 289     NSK_DISPLAY0("Disable events\n");
 290     if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
 291         return NSK_FALSE;
 292 
 293     return NSK_TRUE;
 294 }
 295 
 296 /* ============================================================================= */
 297 
 298 /**
 299  * COMPILED_METHOD_LOAD callback.
 300  *   - turm on flag that method is compiled
 301  */
 302 JNIEXPORT void JNICALL
 303 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
 304                             jint code_size, const void* code_addr,
 305                             jint map_length, const jvmtiAddrLocationMap* map,
 306                             const void* compile_info) {
 307     int i;
 308 
 309     /* check if event is for tested method and count it */
 310     for (i = 0; i < METHODS_COUNT; i++) {
 311         if (methodsDesc[i].method == method) {
 312             methodsDesc[i].loadEvents[moment]++;
 313             methodsDesc[i].compiled = NSK_TRUE;
 314 
 315             NSK_DISPLAY3("  COMPILED_METHOD_LOAD for method #%d (%s): %d times\n",
 316                                 i, methodsDesc[i].methodName,
 317                                 methodsDesc[i].loadEvents[moment]);
 318             NSK_DISPLAY1("    methodID:   0x%p\n",
 319                                 (void*)methodsDesc[i].method);
 320             NSK_DISPLAY1("    code_size:  %d\n",
 321                                 (int)code_size);
 322             NSK_DISPLAY1("    map_length: %d\n",
 323                                 (int)map_length);
 324             break;
 325         }
 326     }
 327 }
 328 
 329 /**
 330  * COMPILED_METHOD_UNLOAD callback.
 331  *   - turn off flag that method is compiled
 332  */
 333 JNIEXPORT void JNICALL
 334 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
 335                              const void* code_addr) {
 336     int i;
 337 
 338     /* check if event is for tested method and count it */
 339     for (i = 0; i < METHODS_COUNT; i++) {
 340         if (methodsDesc[i].method == method) {
 341             methodsDesc[i].unloadEvents[moment]++;
 342             methodsDesc[i].compiled = NSK_FALSE;
 343 
 344             NSK_DISPLAY3("  COMPILED_METHOD_UNLOAD for method #%d (%s): %d times\n",
 345                                 i, methodsDesc[i].methodName,
 346                                 methodsDesc[i].loadEvents[moment]);
 347             NSK_DISPLAY1("    methodID:   0x%p\n",
 348                                 (void*)methodsDesc[i].method);
 349             break;
 350         }
 351     }
 352 }
 353 
 354 /* ============================================================================= */
 355 
 356 /** Native running method in tested thread. */
 357 JNIEXPORT jint JNICALL
 358 Java_nsk_jvmti_scenarios_events_EM05_em05t002Thread_nativeMethod(JNIEnv* jni,
 359                                                                     jobject obj, jint i) {
 360     jint k = 0;
 361     jint j;
 362 
 363     for (j = 0; j < i; j++) {
 364         k += (i - j);
 365     }
 366     return k;
 367 }
 368 
 369 /* ============================================================================= */
 370 
 371 /** Agent library initialization. */
 372 #ifdef STATIC_BUILD
 373 JNIEXPORT jint JNICALL Agent_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
 374     return Agent_Initialize(jvm, options, reserved);
 375 }
 376 JNIEXPORT jint JNICALL Agent_OnAttach_em05t002(JavaVM *jvm, char *options, void *reserved) {
 377     return Agent_Initialize(jvm, options, reserved);
 378 }
 379 JNIEXPORT jint JNI_OnLoad_em05t002(JavaVM *jvm, char *options, void *reserved) {
 380     return JNI_VERSION_1_8;
 381 }
 382 #endif
 383 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 384 
 385     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 386         return JNI_ERR;
 387 
 388     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 389 
 390     if (!NSK_VERIFY((jvmti =
 391             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 392         return JNI_ERR;
 393 
 394     {
 395         jvmtiCapabilities caps;
 396         memset(&caps, 0, sizeof(caps));
 397         caps.can_generate_compiled_method_load_events = 1;
 398         if (!NSK_JVMTI_VERIFY(
 399                 NSK_CPP_STUB2(AddCapabilities, jvmti, &caps)))
 400             return JNI_ERR;
 401     }
 402 
 403     {
 404         jvmtiEventCallbacks eventCallbacks;
 405         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 406         eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
 407         eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
 408         if (!NSK_JVMTI_VERIFY(
 409                 NSK_CPP_STUB3(SetEventCallbacks, jvmti,
 410                                     &eventCallbacks, sizeof(eventCallbacks))))
 411             return JNI_ERR;
 412     }
 413 
 414     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 415         return JNI_ERR;
 416 
 417     return JNI_OK;
 418 }
 419 
 420 /* ============================================================================= */
 421 
 422 }