--- /dev/null 2015-04-06 08:40:03.942185037 -0400 +++ new/test/runtime/SelectionResolution/ClassBuilder.java 2015-04-17 16:07:51.977375286 -0400 @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2013, 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. + * + */ + +import static jdk.internal.org.objectweb.asm.Opcodes.*; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Constructs classes and interfaces based on the information from a + * DefaultMethodTestCase + * + */ +public class ClassBuilder extends Builder { + private final ArrayList 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", -1, ACC_PUBLIC); + 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 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; + } + +}