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/em05t001"
  41 #define THREAD_CLASS_NAME       "nsk/jvmti/scenarios/events/EM05/em05t001Thread"
  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 
  50 /* tested events */
  51 static jvmtiEvent eventsList[EVENTS_COUNT] = {
  52     JVMTI_EVENT_COMPILED_METHOD_LOAD,
  53     JVMTI_EVENT_COMPILED_METHOD_UNLOAD
  54 };
  55 
  56 /* method description structure */
  57 typedef struct {
  58     char methodName[MAX_NAME_LENGTH];
  59     char methodSig[MAX_NAME_LENGTH];
  60     jmethodID method;
  61     int compiled;
  62     int loadEvents;
  63     int unloadEvents;
  64 } MethodDesc;
  65 
  66 /* descriptions of tested methods */
  67 static MethodDesc methodsDesc[METHODS_COUNT] = {
  68     {"javaMethod", "(I)I", NULL, 0, 0, 0},
  69     {"nativeMethod", "(I)I", NULL, 0, 0, 0}
  70 };
  71 
  72 /* ============================================================================= */
  73 
  74 /* testcase(s) */
  75 static int prepare();
  76 static int checkEvents();
  77 static int clean();
  78 
  79 /* ============================================================================= */
  80 
  81 /** Agent algorithm. */
  82 static void JNICALL
  83 agentProc(jvmtiEnv* jvmti, JNIEnv* agentJNI, void* arg) {
  84     jni = agentJNI;
  85 
  86     NSK_DISPLAY0("Wait for debuggee to become ready\n");
  87     if (!nsk_jvmti_waitForSync(timeout))
  88         return;
  89 
  90     {
  91         NSK_DISPLAY0("Prepare data\n");
  92         if (!prepare()) {
  93             nsk_jvmti_setFailStatus();
  94             return;
  95         }
  96 
  97         NSK_DISPLAY0("Provoke methods compilation\n");
  98         if (!nsk_jvmti_resumeSync())
  99             return;
 100 
 101         NSK_DISPLAY0("Wait for threads to complete\n");
 102         if (!nsk_jvmti_waitForSync(timeout))
 103             return;
 104 
 105         NSK_DISPLAY0("Check if events received\n");
 106         if (!checkEvents())
 107             return;
 108 
 109         NSK_DISPLAY0("Clean data\n");
 110         if (!clean()) {
 111             nsk_jvmti_setFailStatus();
 112             return;
 113         }
 114     }
 115 
 116     NSK_DISPLAY0("Let debuggee to finish\n");
 117     if (!nsk_jvmti_resumeSync())
 118         return;
 119 }
 120 
 121 /* ============================================================================= */
 122 
 123 /**
 124  * Enable or disable tested events.
 125  */
 126 static int enableEvents(jvmtiEventMode enable) {
 127     int i;
 128 
 129     for (i = 0; i < EVENTS_COUNT; i++) {
 130         if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(enable, eventsList[i], NULL))) {
 131             nsk_jvmti_setFailStatus();
 132             return NSK_FALSE;
 133         }
 134     }
 135     return NSK_TRUE;
 136 }
 137 
 138 /**
 139  * Prepare data.
 140  *    - find tested thread
 141  *    - get tested methodIDs
 142  *    - enable events
 143  */
 144 static int prepare() {
 145     jclass debugeeClass = NULL;
 146     jclass threadClass = NULL;
 147     jfieldID threadFieldID = NULL;
 148     jthread thread = NULL;
 149     int i;
 150 
 151     for (i = 0; i < METHODS_COUNT; i++) {
 152         methodsDesc[i].method = (jmethodID)NULL;
 153         methodsDesc[i].loadEvents = 0;
 154         methodsDesc[i].unloadEvents = 0;
 155     }
 156 
 157     if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL))
 158         return NSK_FALSE;
 159 
 160     if (!NSK_JNI_VERIFY(jni, (threadFieldID =
 161             jni->GetStaticFieldID(debugeeClass, THREAD_FIELD_NAME, THREAD_FIELD_SIG)) != NULL))
 162         return NSK_FALSE;
 163 
 164     if (!NSK_JNI_VERIFY(jni, (thread = (jthread)
 165             jni->GetStaticObjectField(debugeeClass, threadFieldID)) != NULL))
 166         return NSK_FALSE;
 167 
 168     if (!NSK_JNI_VERIFY(jni, (threadClass = jni->GetObjectClass(thread)) != NULL))
 169         return NSK_FALSE;
 170 
 171     NSK_DISPLAY0("Find tested methods:\n");
 172     for (i = 0; i < METHODS_COUNT; i++) {
 173         if (!NSK_JNI_VERIFY(jni, (methodsDesc[i].method =
 174                 jni->GetMethodID(threadClass, methodsDesc[i].methodName, methodsDesc[i].methodSig)) != NULL))
 175             return NSK_FALSE;
 176         NSK_DISPLAY3("    method #%d (%s): 0x%p\n",
 177                                 i, methodsDesc[i].methodName, (void*)methodsDesc[i].method);
 178     }
 179 
 180     NSK_DISPLAY0("Enable events\n");
 181     if (!nsk_jvmti_enableEvents(JVMTI_ENABLE, EVENTS_COUNT, eventsList, NULL))
 182         return NSK_FALSE;
 183 
 184     return NSK_TRUE;
 185 }
 186 
 187 /**
 188  * Testcase: check tested events.
 189  *   - check if expected events received for each method
 190  *
 191  * Returns NSK_TRUE if test may continue; or NSK_FALSE for test break.
 192  */
 193 static int checkEvents() {
 194     int i;
 195 
 196     for (i = 0; i < METHODS_COUNT; i++) {
 197         NSK_DISPLAY2("  method #%d (%s):\n",
 198                                 i, methodsDesc[i].methodName);
 199         NSK_DISPLAY2("    COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 200                                 methodsDesc[i].loadEvents, methodsDesc[i].unloadEvents);
 201 
 202         if (methodsDesc[i].loadEvents <= 0) {
 203             NSK_DISPLAY1("# WARNING: No COMPILED_METHOD_LOAD events for method: %s\n",
 204                                 methodsDesc[i].methodName);
 205         }
 206 
 207         if (methodsDesc[i].unloadEvents > methodsDesc[i].loadEvents) {
 208             NSK_DISPLAY1("# WARNING: Too many COMPILED_METHOD_UNLOAD events for method: %s\n",
 209                                 methodsDesc[i].methodName);
 210             NSK_DISPLAY2("#   COMPILED_METHOD_LOAD: %d, COMPILED_METHOD_UNLOAD: %d\n",
 211                                 methodsDesc[i].loadEvents, methodsDesc[i].unloadEvents);
 212         }
 213     }
 214     return NSK_TRUE;
 215 }
 216 
 217 /**
 218  * Clean data:
 219  *   - disable events
 220  */
 221 static int clean() {
 222     NSK_DISPLAY0("Disable events\n");
 223     if (!nsk_jvmti_enableEvents(JVMTI_DISABLE, EVENTS_COUNT, eventsList, NULL))
 224         return NSK_FALSE;
 225 
 226     return NSK_TRUE;
 227 }
 228 
 229 /* ============================================================================= */
 230 
 231 /**
 232  * COMPILED_METHOD_LOAD callback.
 233  *   - turn on flag if method is compiled
 234  */
 235 JNIEXPORT void JNICALL
 236 callbackCompiledMethodLoad(jvmtiEnv* jvmti, jmethodID method,
 237                             jint code_size, const void* code_addr,
 238                             jint map_length, const jvmtiAddrLocationMap* map,
 239                             const void* compile_info) {
 240     int i;
 241 
 242     for (i = 0; i < METHODS_COUNT; i++) {
 243         if (methodsDesc[i].method == method) {
 244             methodsDesc[i].loadEvents++;
 245             NSK_DISPLAY3("  COMPILED_METHOD_LOAD for method #%d (%s): %d times\n",
 246                                 i, methodsDesc[i].methodName, methodsDesc[i].loadEvents);
 247             NSK_DISPLAY1("    methodID:   0x%p\n",
 248                                 (void*)methodsDesc[i].method);
 249             NSK_DISPLAY1("    code_size:  %d\n",
 250                                 (int)code_size);
 251             NSK_DISPLAY1("    map_length: %d\n",
 252                                 (int)map_length);
 253             break;
 254         }
 255     }
 256 }
 257 
 258 /**
 259  * COMPILED_METHOD_UNLOAD callback.
 260  *   - turn off flag that method is compiled
 261  */
 262 JNIEXPORT void JNICALL
 263 callbackCompiledMethodUnload(jvmtiEnv* jvmti, jmethodID method,
 264                              const void* code_addr) {
 265     int i;
 266 
 267     for (i = 0; i < METHODS_COUNT; i++) {
 268         if (methodsDesc[i].method == method) {
 269             methodsDesc[i].unloadEvents++;
 270             NSK_DISPLAY3("  COMPILED_METHOD_UNLOAD for method #%d (%s): %d times\n",
 271                                 i, methodsDesc[i].methodName, methodsDesc[i].loadEvents);
 272             NSK_DISPLAY1("    methodID:   0x%p\n",
 273                                 (void*)methodsDesc[i].method);
 274             break;
 275         }
 276     }
 277 }
 278 
 279 /* ============================================================================= */
 280 
 281 /** Native running method in tested thread. */
 282 JNIEXPORT jint JNICALL
 283 Java_nsk_jvmti_scenarios_events_EM05_em05t001Thread_nativeMethod(JNIEnv* jni,
 284                                                                     jobject obj,
 285                                                                     jint i) {
 286     jint k = 0;
 287     jint j;
 288 
 289     for (j = 0; j < i; j++) {
 290         k += (i - j);
 291     }
 292     return k;
 293 }
 294 
 295 /* ============================================================================= */
 296 
 297 /** Agent library initialization. */
 298 #ifdef STATIC_BUILD
 299 JNIEXPORT jint JNICALL Agent_OnLoad_em05t001(JavaVM *jvm, char *options, void *reserved) {
 300     return Agent_Initialize(jvm, options, reserved);
 301 }
 302 JNIEXPORT jint JNICALL Agent_OnAttach_em05t001(JavaVM *jvm, char *options, void *reserved) {
 303     return Agent_Initialize(jvm, options, reserved);
 304 }
 305 JNIEXPORT jint JNI_OnLoad_em05t001(JavaVM *jvm, char *options, void *reserved) {
 306     return JNI_VERSION_1_8;
 307 }
 308 #endif
 309 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 310 
 311     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 312         return JNI_ERR;
 313 
 314     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 315 
 316     if (!NSK_VERIFY((jvmti =
 317             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 318         return JNI_ERR;
 319 
 320     {
 321         jvmtiCapabilities caps;
 322         memset(&caps, 0, sizeof(caps));
 323         caps.can_generate_compiled_method_load_events = 1;
 324         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
 325             return JNI_ERR;
 326     }
 327 
 328     {
 329         jvmtiEventCallbacks eventCallbacks;
 330         memset(&eventCallbacks, 0, sizeof(eventCallbacks));
 331         eventCallbacks.CompiledMethodLoad = callbackCompiledMethodLoad;
 332         eventCallbacks.CompiledMethodUnload = callbackCompiledMethodUnload;
 333         if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&eventCallbacks, sizeof(eventCallbacks))))
 334             return JNI_ERR;
 335     }
 336 
 337     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 338         return JNI_ERR;
 339 
 340     return JNI_OK;
 341 }
 342 
 343 /* ============================================================================= */
 344 
 345 }