--- /dev/null
+package org.simantics.scl.compiler.internal.codegen.utils;
+
+import java.io.PrintWriter;
+
+import org.cojen.classfile.MethodDesc;
+import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.commons.CodeSizeEvaluator;
+import org.objectweb.asm.util.TraceClassVisitor;
+import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
+
+public class ClassBuilder {
+ ModuleBuilder moduleBuilder;
+ String className;
+ String superClassName;
+ ClassVisitor classVisitor;
+ ClassWriter classWriter;
+
+ public ClassBuilder(ModuleBuilder moduleBuilder, int access, String className, String superClassName,
+ String ... interfaces) {
+ checkClassName(className);
+ checkClassName(superClassName);
+ this.moduleBuilder = moduleBuilder;
+ this.className = className;
+ this.superClassName = superClassName;
+ this.classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+ this.classVisitor = SCLCompilerConfiguration.SHOW_COMPILED_BYTECODE
+ ? new TraceClassVisitor(classWriter, new PrintWriter(System.out))
+ : classWriter;
+ classVisitor.visit(Opcodes.V1_5, access, className, null, superClassName, interfaces);
+ }
+
+ public void setSourceFile(String fileName) {
+ classVisitor.visitSource(fileName, null);
+ }
+
+ public MethodBuilder addMethod(int access,
+ String methodName,
+ TypeDesc ret,
+ TypeDesc[] params) {
+ MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
+ MethodDesc.forArguments(ret, params).getDescriptor(),
+ null, null);
+ methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
+ return new MethodBuilder(this, moduleBuilder, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
+ }
+
+ private MethodVisitor augmentMethodVisitor(String methodName, MethodVisitor methodVisitor) {
+ if(SCLCompilerConfiguration.TRACE_MAX_METHOD_SIZE && moduleBuilder != null) {
+ methodVisitor = new CodeSizeEvaluator(methodVisitor) {
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ if(moduleBuilder.methodSizeCounter == null)
+ moduleBuilder.methodSizeCounter = new MethodSizeCounter();
+ moduleBuilder.methodSizeCounter.update(methodName, getMinSize(), getMaxSize());
+ }
+ };
+ }
+ return methodVisitor;
+ }
+
+ public MethodBuilderBase addMethodBase(int access,
+ String methodName,
+ TypeDesc ret,
+ TypeDesc[] params) {
+ MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
+ MethodDesc.forArguments(ret, params).getDescriptor(),
+ null, null);
+ methodVisitor = augmentMethodVisitor(methodName, methodVisitor);
+ return new MethodBuilderBase(this, (access&Opcodes.ACC_STATIC) != 0, methodVisitor, params);
+ }
+
+ public void addAbstractMethod(int access,
+ String methodName,
+ TypeDesc ret,
+ TypeDesc[] params) {
+ MethodVisitor methodVisitor = classVisitor.visitMethod(access, methodName,
+ MethodDesc.forArguments(ret, params).getDescriptor(),
+ null, null);
+ for(int i=0;i<params.length;++i)
+ methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
+ methodVisitor.visitEnd();
+ }
+
+ public MethodBuilderBase addConstructor(int access, TypeDesc[] params) {
+ return addMethodBase(access, "<init>", TypeDesc.VOID, params);
+ }
+
+ public MethodBuilder addInitializer() {
+ return addMethod(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
+ }
+
+ public MethodBuilderBase addInitializerBase() {
+ return addMethodBase(Opcodes.ACC_PUBLIC, "<clinit>", TypeDesc.VOID, Constants.EMPTY_TYPEDESC_ARRAY);
+ }
+
+ public void addField(int access, String fieldName,
+ TypeDesc type) {
+ FieldVisitor fieldVisitor = classVisitor.visitField(access, fieldName, type.getDescriptor(), null, null);
+ fieldVisitor.visitEnd();
+ }
+
+ public byte[] finishClass() {
+ classVisitor.visitEnd();
+ return classWriter.toByteArray();
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void addDefaultConstructor() {
+ MethodVisitor methodVisitor = classVisitor.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, superClassName, "<init>", "()V", false);
+ methodVisitor.visitInsn(Opcodes.RETURN);
+ methodVisitor.visitMaxs(0, 0);
+ methodVisitor.visitEnd();
+ }
+
+ public TypeDesc getType() {
+ return TypeDesc.forClass(className);
+ }
+
+ public String getSuperClassName() {
+ return superClassName;
+ }
+
+ public static void checkClassName(String className) {
+ /*if(className != null && className.contains(".")) {
+ System.out.print(className);
+ System.out.println();
+ }*/
+ }
+}