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 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(JNIEnv* jni, 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) { 338 jclass thrClass; 339 jmethodID cid; 340 jthread result = NULL; 341 342 thrClass = jni->FindClass("java/lang/Thread"); 343 if (!NSK_JNI_VERIFY(jni, thrClass != NULL)) { 344 nsk_jvmti_setFailStatus(); 345 return result; 346 } 347 348 cid = jni->GetMethodID(thrClass, "<init>", "()V"); 349 if (!NSK_JNI_VERIFY(jni, cid != NULL)) { 350 nsk_jvmti_setFailStatus(); 351 return result; 352 } 353 354 result = jni->NewObject(thrClass, cid); 355 if (!NSK_JNI_VERIFY(jni, result != NULL)) { 356 nsk_jvmti_setFailStatus(); 357 return result; 358 } 359 360 return result; 361 } 362 363 /***********************************************************************/ 364 365 /** Clean counters and start new agent thread with agent_start() body. */ 366 static int prepareToIteration (JNIEnv* jni) { 367 jthread threadObj = NULL; 368 369 setCounter(&iterationCount, 0); 370 setCounter(&objectCount, 0); 371 372 threadObj = newThreadObj(jni); 373 if (!NSK_VERIFY(threadObj != NULL)) { 374 nsk_jvmti_setFailStatus(); 375 return NSK_FALSE; 376 } 377 378 /* enter endLock */ 379 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(endLock))) { 380 nsk_jvmti_setFailStatus(); 381 } 382 383 NSK_DISPLAY0("Starting new agent thread...\n"); 384 return startThread(jni, threadObj); 385 } 386 387 /** Wait for new agent thread to complete. */ 388 static void afterIteration (JNIEnv* jni) { 389 390 /* notify new agent thread (in case if not yet notified) */ 391 notifyThread(); 392 393 NSK_DISPLAY0("Wait for new agent thread to complete\n"); 394 395 /* wait on endLock */ 396 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorWait(endLock, timeout))) { 397 nsk_jvmti_setFailStatus(); 398 } 399 400 /* exit endLock */ 401 if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(endLock))) { 402 nsk_jvmti_setFailStatus(); 403 } 404 } 405 406 /***********************************************************************/ 407 408 JNIEXPORT void JNICALL 409 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_setTag(JNIEnv* jni, 410 jclass klass, 411 jobject target, /* object to be tagged */ 412 jlong tag) { 413 414 if (!NSK_JVMTI_VERIFY(jvmti->SetTag(target, tag))) { 415 nsk_jvmti_setFailStatus(); 416 } 417 } 418 419 JNIEXPORT void JNICALL 420 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverHeap(JNIEnv* jni, 421 jclass klass) { 422 int modified = 0; 423 int found = 0; 424 425 if (!prepareToIteration(jni)) 426 return; 427 428 NSK_DISPLAY0("Calling IterateOverHeap...\n"); 429 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_TAGGED, 430 heapObjectCallback, 431 NULL /*user_data*/))) { 432 nsk_jvmti_setFailStatus(); 433 } 434 NSK_DISPLAY0("IterateOverHeap finished.\n"); 435 436 afterIteration(jni); 437 438 found = getCounter(&objectCount); 439 NSK_DISPLAY1("Found tagged objects: %d\n", found); 440 441 modified = OBJ_MAX_COUNT - found; 442 if (modified > 0) { 443 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 444 modified, OBJ_MAX_COUNT); 445 nsk_jvmti_setFailStatus(); 446 } 447 } 448 449 JNIEXPORT void JNICALL 450 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverReachableObjects(JNIEnv* jni, 451 jclass klass) { 452 int modified = 0; 453 int found = 0; 454 455 if (!prepareToIteration(jni)) 456 return; 457 458 NSK_DISPLAY0("Calling IterateOverReachableObjects...\n"); 459 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverReachableObjects(heapRootCallback, 460 stackReferenceCallback, 461 objectReferenceCallback, 462 NULL /*user_data*/))) { 463 nsk_jvmti_setFailStatus(); 464 } 465 NSK_DISPLAY0("IterateOverReachableObjects finished.\n"); 466 467 afterIteration(jni); 468 469 found = getCounter(&objectCount); 470 NSK_DISPLAY1("Found tagged objects: %d\n", found); 471 472 modified = OBJ_MAX_COUNT - found; 473 if (modified > 0) { 474 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 475 modified, OBJ_MAX_COUNT); 476 nsk_jvmti_setFailStatus(); 477 } 478 } 479 480 JNIEXPORT void JNICALL 481 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverInstancesOfClass(JNIEnv* jni, 482 jclass klass) { 483 int modified = 0; 484 int found = 0; 485 486 if (!prepareToIteration(jni)) 487 return; 488 489 NSK_DISPLAY0("Calling IterateOverInstancesOfClass...\n"); 490 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverInstancesOfClass(debugeeClass, 491 JVMTI_HEAP_OBJECT_TAGGED, 492 heapObjectCallback, 493 NULL /*user_data*/))) { 494 nsk_jvmti_setFailStatus(); 495 } 496 NSK_DISPLAY0("IterateOverInstancesOfClass finished.\n"); 497 498 afterIteration(jni); 499 500 found = getCounter(&objectCount); 501 NSK_DISPLAY1("Found tagged objects: %d\n", found); 502 503 modified = OBJ_MAX_COUNT - found; 504 if (modified > 0) { 505 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 506 modified, OBJ_MAX_COUNT); 507 nsk_jvmti_setFailStatus(); 508 } 509 } 510 511 JNIEXPORT void JNICALL 512 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t003_runIterateOverObjectsReachableFromObject(JNIEnv* jni, 513 jclass klass) { 514 jobject root = NULL; 515 int modified = 0; 516 int found = 0; 517 518 root = jni->GetStaticObjectField(debugeeClass, rootFieldID); 519 if (!NSK_JNI_VERIFY(jni, root != NULL)) { 520 NSK_COMPLAIN0("GetStaticObjectField returned NULL for 'root' field value\n\n"); 521 nsk_jvmti_setFailStatus(); 522 return; 523 } 524 525 if (!prepareToIteration(jni)) 526 return; 527 528 NSK_DISPLAY0("Calling IterateOverObjectsReachableFromObject...\n"); 529 if (!NSK_JVMTI_VERIFY(jvmti->IterateOverObjectsReachableFromObject(root, 530 objectReferenceCallback, 531 NULL /*user_data*/))) { 532 nsk_jvmti_setFailStatus(); 533 } 534 NSK_DISPLAY0("IterateOverObjectsReachableFromObject finished.\n"); 535 536 afterIteration(jni); 537 538 found = getCounter(&objectCount); 539 NSK_DISPLAY1("Found tagged objects: %d\n", found); 540 541 modified = OBJ_MAX_COUNT - found; 542 if (modified > 0) { 543 NSK_COMPLAIN2("Tags were modified by other thread during heap iteration: %d of %d\n", 544 modified, OBJ_MAX_COUNT); 545 nsk_jvmti_setFailStatus(); 546 } 547 } 548 549 static void JNICALL 550 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) { 551 552 NSK_DISPLAY0("Wait for debugee start\n\n"); 553 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 554 return; 555 556 NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_SIGNATURE); 557 debugeeClass = nsk_jvmti_classBySignature(DEBUGEE_SIGNATURE); 558 if (debugeeClass == NULL) { 559 nsk_jvmti_setFailStatus(); 560 return; 561 } 562 563 debugeeClass = (jclass) jni->NewGlobalRef(debugeeClass); 564 if (!NSK_JNI_VERIFY(jni, debugeeClass != NULL)) 565 return; 566 567 NSK_DISPLAY1("Find ID of 'root' field: %s\n", ROOT_SIGNATURE); 568 rootFieldID = jni->GetStaticFieldID(debugeeClass, "root", ROOT_SIGNATURE); 569 if (!NSK_JNI_VERIFY(jni, rootFieldID != NULL)) { 570 nsk_jvmti_setFailStatus(); 571 return; 572 } 573 574 NSK_DISPLAY0("Let debugee to run test cases\n"); 575 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 576 return; 577 578 NSK_DISPLAY0("Wait for completion of test cases\n\n"); 579 if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) 580 return; 581 582 NSK_TRACE(jni->DeleteGlobalRef(debugeeClass)); 583 NSK_TRACE(jvmti->DestroyRawMonitor(counterMonitor_ptr)); 584 NSK_TRACE(jvmti->DestroyRawMonitor(startLock)); 585 NSK_TRACE(jvmti->DestroyRawMonitor(runLock)); 586 NSK_TRACE(jvmti->DestroyRawMonitor(endLock)); 587 588 NSK_DISPLAY0("Let debugee to finish\n"); 589 if (!NSK_VERIFY(nsk_jvmti_resumeSync())) 590 return; 591 } 592 593 #ifdef STATIC_BUILD 594 JNIEXPORT jint JNICALL Agent_OnLoad_ap04t003(JavaVM *jvm, char *options, void *reserved) { 595 return Agent_Initialize(jvm, options, reserved); 596 } 597 JNIEXPORT jint JNICALL Agent_OnAttach_ap04t003(JavaVM *jvm, char *options, void *reserved) { 598 return Agent_Initialize(jvm, options, reserved); 599 } 600 JNIEXPORT jint JNI_OnLoad_ap04t003(JavaVM *jvm, char *options, void *reserved) { 601 return JNI_VERSION_1_8; 602 } 603 #endif 604 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 605 /* init framework and parse options */ 606 if (!NSK_VERIFY(nsk_jvmti_parseOptions(options))) 607 return JNI_ERR; 608 609 /* create JVMTI environment */ 610 jvmti = nsk_jvmti_createJVMTIEnv(jvm, reserved); 611 if (!NSK_VERIFY(jvmti != NULL)) 612 return JNI_ERR; 613 614 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("counterMonitor", &counterMonitor_ptr))) { 615 return JNI_ERR; 616 } 617 618 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("startLock", &startLock))) { 619 return JNI_ERR; 620 } 621 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("runLock", &runLock))) { 622 return JNI_ERR; 623 } 624 if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("endLock", &endLock))) { 625 return JNI_ERR; 626 } 627 628 memset(&caps, 0, sizeof(jvmtiCapabilities)); 629 caps.can_tag_objects = 1; 630 631 if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) 632 return JNI_ERR; 633 634 if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps))) 635 return JNI_ERR; 636 637 if (!caps.can_tag_objects) 638 NSK_DISPLAY0("Warning: tagging objects is not available\n"); 639 640 if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL))) 641 return JNI_ERR; 642 NSK_DISPLAY0("agentProc has been set\n\n"); 643 644 return JNI_OK; 645 } 646 647 }