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

When using clhsdb to "inspect" a java object, clhsdb prints "Oop for..." twice

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 17
    • 17
    • hotspot
    • None
    • b11

      When inspecting a java object, clhsdb prints "Oop for..." twice for each field that is an oop. It also prints the address of the java object twice. The following example show this when inspecting the java.lang.System Class instance, which we get to via the InstanceKlass mirror:

      hsdb> class java.lang.System
      java/lang/System @0x000000080000f388

      hsdb> inspect 0x000000080000f388
      Type is InstanceKlass (size of 480)
      ...
      OopHandle Klass::_java_mirror: OopHandle @ 0x000000080000f400
      ...

      hsdb> examine 0x000000080000f400
      0x000000080000f400: 0x00007fd8b812e5e8

      hsdb> examine 0x00007fd8b812e5e8
      0x00007fd8b812e5e8: 0x00000007fef00770

      hsdb> inspect 0x00000007fef00770
      instance of Oop for java/lang/Class @ 0x00000007fef00770 @ 0x00000007fef00770 (size = 160)
      in: Oop for java/io/BufferedInputStream @ 0x0000000082005b08 Oop for java/io/BufferedInputStream @ 0x0000000082005b08
      out: Oop for java/io/PrintStream @ 0x0000000082007b60 Oop for java/io/PrintStream @ 0x0000000082007b60
      err: Oop for java/io/PrintStream @ 0x000000008200e0c8 Oop for java/io/PrintStream @ 0x000000008200e0c8
      ...

      For the first line of output where the address of Oop is printed twice, the issue is in the implementation of the "inspect" command:

                              out.println("instance of " + node.getValue() + " @ " + a +
                                          " (size = " + oop.getObjectSize() + ")");

      node.getValue() already includes the address, so no need for this println to also do it. The address comes from the following in Oop.printOopValueOn():

            obj.printValueOn(tty);
            tty.print(" @ " + VM.getVM().getUniverse().heap().oopAddressDescription(obj.getHandle()));

      For the lines that follow, which are all Oop fields of the class, this issue also stems from the fact that Oop.printOopValueOn() is used, and not only does it include the address, but it also includes the "Oop for" part by calling Oop.printValueOn():

        public void printValueOn(PrintStream tty) {
            (new Throwable()).printStackTrace(tty);
          try {
            tty.print("Oop for " + getKlass().getName().asString());
          } catch (java.lang.NullPointerException e) {
            tty.print("Oop");
          }

      And this is the stack when it is called:

      at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printValueOn(Oop.java:187)
      at jdk.hotspot.agent/sun.jvm.hotspot.oops.Instance.printValueOn(Instance.java:79)
      at jdk.hotspot.agent/sun.jvm.hotspot.oops.Oop.printOopValueOn(Oop.java:168)
      at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.OopTreeNodeAdapter.getValue(OopTreeNodeAdapter.java:107)
      at jdk.hotspot.agent/sun.jvm.hotspot.ui.tree.FieldTreeNodeAdapter.toString(FieldTreeNodeAdapter.java:62)
      at java.base/java.lang.String.valueOf(String.java:3365)
      at java.base/java.io.PrintStream.print(PrintStream.java:877)
      at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$Command.printNode(CommandProcessor.java:289)
      at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor$23.doit(CommandProcessor.java:1062)
      at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2060)
      at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.executeCommand(CommandProcessor.java:2030)
      at jdk.hotspot.agent/sun.jvm.hotspot.CommandProcessor.run(CommandProcessor.java:1910)

      The second "Oop for" and the second address comes from CommandProcessor.printOopValue():

                      if (s != null) {
                          out.print("Oop for " + s.asString() + " @ ");
                      } else {
                          out.print("Oop @ ");
                      }
                      Oop.printOopAddressOn(oop, out);

      Although the real problem is that this code is called in the first place from CommandProcessor.printNode():

                          if (field instanceof OopTreeNodeAdapter) {
                              out.print(field);
                              out.print(" ");
                              printOopValue(((OopTreeNodeAdapter)field).getOop());
                              out.println();
                          } else {
                              out.println(field);
                          }

      It should instead just unconditionally call out.println(field), which will trigger calling Oop.printOopValueOn(), which will include something like "Oop for java/io/PrintStream @ 0x0000000082007b60"

            cjplummer Chris Plummer
            cjplummer Chris Plummer
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: