1 /*
   2  * Copyright (c) 2007, 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 static jlong timeout = 0;
  35 
  36 #define DEBUGEE_CLASS_NAME      "nsk/jvmti/unit/FollowReferences/followref002"
  37 #define ROOT_OBJECT_CLASS_NAME  "nsk/jvmti/unit/FollowReferences/followref002RootTestedClass"
  38 #define ROOT_OBJECT_CLASS_SIG   "L" ROOT_OBJECT_CLASS_NAME ";"
  39 #define CHAIN_OBJECT_CLASS_NAME "nsk/jvmti/unit/FollowReferences/followref002TestedClass"
  40 #define CHAIN_OBJECT_CLASS_SIG  "L" CHAIN_OBJECT_CLASS_NAME ";"
  41 
  42 #define OBJECT_FIELD_NAME               "object"
  43 #define REACHABLE_CHAIN_FIELD_NAME      "reachableChain"
  44 #define UNREACHABLE_CHAIN_FIELD_NAME    "unreachableChain"
  45 #define TAIL_FIELD_NAME                 "tail"
  46 
  47 
  48 #define DEFAULT_CHAIN_LENGTH 3
  49 
  50 typedef struct ObjectDescStruct {
  51     jlong tag;           /* Tag of the object */
  52     jlong exp_class_tag; /* Expected tag of the object class */
  53     jlong class_tag;     /* Reported tag of the object class */
  54     jint  exp_found;     /* Expected number of iterations through the object */
  55     jint  found;         /* Reported number of iterations through the object */
  56 } ObjectDesc;
  57 
  58 static int chainLength   = 0;
  59 static int objectsCount  = 0;
  60 static int fakeUserData  = 0;
  61 static int userDataError = 0;
  62 
  63 static ObjectDesc* objectDescList = NULL;
  64 
  65 static jlong rootClassTag   = 9;
  66 static jlong chainClassTag  = 99;
  67 static jlong rootObjectTag  = 10;
  68 static jlong chainObjectTag = 100;
  69 
  70 static jvmtiHeapCallbacks heapCallbacks;
  71 
  72 static const char* ref_kind_str[28] = {
  73    "unknown_0",
  74    "JVMTI_HEAP_REFERENCE_CLASS",
  75    "JVMTI_HEAP_REFERENCE_FIELD",
  76    "JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT",
  77    "JVMTI_HEAP_REFERENCE_CLASS_LOADER",
  78    "JVMTI_HEAP_REFERENCE_SIGNERS",
  79    "JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN",
  80    "JVMTI_HEAP_REFERENCE_INTERFACE",
  81    "JVMTI_HEAP_REFERENCE_STATIC_FIELD",
  82    "JVMTI_HEAP_REFERENCE_CONSTANT_POOL",
  83    "unknown_10", "unknown_11", "unknown_12",
  84    "unknown_13", "unknown_14", "unknown_15", "unknown_16",
  85    "unknown_17", "unknown_18", "unknown_19", "unknown_20",
  86    "JVMTI_HEAP_REFERENCE_JNI_GLOBAL",
  87    "JVMTI_HEAP_REFERENCE_SYSTEM_CLASS",
  88    "JVMTI_HEAP_REFERENCE_MONITOR",
  89    "JVMTI_HEAP_REFERENCE_STACK_LOCAL",
  90    "JVMTI_HEAP_REFERENCE_JNI_LOCAL",
  91    "JVMTI_HEAP_REFERENCE_THREAD",
  92    "JVMTI_HEAP_REFERENCE_OTHER"
  93 };
  94 
  95 #define DEREF(ptr) (((ptr) == NULL ? 0 : *(ptr)))
  96 
  97 /* ============================================================================= */
  98 
  99 /** Obtain chain of tested objects and tag them recursively. */
 100 static int getAndTagChainObjects(
 101     jvmtiEnv*  jvmti,
 102     JNIEnv*    jni,
 103     jobject    firstObject,
 104     jfieldID   firstField,
 105     const char firstFieldName[],
 106     jfieldID   nextField,
 107     const char nextFieldName[],
 108     int        count,
 109     ObjectDesc objectDescList[],
 110     jlong      tag,
 111     int        reachable)
 112 {
 113     jobject obj = NULL;
 114     jlong objTag = (reachable ? tag : -tag);
 115 
 116     if (count <= 0)
 117         return NSK_TRUE;
 118 
 119     count--;
 120     tag++;
 121 
 122     if (!NSK_JNI_VERIFY(jni, (obj = jni->GetObjectField(firstObject, firstField)) != NULL)) {
 123         nsk_jvmti_setFailStatus();
 124         return NSK_FALSE;
 125     }
 126 
 127     objectDescList[count].tag = objTag;
 128     if (reachable) {
 129         objectDescList[count].exp_found++;
 130     }
 131 
 132     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(obj, objTag))) {
 133         nsk_jvmti_setFailStatus();
 134     }
 135     printf("        tag=%-5ld object=0x%p\n", (long)objTag, (void*)obj);
 136     fflush(0);
 137     if (!getAndTagChainObjects(jvmti, jni, obj,
 138                                nextField,
 139                                nextFieldName,
 140                                nextField,
 141                                nextFieldName,
 142                                count,
 143                                objectDescList,
 144                                tag,
 145                                reachable)) {
 146         return NSK_FALSE;
 147     }
 148 
 149     NSK_TRACE(jni->DeleteLocalRef(obj));
 150     return NSK_TRUE;
 151 } /* getAndTagChainObjects */
 152 
 153 /** Obtain all tested objects from debugee class and tag them recursively. */
 154 static int getAndTagTestedObjects(
 155     jvmtiEnv*    jvmti,
 156     JNIEnv*      jni,
 157     int          chainLength,
 158     int*         objectsCount,
 159     ObjectDesc** objectDescList,
 160     jobject*     rootObject)
 161 {
 162     jclass debugeeClass = NULL;
 163     jclass rootObjectClass = NULL;
 164     jclass chainObjectClass = NULL;
 165 
 166     jfieldID objectField = NULL;
 167     jfieldID reachableChainField = NULL;
 168     jfieldID unreachableChainField = NULL;
 169     jfieldID tailField = NULL;
 170 
 171     /* root object + reachable and unreachable object chains */
 172     *objectsCount = 1 + 2 * chainLength;
 173 
 174     printf("Allocate memory for objects list: %d objects\n", *objectsCount);
 175     fflush(0);
 176     if (!NSK_JVMTI_VERIFY(jvmti->Allocate((*objectsCount * sizeof(ObjectDesc)),
 177                                           (unsigned char**)objectDescList))) {
 178         nsk_jvmti_setFailStatus();
 179         return NSK_FALSE;
 180     }
 181     printf("  ... allocated array: 0x%p\n", (void*)objectDescList);
 182     fflush(0);
 183 
 184     {
 185         int k;
 186         for (k = 0; k < *objectsCount; k++) {
 187             (*objectDescList)[k].tag = 0;
 188             (*objectDescList)[k].exp_class_tag = chainClassTag;
 189             (*objectDescList)[k].exp_found = 0;
 190             (*objectDescList)[k].found = 0;
 191         }
 192     }
 193     (*objectDescList)[0].exp_class_tag = rootClassTag;
 194 
 195     printf("Find debugee class: %s\n", DEBUGEE_CLASS_NAME);
 196     fflush(0);
 197     if (!NSK_JNI_VERIFY(jni, (debugeeClass = jni->FindClass(DEBUGEE_CLASS_NAME)) != NULL)) {
 198         nsk_jvmti_setFailStatus();
 199         return NSK_FALSE;
 200     }
 201     printf("  ... found class: 0x%p\n", (void*)debugeeClass);
 202 
 203     printf("Find root object class: %s\n", ROOT_OBJECT_CLASS_NAME);
 204     fflush(0);
 205     if (!NSK_JNI_VERIFY(jni, (rootObjectClass = jni->FindClass(ROOT_OBJECT_CLASS_NAME)) != NULL)) {
 206         nsk_jvmti_setFailStatus();
 207         return NSK_FALSE;
 208     }
 209     printf("  ... found class: 0x%p\n", (void*)rootObjectClass);
 210 
 211     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(rootObjectClass, rootClassTag))) {
 212         nsk_jvmti_setFailStatus();
 213     }
 214     printf("        tag=%-5ld rootClass=0x%p\n", (long)rootClassTag, (void*)rootObjectClass);
 215 
 216     printf("Find chain object class: %s\n", CHAIN_OBJECT_CLASS_NAME);
 217     fflush(0);
 218     if (!NSK_JNI_VERIFY(jni, (chainObjectClass =
 219             jni->FindClass(CHAIN_OBJECT_CLASS_NAME)) != NULL)) {
 220         nsk_jvmti_setFailStatus();
 221         return NSK_FALSE;
 222     }
 223     printf("  ... found class: 0x%p\n", (void*)chainObjectClass);
 224 
 225     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(chainObjectClass, chainClassTag))) {
 226         nsk_jvmti_setFailStatus();
 227     }
 228     printf("        tag=%-5ld chainClass=0x%p\n", (long)chainClassTag, (void*)chainObjectClass);
 229 
 230     printf("Find static field in debugee class: %s\n", OBJECT_FIELD_NAME);
 231     fflush(0);
 232     if (!NSK_JNI_VERIFY(jni, (objectField =
 233             jni->GetStaticFieldID(debugeeClass, OBJECT_FIELD_NAME, ROOT_OBJECT_CLASS_SIG)) != NULL)) {
 234         nsk_jvmti_setFailStatus();
 235         return NSK_FALSE;
 236     }
 237     printf("  ... got fieldID: 0x%p\n", (void*)objectField);
 238 
 239     printf("Find instance field in root object class: %s\n", REACHABLE_CHAIN_FIELD_NAME);
 240     fflush(0);
 241     if (!NSK_JNI_VERIFY(jni, (reachableChainField =
 242             jni->GetFieldID(rootObjectClass, REACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 243         nsk_jvmti_setFailStatus();
 244         return NSK_FALSE;
 245     }
 246     printf("  ... got fieldID: 0x%p\n", (void*)reachableChainField);
 247 
 248     printf("Find instance field in root object class: %s\n", UNREACHABLE_CHAIN_FIELD_NAME);
 249     fflush(0);
 250     if (!NSK_JNI_VERIFY(jni, (unreachableChainField =
 251             jni->GetFieldID(rootObjectClass, UNREACHABLE_CHAIN_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 252         nsk_jvmti_setFailStatus();
 253         return NSK_FALSE;
 254     }
 255     printf("  ... got fieldID: 0x%p\n", (void*)unreachableChainField);
 256 
 257     printf("Find instance field in chain object class: %s\n", TAIL_FIELD_NAME);
 258     fflush(0);
 259     if (!NSK_JNI_VERIFY(jni, (tailField =
 260             jni->GetFieldID(chainObjectClass, TAIL_FIELD_NAME, CHAIN_OBJECT_CLASS_SIG)) != NULL)) {
 261         nsk_jvmti_setFailStatus();
 262         return NSK_FALSE;
 263     }
 264     printf("  ... got fieldID: 0x%p\n", (void*)tailField);
 265 
 266     printf("Get root object from static field: %s\n", OBJECT_FIELD_NAME);
 267     fflush(0);
 268     if (!NSK_JNI_VERIFY(jni, (*rootObject =
 269             jni->GetStaticObjectField(debugeeClass, objectField)) != NULL)) {
 270         nsk_jvmti_setFailStatus();
 271         return NSK_FALSE;
 272     }
 273     printf("  ... got object: 0x%p\n", (void*)*rootObject);
 274     fflush(0);
 275 
 276     if (!NSK_JNI_VERIFY(jni, (*rootObject = jni->NewGlobalRef(*rootObject)) != NULL)) {
 277         nsk_jvmti_setFailStatus();
 278         return NSK_FALSE;
 279     }
 280     printf("  ... global ref: 0x%p\n", (void*)*rootObject);
 281 
 282     printf("Obtain and tag chain objects:\n");
 283 
 284     printf("    root tested object:\n");
 285     fflush(0);
 286     if (!NSK_JVMTI_VERIFY(jvmti->SetTag(*rootObject, rootObjectTag))) {
 287         nsk_jvmti_setFailStatus();
 288     }
 289     printf("        tag=%-5ld object=0x%p\n", (long)rootObjectTag, (void*)*rootObject);
 290 
 291     (*objectDescList)[0].tag = rootObjectTag;
 292 
 293     /* Root object must be referenced 1 time */
 294     (*objectDescList)[0].exp_found = 1;
 295 
 296     /* Object with tag=101 must be referenced 2 times */
 297     (*objectDescList)[chainLength].exp_found = 1;
 298 
 299     printf("    reachable objects chain: %d objects\n", chainLength);
 300     fflush(0);
 301     if (!getAndTagChainObjects(jvmti, jni, *rootObject,
 302                                reachableChainField,
 303                                REACHABLE_CHAIN_FIELD_NAME,
 304                                tailField,
 305                                TAIL_FIELD_NAME,
 306                                chainLength,
 307                                (*objectDescList) + 1,
 308                                chainObjectTag,
 309                                NSK_TRUE)) {
 310         nsk_jvmti_setFailStatus();
 311         return NSK_FALSE;
 312     }
 313 
 314     printf("    unreachable objects chain: %d objects\n", chainLength);
 315     if (!getAndTagChainObjects(jvmti, jni, *rootObject,
 316                                unreachableChainField,
 317                                UNREACHABLE_CHAIN_FIELD_NAME,
 318                                tailField,
 319                                TAIL_FIELD_NAME,
 320                                chainLength,
 321                                (*objectDescList) + 1 + chainLength,
 322                                chainObjectTag,
 323                                NSK_FALSE)) {
 324         nsk_jvmti_setFailStatus();
 325         return NSK_FALSE;
 326     }
 327 
 328     return NSK_TRUE;
 329 } /* getAndTagTestedObjects */
 330 
 331 /** Check if tagged objects were iterated. */
 332 static int checkTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni,
 333                                 int chainLength, ObjectDesc objectDescList[]) {
 334     int success = NSK_TRUE;
 335     int i, idx;
 336 
 337     printf("Following tagged objects were iterated:\n");
 338 
 339     printf("Root tested object:\n");
 340     printf("   tag:                 %ld\n"
 341            "   expected to iterate: %d times\n"
 342            "   iterated:            %d times\n",
 343            (long) objectDescList[0].tag,
 344                   objectDescList[0].exp_found,
 345                   objectDescList[0].found);
 346     if (objectDescList[0].found != objectDescList[0].exp_found) {
 347         NSK_COMPLAIN1("Root tested object unexpectedly iterated %d times\n",
 348                       objectDescList[0].found);
 349         nsk_jvmti_setFailStatus();
 350     }
 351 
 352     printf("\nReachable objects:\n");
 353     fflush(0);
 354     for (i = 0; i < chainLength; i++) {
 355         idx = i + 1;
 356         printf("Reachable object:\n"
 357                "   tag:                 %-3ld\n"
 358                "   expected to iterate: %d times\n"
 359                "   iterated:            %d times\n",
 360                 (long) objectDescList[idx].tag,
 361                        objectDescList[idx].exp_found,
 362                        objectDescList[idx].found);
 363         if (objectDescList[i + 1].found <= 0 && objectDescList[i + 1].exp_found > 0) {
 364             NSK_COMPLAIN0("Reachable object was not iterated\n");
 365             nsk_jvmti_setFailStatus();
 366         }
 367         if (objectDescList[idx].found != objectDescList[idx].exp_found) {
 368             NSK_COMPLAIN0("Reachable object was iterated unexpected number of times\n");
 369             nsk_jvmti_setFailStatus();
 370         }
 371     }
 372 
 373     printf("\nUnreachable objects:\n");
 374     for (i = 0; i < chainLength; i++) {
 375         idx = i + 1 + chainLength;
 376 
 377         printf("Unreachable object:\n"
 378                "   tag:                 %ld\n"
 379                "   expected to iterate: %d times\n"
 380                "   iterated:            %d times\n",
 381                 (long) objectDescList[idx].tag,
 382                        objectDescList[idx].exp_found,
 383                        objectDescList[idx].found);
 384         if (objectDescList[idx].found > 0) {
 385             NSK_COMPLAIN0("Unreachable object was iterated\n");
 386             nsk_jvmti_setFailStatus();
 387         }
 388         fflush(0);
 389     }
 390 
 391     return NSK_TRUE;
 392 } /* checkTestedObjects */
 393 
 394 /** Release references to the tested objects and free allocated memory. */
 395 static int releaseTestedObjects(jvmtiEnv* jvmti, JNIEnv* jni, int chainLength,
 396                                 ObjectDesc* objectDescList, jobject rootObject) {
 397     if (rootObject != NULL) {
 398         printf("Release object reference to root tested object: 0x%p\n", rootObject);
 399         NSK_TRACE(jni->DeleteGlobalRef(rootObject));
 400     }
 401 
 402     if (objectDescList != NULL) {
 403         printf("Deallocate objects list: 0x%p\n", (void*)objectDescList);
 404         if (!NSK_JVMTI_VERIFY(jvmti->Deallocate((unsigned char*)objectDescList))) {
 405             nsk_jvmti_setFailStatus();
 406         }
 407     }
 408 
 409     fflush(0);
 410     return NSK_TRUE;
 411 } /* releaseTestedObjects */
 412 
 413 /* ============================================================================= */
 414 
 415 /** heapReferenceCallback for heap iterator. */
 416 jint JNICALL heapReferenceCallback(
 417      jvmtiHeapReferenceKind        reference_kind,
 418      const jvmtiHeapReferenceInfo* reference_info,
 419      jlong                         class_tag,
 420      jlong                         referrer_class_tag,
 421      jlong                         size,
 422      jlong*                        tag_ptr,
 423      jlong*                        referrer_tag_ptr,
 424      jint                          length,
 425      void*                         user_data)
 426 {
 427     jint referrer_index = 0;
 428     jlong tag     = DEREF(tag_ptr);
 429     jlong ref_tag = DEREF(referrer_tag_ptr);
 430 
 431     switch (reference_kind) {
 432         case JVMTI_HEAP_REFERENCE_CONSTANT_POOL:
 433             referrer_index = reference_info->constant_pool.index;
 434             break;
 435         case JVMTI_HEAP_REFERENCE_FIELD:
 436         case JVMTI_HEAP_REFERENCE_STATIC_FIELD:
 437             referrer_index = reference_info->field.index;
 438             break;
 439         case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT:
 440             referrer_index = reference_info->array.index;
 441             break;
 442         case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
 443             referrer_index = reference_info->stack_local.slot;
 444             /* Fall through */
 445         case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
 446             referrer_index |= reference_info->stack_local.depth << 16;
 447             break;
 448         default:
 449             // TODO: check that realy should be done w/ other jvmtiHeapReferenceKind
 450             break;
 451     }
 452 
 453     printf("     heapReferenceCallback: ref=%s, class_tag=%-3ld, tag=%-3ld,"
 454            " size=%-3ld, ref_tag=%-3ld, ref_idx=%#x\n",
 455            ref_kind_str[reference_kind],
 456            (long) class_tag,
 457            (long) tag,
 458            (long) size,
 459            (long) ref_tag,
 460            (int ) referrer_index);
 461     fflush(0);
 462 
 463     if (tag_ptr == NULL) {
 464         NSK_COMPLAIN1("NULL tag_ptr is passed to heapReferenceCallback:"
 465                       " tag_ptr=0x%p\n", (void*)tag_ptr);
 466         nsk_jvmti_setFailStatus();
 467     }
 468 
 469     if (tag_ptr != NULL && *tag_ptr != 0) {
 470         int found = 0;
 471         int i;
 472 
 473         for (i = 0; i < objectsCount; i++) {
 474             if (*tag_ptr == objectDescList[i].tag) {
 475                 found++;
 476                 objectDescList[i].found++;
 477 
 478                 if (*tag_ptr < 0) {
 479                     NSK_COMPLAIN0("Unreachable tagged object is passed to heapReferenceCallback\n");
 480                     nsk_jvmti_setFailStatus();
 481                 }
 482                 break;
 483             }
 484         }
 485 
 486         if (reference_kind != JVMTI_HEAP_REFERENCE_CLASS && found <= 0) {
 487             NSK_COMPLAIN0("Unknown tagged object is passed to heapReferenceCallback\n");
 488             nsk_jvmti_setFailStatus();
 489         }
 490     }
 491 
 492     if (user_data != &fakeUserData && !userDataError) {
 493        NSK_COMPLAIN2("Unexpected user_data is passed to heapReferenceCallback:\n"
 494                       "   expected:       0x%p\n"
 495                       "   actual:         0x%p\n",
 496                       user_data,
 497                       &fakeUserData);
 498         nsk_jvmti_setFailStatus();
 499         userDataError++;
 500     }
 501 
 502     switch (reference_kind) {
 503         int i;
 504         case JVMTI_HEAP_REFERENCE_CLASS: {
 505             if (tag == 0) {
 506                 break;
 507             }
 508             if (tag != rootClassTag && tag != chainClassTag) {
 509                 NSK_COMPLAIN0("Unknown tagged class is passed to heapReferenceCallback\n");
 510                 nsk_jvmti_setFailStatus();
 511             }
 512             for (i = 0; i < objectsCount; i++) {
 513                if (ref_tag == objectDescList[i].tag) {
 514                    if (objectDescList[i].exp_class_tag != tag) {
 515                        NSK_COMPLAIN2("Wrong tag in heapReferenceCallback/JVMTI_HEAP_REFERENCE_CLASS:\n"
 516                                      "Expected: %-3ld\n"
 517                                      "Passed:   %-3ld\n",
 518                                       objectDescList[i].exp_class_tag,
 519                                       tag);
 520                        nsk_jvmti_setFailStatus();
 521                    }
 522                    break;
 523                }
 524             }
 525             break;
 526         }
 527         case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:
 528         case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS:
 529         case JVMTI_HEAP_REFERENCE_MONITOR:
 530         case JVMTI_HEAP_REFERENCE_STACK_LOCAL:
 531         case JVMTI_HEAP_REFERENCE_JNI_LOCAL:
 532         case JVMTI_HEAP_REFERENCE_THREAD:
 533         case JVMTI_HEAP_REFERENCE_OTHER: {
 534             NSK_COMPLAIN1("This reference kind was not expected: %s\n",
 535                            ref_kind_str[reference_kind]);
 536             fflush(0);
 537             nsk_jvmti_setFailStatus();
 538             return 0;
 539         }
 540         default:
 541             // TODO: check that realy should be done w/ other jvmtiHeapReferenceKind
 542             break;
 543     }
 544     return JVMTI_VISIT_OBJECTS;
 545 }
 546 
 547 jint JNICALL primitiveFieldCallback(
 548      jvmtiHeapReferenceKind        reference_kind,
 549      const jvmtiHeapReferenceInfo* reference_info,
 550      jlong                         class_tag,
 551      jlong*                        tag_ptr,
 552      jvalue                        value,
 553      jvmtiPrimitiveType            value_type,
 554      void*                         user_data)
 555 {
 556     printf(" primitiveFieldCallback: ref=%s, class_tag=%-3ld, tag=%-3ld, type=%c\n",
 557            ref_kind_str[reference_kind],
 558            (long) class_tag,
 559            (long) DEREF(tag_ptr),
 560            (int ) value_type);
 561     fflush(0);
 562     return 0;
 563 }
 564 
 565 jint JNICALL arrayPrimitiveValueCallback(
 566      jlong              class_tag,
 567      jlong              size,
 568      jlong*             tag_ptr,
 569      jint               element_count,
 570      jvmtiPrimitiveType element_type,
 571      const void*        elements,
 572      void*              user_data)
 573 {
 574     printf(" arrayPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d, type=%c\n",
 575            (long) class_tag,
 576            (long) DEREF(tag_ptr),
 577            (int ) element_count,
 578            (int ) element_type);
 579     fflush(0);
 580     return 0;
 581 }
 582 
 583 jint JNICALL stringPrimitiveValueCallback(
 584      jlong        class_tag,
 585      jlong        size,
 586      jlong*       tag_ptr,
 587      const jchar* value,
 588      jint         value_length,
 589      void*        user_data)
 590 {
 591     printf("stringPrimitiveValueCallback: class_tag=%-3ld, tag=%-3ld, len=%d\n",
 592            (long) class_tag,
 593            (long) DEREF(tag_ptr),
 594            (int ) value_length);
 595     fflush(0);
 596     return 0;
 597 }
 598 
 599 /* ============================================================================= */
 600 
 601 /** Agent algorithm. */
 602 static void JNICALL
 603 agentProc(jvmtiEnv* jvmti, JNIEnv* jni, void* arg) {
 604     jobject rootObject = NULL;
 605 
 606     printf("Wait for tested objects created\n");
 607     fflush(0);
 608     if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 609         return;
 610     }
 611 
 612     printf(">>> Obtain and tag tested objects from debugee class\n");
 613     fflush(0);
 614     {
 615         if (!NSK_VERIFY(getAndTagTestedObjects(jvmti, jni,
 616                                                chainLength, &objectsCount,
 617                                                &objectDescList, &rootObject))) {
 618             return;
 619         }
 620     }
 621 
 622     printf(">>> Let debugee to clean links to unreachable objects\n");
 623     fflush(0);
 624     {
 625         if (!NSK_VERIFY(nsk_jvmti_resumeSync())) {
 626             return;
 627         }
 628         if (!NSK_VERIFY(nsk_jvmti_waitForSync(timeout))) {
 629             return;
 630         }
 631     }
 632 
 633     printf("\n\n>>> Start 1-st iteration for root tested object: 0x%p\n", rootObject);
 634     fflush(0);
 635     {
 636         jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED;
 637         if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences(heap_filter,
 638                                                       (jclass) NULL, /* class          */
 639                                                       rootObject,    /* initial_object */
 640                                                       &heapCallbacks,
 641                                                       (const void *) &fakeUserData))) {
 642              nsk_jvmti_setFailStatus();
 643              return;
 644         }
 645     }
 646 
 647     printf(">>> Check if reachable objects were iterated\n");
 648     fflush(0);
 649     {
 650         if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
 651             nsk_jvmti_setFailStatus();
 652         }
 653     }
 654 
 655 
 656     {            /* Reinstall the expectations */
 657         int k;
 658         for (k = 0; k < objectsCount; k++) {
 659             (objectDescList)[k].exp_found = 0;
 660             (objectDescList)[k].found = 0;
 661         }
 662     }
 663 
 664     printf("\n\n>>> Start 2-nd iteration for root tested object: 0x%p\n", rootObject);
 665     fflush(0);
 666     {
 667         /* This time everythig is filtered out */
 668         jint heap_filter = JVMTI_HEAP_FILTER_UNTAGGED | JVMTI_HEAP_FILTER_CLASS_UNTAGGED |
 669                            JVMTI_HEAP_FILTER_TAGGED   | JVMTI_HEAP_FILTER_CLASS_TAGGED;
 670         if (!NSK_JVMTI_VERIFY(jvmti->FollowReferences(heap_filter,
 671                                                       (jclass) NULL, /* class          */
 672                                                       rootObject,    /* initial_object */
 673                                                       &heapCallbacks,
 674                                                       (const void *) &fakeUserData))) {
 675              nsk_jvmti_setFailStatus();
 676              return;
 677         }
 678     }
 679 
 680     printf(">>> Check if reachable objects were not reported this time\n");
 681     fflush(0);
 682     {
 683         if (!checkTestedObjects(jvmti, jni, chainLength, objectDescList)) {
 684             nsk_jvmti_setFailStatus();
 685         }
 686     }
 687 
 688     printf(">>> Clean used data\n");
 689     fflush(0);
 690     {
 691         if (!NSK_VERIFY(releaseTestedObjects(jvmti, jni, chainLength, objectDescList, rootObject))) {
 692             return;
 693         }
 694     }
 695 
 696     printf("Let debugee to finish\n");
 697     fflush(0);
 698     if (!NSK_VERIFY(nsk_jvmti_resumeSync()))
 699         return;
 700 }
 701 
 702 /* ============================================================================= */
 703 
 704 /** Agent library initialization. */
 705 #ifdef STATIC_BUILD
 706 JNIEXPORT jint JNICALL Agent_OnLoad_followref002(JavaVM *jvm, char *options, void *reserved) {
 707     return Agent_Initialize(jvm, options, reserved);
 708 }
 709 JNIEXPORT jint JNICALL Agent_OnAttach_followref002(JavaVM *jvm, char *options, void *reserved) {
 710     return Agent_Initialize(jvm, options, reserved);
 711 }
 712 JNIEXPORT jint JNI_OnLoad_followref002(JavaVM *jvm, char *options, void *reserved) {
 713     return JNI_VERSION_1_8;
 714 }
 715 #endif
 716 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 717     jvmtiEnv* jvmti = NULL;
 718 
 719     if (!NSK_VERIFY(nsk_jvmti_parseOptions(options)))
 720         return JNI_ERR;
 721 
 722     timeout = nsk_jvmti_getWaitTime() * 60 * 1000;
 723 
 724     chainLength = nsk_jvmti_findOptionIntValue("objects", DEFAULT_CHAIN_LENGTH);
 725     if (!NSK_VERIFY(chainLength > 0))
 726         return JNI_ERR;
 727 
 728     if (!NSK_VERIFY((jvmti =
 729             nsk_jvmti_createJVMTIEnv(jvm, reserved)) != NULL))
 730         return JNI_ERR;
 731 
 732     {
 733         jvmtiCapabilities caps;
 734 
 735         memset(&caps, 0, sizeof(caps));
 736         caps.can_tag_objects = 1;
 737         if (!NSK_JVMTI_VERIFY(jvmti->AddCapabilities(&caps))) {
 738             return JNI_ERR;
 739         }
 740     }
 741 
 742     /* Setting Heap Callbacks */
 743     heapCallbacks.heap_iteration_callback         = NULL;
 744     heapCallbacks.heap_reference_callback         = heapReferenceCallback;
 745     heapCallbacks.primitive_field_callback        = primitiveFieldCallback;
 746     heapCallbacks.array_primitive_value_callback  = arrayPrimitiveValueCallback;
 747     heapCallbacks.string_primitive_value_callback = stringPrimitiveValueCallback;
 748 
 749     if (!NSK_VERIFY(nsk_jvmti_setAgentProc(agentProc, NULL)))
 750         return JNI_ERR;
 751 
 752     return JNI_OK;
 753 }
 754 
 755 /* ============================================================================= */
 756 
 757 }