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/ap04t002;";
  46 static const char* ROOT_SIGNATURE    = "[Lnsk/jvmti/scenarios/allocation/AP04/ap04t002;";
  47 
  48 static volatile int modificationCount = 0;
  49 static volatile int iterationCount = 0;
  50 static volatile int errorCount = 0;
  51 
  52 static jclass debugeeClass = NULL;
  53 static jfieldID rootFieldID;
  54 static jfieldID modifiedFieldID;
  55 
  56 /***********************************************************************/
  57 
  58 static jrawMonitorID counterMonitor_ptr = NULL;
  59 
  60 static void increaseCounter(volatile int* counterPtr) {
  61 
  62     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) {
  63         nsk_jvmti_setFailStatus();
  64     }
  65 
  66     (*counterPtr)++;
  67 
  68     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) {
  69         nsk_jvmti_setFailStatus();
  70     }
  71 }
  72 
  73 static void setCounter(volatile int* counterPtr, int value) {
  74 
  75     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) {
  76         nsk_jvmti_setFailStatus();
  77     }
  78 
  79     *counterPtr = value;
  80 
  81     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) {
  82         nsk_jvmti_setFailStatus();
  83     }
  84 }
  85 
  86 static int getCounter(volatile int* counterPtr) {
  87     int result;
  88 
  89     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorEnter(counterMonitor_ptr))) {
  90         nsk_jvmti_setFailStatus();
  91     }
  92 
  93     result = *counterPtr;
  94 
  95     if (!NSK_JVMTI_VERIFY(jvmti->RawMonitorExit(counterMonitor_ptr))) {
  96         nsk_jvmti_setFailStatus();
  97     }
  98 
  99     return result;
 100 }
 101 
 102 /***********************************************************************/
 103 
 104 jvmtiIterationControl JNICALL
 105 heapObjectCallback( jlong  class_tag,
 106                     jlong  size,
 107                     jlong* tag_ptr,
 108                     void*  user_data) {
 109 
 110     int count = 0;
 111 
 112     /* clean modificationCounter on first iteration */
 113     if (getCounter(&iterationCount) == 0) {
 114         setCounter(&modificationCount, 0);
 115     }
 116     increaseCounter(&iterationCount);
 117 
 118     /* check if modificationCounter is 0 for each iteration */
 119     count = getCounter(&modificationCount);
 120     if (count > 0) {
 121         setCounter(&errorCount, count);
 122     }
 123 
 124     return JVMTI_ITERATION_CONTINUE;
 125 }
 126 
 127 /* jvmtiHeapRootCallback */
 128 jvmtiIterationControl JNICALL
 129 heapRootCallback( jvmtiHeapRootKind root_kind,
 130                   jlong class_tag,
 131                   jlong size,
 132                   jlong* tag_ptr,
 133                   void* user_data) {
 134 
 135     int count = 0;
 136 
 137     /* clean modificationCounter on first iteration */
 138     if (getCounter(&iterationCount) == 0) {
 139         setCounter(&modificationCount, 0);
 140     }
 141     increaseCounter(&iterationCount);
 142 
 143     /* check if modificationCounter is 0 for each iteration */
 144     count = getCounter(&modificationCount);
 145     if (count > 0) {
 146         setCounter(&errorCount, count);
 147     }
 148 
 149     return JVMTI_ITERATION_CONTINUE;
 150 }
 151 
 152 /* jvmtiStackReferenceCallback */
 153 jvmtiIterationControl JNICALL
 154 stackReferenceCallback( jvmtiHeapRootKind root_kind,
 155                         jlong     class_tag,
 156                         jlong     size,
 157                         jlong*    tag_ptr,
 158                         jlong     thread_tag,
 159                         jint      depth,
 160                         jmethodID method,
 161                         jint      slot,
 162                         void*     user_data) {
 163 
 164     int count = 0;
 165 
 166     /* clean modificationCounter on first iteration */
 167     if (getCounter(&iterationCount) == 0) {
 168         setCounter(&modificationCount, 0);
 169     }
 170     increaseCounter(&iterationCount);
 171 
 172     /* check if modificationCounter is 0 for each iteration */
 173     count = getCounter(&modificationCount);
 174     if (count > 0) {
 175         setCounter(&errorCount, count);
 176     }
 177 
 178     return JVMTI_ITERATION_CONTINUE;
 179 }
 180 
 181 
 182 /* jvmtiObjectReferenceCallback */
 183 jvmtiIterationControl JNICALL
 184 objectReferenceCallback( jvmtiObjectReferenceKind reference_kind,
 185                          jlong  class_tag,
 186                          jlong  size,
 187                          jlong* tag_ptr,
 188                          jlong  referrer_tag,
 189                          jint   referrer_index,
 190                          void*  user_data) {
 191 
 192     int count = 0;
 193 
 194     /* clean modificationCounter on first iteration */
 195     if (getCounter(&iterationCount) == 0) {
 196         setCounter(&modificationCount, 0);
 197     }
 198     increaseCounter(&iterationCount);
 199 
 200     /* check if modificationCounter is 0 for each iteration */
 201     count = getCounter(&modificationCount);
 202     if (count > 0) {
 203         setCounter(&errorCount, count);
 204     }
 205 
 206     return JVMTI_ITERATION_CONTINUE;
 207 }
 208 
 209 
 210 /***********************************************************************/
 211 
 212 void JNICALL
 213 FieldModification( jvmtiEnv    *jvmti_env,
 214                    JNIEnv      *env,
 215                    jthread     thr,
 216                    jmethodID   method,
 217                    jlocation   location,
 218                    jclass      field_klass,
 219                    jobject     obj,
 220                    jfieldID    field,
 221                    char        sig,
 222                    jvalue      new_value ) {
 223 
 224     increaseCounter(&modificationCount);
 225 }
 226 
 227 /***********************************************************************/
 228 
 229 JNIEXPORT void JNICALL
 230 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t002_setTag( JNIEnv* jni,
 231                                                           jclass  klass,
 232                                                           jobject target, /* object to be tagged */
 233                                                           jlong   tag ) {
 234 
 235     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(target, tag))) {
 236         nsk_jvmti_setFailStatus();
 237     }
 238 }
 239 
 240 JNIEXPORT void JNICALL
 241 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t002_runIterateOverHeap( JNIEnv* jni,
 242                                                                       jclass  klass ) {
 243     int count = 0;
 244 
 245     setCounter(&errorCount, 0);
 246     setCounter(&modificationCount, 0);
 247     setCounter(&iterationCount, 0);
 248 
 249     NSK_DISPLAY0("Calling IterateOverHeap...\n");
 250     if (!NSK_JVMTI_VERIFY(jvmti->IterateOverHeap(JVMTI_HEAP_OBJECT_TAGGED,
 251                                                  heapObjectCallback,
 252                                                  NULL /*user_data*/))) {
 253         nsk_jvmti_setFailStatus();
 254     }
 255     NSK_DISPLAY0("IterateOverHeap finished.\n");
 256 
 257     NSK_DISPLAY1("Iterations count: %d\n", getCounter(&iterationCount));
 258     NSK_DISPLAY1("Modifications count: %d\n", getCounter(&modificationCount));
 259 
 260     count = getCounter(&errorCount);
 261     NSK_DISPLAY1("Errors detected: %d\n", count);
 262     // because of racing in FieldModification event, one event can be fired before safepoint occures
 263     if (count > 1) {
 264         NSK_COMPLAIN1("FieldMofification events detected during heap iteration: %d\n", count);
 265         nsk_jvmti_setFailStatus();
 266     }
 267 }
 268 
 269 JNIEXPORT void JNICALL
 270 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t002_runIterateOverReachableObjects( JNIEnv* jni,
 271                                                                                   jclass  klass ) {
 272     int count = 0;
 273 
 274     setCounter(&errorCount, 0);
 275     setCounter(&modificationCount, 0);
 276     setCounter(&iterationCount, 0);
 277 
 278     NSK_DISPLAY0("Calling IterateOverReachableObjects...\n");
 279     if (!NSK_JVMTI_VERIFY(jvmti->IterateOverReachableObjects(heapRootCallback,
 280                                                              stackReferenceCallback,
 281                                                              objectReferenceCallback,
 282                                                              NULL /*user_data*/))) {
 283         nsk_jvmti_setFailStatus();
 284     }
 285     NSK_DISPLAY0("IterateOverReachableObjects finished.\n");
 286 
 287     NSK_DISPLAY1("Iterations count: %d\n", getCounter(&iterationCount));
 288     NSK_DISPLAY1("Modifications count: %d\n", getCounter(&modificationCount));
 289 
 290     count = getCounter(&errorCount);
 291     NSK_DISPLAY1("Errors detected: %d\n", count);
 292     // because of racing in FieldModification event, one event can be fired before safepoint occures
 293     if (count > 1) {
 294         NSK_COMPLAIN1("FieldMofification events detected during heap iteration: %d\n", count);
 295         nsk_jvmti_setFailStatus();
 296     }
 297 }
 298 
 299 JNIEXPORT void JNICALL
 300 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t002_runIterateOverInstancesOfClass( JNIEnv* jni,
 301                                                                                   jclass  klass ) {
 302     int count = 0;
 303 
 304     setCounter(&errorCount, 0);
 305     setCounter(&modificationCount, 0);
 306     setCounter(&iterationCount, 0);
 307 
 308     NSK_DISPLAY0("Calling IterateOverInstancesOfClass...\n");
 309     if (!NSK_JVMTI_VERIFY(jvmti->IterateOverInstancesOfClass(debugeeClass,
 310                                                              JVMTI_HEAP_OBJECT_TAGGED,
 311                                                              heapObjectCallback,
 312                                                              NULL /*user_data*/))) {
 313         nsk_jvmti_setFailStatus();
 314     }
 315     NSK_DISPLAY0("IterateOverInstancesOfClass finished.\n");
 316 
 317     NSK_DISPLAY1("Iterations count: %d\n", getCounter(&iterationCount));
 318     NSK_DISPLAY1("Modifications count: %d\n", getCounter(&modificationCount));
 319 
 320     count = getCounter(&errorCount);
 321     NSK_DISPLAY1("Errors detected: %d\n", count);
 322     // because of racing in FieldModification event, one event can be fired before safepoint occures
 323     if (count > 1) {
 324         NSK_COMPLAIN1("FieldMofification events detected during heap iteration: %d\n", count);
 325         nsk_jvmti_setFailStatus();
 326     }
 327 }
 328 
 329 JNIEXPORT void JNICALL
 330 Java_nsk_jvmti_scenarios_allocation_AP04_ap04t002_runIterateOverObjectsReachableFromObject( JNIEnv* jni,
 331                                                                                             jclass  klass ) {
 332     jobject root = NULL;
 333     int count = 0;
 334 
 335     if (!NSK_JNI_VERIFY(jni, (root =
 336                 jni->GetStaticObjectField(debugeeClass, rootFieldID)) != NULL )) {
 337         NSK_COMPLAIN0("GetStaticObjectField returned NULL for 'root' field value\n\n");
 338         nsk_jvmti_setFailStatus();
 339         return;
 340     }
 341 
 342     setCounter(&errorCount, 0);
 343     setCounter(&modificationCount, 0);
 344     setCounter(&iterationCount, 0);
 345 
 346     NSK_DISPLAY0("Calling IterateOverObjectsReachableFromObject...\n");
 347     if (!NSK_JVMTI_VERIFY(jvmti->IterateOverObjectsReachableFromObject(root,
 348                                                                        objectReferenceCallback,
 349                                                                        NULL /*user_data*/))) {
 350         nsk_jvmti_setFailStatus();
 351     }
 352     NSK_DISPLAY0("IterateOverObjectsReachableFromObject finished.\n");
 353 
 354     NSK_DISPLAY1("Iterations count: %d\n", getCounter(&iterationCount));
 355     NSK_DISPLAY1("Modifications count: %d\n", getCounter(&modificationCount));
 356 
 357     count = getCounter(&errorCount);
 358     NSK_DISPLAY1("Errors detected: %d\n", count);
 359     // because of racing in FieldModification event, one event can be fired before safepoint occures
 360     if (count > 1) {
 361         NSK_COMPLAIN1("FieldMofification events detected during heap iteration: %d\n", count);
 362         nsk_jvmti_setFailStatus();
 363     }
 364 }
 365 
 366 static void JNICALL
 367 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
 368 
 369     NSK_DISPLAY0("Wait for debugee start\n\n");
 370     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
 371         return;
 372 
 373     NSK_DISPLAY1("Find debugee class: %s\n", DEBUGEE_SIGNATURE);
 374     debugeeClass = nsk_jvmti_classBySignature(DEBUGEE_SIGNATURE);
 375     if (debugeeClass == NULL) {
 376         nsk_jvmti_setFailStatus();
 377         return;
 378     }
 379 
 380     if (!NSK_JNI_VERIFY(jni, (debugeeClass = (jclass)jni->NewGlobalRef(debugeeClass)) != NULL))
 381         return;
 382 
 383     NSK_DISPLAY1("Find ID of 'root' field: %s\n", ROOT_SIGNATURE);
 384     if (!NSK_JNI_VERIFY(jni, (rootFieldID =
 385             jni->GetStaticFieldID(debugeeClass, "root", ROOT_SIGNATURE)) != NULL )) {
 386         nsk_jvmti_setFailStatus();
 387         return;
 388     }
 389 
 390     NSK_DISPLAY0("Find ID of 'modified' field\n");
 391     if (!NSK_JNI_VERIFY(jni, (modifiedFieldID =
 392             jni->GetStaticFieldID(debugeeClass, "modified", "I")) != NULL )) {
 393         nsk_jvmti_setFailStatus();
 394         return;
 395     }
 396 
 397     NSK_DISPLAY0("Set FieldModification watchpoint for 'modified' field\n");
 398     if (!NSK_JVMTI_VERIFY(jvmti->SetFieldModificationWatch(debugeeClass, modifiedFieldID))) {
 399         nsk_jvmti_setFailStatus();
 400         return;
 401     }
 402 
 403     NSK_DISPLAY0("Let debugee to run test cases\n");
 404     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
 405         return;
 406 
 407     NSK_DISPLAY0("Wait for completion of test cases\n\n");
 408     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout)))
 409         return;
 410 
 411     NSK_TRACE(jni->DeleteGlobalRef(debugeeClass));
 412     NSK_TRACE(jvmti->DestroyRawMonitor(counterMonitor_ptr));
 413 
 414     NSK_DISPLAY0("Let debugee to finish\n");
 415     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
 416         return;
 417 }
 418 
 419 #ifdef STATIC_BUILD
 420 JNIEXPORT jint JNICALL Agent_OnLoad_ap04t002(JavaVM *jvm, char *options, void *reserved) {
 421     return Agent_Initialize(jvm, options, reserved);
 422 }
 423 JNIEXPORT jint JNICALL Agent_OnAttach_ap04t002(JavaVM *jvm, char *options, void *reserved) {
 424     return Agent_Initialize(jvm, options, reserved);
 425 }
 426 JNIEXPORT jint JNI_OnLoad_ap04t002(JavaVM *jvm, char *options, void *reserved) {
 427     return JNI_VERSION_1_8;
 428 }
 429 #endif
 430 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 431     /* init framework and parse options */
 432     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 433         return JNI_ERR;
 434 
 435     /* create JVMTI environment */
 436     if (!NSK_VERIFY((jvmti =
 437             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 438         return JNI_ERR;
 439 
 440     if (!NSK_JVMTI_VERIFY(jvmti->CreateRawMonitor("counterMonitor", &counterMonitor_ptr))) {
 441         return JNI_ERR;
 442     }
 443 
 444     memset(&caps, 0, sizeof(jvmtiCapabilities));
 445     caps.can_tag_objects = 1;
 446     caps.can_generate_field_modification_events = 1;
 447 
 448     if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps)))
 449         return JNI_ERR;
 450 
 451     if (!NSK_JVMTI_VERIFY(jvmti->GetCapabilities(&caps)))
 452         return JNI_ERR;
 453 
 454     if (!caps.can_tag_objects)
 455         NSK_DISPLAY0("Warning: tagging objects is not available\n");
 456     if (!caps.can_generate_field_modification_events)
 457         NSK_DISPLAY0("Warning: generation of field modification events is not available\n");
 458 
 459     /* set event callback */
 460     NSK_DISPLAY0("setting event callbacks ...\n");
 461     (void) memset(&callbacks, 0, sizeof(callbacks));
 462 
 463     callbacks.FieldModification = &FieldModification;
 464     if (!NSK_JVMTI_VERIFY(jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks))))
 465         return JNI_ERR;
 466 
 467     NSK_DISPLAY0("setting event callbacks done.\n");
 468 
 469     NSK_DISPLAY0("enabling JVMTI events ...\n");
 470     if (!NSK_JVMTI_VERIFY(jvmti->SetEventNotificationMode(JVMTI_ENABLE,
 471                                                           JVMTI_EVENT_FIELD_MODIFICATION,
 472                                                           NULL)))
 473         return JNI_ERR;
 474     NSK_DISPLAY0("enabling the events done.\n");
 475 
 476     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 477         return JNI_ERR;
 478     NSK_DISPLAY0("agentProc has been set\n\n");
 479 
 480     return JNI_OK;
 481 }
 482 
 483 }