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 }