Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8299414

JVMTI FollowReferences should support references from VirtualThread stack

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 21
    • 19, 20
    • hotspot
    • b25
    • generic
    • generic

    Description

      ADDITIONAL SYSTEM INFORMATION :
      Ubunu 22.10 x86_64
      openjdk version "20-ea" 2023-03-21
      OpenJDK Runtime Environment (build 20-ea+29-2280)
      OpenJDK 64-Bit Server VM (build 20-ea+29-2280, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      Objects only referenced by the stack of unmounted VirtualThreads are not visit in any way. Maybe this could be done as a new kind of instance reference of StackChunk or as a new synthetic root. This functionality would be necessary for a JVMTI-based heap dump.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      With the attached sources and JAVA_HOME set to a JDK 20:

      g++ -shared -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC VThreadStackRefTest.cpp -o libVThreadStackRefTest.so

      $JAVA_HOME/bin/javac --enable-preview --release=20 VThreadStackRefTest.java

      LD_LIBRARY_PATH=. $JAVA_HOME/bin/java --enable-preview -agentlib:VThreadStackRefTest VThreadStackRefTest

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The test should exit with 0.
      ACTUAL -
      The test shows "did not find expected references: VThreadReferenced: 0, PThreadReferenced: 1" and exits with 1.

      ---------- BEGIN SOURCE ----------
      -- VThreadStackRefTest.java -----------------------------------------------------------
      import java.util.concurrent.CountDownLatch;

      public class VThreadStackRefTest {
          private static native int[] getReferenceCount(Class<?>... classes);

          public static void main(String[] args) throws InterruptedException {
              CountDownLatch dumpedLatch = new CountDownLatch(1);
              Thread vthread = Thread.ofVirtual().start(() -> {
                  Object referenced = new VThreadReferenced();
                  System.out.println(referenced.getClass());
                  await(dumpedLatch);
                  System.out.println(referenced.getClass());
              });
              Thread pthread = Thread.ofPlatform().start(() -> {
                  Object referenced = new PThreadReferenced();
                  System.out.println(referenced.getClass());
                  await(dumpedLatch);
                  System.out.println(referenced.getClass());
              });
              Thread.sleep(2000); // wait for reference and unmount
              int[] count = getReferenceCount(VThreadReferenced.class, PThreadReferenced.class);
              dumpedLatch.countDown();
              vthread.join();
              pthread.join();
              if (count[0] != 1 || count[1] != 1) {
                  System.err.println("did not find expected references: VThreadReferenced: " + count[0] + ", PThreadReferenced: " + count[1]);
                  System.exit(1);
              }
          }

          private static void await(CountDownLatch dumpedLatch) {
              try {
                  dumpedLatch.await();
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
          }

          public static class VThreadReferenced {
          }
          public static class PThreadReferenced {
          }
      }
      --------------------------------------------------------------------------------------
      -- VThreadStackRefTest.cpp -----------------------------------------------------------
      #include <jvmti.h>
      #include <cstdlib>
      #include <cstring>

      namespace {
          jvmtiEnv *jvmti = nullptr;

          void checkJvmti(int code, const char* message) {
              if (code != JVMTI_ERROR_NONE) {
                  printf("Error %s: %d\n", message, code);
                  abort();
              }
          }

          const int TAG_START = 100;
      }

      jint JNICALL testJvmtiHeapReferenceCallback(jvmtiHeapReferenceKind reference_kind, const jvmtiHeapReferenceInfo* reference_info,
          jlong class_tag, jlong referrer_class_tag, jlong size, jlong* tag_ptr, jlong* referrer_tag_ptr, jint length, void* user_data) {
          if (class_tag >= TAG_START) {
              ((jint*)user_data)[class_tag - TAG_START]++;
          }
          return JVMTI_VISIT_OBJECTS;
      }

      extern "C" JNIEXPORT jintArray JNICALL Java_VThreadStackRefTest_getReferenceCount(JNIEnv* env, jclass clazz, jobjectArray classes) {
          int classesCount = env->GetArrayLength(classes);
          for (int i=0; i<classesCount; i++) {
              jvmti->SetTag(env->GetObjectArrayElement(classes, i), TAG_START + i);
          }
          jint* counter = new jint[classesCount];
          jvmtiHeapCallbacks heapCallBacks;
          memset(&heapCallBacks, 0, sizeof(jvmtiHeapCallbacks));
          heapCallBacks.heap_reference_callback = testJvmtiHeapReferenceCallback;
          checkJvmti(jvmti->FollowReferences(0, nullptr, nullptr, &heapCallBacks, counter), "follow references");
          jintArray result = env->NewIntArray(classesCount);
          env->SetIntArrayRegion(result, 0, classesCount, counter);
          return result;
      }

      extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
          if (vm->GetEnv(reinterpret_cast<void **>(&jvmti), JVMTI_VERSION) != JNI_OK || !jvmti) {
              printf("Could not initialize JVMTI\n");
              abort();
          }
          jvmtiCapabilities capabilities;
          memset(&capabilities, 0, sizeof(capabilities));
          capabilities.can_tag_objects = 1;
          checkJvmti(jvmti->AddCapabilities(&capabilities), "adding capabilities");
          return JVMTI_ERROR_NONE;
      }

      --------------------------------------------------------------------------------------

      ---------- END SOURCE ----------

      FREQUENCY : always


      Attachments

        Issue Links

          Activity

            People

              amenkov Alex Menkov
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: