package org.python.compiler;
import java.util.BitSet;
import java.util.Vector;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
class Code implements MethodVisitor, Opcodes {
MethodVisitor mv;
String sig;
String locals[];
int nlocals;
int argcount;
int returnLocal;
BitSet finallyLocals = new java.util.BitSet();
//XXX: I'd really like to get sig and access out of here since MethodVistitor
// should already have this information.
public Code(MethodVisitor mv, String sig, int access) {
this.mv = mv;
this.sig = sig;
nlocals = -sigSize(sig, false);
if ((access & ACC_STATIC) != ACC_STATIC) nlocals = nlocals+1;
argcount = nlocals;
locals = new String[nlocals+128];
}
public int getLocal(String type) {
//Could optimize this to skip arguments?
for(int l = argcount; l<nlocals; l++) {
if (locals[l] == null) {
locals[l] = type;
return l;
}
}
if (nlocals >= locals.length) {
String[] new_locals = new String[locals.length*2];
System.arraycopy(locals, 0, new_locals, 0, locals.length);
locals = new_locals;
}
locals[nlocals] = type;
nlocals += 1;
return nlocals-1;
}
public void freeLocal(int l) {
if (locals[l] == null) {
System.out.println("Double free:" + l);
}
locals[l] = null;
}
public int getFinallyLocal(String type) {
int l = getLocal(type);
finallyLocals.set(l);
return l;
}
public void freeFinallyLocal(int l) {
finallyLocals.clear(l);
freeLocal(l);
}
public int getReturnLocal() {
if (returnLocal == 0)
returnLocal = getLocal("return");
return returnLocal;
}
public Vector<String> getActiveLocals() {
Vector<String> ret = new Vector<String>();
ret.setSize(nlocals);
for (int l = argcount; l<nlocals; l++) {
if (l == returnLocal || finallyLocals.get(l))
continue;
ret.setElementAt(locals[l], l);
}
return ret;
}
public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
return mv.visitAnnotation(arg0, arg1);
}
public AnnotationVisitor visitAnnotationDefault() {
return mv.visitAnnotationDefault();
}
public void visitAttribute(Attribute arg0) {
mv.visitAttribute(arg0);
}
public void visitCode() {
mv.visitCode();
}
public void visitEnd() {
mv.visitEnd();
}
public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) {
mv.visitFieldInsn(arg0, arg1, arg2, arg3);
}
public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4) {
mv.visitFrame(arg0, arg1, arg2, arg3, arg4);
}
public void visitIincInsn(int arg0, int arg1) {
mv.visitIincInsn(arg0, arg1);
}
public void visitInsn(int arg0) {
mv.visitInsn(arg0);
}
public void visitIntInsn(int arg0, int arg1) {
mv.visitIntInsn(arg0, arg1);
}
public void visitJumpInsn(int arg0, Label arg1) {
mv.visitJumpInsn(arg0, arg1);
}
public void visitLabel(Label arg0) {
mv.visitLabel(arg0);
}
public void visitLdcInsn(Object arg0) {
mv.visitLdcInsn(arg0);
}
public void visitLineNumber(int arg0, Label arg1) {
mv.visitLineNumber(arg0, arg1);
}
public void visitLocalVariable(String arg0, String arg1, String arg2, Label arg3, Label arg4, int arg5) {
mv.visitLocalVariable(arg0, arg1, arg2, arg3, arg4, arg5);
}
public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) {
mv.visitLookupSwitchInsn(arg0, arg1, arg2);
}
public void visitMaxs(int arg0, int arg1) {
mv.visitMaxs(arg0, arg1);
}
public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) {
mv.visitMethodInsn(arg0, arg1, arg2, arg3);
}
public void visitMultiANewArrayInsn(String arg0, int arg1) {
mv.visitMultiANewArrayInsn(arg0, arg1);
}
public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1, boolean arg2) {
return mv.visitParameterAnnotation(arg0, arg1, arg2);
}
public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label[] arg3) {
mv.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
}
public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2, String arg3) {
mv.visitTryCatchBlock(arg0, arg1, arg2, arg3);
}
public void visitTypeInsn(int arg0, String arg1) {
mv.visitTypeInsn(arg0, arg1);
}
public void visitVarInsn(int arg0, int arg1) {
mv.visitVarInsn(arg0, arg1);
}
@SuppressWarnings("fallthrough")
private int sigSize(String sig, boolean includeReturn) {
int stack = 0;
int i = 0;
char[] c = sig.toCharArray();
int n = c.length;
boolean ret=false;
boolean array=false;
while (++i<n) {
switch (c[i]) {
case ')':
if (!includeReturn)
return stack;
ret=true;
continue;
case '[':
array=true;
continue;
case 'V':
continue;
case 'D':
case 'J':
if (array) {
if (ret) stack += 1;
else stack -=1;
array = false;
} else {
if (ret) stack += 2;
else stack -=2;
}
break;
case 'L':
while (c[++i] != ';') {}
default:
if (ret) stack++;
else stack--;
array = false;
}
}
return stack;
}
public void aaload() {
mv.visitInsn(AALOAD);
}
public void aastore() {
mv.visitInsn(AASTORE);
}
public void aconst_null() {
mv.visitInsn(ACONST_NULL);
}
public void aload(int index) {
mv.visitVarInsn(ALOAD, index);
}
public void anewarray(String index) {
mv.visitTypeInsn(ANEWARRAY, index);
}
public void areturn() {
mv.visitInsn(ARETURN);
}
public void arraylength() {
mv.visitInsn(ARRAYLENGTH);
}
public void astore(int index) {
mv.visitVarInsn(ASTORE, index);
}
public void athrow() {
mv.visitInsn(ATHROW);
}
public void baload() {
mv.visitInsn(BALOAD);
}
public void bastore() {
mv.visitInsn(BASTORE);
}
public void bipush(int value) {
mv.visitIntInsn(BIPUSH, value);
}
public void checkcast(String type) {
mv.visitTypeInsn(CHECKCAST, type);
}
public void dconst_0() {
mv.visitInsn(DCONST_0);
}
public void dload(int index) {
mv.visitVarInsn(DLOAD, index);
}
public void dreturn() {
mv.visitInsn(DRETURN);
}
public void dup() {
mv.visitInsn(DUP);
}
public void dup2() {
mv.visitInsn(DUP2);
}
public void dup_x1() {
mv.visitInsn(DUP_X1);
}
public void dup_x2() {
mv.visitInsn(DUP_X2);
}
public void dup2_x1() {
mv.visitInsn(DUP2_X1);
}
public void dup2_x2() {
mv.visitInsn(DUP2_X2);
}
public void fconst_0() {
mv.visitInsn(FCONST_0);
}
public void fload(int index) {
mv.visitVarInsn(FLOAD, index);
}
public void freturn() {
mv.visitInsn(FRETURN);
}
public void getfield(String owner, String name, String type) {
mv.visitFieldInsn(GETFIELD, owner, name, type);
}
public void getstatic(String owner, String name, String type) {
mv.visitFieldInsn(GETSTATIC, owner, name, type);
}
public void goto_(Label label) {
mv.visitJumpInsn(GOTO, label);
}
public void iconst(int value) {
if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) {
switch (value) {
case -1:
iconst_m1();
break;
case 0:
iconst_0();
break;
case 1:
iconst_1();
break;
case 2:
iconst_2();
break;
case 3:
iconst_3();
break;
case 4:
iconst_4();
break;
case 5:
iconst_5();
break;
default:
bipush(value);
break;
}
} else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) {
sipush(value);
} else {
ldc(value);
}
}
public void iconst_m1() {
mv.visitInsn(ICONST_M1);
}
public void iconst_0() {
mv.visitInsn(ICONST_0);
}
public void iconst_1() {
mv.visitInsn(ICONST_1);
}
public void iconst_2() {
mv.visitInsn(ICONST_2);
}
public void iconst_3() {
mv.visitInsn(ICONST_3);
}
public void iconst_4() {
mv.visitInsn(ICONST_4);
}
public void iconst_5() {
mv.visitInsn(ICONST_5);
}
public void ifeq(Label label) {
mv.visitJumpInsn(IFEQ, label);
}
public void ifle(Label label) {
mv.visitJumpInsn(IFLE, label);
}
public void ifne(Label label) {
mv.visitJumpInsn(IFNE, label);
}
public void ifnull(Label label) {
mv.visitJumpInsn(IFNULL, label);
}
public void ifnonnull(Label label) {
mv.visitJumpInsn(IFNONNULL, label);
}
public void if_acmpne(Label label) {
mv.visitJumpInsn(IF_ACMPNE, label);
}
public void if_acmpeq(Label label) {
mv.visitJumpInsn(IF_ACMPEQ, label);
}
public void if_icmple(Label label) {
mv.visitJumpInsn(IF_ICMPLE, label);
}
public void if_icmpgt(Label label) {
mv.visitJumpInsn(IF_ICMPGT, label);
}
public void if_icmplt(Label label) {
mv.visitJumpInsn(IF_ICMPLT, label);
}
public void if_icmpne(Label label) {
mv.visitJumpInsn(IF_ICMPNE, label);
}
public void if_icmpeq(Label label) {
mv.visitJumpInsn(IF_ICMPEQ, label);
}
public void iadd() {
mv.visitInsn(IADD);
}
public void iaload() {
mv.visitInsn(IALOAD);
}
public void iinc() {
mv.visitInsn(IINC);
}
public void iload(int index) {
mv.visitVarInsn(ILOAD, index);
}
public void instanceof_(String type) {
mv.visitTypeInsn(INSTANCEOF, type);
}
public void invokeinterface(String owner, String name, String type) {
mv.visitMethodInsn(INVOKEINTERFACE, owner, name, type);
}
public void invokespecial(String owner, String name, String type) {
mv.visitMethodInsn(INVOKESPECIAL, owner, name, type);
}
public void invokestatic(String owner, String name, String type) {
mv.visitMethodInsn(INVOKESTATIC, owner, name, type);
}
public void invokevirtual(String owner, String name, String type) {
mv.visitMethodInsn(INVOKEVIRTUAL, owner, name, type);
}
public void ireturn() {
mv.visitInsn(IRETURN);
}
public void istore(int index) {
mv.visitVarInsn(ISTORE, index);
}
public void isub() {
mv.visitInsn(ISUB);
}
public void label(Label label) {
mv.visitLabel(label);
}
public void lconst_0() {
mv.visitInsn(LCONST_0);
}
public void ldc(Object cst) {
if (cst instanceof String) {
String value = (String) cst;
final int len = value.length();
// 65535 / 4 (max utf-8 expansion for non BMP characters)
final int maxlen = 16000;
if (len > maxlen) {
new_("java/lang/StringBuilder");
dup();
iconst(len);
invokespecial("java/lang/StringBuilder", "<init>", "(I)V");
for (int i = 0; i < len; i += maxlen) {
int j = i + maxlen;
if (j > len) {
j = len;
}
mv.visitLdcInsn(value.substring(i, j));
invokevirtual("java/lang/StringBuilder", "append", "(Ljava/lang/String;)" + "Ljava/lang/StringBuilder;");
}
invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
} else {
mv.visitLdcInsn(value);
}
} else {
mv.visitLdcInsn(cst);
}
}
public void lload(int index) {
mv.visitVarInsn(LLOAD, index);
}
public void lreturn() {
mv.visitInsn(LRETURN);
}
public void newarray(int atype) {
mv.visitIntInsn(NEWARRAY, atype);
}
public void new_(String type) {
mv.visitTypeInsn(NEW, type);
}
public void nop() {
mv.visitInsn(NOP);
}
public void pop() {
mv.visitInsn(POP);
}
public void pop2() {
mv.visitInsn(POP2);
}
public void putstatic(String owner, String name, String type) {
mv.visitFieldInsn(PUTSTATIC, owner, name, type);
}
public void putfield(String owner, String name, String type) {
mv.visitFieldInsn(PUTFIELD, owner, name, type);
}
public void ret(int index) {
mv.visitVarInsn(RET, index);
}
void return_() {
mv.visitInsn(RETURN);
}
public void sipush(int value) {
mv.visitIntInsn(SIPUSH, value);
}
public void swap() {
mv.visitInsn(SWAP);
}
public void swap2() {
dup2_x2();
pop2();
}
public void tableswitch(int arg0, int arg1, Label arg2, Label[] arg3) {
mv.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
}
public void trycatch(Label start, Label end, Label handlerStart, String type) {
mv.visitTryCatchBlock(start, end, handlerStart, type);
}
public void setline(int line) {
mv.visitLineNumber(line, new Label());
}
}