]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / ClassBuilder.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/ClassBuilder.java
new file mode 100644 (file)
index 0000000..c3db313
--- /dev/null
@@ -0,0 +1,141 @@
+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();
+        }*/
+    }
+}