]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java
Make it possible to debug SCL compiler in production builds
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / ClassBuilder.java
1 package org.simantics.scl.compiler.internal.codegen.utils;
2
3 import java.io.PrintWriter;
4
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;
18
19 public class ClassBuilder {
20
21     private static final Logger LOGGER = LoggerFactory.getLogger(ClassBuilder.class);
22
23     ModuleBuilder moduleBuilder;
24     String className;
25     String superClassName;
26     ClassVisitor classVisitor;
27     ClassWriter classWriter;
28     
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)))
40                 : classWriter; 
41         classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
42     }
43
44     public void setSourceFile(String fileName) {
45         classVisitor.visitSource(fileName, null);
46     }
47
48     public MethodBuilder addMethod(int access,
49             String methodName,
50             TypeDesc ret,
51             TypeDesc[] params) {
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(),
57                 null, null);
58         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
59         return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
60     }
61     
62     private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
63         if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
64             methodVisitor = new CodeSizeEvaluator(methodVisitor) {
65                 @Override
66                 public void visitEnd() {
67                     super.visitEnd();
68                     if(moduleBuilder.methodSizeCounter == null)
69                         moduleBuilder.methodSizeCounter = new MethodSizeCounter();
70                     moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
71                 }
72             };
73         }
74         return methodVisitor;
75     }
76     
77     public MethodBuilderBase addMethodBase(int access,
78             String methodName,
79             TypeDesc ret,
80             TypeDesc[] params) {
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(),
86                 null, null);
87         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
88         return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
89     }
90     
91     public void addAbstractMethod(int access,
92             String methodName,
93             TypeDesc ret,
94             TypeDesc[] params) {
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(),
100                 null, null);
101         for(int i=0;i<params.length;++i)
102             methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
103         methodVisitor.visitEnd();
104     }
105
106     public MethodBuilderBase addConstructorBase(int access, TypeDesc[] params) {
107         return addMethodBase(access, "<init>", TypeDesc.VOID, params);
108     }
109     
110     public MethodBuilder addConstructor(int access, TypeDesc[] params) {
111         return addMethod(access, "<init>", TypeDesc.VOID, params);
112     }
113
114     public MethodBuilder addInitializer() {
115         return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
116     }
117     
118     public MethodBuilderBase addInitializerBase() {
119         return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
120     }
121
122     public void addField(int access, String fieldName,
123             TypeDesc type) {
124         if(type.equals(TypeDesc.VOID))
125             throw new IllegalArgumentException();
126         FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
127         fieldVisitor.visitEnd();
128     }
129
130     public byte[] finishClass() {
131         classVisitor.visitEnd();
132         return classWriter.toByteArray();
133     }
134
135     public String getClassName() {
136         return className;
137     }
138
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();
147     }
148
149     public TypeDesc getType() {
150         return TypeDesc.forClass(className);
151     }
152
153     public String getSuperClassName() {
154         return superClassName;
155     }
156
157     public static void checkClassName(String className) {
158         /*if(className != null && className.contains(".")) {
159             System.out.print(className);
160             System.out.println();
161         }*/
162     }
163     
164     public ModuleBuilder getModuleBuilder() {
165         return moduleBuilder;
166     }
167 }