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