package org.simantics.scl.compiler.internal.codegen.utils; import java.io.PrintWriter; import org.cojen.classfile.MethodDesc; import org.cojen.classfile.TypeDesc; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.commons.CodeSizeEvaluator; import org.objectweb.asm.util.TraceClassVisitor; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; public class ClassBuilder { ModuleBuilder moduleBuilder; String className; String superClassName; ClassVisitor classVisitor; ClassWriter classWriter; public ClassBuilder(ModuleBuilder moduleBuilder, int access, String className, String superClassName, String ... interfaces) { checkClassName(className); checkClassName(superClassName); this.moduleBuilder = moduleBuilder; this.className = className; this.superClassName = superClassName; this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE && SCLCompilerConfiguration.debugFilter(moduleBuilder.namingPolicy.getModuleName()) ? new TraceClassVisitor(classWriter, new PrintWriter(System.out)) : classWriter; classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces); } public void setSourceFile(String fileName) { classVisitor.visitSource(fileName, null); } public MethodBuilder addMethod(int access, String methodName, TypeDesc ret, TypeDesc[] params) { for(TypeDesc param : params) if(param.equals(TypeDesc.VOID)) throw new IllegalArgumentException(); MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName, MethodDesc.forArguments(ret, params).getDescriptor(), null, null); methodVisitor = augmentMethodVisitor(methodName, methodVisitor); return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params); } private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) { if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) { methodVisitor = new CodeSizeEvaluator(methodVisitor) { @Override public void visitEnd() { super.visitEnd(); if(moduleBuilder.methodSizeCounter == null) moduleBuilder.methodSizeCounter = new MethodSizeCounter(); moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize()); } }; } return methodVisitor; } public MethodBuilderBase addMethodBase(int access, String methodName, TypeDesc ret, TypeDesc[] params) { for(TypeDesc param : params) if(param.equals(TypeDesc.VOID)) throw new IllegalArgumentException(); MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName, MethodDesc.forArguments(ret, params).getDescriptor(), null, null); methodVisitor = augmentMethodVisitor(methodName, methodVisitor); return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params); } public void addAbstractMethod(int access, String methodName, TypeDesc ret, TypeDesc[] params) { for(TypeDesc param : params) if(param.equals(TypeDesc.VOID)) throw new IllegalArgumentException(); MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName, MethodDesc.forArguments(ret, params).getDescriptor(), null, null); for(int i=0;i", TypeDesc.VOID, params); } public MethodBuilder addConstructor(int access, TypeDesc[] params) { return addMethod(access, "", TypeDesc.VOID, params); } public MethodBuilder addInitializer() { return addMethod(Opcodes.ACC_PUBLIC, "", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY); } public MethodBuilderBase addInitializerBase() { return addMethodBase(Opcodes.ACC_PUBLIC, "", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY); } public void addField(int access, String fieldName, TypeDesc type) { if(type.equals(TypeDesc.VOID)) throw new IllegalArgumentException(); FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null); fieldVisitor.visitEnd(); } public byte[] finishClass() { classVisitor.visitEnd(); return classWriter.toByteArray(); } public String getClassName() { return className; } public void addDefaultConstructor() { MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "", "()V", false); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(0, 0); methodVisitor.visitEnd(); } public TypeDesc getType() { return TypeDesc.forClass(className); } public String getSuperClassName() { return superClassName; } public static void checkClassName(String className) { /*if(className != null && className.contains(".")) { System.out.print(className); System.out.println(); }*/ } public ModuleBuilder getModuleBuilder() { return moduleBuilder; } }