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 }