package org.codehaus.groovy.gjit;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;
import org.codehaus.groovy.gjit.db.SiteTypePersistentCache;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.commons.EmptyVisitor;
import org.objectweb.asm.tree.MethodNode;
public class PreProcess extends ClassAdapter {
private String className;
private boolean groovyClassFile = false;
private Map<String, MethodNode> methods = new HashMap<String, MethodNode>();
public PreProcess(ClassVisitor cv) {
super(cv);
}
enum CallSiteCollectingState {
START,
GOT_SIZE,
GOT_INDEX,
GOT_NAME
};
class CallSiteCollectorMV extends MethodAdapter {
public CallSiteCollectorMV(MethodVisitor mv) {
super(mv);
}
CallSiteCollectingState state = CallSiteCollectingState.START;
private int size;
private int index;
private String[] names;
// public CallSiteCollectorMV(int access, String name, String desc,
// String signature, String[] exceptions) {
// super(access, name, desc, signature, exceptions);
// }
@Override
public void visitLdcInsn(Object cst) {
switch(state) {
case START: size = (Integer)cst;
names = new String[size];
state = CallSiteCollectingState.GOT_SIZE;
break;
case GOT_SIZE:
case GOT_NAME: index = (Integer)cst;
state = CallSiteCollectingState.GOT_INDEX;
break;
case GOT_INDEX: String name = (String)cst;
names[index] = name;
state = CallSiteCollectingState.GOT_NAME;
break;
}
super.visitLdcInsn(cst);
}
@Override
public void visitEnd() {
super.visitEnd();
CallSiteArrayPack.v().put(className, names);
}
}
enum ConstantCollectingState {
START,
GOT_VALUE,
GOT_NAME
};
class ConstantCollectorMV extends MethodAdapter {
public ConstantCollectorMV(MethodVisitor mv) {
super(mv);
}
private ConstantCollectingState state = ConstantCollectingState.START;
private ConstantPack pack = new ConstantPack();
private Object value;
// public ConstantCollectorMV(int access, String name, String desc,
// String signature, String[] exceptions) {
// super(access, name, desc, signature, exceptions);
// }
@Override
public void visitFieldInsn(int opcode, String owner, String name,String desc) {
if( state == ConstantCollectingState.GOT_VALUE) {
if(name.startsWith("$const$")) {
// System.out.println("current type: " + desc);
// System.out.println("cst: " + value.getClass());
if(desc.equals("Ljava/lang/Integer;") && value instanceof Long) {
pack.put(name, ((Long)value).intValue());
} else {
pack.put(name, value);
}
state = ConstantCollectingState.GOT_NAME;
} else if(name.startsWith("__timeStamp")) {
// TODO here is the call to SiteTypePersistentCache
// DebugUtils.println("owner: " + owner);
SiteTypePersistentCache.v().add(owner, (Long)value);
}
// TODO get __timeStamp
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLdcInsn(Object cst) {
if( state == ConstantCollectingState.START ||
state == ConstantCollectingState.GOT_NAME) {
value = cst;
state = ConstantCollectingState.GOT_VALUE;
}
super.visitLdcInsn(cst);
}
@Override
public void visitEnd() {
super.visitEnd();
ConstantRecord.v().put(className, pack);
}
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
this.className = name;
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,String signature, Object value) {
if(name.startsWith("__timeStamp__")==true) {
this.groovyClassFile = true;
}
return super.visitField(access, name, desc, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
// DebugUtils.println(name);
if(this.groovyClassFile == true) {
if(name.equals("$createCallSiteArray")) {
return new CallSiteCollectorMV(super.visitMethod(access, name, desc, signature, exceptions));
} else if(name.equals("<clinit>")) {
return new ConstantCollectorMV(super.visitMethod(access, name, desc, signature, exceptions));
} else if(isSkippable(name,desc)) {
return super.visitMethod(access, name, desc, signature, exceptions);
}
MethodNode mn = new MethodNode(access, name, desc, signature, exceptions);
methods.put(name+desc, mn);
return mn;
} else {
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
private boolean isSkippable(String name, String desc) {
if(name.startsWith("$get$$class$")) return true;
if(name.equals("class$")) return true;
if(name.equals("$getCallSiteArray")) return true;
if(name.equals("$getStaticMetaClass")) return true;
if(name.startsWith("super$1$")) return true;
if(name.startsWith("this$2$")) return true;
if((name+desc).equals("getMetaClass()Lgroovy/lang/MetaClass;")) return true;
if((name+desc).equals("setMetaClass(Lgroovy/lang/MetaClass;)V")) return true;
if((name+desc).equals("invokeMethod(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;")) return true;
if((name+desc).equals("getProperty(Ljava/lang/String;)Ljava/lang/Object;")) return true;
if((name+desc).equals("setProperty(Ljava/lang/String;Ljava/lang/Object;)V")) return true;
return false;
}
public Map<String, MethodNode> getMethods() {
return methods;
}
public boolean isGroovyClassFile() {
return groovyClassFile;
}
public static PreProcess perform(byte[] bytes, int mode) {
ClassReader cr = new ClassReader(bytes);
PreProcess cv = new PreProcess(new EmptyVisitor());
cr.accept(cv, mode);
return cv;
}
public static PreProcess perform(byte[] bytes) {
return perform(bytes, 0);
}
public static void main(String[] args) throws Throwable {
RandomAccessFile r = new RandomAccessFile(new File("C:\\groovy-ck1\\groovy\\my\\TreeNode.class"), "r");
byte[] bytes = new byte[(int) r.length()];
r.readFully(bytes);
PreProcess.perform(bytes);
}
}