]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java
Merge "Ensure GetElementClassRequest is not constructed without elementFactory"
[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.top.SCLCompilerConfiguration;
15
16 public class ClassBuilder {
17     ModuleBuilder moduleBuilder;
18     String className;
19     String superClassName;
20     ClassVisitor classVisitor;
21     ClassWriter classWriter;
22     
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                 ? new TraceClassVisitor(classWriter, new PrintWriter(System.out))
33                 : classWriter; 
34         classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
35     }
36
37     public void setSourceFile(String fileName) {
38         classVisitor.visitSource(fileName, null);
39     }
40
41     public MethodBuilder addMethod(int access,
42             String methodName,
43             TypeDesc ret,
44             TypeDesc[] params) {
45         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
46                 MethodDesc.forArguments(ret, params).getDescriptor(),
47                 null, null);
48         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
49         return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
50     }
51     
52     private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
53         if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
54             methodVisitor = new CodeSizeEvaluator(methodVisitor) {
55                 @Override
56                 public void visitEnd() {
57                     super.visitEnd();
58                     if(moduleBuilder.methodSizeCounter == null)
59                         moduleBuilder.methodSizeCounter = new MethodSizeCounter();
60                     moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
61                 }
62             };
63         }
64         return methodVisitor;
65     }
66     
67     public MethodBuilderBase addMethodBase(int access,
68             String methodName,
69             TypeDesc ret,
70             TypeDesc[] params) {
71         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
72                 MethodDesc.forArguments(ret, params).getDescriptor(),
73                 null, null);
74         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
75         return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
76     }
77     
78     public void addAbstractMethod(int access,
79             String methodName,
80             TypeDesc ret,
81             TypeDesc[] params) {
82         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
83                 MethodDesc.forArguments(ret, params).getDescriptor(),
84                 null, null);
85         for(int i=0;i<params.length;++i)
86             methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
87         methodVisitor.visitEnd();
88     }
89
90     public MethodBuilderBase addConstructor(int access, TypeDesc[] params) {
91         return addMethodBase(access, "<init>", TypeDesc.VOID, params);
92     }
93
94     public MethodBuilder addInitializer() {
95         return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
96     }
97     
98     public MethodBuilderBase addInitializerBase() {
99         return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
100     }
101
102     public void addField(int access, String fieldName,
103             TypeDesc type) {
104         FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
105         fieldVisitor.visitEnd();
106     }
107
108     public byte[] finishClass() {
109         classVisitor.visitEnd();
110         return classWriter.toByteArray();
111     }
112
113     public String getClassName() {
114         return className;
115     }
116
117     public void addDefaultConstructor() {
118         MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
119         methodVisitor.visitCode();
120         methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
121         methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
122         methodVisitor.visitInsn(Opcodes.RETURN);
123         methodVisitor.visitMaxs(0, 0);
124         methodVisitor.visitEnd();
125     }
126
127     public TypeDesc getType() {
128         return TypeDesc.forClass(className);
129     }
130
131     public String getSuperClassName() {
132         return superClassName;
133     }
134
135     public static void checkClassName(String className) {
136         /*if(className != null && className.contains(".")) {
137             System.out.print(className);
138             System.out.println();
139         }*/
140     }
141     
142     public ModuleBuilder getModuleBuilder() {
143         return moduleBuilder;
144     }
145 }