]> gerrit.simantics Code Review - simantics/platform.git/blob
0fe185e611df41ae90efad7e394b77119b0328f4
[simantics/platform.git] /
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         for(TypeDesc param : params)
46             if(param.equals(TypeDesc.VOID))
47                 throw new IllegalArgumentException();
48         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
49                 MethodDesc.forArguments(ret, params).getDescriptor(),
50                 null, null);
51         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
52         return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
53     }
54     
55     private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
56         if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
57             methodVisitor = new CodeSizeEvaluator(methodVisitor) {
58                 @Override
59                 public void visitEnd() {
60                     super.visitEnd();
61                     if(moduleBuilder.methodSizeCounter == null)
62                         moduleBuilder.methodSizeCounter = new MethodSizeCounter();
63                     moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
64                 }
65             };
66         }
67         return methodVisitor;
68     }
69     
70     public MethodBuilderBase addMethodBase(int access,
71             String methodName,
72             TypeDesc ret,
73             TypeDesc[] params) {
74         for(TypeDesc param : params)
75             if(param.equals(TypeDesc.VOID))
76                 throw new IllegalArgumentException();
77         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
78                 MethodDesc.forArguments(ret, params).getDescriptor(),
79                 null, null);
80         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
81         return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
82     }
83     
84     public void addAbstractMethod(int access,
85             String methodName,
86             TypeDesc ret,
87             TypeDesc[] params) {
88         for(TypeDesc param : params)
89             if(param.equals(TypeDesc.VOID))
90                 throw new IllegalArgumentException();
91         MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
92                 MethodDesc.forArguments(ret, params).getDescriptor(),
93                 null, null);
94         for(int i=0;i<params.length;++i)
95             methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
96         methodVisitor.visitEnd();
97     }
98
99     public MethodBuilderBase addConstructor(int access, TypeDesc[] params) {
100         return addMethodBase(access, "<init>", TypeDesc.VOID, params);
101     }
102
103     public MethodBuilder addInitializer() {
104         return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
105     }
106     
107     public MethodBuilderBase addInitializerBase() {
108         return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
109     }
110
111     public void addField(int access, String fieldName,
112             TypeDesc type) {
113         if(type.equals(TypeDesc.VOID))
114             throw new IllegalArgumentException();
115         FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
116         fieldVisitor.visitEnd();
117     }
118
119     public byte[] finishClass() {
120         classVisitor.visitEnd();
121         return classWriter.toByteArray();
122     }
123
124     public String getClassName() {
125         return className;
126     }
127
128     public void addDefaultConstructor() {
129         MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
130         methodVisitor.visitCode();
131         methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
132         methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
133         methodVisitor.visitInsn(Opcodes.RETURN);
134         methodVisitor.visitMaxs(0, 0);
135         methodVisitor.visitEnd();
136     }
137
138     public TypeDesc getType() {
139         return TypeDesc.forClass(className);
140     }
141
142     public String getSuperClassName() {
143         return superClassName;
144     }
145
146     public static void checkClassName(String className) {
147         /*if(className != null && className.contains(".")) {
148             System.out.print(className);
149             System.out.println();
150         }*/
151     }
152     
153     public ModuleBuilder getModuleBuilder() {
154         return moduleBuilder;
155     }
156 }