Path: blob/master/test/hotspot/jtreg/runtime/InvocationTests/shared/GenericClassGenerator.java
40948 views
/*1* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package shared;2526import jdk.internal.org.objectweb.asm.ClassWriter;27import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_FRAMES;28import static jdk.internal.org.objectweb.asm.ClassWriter.COMPUTE_MAXS;29import jdk.internal.org.objectweb.asm.MethodVisitor;30import static jdk.internal.org.objectweb.asm.Opcodes.*;31import static shared.AccessCheck.*;3233public class GenericClassGenerator<T extends GenericClassGenerator> {34private static final String targetMethodName = Utils.TARGET_METHOD_NAME;3536private int flags = 0;37private ClassWriter writer;38private String fullClassName = null;39private String parentClassName = null;4041/*******************************************************************/42public GenericClassGenerator(String fullClassName) {43this(fullClassName, "java/lang/Object");44}4546/*******************************************************************/47public GenericClassGenerator(String fullClassName, String parentClassName ) {48this(fullClassName, parentClassName, ACC_PUBLIC);49}5051/*******************************************************************/52public GenericClassGenerator(String fullClassName, String parentClassName, int flags) {53this(fullClassName, parentClassName, flags, new String[0]);54}5556/*******************************************************************/57public GenericClassGenerator(String fullClassName, String parentClassName, int flags, String[] implementedInterfaces) {58writer = new ClassWriter(COMPUTE_FRAMES | COMPUTE_MAXS);5960this.fullClassName = fullClassName;61this.flags = flags;6263// Construct simple class64if (parentClassName != null) {65this.parentClassName = getInternalName(parentClassName);66} else {67this.parentClassName = "java/lang/Object";68}6970String parent = this.parentClassName;71String name = getInternalName(fullClassName);7273if (Utils.isACC_SUPER) {74flags = flags | ACC_SUPER;75}7677writer.visit(Utils.version, flags, name, null, parent, implementedInterfaces);7879// Add constructor80if ( !isInterface(flags) ) {81MethodVisitor m =82writer.visitMethod(83ACC_PUBLIC84, "<init>"85, "()V"86, null87, null88);8990m.visitCode();91m.visitVarInsn(ALOAD, 0);92m.visitMethodInsn(93INVOKESPECIAL94, getInternalName(parent)95, "<init>"96, "()V"97);98m.visitInsn(RETURN);99m.visitEnd();100m.visitMaxs(0,0);101}102}103104/*******************************************************************/105protected static String getInternalName(String fullClassName) {106return fullClassName.replaceAll("\\.", "/");107}108109/*******************************************************************/110public T addTargetConstructor(AccessType access) {111// AccessType.UNDEF means that the target method isn't defined, so do nothing112if (access == AccessType.UNDEF || isInterface(flags) ) {113return (T)this;114}115116// Add target constructor117int methodAccessType = access.value();118119MethodVisitor m =120writer.visitMethod(121methodAccessType122, "<init>"123, "(I)V"124, null125, null126);127128// Add a call to parent constructor129m.visitCode();130m.visitVarInsn(ALOAD, 0);131m.visitMethodInsn(132INVOKESPECIAL133, getInternalName(parentClassName)134, "<init>"135, "()V"136);137138// Add result reporting139String shortName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);140m.visitLdcInsn(shortName+".<init>");141m.visitFieldInsn(142PUTSTATIC143, "Result"144, "value"145, "Ljava/lang/String;"146);147148m.visitInsn(RETURN);149m.visitEnd();150m.visitMaxs(0,0);151152return (T)this;153154}155156/*******************************************************************/157public T addTargetMethod(AccessType access) {158return addTargetMethod(access, 0);159}160161/*******************************************************************/162public T addTargetMethod(AccessType access, int additionalFlags) {163// AccessType.UNDEF means that the target method isn't defined, so do nothing164if (access == AccessType.UNDEF) {165return (T)this;166}167168// Add target method169int methodAccessType = access.value();170if ( isInterface(flags) || isAbstract(flags) ) {171methodAccessType |= ACC_ABSTRACT;172}173174// Skip method declaration for abstract private case, which doesn't pass175// classfile verification stage176if ( isPrivate(methodAccessType) && isAbstract(methodAccessType) ) {177return (T)this;178}179180MethodVisitor m =181writer.visitMethod(182methodAccessType | additionalFlags183, targetMethodName184, "()Ljava/lang/String;"185, null186, null187);188189// Don't generate body if the method is abstract190if ( (methodAccessType & ACC_ABSTRACT) == 0 ) {191String shortName = fullClassName.substring(fullClassName.lastIndexOf('.') + 1);192193// Simply returns info about itself194m.visitCode();195m.visitLdcInsn(shortName+"."+targetMethodName);196m.visitInsn(ARETURN);197m.visitEnd();198m.visitMaxs(0,0);199}200201return (T)this;202}203204/*******************************************************************/205public T addField(int access, String name, String type) {206writer.visitField(207access208, name209, getInternalName(type)210, null211, null212)213.visitEnd();214215return (T)this;216}217218/*******************************************************************/219// Add target method call site into current class220public T addCaller(String targetClass, int callType) {221MethodVisitor m = writer.visitMethod(222ACC_PUBLIC | ACC_STATIC223, "call"224, String.format( "(L%s;)Ljava/lang/String;" , getInternalName(targetClass))225, null226, null227);228229m.visitCode();230m.visitVarInsn(ALOAD, 0);231m.visitMethodInsn(232callType233, getInternalName(targetClass)234, targetMethodName235, "()Ljava/lang/String;"236);237m.visitInsn(ARETURN);238m.visitEnd();239m.visitMaxs(0,0);240241return (T)this;242}243244/*******************************************************************/245public byte[] getClassFile() {246writer.visitEnd();247return writer.toByteArray();248}249250/*******************************************************************/251public String getFullClassName() {252return fullClassName;253}254}255256257