d52a995f35
Reviewed-by: lmesnik, dholmes, rriggs, stefank
201 lines
7.2 KiB
Java
201 lines
7.2 KiB
Java
/*
|
|
* Copyright (c) 2023, 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
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
/**
|
|
* @test
|
|
*
|
|
* @library /test/lib
|
|
* @requires vm.hasSA
|
|
* @modules jdk.hotspot.agent/sun.jvm.hotspot
|
|
* jdk.hotspot.agent/sun.jvm.hotspot.debugger
|
|
* jdk.hotspot.agent/sun.jvm.hotspot.types
|
|
* jdk.hotspot.agent/sun.jvm.hotspot.types.basic
|
|
*
|
|
* @run driver UniqueVtableTest
|
|
*/
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import sun.jvm.hotspot.HotSpotAgent;
|
|
import sun.jvm.hotspot.debugger.Address;
|
|
import sun.jvm.hotspot.types.Type;
|
|
import sun.jvm.hotspot.types.basic.BasicTypeDataBase;
|
|
|
|
import jdk.test.lib.apps.LingeredApp;
|
|
import jdk.test.lib.process.ProcessTools;
|
|
import jdk.test.lib.process.OutputAnalyzer;
|
|
import jdk.test.lib.SA.SATestUtils;
|
|
|
|
|
|
public class UniqueVtableTest {
|
|
|
|
private static String type2String(Type t) {
|
|
return t + " (extends " + t.getSuperclass() + ")";
|
|
}
|
|
|
|
private static void log(Object o) {
|
|
System.out.println(o);
|
|
}
|
|
|
|
private static void runTest(long pid) throws Throwable {
|
|
HotSpotAgent agent = new HotSpotAgent();
|
|
log("Attaching to process ID " + pid + "...");
|
|
agent.attach((int) pid);
|
|
log("Attached successfully.");
|
|
|
|
Throwable reasonToFail = null;
|
|
|
|
try {
|
|
runTest(agent);
|
|
} catch (Throwable ex) {
|
|
reasonToFail = ex;
|
|
} finally {
|
|
try {
|
|
agent.detach();
|
|
} catch (Exception ex) {
|
|
log("detach error:");
|
|
ex.printStackTrace(System.out);
|
|
// do not override original error
|
|
if (reasonToFail != null) {
|
|
reasonToFail = ex;
|
|
}
|
|
}
|
|
}
|
|
if (reasonToFail != null) {
|
|
throw reasonToFail;
|
|
}
|
|
}
|
|
|
|
private static void runTest(HotSpotAgent agent) throws Throwable {
|
|
Map<Address, List<Type>> vtableToTypesMap = new HashMap<>();
|
|
Iterator<Type> it = agent.getTypeDataBase().getTypes();
|
|
int dupsFound = 0;
|
|
// TypeDataBase knows nothing about vtables,
|
|
// but actually agent.getTypeDataBase() returns HotSpotTypeDataBase (extends BasicTypeDataBase)
|
|
// and BasicTypeDataBase has a method to get vtable for Types.
|
|
BasicTypeDataBase typeDB = (BasicTypeDataBase)(agent.getTypeDataBase());
|
|
int total = 0;
|
|
int vm_classes_with_vtable = 0;
|
|
int vm_classes_without_vtable = 0;
|
|
while (it.hasNext()) {
|
|
total++;
|
|
Type t = it.next();
|
|
Address vtable = typeDB.vtblForType(t);
|
|
if (vtable != null) {
|
|
vm_classes_with_vtable++;
|
|
List<Type> typeList = vtableToTypesMap.get(vtable);
|
|
if (typeList == null) {
|
|
vtableToTypesMap.put(vtable, new ArrayList<>(List.of(t)));
|
|
} else {
|
|
// duplicate found
|
|
dupsFound++;
|
|
typeList.add(t);
|
|
}
|
|
}
|
|
|
|
// IntegerType/StringType/JavaPrimitiveType/OopType/PointerType types
|
|
// are expected to have no vtable.
|
|
// Log classes which might need vtable.
|
|
if (vtable == null
|
|
&& !t.isCIntegerType()
|
|
&& !t.isCStringType()
|
|
&& !t.isJavaPrimitiveType()
|
|
&& !t.isOopType()
|
|
&& !t.isPointerType()) {
|
|
vm_classes_without_vtable++;
|
|
log("vtable is null for " + type2String(t));
|
|
}
|
|
}
|
|
log("total: " + total
|
|
+ ", vm_classes_with_vtable: " + vm_classes_with_vtable
|
|
+ ", vm_classes_without_vtable: " + vm_classes_without_vtable);
|
|
if (dupsFound > 0) {
|
|
vtableToTypesMap.forEach((vtable, list) -> {
|
|
if (list.size() > 1) {
|
|
log("Duplicate vtable: " + vtable + ": ");
|
|
list.forEach(t -> log(" - " + type2String(t)));
|
|
}
|
|
});
|
|
throw new RuntimeException("Duplicate vtable(s) found: " + dupsFound);
|
|
}
|
|
}
|
|
|
|
private static void createAnotherToAttach(long lingeredAppPid) throws Throwable {
|
|
// Start a new process to attach to the lingered app
|
|
ProcessBuilder processBuilder = ProcessTools.createLimitedTestJavaProcessBuilder(
|
|
"--add-modules=jdk.hotspot.agent",
|
|
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED",
|
|
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.debugger=ALL-UNNAMED",
|
|
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.types=ALL-UNNAMED",
|
|
"--add-exports=jdk.hotspot.agent/sun.jvm.hotspot.types.basic=ALL-UNNAMED",
|
|
"UniqueVtableTest",
|
|
Long.toString(lingeredAppPid));
|
|
SATestUtils.addPrivilegesIfNeeded(processBuilder);
|
|
OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
|
|
output.shouldHaveExitValue(0);
|
|
System.out.println(output.getOutput());
|
|
}
|
|
|
|
private static void runMain() throws Throwable {
|
|
Throwable reasonToFail = null;
|
|
LingeredApp app = null;
|
|
try {
|
|
app = LingeredApp.startApp();
|
|
createAnotherToAttach(app.getPid());
|
|
} catch (Throwable ex) {
|
|
reasonToFail = ex;
|
|
} finally {
|
|
try {
|
|
LingeredApp.stopApp(app);
|
|
} catch (Exception ex) {
|
|
log("LingeredApp.stopApp error:");
|
|
ex.printStackTrace(System.out);
|
|
// do not override original error
|
|
if (reasonToFail != null) {
|
|
reasonToFail = ex;
|
|
}
|
|
}
|
|
}
|
|
if (reasonToFail != null) {
|
|
throw reasonToFail;
|
|
}
|
|
}
|
|
|
|
public static void main(String... args) throws Throwable {
|
|
SATestUtils.skipIfCannotAttach(); // throws SkippedException if attach not expected to work.
|
|
|
|
if (args == null || args.length == 0) {
|
|
// Main test process.
|
|
runMain();
|
|
} else {
|
|
// Sub-process to attach, arg[0] is the target process pid.
|
|
runTest(Long.parseLong(args[0]));
|
|
}
|
|
}
|
|
|
|
}
|