1 package org.simantics.scl.compiler.internal.codegen.utils;
3 import java.io.PrintWriter;
5 import org.cojen.classfile.MethodDesc;
6 import org.cojen.classfile.TypeDesc;
7 import org.objectweb.asm.ClassVisitor;
8 import org.objectweb.asm.ClassWriter;
9 import org.objectweb.asm.FieldVisitor;
10 import org.objectweb.asm.MethodVisitor;
11 import org.objectweb.asm.Opcodes;
12 import org.objectweb.asm.commons.CodeSizeEvaluator;
13 import org.objectweb.asm.util.TraceClassVisitor;
14 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
16 public class ClassBuilder {
17 ModuleBuilder moduleBuilder;
19 String superClassName;
20 ClassVisitor classVisitor;
21 ClassWriter classWriter;
23 public ClassBuilder(ModuleBuilder moduleBuilder, int access, String className, String superClassName,
24 String ... interfaces) {
25 checkClassName(className);
26 checkClassName(superClassName);
27 this.moduleBuilder = moduleBuilder;
28 this.className = className;
29 this.superClassName = superClassName;
30 this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
31 this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE
32 && SCLCompilerConfiguration.debugFilter(moduleBuilder.namingPolicy.getModuleName())
33 ? new TraceClassVisitor(classWriter, new PrintWriter(System.out))
35 classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
38 public void setSourceFile(String fileName) {
39 classVisitor.visitSource(fileName, null);
42 public MethodBuilder addMethod(int access,
46 for(TypeDesc param : params)
47 if(param.equals(TypeDesc.VOID))
48 throw new IllegalArgumentException();
49 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
50 MethodDesc.forArguments(ret, params).getDescriptor(),
52 methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
53 return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
56 private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
57 if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
58 methodVisitor = new CodeSizeEvaluator(methodVisitor) {
60 public void visitEnd() {
62 if(moduleBuilder.methodSizeCounter == null)
63 moduleBuilder.methodSizeCounter = new MethodSizeCounter();
64 moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
71 public MethodBuilderBase addMethodBase(int access,
75 for(TypeDesc param : params)
76 if(param.equals(TypeDesc.VOID))
77 throw new IllegalArgumentException();
78 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
79 MethodDesc.forArguments(ret, params).getDescriptor(),
81 methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
82 return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
85 public void addAbstractMethod(int access,
89 for(TypeDesc param : params)
90 if(param.equals(TypeDesc.VOID))
91 throw new IllegalArgumentException();
92 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
93 MethodDesc.forArguments(ret, params).getDescriptor(),
95 for(int i=0;i<params.length;++i)
96 methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
97 methodVisitor.visitEnd();
100 public MethodBuilderBase addConstructorBase(int access, TypeDesc[] params) {
101 return addMethodBase(access, "<init>", TypeDesc.VOID, params);
104 public MethodBuilder addConstructor(int access, TypeDesc[] params) {
105 return addMethod(access, "<init>", TypeDesc.VOID, params);
108 public MethodBuilder addInitializer() {
109 return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
112 public MethodBuilderBase addInitializerBase() {
113 return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
116 public void addField(int access, String fieldName,
118 if(type.equals(TypeDesc.VOID))
119 throw new IllegalArgumentException();
120 FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
121 fieldVisitor.visitEnd();
124 public byte[] finishClass() {
125 classVisitor.visitEnd();
126 return classWriter.toByteArray();
129 public String getClassName() {
133 public void addDefaultConstructor() {
134 MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
135 methodVisitor.visitCode();
136 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
137 methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
138 methodVisitor.visitInsn(Opcodes.RETURN);
139 methodVisitor.visitMaxs(0, 0);
140 methodVisitor.visitEnd();
143 public TypeDesc getType() {
144 return TypeDesc.forClass(className);
147 public String getSuperClassName() {
148 return superClassName;
151 public static void checkClassName(String className) {
152 /*if(className != null && className.contains(".")) {
153 System.out.print(className);
154 System.out.println();
158 public ModuleBuilder getModuleBuilder() {
159 return moduleBuilder;