jdk-24/test/hotspot/jtreg/runtime/SelectionResolution/classes/selectionresolution/ClassBuilder.java
Harold Seigel 55b36c6f3b 8276825: hotspot/runtime/SelectionResolution test errors
Reviewed-by: dholmes, shade
2021-11-10 13:11:16 +00:00

241 lines
7.9 KiB
Java

/*
* Copyright (c) 2016, 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
* 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.
*/
package selectionresolution;
import java.util.ArrayList;
import java.util.Iterator;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PROTECTED;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
/**
* Constructs classes and interfaces based on the information from a
* DefaultMethodTestCase
*
*/
public class ClassBuilder extends Builder {
private final ArrayList<ClassConstruct> classes;
// Add a class in every package to be able to instantiate package
// private classes from outside the package
private final Clazz[] helpers = new Clazz[4];
private ClassConstruct callsiteClass;
public enum ExecutionMode { DIRECT, INDY, MH_INVOKE_EXACT, MH_INVOKE_GENERIC}
private final ExecutionMode execMode;
public ClassBuilder(SelectionResolutionTestCase testcase,
ExecutionMode execMode) {
super(testcase);
this.classes = new ArrayList<>();
this.execMode = execMode;
}
public ClassConstruct[] build() throws Exception {
buildClassConstructs();
return classes.toArray(new ClassConstruct[0]);
}
public ClassConstruct getCallsiteClass() {
return callsiteClass;
}
private void buildClassConstructs() throws Exception {
TestBuilder tb = new TestBuilder(testcase.methodref, testcase);
classes.add(new Clazz("Test", ACC_PUBLIC, -1));
for (int classId = 0; classId < classdata.size(); classId++) {
ClassConstruct C;
String[] interfaces = getInterfaces(classId);
ClassData data = classdata.get(classId);
if (isClass(classId)) {
C = new Clazz(getName(classId),
getExtending(classId),
getClassModifiers(data),
classId,
interfaces);
addHelperMethod(classId);
} else {
C = new Interface(getName(classId),
getAccessibility(data.access),
classId, interfaces);
}
// Add a method "m()LTestObject;" if applicable
if (containsMethod(data)) {
// Method will either be abstract or concrete depending on the
// abstract modifier
C.addTestMethod(getMethodModifiers(data));
}
if (classId == testcase.callsite) {
// Add test() method
tb.addTest(C, execMode);
callsiteClass = C;
}
classes.add(C);
}
classes.add(tb.getMainTestClass());
}
private void addHelperMethod(int classId) {
int packageId = classdata.get(classId).packageId.ordinal();
Clazz C = helpers[packageId];
if (C == null) {
C = new Clazz(getPackageName(packageId) + "Helper", ACC_PUBLIC, -1);
helpers[packageId] = C;
classes.add(C);
}
Method m = C.addMethod("get" + getClassName(classId),
"()L" + getName(classId) + ";",
ACC_PUBLIC + ACC_STATIC);
m.makeInstantiateMethod(getName(classId));
}
private String[] getInterfaces(int classId) {
ArrayList<String> interfaces = new ArrayList<>();
// Figure out if we're extending/implementing an interface
for (final int intf : hier.interfaces()) {
if (hier.inherits(classId, intf)) {
interfaces.add(getName(intf));
}
}
return interfaces.toArray(new String[0]);
}
private String getExtending(int classId) {
int extending = -1;
// See if we're extending another class
for (final int extendsClass : hier.classes()) {
if (hier.inherits(classId, extendsClass)) {
// Sanity check that we haven't already found an extending class
if (extending != -1) {
throw new RuntimeException("Multiple extending classes");
}
extending = extendsClass;
}
}
return extending == -1 ? null : getName(extending);
}
/**
* Returns modifiers for a Class
* @param cd ClassData for the Class
* @return ASM modifiers for a Class
*/
private int getClassModifiers(ClassData cd) {
// For Classes we only care about accessibility (public, private etc)
return getAccessibility(cd.access) | getAbstraction(cd.abstraction);
}
/**
* Returns modifiers for Method type
* @param cd ClassData for the Class or Interface where the Method resides
* @return ASM modifiers for the Method
*/
private int getMethodModifiers(ClassData cd) {
int mod = 0;
// For methods we want everything
mod += getAccessibility(cd.methoddata.access);
mod += getAbstraction(cd.methoddata.context);
mod += getContext(cd.methoddata.context);
mod += getExtensibility();
return mod;
}
/**
* Convert ClassData access type to ASM
* @param access
* @return ASM version of accessibility (public / private / protected)
*/
private int getAccessibility(MethodData.Access access) {
switch(access) {
case PACKAGE:
//TODO: Do I need to set this or will this be the default?
return 0;
case PRIVATE:
return ACC_PRIVATE;
case PROTECTED:
return ACC_PROTECTED;
case PUBLIC:
return ACC_PUBLIC;
default:
throw new RuntimeException("Illegal accessibility modifier: " + access);
}
}
/**
* Convert ClassData abstraction type to ASM
* @param abstraction
* @return ASM version of abstraction (abstract / non-abstract)
*/
private int getAbstraction(MethodData.Context context) {
return context == MethodData.Context.ABSTRACT ? ACC_ABSTRACT : 0;
}
/**
* Convert ClassData context type to ASM
* @param context
* @return ASM version of context (static / non-static)
*/
private int getContext(MethodData.Context context) {
return context == MethodData.Context.STATIC ? ACC_STATIC : 0;
}
/**
* Convert ClassData extensibility type to ASM
* @param extensibility
* @return ASM version of extensibility (final / non-final)
*/
private int getExtensibility() {
return 0;
}
/**
* Determine if we need a method at all, abstraction is set to null if this
* Class/Interface should not have a test method
* @param cd
* @return
*/
private boolean containsMethod(ClassData cd) {
return cd.methoddata != null;
}
}