1 /* 2 * Copyright (c) 2004, 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 <stdio.h> 25 #include <string.h> 26 #include <jvmti.h> 27 #include "agent_common.h" 28 #include "ExceptionCheckingJniEnv.hpp" 29 #include "nsk_tools.h" 30 #include "jni_tools.h" 31 #include "JVMTITools.h" 32 #include "jvmti_tools.h" 33 34 extern "C" { 35 36 #define OBJ_MAX_COUNT 100000 37 38 static JNIEnv *jni = NULL; 39 static jvmtiEnv *jvmti = NULL; 40 static jvmtiEventCallbacks callbacks; 41 static jvmtiCapabilities caps; 42 43 static jlong timeout = 0; 44 45 static const char* DEBUGEE_SIGNATURE = "Lnsk/jvmti/scenarios/allocation/AP04/ap04t003;"; 46 static const char* ROOT_SIGNATURE = "[Lnsk/jvmti/scenarios/allocation/AP04/ap04t003;"; 47 48 static jclass debugeeClass = NULL; 49 static jfieldID rootFieldID; 50 51 static jrawMonitorID startLock = NULL; 52 static jrawMonitorID runLock = NULL; 53 static jrawMonitorID endLock = NULL; 54 55 static volatile int iterationCount = 0; 56 static volatile int objectCount = 0; 57 58 /***********************************************************************/ 59 60 static jrawMonitorID counterMonitor_ptr = NULL; 61 62 static void increaseCounter(volatile int* counterPtr) { 63 64 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) { 65 nsk_jvmti_setFailStatus(); 66 } 67 68 (*counterPtr)++; 69 70 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) { 71 nsk_jvmti_setFailStatus(); 72 } 73 } 74 75 static void setCounter(volatile int* counterPtr, int value) { 76 77 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) { 78 nsk_jvmti_setFailStatus(); 79 } 80 81 *counterPtr = value; 82 83 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) { 84 nsk_jvmti_setFailStatus(); 85 } 86 } 87 88 static int getCounter(volatile int* counterPtr) { 89 int result; 90 91 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) { 92 nsk_jvmti_setFailStatus(); 93 } 94 95 result = *counterPtr; 96 97 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) { 98 nsk_jvmti_setFailStatus(); 99 } 100 101 return result; 102 } 103 104 /***********************************************************************/ 105 106 void notifyThread() { 107 108 /* enter and notify runLock */ 109 { 110 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(runLock))) { 111 nsk_jvmti_setFailStatus(); 112 } 113 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorNotify(runLock))) { 114 nsk_jvmti_setFailStatus(); 115 } 116 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(runLock))) { 117 nsk_jvmti_setFailStatus(); 118 } 119 } 120 } 121 122 jvmtiIterationControl JNICALL 123 heapObjectCallback(jlong class_tag, 124 jlong size, 125 jlong* tag_ptr, 126 void* user_data) { 127 128 if (getCounter(&iterationCount) == 0) { 129 notifyThread(); 130 } 131 increaseCounter(&iterationCount); 132 133 if (*tag_ptr > 0) { 134 increaseCounter(&objectCount); 135 } 136 137 return JVMTI_ITERATION_CONTINUE; 138 } 139 140 /* jvmtiHeapRootCallback */ 141 jvmtiIterationControl JNICALL 142 heapRootCallback(jvmtiHeapRootKind root_kind, 143 jlong class_tag, 144 jlong size, 145 jlong* tag_ptr, 146 void* user_data) { 147 148 if (getCounter(&iterationCount) == 0) { 149 notifyThread(); 150 } 151 increaseCounter(&iterationCount); 152 153 if (*tag_ptr > 0) { 154 increaseCounter(&objectCount); 155 } 156 157 return JVMTI_ITERATION_CONTINUE; 158 } 159 160 /* jvmtiStackReferenceCallback */ 161 jvmtiIterationControl JNICALL 162 stackReferenceCallback(jvmtiHeapRootKind root_kind, 163 jlong class_tag, 164 jlong size, 165 jlong* tag_ptr, 166 jlong thread_tag, 167 jint depth, 168 jmethodID method, 169 jint slot, 170 void* user_data) { 171 172 if (getCounter(&iterationCount) == 0) { 173 notifyThread(); 174 } 175 increaseCounter(&iterationCount); 176 177 if (*tag_ptr > 0) { 178 increaseCounter(&objectCount); 179 } 180 181 return JVMTI_ITERATION_CONTINUE; 182 } 183 184 185 /* jvmtiObjectReferenceCallback */ 186 jvmtiIterationControl JNICALL 187 objectReferenceCallback(jvmtiObjectReferenceKind reference_kind, 188 jlong class_tag, 189 jlong size, 190 jlong* tag_ptr, 191 jlong referrer_tag, 192 jint referrer_index, 193 void* user_data) { 194 195 if (getCounter(&iterationCount) == 0) { 196 notifyThread(); 197 } 198 increaseCounter(&iterationCount); 199 200 if (*tag_ptr > 0) { 201 increaseCounter(&objectCount); 202 } 203 204 return JVMTI_ITERATION_CONTINUE; 205 } 206 207 /********* Agent thread modifying tags of objects ************/ 208 209 /** Body of new agent thread: modify tags of tagged object. */ 210 void JNICALL agent_start(jvmtiEnv* jvmti, JNIEnv* jni, void *p) { 211 212 jint taggedObjectsCount = 0; 213 jobject* taggedObjectsList = NULL; 214 215 NSK_DISPLAY0("Agent thread: started.\n"); 216 217 /* obtain tagged objects list */ 218 { 219 jlong tag = (jlong)1; 220 221 if (!NSK_JVMTI_VERIFY(jvmti->GetObjectsWithTags( 222 1, &tag, &taggedObjectsCount, &taggedObjectsList, NULL))) { 223 nsk_jvmti_setFailStatus(); 224 return; 225 } 226 } 227 228 NSK_DISPLAY1("Agent thread: got tagged objects: %d\n", (int)taggedObjectsCount); 229 230 if (!NSK_VERIFY(taggedObjectsCount == OBJ_MAX_COUNT)) { 231 nsk_jvmti_setFailStatus(); 232 return; 233 } 234 235 /* enter runLock */ 236 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(runLock))) { 237 nsk_jvmti_setFailStatus(); 238 } 239 240 /* enter and notify startLock */ 241 { 242 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(startLock))) { 243 nsk_jvmti_setFailStatus(); 244 } 245 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorNotify(startLock))) { 246 nsk_jvmti_setFailStatus(); 247 } 248 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(startLock))) { 249 nsk_jvmti_setFailStatus(); 250 } 251 } 252 253 NSK_DISPLAY0("Agent thread: wait for run notification\n"); 254 255 /* wait on runLock */ 256 { 257 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(runLock, timeout))) { 258 nsk_jvmti_setFailStatus(); 259 } 260 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(runLock))) { 261 nsk_jvmti_setFailStatus(); 262 } 263 } 264 265 NSK_DISPLAY0("Agent thread: modify tags of each even object.\n"); 266 267 /* modify tags of each even object */ 268 { 269 int modified = 0; 270 int i; 271 for (i = 0; i < taggedObjectsCount; i+=2) { 272 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(taggedObjectsList[i], 0))) { 273 nsk_jvmti_setFailStatus(); 274 continue; 275 } 276 modified++; 277 } 278 279 NSK_DISPLAY2("Agent thread: tags modified: %d of %d\n", 280 modified, (int)taggedObjectsCount); 281 } 282 283 /* destroy objects list */ 284 { 285 if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)taggedObjectsList))) { 286 nsk_jvmti_setFailStatus(); 287 } 288 } 289 290 /* enter and notify endLock */ 291 { 292 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(endLock))) { 293 nsk_jvmti_setFailStatus(); 294 } 295 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorNotify(endLock))) { 296 nsk_jvmti_setFailStatus(); 297 } 298 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(endLock))) { 299 nsk_jvmti_setFailStatus(); 300 } 301 } 302 303 NSK_DISPLAY0("Agent thread: finished.\n"); 304 } 305 306 /***********************************************************************/ 307 308 static int startThread(jthread threadObj) { 309 int success = NSK_TRUE; 310 311 /* enter startLock */ 312 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(startLock))) { 313 nsk_jvmti_setFailStatus(); 314 } 315 316 /* start thread */ 317 if (!NSK_JVMTI_VERIFY( 318 jvmti->RunAgentThread(threadObj, agent_start, NULL, JVMTI_THREAD_NORM_PRIORITY))) { 319 success = NSK_FALSE; 320 nsk_jvmti_setFailStatus(); 321 } else { 322 /* wait on startLock */ 323 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(startLock, timeout))) { 324 nsk_jvmti_setFailStatus(); 325 } 326 } 327 328 /* exit starLock */ 329 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(startLock))) { 330 nsk_jvmti_setFailStatus(); 331 } 332 333 return success; 334 } 335 336 /** Create thread object for new agent thread. */ 337 static jthread newThreadObj(JNIEnv* jni_env) { 338 ExceptionCheckingJniEnvPtr jni(jni_env); 339 jclass thrClass; 340 jmethodID cid; 341 jthread result = NULL; 342 343 thrClass = jni->FindClass("java/lang/Thread", TRACE_JNI_CALL); 344 cid = jni->GetMethodID(thrClass, "<init>", "()V", TRACE_JNI_CALL); 345 return jni->NewObject(thrClass, cid, TRACE_JNI_CALL); 346 } 347 348 /***********************************************************************/ 349 350 /** Clean counters and start new agent thread with agent_start() body. */ 351 static int prepareToIteration(JNIEnv* jni) { 352 jthread threadObj = NULL; 353 354 setCounter(&iterationCount, 0); 355 setCounter(&objectCount, 0); 356 357 threadObj = newThreadObj(jni); 358 359 /* enter endLock */ 360 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(endLock))) { 361 nsk_jvmti_setFailStatus(); 362 } 363 364 NSK_DISPLAY0("Starting new agent thread...\n"); 365 return startThread(threadObj); 366 } 367 368 /** Wait for new agent thread to complete. */ 369 static void afterIteration() { 370 371 /* notify new agent thread (in case if not yet notified) */ 372 notifyThread(); 373 374 NSK_DISPLAY0("Wait for new agent thread to complete\n"); 375 376 /* wait on endLock */ 377 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(endLock, timeout))) { 378 nsk_jvmti_setFailStatus(); 379 } 380 381 /* exit endLock */ 382 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(endLock))) { 383 nsk_jvmti_setFailStatus(); 384 } 385 } 386 387 /***********************************************************************/ 388 389 JNIEXPORT void JNICALL 390 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_setTag(JNIEnv* jni, 391 jclass klass, 392 jobject target, /* object to be tagged */ 393 jlong tag) { 394 395 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(target, tag))) { 396 nsk_jvmti_setFailStatus(); 397 } 398 } 399 400 JNIEXPORT void JNICALL 401 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverHeap(JNIEnv* jni, 402 jclass klass) { 403 int modified = 0; 404 int found = 0; 405 406 if (!prepareToIteration(jni)) 407 return; 408 409 NSK_DISPLAY0("Calling IterateOverHeap...\n"); 410 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_TAGGED, 411 heapObjectCallback, 412 NULL /*user_data*/))) { 413 nsk_jvmti_setFailStatus(); 414 } 415 NSK_DISPLAY0("IterateOverHeap finished.\n"); 416 417 afterIteration(); 418 419 found = getCounter(&objectCount); 420 NSK_DISPLAY1("Found tagged objects: %d\n", found); 421 422 modified = OBJ_MAX_COUNT - found; 423 if (modified > 0) { 424 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 425 modified, OBJ_MAX_COUNT); 426 nsk_jvmti_setFailStatus(); 427 } 428 } 429 430 JNIEXPORT void JNICALL 431 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverReachableObjects(JNIEnv* jni, 432 jclass klass) { 433 int modified = 0; 434 int found = 0; 435 436 if (!prepareToIteration(jni)) 437 return; 438 439 NSK_DISPLAY0("Calling IterateOverReachableObjects...\n"); 440 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverReachableObjects(heapRootCallback, 441 stackReferenceCallback, 442 objectReferenceCallback, 443 NULL /*user_data*/))) { 444 nsk_jvmti_setFailStatus(); 445 } 446 NSK_DISPLAY0("IterateOverReachableObjects finished.\n"); 447 448 afterIteration(); 449 450 found = getCounter(&objectCount); 451 NSK_DISPLAY1("Found tagged objects: %d\n", found); 452 453 modified = OBJ_MAX_COUNT - found; 454 if (modified > 0) { 455 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 456 modified, OBJ_MAX_COUNT); 457 nsk_jvmti_setFailStatus(); 458 } 459 } 460 461 JNIEXPORT void JNICALL 462 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverInstancesOfClass(JNIEnv* jni, 463 jclass klass) { 464 int modified = 0; 465 int found = 0; 466 467 if (!prepareToIteration(jni)) 468 return; 469 470 NSK_DISPLAY0("Calling IterateOverInstancesOfClass...\n"); 471 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverInstancesOfClass(debugeeClass, 472 JVMTI_HEAP_OBJECT_TAGGED, 473 heapObjectCallback, 474 NULL /*user_data*/))) { 475 nsk_jvmti_setFailStatus(); 476 } 477 NSK_DISPLAY0("IterateOverInstancesOfClass finished.\n"); 478 479 afterIteration(); 480 481 found = getCounter(&objectCount); 482 NSK_DISPLAY1("Found tagged objects: %d\n", found); 483 484 modified = OBJ_MAX_COUNT - found; 485 if (modified > 0) { 486 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 487 modified, OBJ_MAX_COUNT); 488 nsk_jvmti_setFailStatus(); 489 } 490 } 491 492 JNIEXPORT void JNICALL 493 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverObjectsReachableFromObject(JNIEnv* jni_env, 494 jclass klass) { 495 ExceptionCheckingJniEnvPtr jni(jni_env); 496 jobject root = NULL; 497 int modified = 0; 498 int found = 0; 499 500 root = jni->GetStaticObjectField(debugeeClass, rootFieldID, TRACE_JNI_CALL); 501 502 if (!prepareToIteration(jni_env)) 503 return; 504 505 NSK_DISPLAY0("Calling IterateOverObjectsReachableFromObject...\n"); 506 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverObjectsReachableFromObject(root, 507 objectReferenceCallback, 508 NULL /*user_data*/))) { 509 nsk_jvmti_setFailStatus(); 510 } 511 NSK_DISPLAY0("IterateOverObjectsReachableFromObject finished.\n"); 512 513 afterIteration(); 514 515 found = getCounter(&objectCount); 516 NSK_DISPLAY1("Found tagged objects: %d\n", found); 517 518 modified = OBJ_MAX_COUNT - found; 519 if (modified > 0) { 520 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 521 modified, OBJ_MAX_COUNT); 522 nsk_jvmti_setFailStatus(); 523 } 524 } 525 526 static void JNICALL 527 agentProc(jvmtiEnv* jvmti, JNIEnv* jni_env, void* arg) { 528 ExceptionCheckingJniEnvPtr jni(jni_env); 529 NSK_DISPLAY0("Wait for debugee start\n\n"); 530 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 531 return; 532 533 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_SIGNATURE); 534 debugeeClass = nsk_jvmti_classBySignature(DEBUGEE_SIGNATURE); 535 if (debugeeClass == NULL) { 536 nsk_jvmti_setFailStatus(); 537 return; 538 } 539 540 debugeeClass = (jclass) jni->NewGlobalRef(debugeeClass, TRACE_JNI_CALL); 541 542 NSK_DISPLAY1("Find ID of 'root' field: %s\n", ROOT_SIGNATURE); 543 rootFieldID = jni->GetStaticFieldID(debugeeClass, "root", 544 ROOT_SIGNATURE, TRACE_JNI_CALL); 545 546 NSK_DISPLAY0("Let debugee to run test cases\n"); 547 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 548 return; 549 550 NSK_DISPLAY0("Wait for completion of test cases\n\n"); 551 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 552 return; 553 554 jni->DeleteGlobalRef(debugeeClass, TRACE_JNI_CALL); 555 NSK_TRACE(jvmti->DestroyRawMonitor(counterMonitor_ptr)); 556 NSK_TRACE(jvmti->DestroyRawMonitor(startLock)); 557 NSK_TRACE(jvmti->DestroyRawMonitor(runLock)); 558 NSK_TRACE(jvmti->DestroyRawMonitor(endLock)); 559 560 NSK_DISPLAY0("Let debugee to finish\n"); 561 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 562 return; 563 } 564 565 #ifdef STATIC_BUILD 566 JNIEXPORT jint JNICALL Agent_OnLoad_ap04t003(JavaVM *jvm, char *options, void *reserved) { 567 return Agent_Initialize(jvm, options, reserved); 568 } 569 JNIEXPORT jint JNICALL Agent_OnAttach_ap04t003(JavaVM *jvm, char *options, void *reserved) { 570 return Agent_Initialize(jvm, options, reserved); 571 } 572 JNIEXPORT jint JNI_OnLoad_ap04t003(JavaVM *jvm, char *options, void *reserved) { 573 return JNI_VERSION_1_8; 574 } 575 #endif 576 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 577 /* init framework and parse options */ 578 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 579 return JNI_ERR; 580 581 /* create JVMTI environment */ 582 jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved); 583 if (!NSK_VERIFY(jvmti != NULL)) 584 return JNI_ERR; 585 586 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("counterMonitor", &counterMonitor_ptr))) { 587 return JNI_ERR; 588 } 589 590 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("startLock", &startLock))) { 591 return JNI_ERR; 592 } 593 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("runLock", &runLock))) { 594 return JNI_ERR; 595 } 596 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("endLock", &endLock))) { 597 return JNI_ERR; 598 } 599 600 memset(&caps, 0, sizeof(jvmtiCapabilities)); 601 caps.can_tag_objects = 1; 602 603 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) 604 return JNI_ERR; 605 606 if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps))) 607 return JNI_ERR; 608 609 if (!caps.can_tag_objects) 610 NSK_DISPLAY0("Warning: tagging objects is not available\n"); 611 612 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 613 return JNI_ERR; 614 NSK_DISPLAY0("agentProc has been set\n\n"); 615 616 return JNI_OK; 617 } 618 619 }