]> gerrit.simantics Code Review - simantics/platform.git/blob
5316b861dc52e3e7a2e9b6424e0debf29ce96a13
[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                   && SCLCompilerConfiguration.debugFilter(moduleBuilder.namingPolicy.getModuleName())
33                 ? new TraceClassVisitor(classWriter, new PrintWriter(System.out))
34                 : classWriter; 
35         classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
36     }
37
38     public void setSourceFile(String fileName) {
39         classVisitor.visitSource(fileName, null);
40     }
41
42     public MethodBuilder addMethod(int access,
43             String methodName,
44             TypeDesc ret,
45             TypeDesc[] params) {
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(),
51                 null, null);
52         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
53         return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
54     }
55     
56     private MethodVisitor augmentMethodVisitor(final String methodName, MethodVisitor methodVisitor) {
57         if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
58             methodVisitor = new CodeSizeEvaluator(methodVisitor) {
59                 @Override
60                 public void visitEnd() {
61                     super.visitEnd();
62                     if(moduleBuilder.methodSizeCounter == null)
63                         moduleBuilder.methodSizeCounter = new MethodSizeCounter();
64                     moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
65                 }
66             };
67         }
68         return methodVisitor;
69     }
70     
71     public MethodBuilderBase addMethodBase(int access,
72             String methodName,
73             TypeDesc ret,
74             TypeDesc[] params) {
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(),
80                 null, null);
81         methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
82         return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
83     }
84     
85     public void addAbstractMethod(int access,
86             String methodName,
87             TypeDesc ret,
88             TypeDesc[] params) {
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(),
94                 null, null);
95         for(int i=0;i<params.length;++i)
96             methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
97         methodVisitor.visitEnd();
98     }
99
100     public MethodBuilderBase addConstructorBase(int access, TypeDesc[] params) {
101         return addMethodBase(access, "<init>", TypeDesc.VOID, params);
102     }
103     
104     public MethodBuilder addConstructor(int access, TypeDesc[] params) {
105         return addMethod(access, "<init>", TypeDesc.VOID, params);
106     }
107
108     public MethodBuilder addInitializer() {
109         return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
110     }
111     
112     public MethodBuilderBase addInitializerBase() {
113         return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
114     }
115
116     public void addField(int access, String fieldName,
117             TypeDesc type) {
118         if(type.equals(TypeDesc.VOID))
119             throw new IllegalArgumentException();
120         FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
121         fieldVisitor.visitEnd();
122     }
123
124     public byte[] finishClass() {
125         classVisitor.visitEnd();
126         return classWriter.toByteArray();
127     }
128
129     public String getClassName() {
130         return className;
131     }
132
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();
141     }
142
143     public TypeDesc getType() {
144         return TypeDesc.forClass(className);
145     }
146
147     public String getSuperClassName() {
148         return superClassName;
149     }
150
151     public static void checkClassName(String className) {
152         /*if(className != null && className.contains(".")) {
153             System.out.print(className);
154             System.out.println();
155         }*/
156     }
157     
158     public ModuleBuilder getModuleBuilder() {
159         return moduleBuilder;
160     }
161 }