package st.gravel.support.compiler;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.util.TraceClassVisitor;
import st.gravel.support.compiler.jvm.BlockSendArgument;
import st.gravel.support.compiler.jvm.JVMClass;
import st.gravel.support.compiler.jvm.JVMField;
import st.gravel.support.compiler.jvm.JVMMethod;
public class ASMClassWriter implements Opcodes {
private JVMClass jvmClass;
private ClassWriter cw;
public static final StClassLoader loader = new StClassLoader();
public ASMClassWriter(JVMClass jvmClass) {
this.jvmClass = jvmClass;
}
public ClassWriter newClassWriter() {
return new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected String getCommonSuperClass(String type1, String type2) {
return "java/lang/Object";
}
};
}
protected byte[] createBytes() {
cw = newClassWriter();
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, jvmClass.type().className(),
null, jvmClass.superType().className(),
new String[] { "java/lang/Cloneable" });
if (jvmClass.source() != null) {
cw.visitSource(jvmClass.source(), null);
}
for (JVMField field : jvmClass.fields()) {
createField(field);
}
for (JVMMethod method : jvmClass.methods()) {
createMethod(method);
}
cw.visitEnd();
return cw.toByteArray();
}
private void createMethod(JVMMethod method) {
ASMMethodWriter writer = new ASMMethodWriter(cw);
try {
writer.write(method);
} catch (Exception e) {
e.toString();
throw e;
}
}
private void createField(JVMField field) {
FieldVisitor fv = cw.visitField(ACC_PUBLIC | (field.isStatic() ? ACC_STATIC : 0), field.varName(), field
.type().descriptorString(), null, null);
fv.visitEnd();
}
public Class<?> createClass() {
byte[] bytes = createBytes();
// if (jvmClass.type().dottedClassName().equals("st.gravel.lang.Float$Factory"))
// printBytecode(bytes);
Class<?> instanceClass = loader.defineClass(jvmClass.type()
.dottedClassName(), bytes);
return instanceClass;
}
private void printBytecode(byte[] bytes) {
ClassReader cr = new ClassReader(bytes);
cr.accept(new TraceClassVisitor(new PrintWriter(System.out)), 0);
}
}