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