8303489: Add a test to verify classes in vmStruct have unique vtables
Reviewed-by: cjplummer, sspitsyn
This commit is contained in:
parent
595645c76d
commit
f9aadb943c
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/types/basic
test/hotspot/jtreg/serviceability/sa
@ -156,9 +156,9 @@ public class BasicTypeDataBase implements TypeDataBase {
|
||||
return VM.getVM().getOopSize();
|
||||
}
|
||||
|
||||
Map<Type, Address> typeToVtbl = new HashMap<>();
|
||||
private Map<Type, Address> typeToVtbl = new HashMap<>();
|
||||
|
||||
private Address vtblForType(Type type) {
|
||||
public Address vtblForType(Type type) {
|
||||
Address vtblAddr = typeToVtbl.get(type);
|
||||
if (vtblAddr == null) {
|
||||
vtblAddr = vtblAccess.getVtblForType(type);
|
||||
|
178
test/hotspot/jtreg/serviceability/sa/UniqueVtableTest.java
Normal file
178
test/hotspot/jtreg/serviceability/sa/UniqueVtableTest.java
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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 main/othervm 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.SA.SATestUtils;
|
||||
|
||||
|
||||
public class UniqueVtableTest {
|
||||
|
||||
private HotSpotAgent agent;
|
||||
|
||||
public UniqueVtableTest() {
|
||||
}
|
||||
|
||||
private static String type2String(Type t) {
|
||||
return t + " (extends " + t.getSuperclass() + ")";
|
||||
}
|
||||
|
||||
private static void log(Object o) {
|
||||
System.out.println(o);
|
||||
}
|
||||
|
||||
private void attach(long pid) throws Throwable {
|
||||
agent = new HotSpotAgent();
|
||||
log("Attaching to process ID " + pid + "...");
|
||||
agent.attach((int) pid);
|
||||
log("Attached successfully.");
|
||||
}
|
||||
|
||||
private void detach() {
|
||||
if (agent != null) {
|
||||
agent.detach();
|
||||
}
|
||||
}
|
||||
|
||||
private void runTest() 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 void run() throws Throwable {
|
||||
Throwable reasonToFail = null;
|
||||
LingeredApp app = null;
|
||||
try {
|
||||
app = LingeredApp.startApp();
|
||||
attach(app.getPid());
|
||||
runTest();
|
||||
} catch (Throwable ex) {
|
||||
reasonToFail = ex;
|
||||
} finally {
|
||||
try {
|
||||
detach();
|
||||
} catch (Exception ex) {
|
||||
log("detach error:");
|
||||
ex.printStackTrace(System.out);
|
||||
// do not override original error
|
||||
if (reasonToFail != null) {
|
||||
reasonToFail = ex;
|
||||
}
|
||||
}
|
||||
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.
|
||||
|
||||
UniqueVtableTest test = new UniqueVtableTest();
|
||||
|
||||
test.run();
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user