Skip to content

Commit

Permalink
8303489: Add a test to verify classes in vmStruct have unique vtables
Browse files Browse the repository at this point in the history
Reviewed-by: cjplummer, sspitsyn
  • Loading branch information
Alex Menkov committed Mar 9, 2023
1 parent 595645c commit f9aadb9
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 2 deletions.
Expand Up @@ -156,9 +156,9 @@ public long getOopSize() {
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);
Expand Down
178 changes: 178 additions & 0 deletions test/hotspot/jtreg/serviceability/sa/UniqueVtableTest.java
@@ -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();
}

}

1 comment on commit f9aadb9

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.