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

Reviewed-by: sspitsyn, kevinw
This commit is contained in:
Chris Plummer 2021-02-22 23:22:50 +00:00
parent a7e2e80ff4
commit aea474c48d
2 changed files with 95 additions and 25 deletions

View File

@ -267,34 +267,12 @@ public class CommandProcessor {
out.println("Usage: " + usage);
}
void printOopValue(Oop oop) {
if (oop != null) {
Klass k = oop.getKlass();
Symbol s = k.getName();
if (s != null) {
out.print("Oop for " + s.asString() + " @ ");
} else {
out.print("Oop @ ");
}
Oop.printOopAddressOn(oop, out);
} else {
out.print("null");
}
}
void printNode(SimpleTreeNode node) {
int count = node.getChildCount();
for (int i = 0; i < count; i++) {
try {
SimpleTreeNode field = node.getChild(i);
if (field instanceof OopTreeNodeAdapter) {
out.print(field);
out.print(" ");
printOopValue(((OopTreeNodeAdapter)field).getOop());
out.println();
} else {
out.println(field);
}
out.println(field);
} catch (Exception e) {
out.println();
out.println("Error: " + e);
@ -1063,7 +1041,7 @@ public class CommandProcessor {
Oop oop = VM.getVM().getObjectHeap().newOop(handle);
node = new OopTreeNodeAdapter(oop, null);
out.println("instance of " + node.getValue() + " @ " + a +
out.println("instance of " + node.getValue() +
" (size = " + oop.getObjectSize() + ")");
} else if (VM.getVM().getCodeCache().contains(a)) {
CodeBlob blob = VM.getVM().getCodeCache().findBlobUnsafe(a);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -94,6 +94,98 @@ public class ClhsdbInspect {
expStrMap.put(cmd, List.of(tokensMap.get(key)));
test.run(theApp.getPid(), cmds, expStrMap, null);
}
// This part is testing JDK-8261269. When inspecting a java object, we want to make
// sure the address is not printed twice and that "Oop for ..." is not printed twice.
//
// The goal of this test is to dump the Class instance for java.lang.System. It contains
// some Oop statics, and that's where the redundant "Oop for..." was noticed. The script
// looks something like this:
//
// 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
String cmd;
Map<String, List<String>> expStrMap;
Map<String, List<String>> unexpStrMap;
// Start with the "class java.lang.System"
cmd = "class java.lang.System";
cmds = List.of(cmd);
expStrMap = new HashMap<>();
expStrMap.put(cmd, List.of("java.lang.System @0x"));
String classCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);
// "inspect" the address produced by the "class java.lang.System". This is the InstanceKlass.
String classAddress = classCmdOutput.substring(classCmdOutput.indexOf("@0x")+1);
lines = classAddress.split("\\R");
classAddress = lines[0];
cmd = "inspect " + classAddress;
cmds = List.of(cmd);
expStrMap = new HashMap<>();
expStrMap.put(cmd, List.of("Type is InstanceKlass", "Klass::_java_mirror: OopHandle @"));
String inspectCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);
// Get the Klass::_java_mirror value from the InstanceKlass
String mirrorPattern = "Klass::_java_mirror: OopHandle @ ";
String mirrorAddress = inspectCmdOutput.substring(
inspectCmdOutput.indexOf(mirrorPattern) + mirrorPattern.length());
lines = mirrorAddress.split("\\R");
mirrorAddress = lines[0];
// Use "examine" to do an indirection of the _java_mirror.
cmd = "examine " + mirrorAddress;
cmds = List.of(cmd);
expStrMap = new HashMap<>();
expStrMap.put(cmd, List.of(mirrorAddress + ": 0x"));
String examineCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);
String examineResult = examineCmdOutput.substring(examineCmdOutput.indexOf(": 0x")+2);
lines = examineResult.split("\\R");
examineResult = lines[0].trim(); // examine leaves a trailing space
// Do another indirection using "examine" to get to the address of the Class instance.
cmd = "examine " + examineResult;
cmds = List.of(cmd);
expStrMap = new HashMap<>();
expStrMap.put(cmd, List.of(examineResult + ": 0x"));
examineCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, null);
examineResult = examineCmdOutput.substring(examineCmdOutput.indexOf(": 0x")+2);
lines = examineResult.split("\\R");
examineResult = lines[0].trim(); // examine leaves a trailing space
// inspect the Class instance
String instanceOfString = "instance of Oop for java/lang/Class @ ";
String staticFieldString = "Oop for java/io/BufferedInputStream @";
cmd = "inspect " + examineResult;
cmds = List.of(cmd);
expStrMap = new HashMap<>();
expStrMap.put(cmd, List.of(instanceOfString + examineResult,
"in: " + staticFieldString));
unexpStrMap = new HashMap<>();
// Make sure we don't see the address of the class intance twice, and make sure
// we don't see "Oop for ..." twice for the "in" static field.
unexpStrMap.put(cmd, List.of(
instanceOfString + examineResult + " @ " + examineResult,
"in: " + staticFieldString + " .* " + staticFieldString));
inspectCmdOutput = test.run(theApp.getPid(), cmds, expStrMap, unexpStrMap);
} catch (SkippedException e) {
throw e;
} catch (Exception ex) {