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.internal.codegen.utils.LoggingOutputStream.LogLevel;
15 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
19 public class ClassBuilder {
21 private static final Logger LOGGER = LoggerFactory.getLogger(ClassBuilder.class);
23 ModuleBuilder moduleBuilder;
25 String superClassName;
26 ClassVisitor classVisitor;
27 ClassWriter classWriter;
29 public ClassBuilder(ModuleBuilder moduleBuilder, int access, String className, String superClassName,
30 String ... interfaces) {
31 checkClassName(className);
32 checkClassName(superClassName);
33 this.moduleBuilder = moduleBuilder;
34 this.className = className;
35 this.superClassName = superClassName;
36 this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
37 this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE
38 && SCLCompilerConfiguration.debugFilter(moduleBuilder.namingPolicy.getModuleName())
39 ? new TraceClassVisitor(classWriter, new PrintWriter(new LoggingOutputStream(LOGGER, LogLevel.INFO)))
41 classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
44 public void setSourceFile(String fileName) {
45 classVisitor.visitSource(fileName, null);
48 public MethodBuilder addMethod(int access,
52 for(TypeDesc param : params)
53 if(param.equals(TypeDesc.VOID))
54 throw new IllegalArgumentException();
55 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
56 MethodDesc.forArguments(ret, params).getDescriptor(),
58 methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
59 return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
62 private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
63 if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
64 methodVisitor = new CodeSizeEvaluator(methodVisitor) {
66 public void visitEnd() {
68 if(moduleBuilder.methodSizeCounter == null)
69 moduleBuilder.methodSizeCounter = new MethodSizeCounter();
70 moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
77 public MethodBuilderBase addMethodBase(int access,
81 for(TypeDesc param : params)
82 if(param.equals(TypeDesc.VOID))
83 throw new IllegalArgumentException();
84 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
85 MethodDesc.forArguments(ret, params).getDescriptor(),
87 methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
88 return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
91 public void addAbstractMethod(int access,
95 for(TypeDesc param : params)
96 if(param.equals(TypeDesc.VOID))
97 throw new IllegalArgumentException();
98 MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
99 MethodDesc.forArguments(ret, params).getDescriptor(),
101 for(int i=0;i<params.length;++i)
102 methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
103 methodVisitor.visitEnd();
106 public MethodBuilderBase addConstructorBase(int access, TypeDesc[] params) {
107 return addMethodBase(access, "<init>", TypeDesc.VOID, params);
110 public MethodBuilder addConstructor(int access, TypeDesc[] params) {
111 return addMethod(access, "<init>", TypeDesc.VOID, params);
114 public MethodBuilder addInitializer() {
115 return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
118 public MethodBuilderBase addInitializerBase() {
119 return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
122 public void addField(int access, String fieldName,
124 if(type.equals(TypeDesc.VOID))
125 throw new IllegalArgumentException();
126 FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
127 fieldVisitor.visitEnd();
130 public byte[] finishClass() {
131 classVisitor.visitEnd();
132 return classWriter.toByteArray();
135 public String getClassName() {
139 public void addDefaultConstructor() {
140 MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
141 methodVisitor.visitCode();
142 methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
143 methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
144 methodVisitor.visitInsn(Opcodes.RETURN);
145 methodVisitor.visitMaxs(0, 0);
146 methodVisitor.visitEnd();
149 public TypeDesc getType() {
150 return TypeDesc.forClass(className);
153 public String getSuperClassName() {
154 return superClassName;
157 public static void checkClassName(String className) {
158 /*if(className != null && className.contains(".")) {
159 System.out.print(className);
160 System.out.println();
164 public ModuleBuilder getModuleBuilder() {
165 return moduleBuilder;