/*
* Copyright 2002-2013 SCOOP Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.scoopgmbh.copper.instrument;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.org.apache.bcel.internal.classfile.ClassFormatException;
import de.scoopgmbh.copper.instrument.StackInfo.ComputationalCategory;
public class BuildStackInfoAdapter extends MethodVisitor implements Opcodes, ByteCodeStackInfo {
static final Logger logger = LoggerFactory.getLogger(BuildStackInfoAdapter.class);
static final Type retAddressType = Type.getObjectType("ReturnAddress");
StackInfo lastDeclaredFrame;
StackInfo currentFrame;
StackInfo previousFrame;
Map<Label, StackInfo> forwardFrames = new HashMap<Label, StackInfo>();
Map<Label, int[]> lineNumbers = new HashMap<Label, int[]>();
List<LocalVariable> localVariables = new ArrayList<LocalVariable>();
MethodVisitor delegate;
public BuildStackInfoAdapter(String classType, boolean isStatic, String methodName, String arguments, String extendedArguments) {
super(ASM4);
int i = 0;
Type[] argumentTypes = Type.getArgumentTypes(arguments);
currentFrame = new StackInfo();
if (!isStatic)
currentFrame.setLocal(i++, Type.getType(classType));
for (Type t : argumentTypes) {
currentFrame.setLocal(i++, t);
if (StackInfo.getCategory(t) == ComputationalCategory.CAT_2)
i++;
}
lastDeclaredFrame = new StackInfo(currentFrame);
this.delegate = new NullMethodVisitor();
}
public void setMethodVisitor(MethodVisitor mVisitor) {
this.delegate = mVisitor;
}
@Override
public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
return delegate.visitAnnotation(arg0, arg1);
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
return delegate.visitAnnotationDefault();
}
@Override
public void visitAttribute(Attribute arg0) {
delegate.visitAttribute(arg0);
}
@Override
public void visitCode() {
delegate.visitCode();
}
@Override
public void visitEnd() {
delegate.visitEnd();
}
@Override
public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) {
savePreviousFrame();
Type t = deferTypFromCanonicalName(arg3);
switch (arg0) {
case GETSTATIC:
currentFrame.pushStack(t); break;
case PUTSTATIC:
currentFrame.popStackUnchecked();
break;
case GETFIELD:
currentFrame.replaceStack(t); break;
case PUTFIELD:
currentFrame.popStackUnchecked();
currentFrame.popStackUnchecked();
break;
default: logger.debug("Unhandled: ");
}
if (logger.isDebugEnabled()) logger.debug("fieldInsn "+getOpCode(arg0)+" '"+arg1+"' '"+arg2+"' '"+arg3+"'");
delegate.visitFieldInsn(arg0, arg1, arg2, arg3);
}
@Override
public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3,
Object[] arg4) {
savePreviousFrame();
if (logger.isDebugEnabled()) logger.debug("stackBefore: "+currentFrame.stack);
if (logger.isDebugEnabled()) logger.debug("localBefore: "+currentFrame.localsToString());
currentFrame = new StackInfo(lastDeclaredFrame);
switch (arg0) {
case F_SAME: // representing frame with exactly the same locals as the previous frame and with the empty stack.
currentFrame.stack.clear(); break;
case F_SAME1: //representing frame with exactly the same locals as the previous frame and with single value on the stack (nStack is 1 and stack[0] contains value for the type of the stack item).
Type t = StackInfo.deferLocalDesc(arg4[0]);
currentFrame.stack.clear(); currentFrame.stack.push(t); break;
case F_APPEND: // representing frame with current locals are the same as the locals in the previous frame, except that additional locals are defined (nLocal is 1, 2 or 3 and local elements contains values representing added types).
currentFrame.appendLocals(arg1, arg2); break;
case F_CHOP: //�Opcodes.F_CHOP representing frame with current locals are the same as the locals in the previous frame, except that the last 1-3 locals are absent and with the empty stack (nLocals is 1, 2 or 3).
currentFrame.removeLocals(arg1); currentFrame.stack.clear(); break;
case Opcodes.F_FULL: //representing complete frame data.
case Opcodes.F_NEW:
currentFrame.clearFrame(); currentFrame.appendLocals(arg1, arg2); currentFrame.appendStack(arg3, arg4); break;
default:
throw new BuildStackFrameException("Unkwnon frame type "+arg0);
}
lastDeclaredFrame = new StackInfo(currentFrame);
if (logger.isDebugEnabled()) logger.debug("stack: "+currentFrame.stack);
if (logger.isDebugEnabled()) logger.debug("local: "+currentFrame.localsToString());
if (logger.isDebugEnabled()) logger.debug("frame "+getFrameType(arg0)+" '"+arg1+"' '"+Arrays.asList(arg2)+"' '"+arg3+"' '"+Arrays.asList(arg4)+"'");
delegate.visitFrame(arg0, arg1, arg2, arg3, arg4);
}
@Override
public void visitIincInsn(int arg0, int arg1) {
savePreviousFrame();
delegate.visitIincInsn(arg0, arg1);
}
@Override
public void visitInsn(int arg0) {
savePreviousFrame();
switch (arg0) {
case ICONST_0:
case ICONST_1:
case ICONST_2:
case ICONST_3:
case ICONST_4:
case ICONST_5:
case ICONST_M1:
currentFrame.pushStack(Type.INT_TYPE); break;
case FCONST_0:
case FCONST_1:
case FCONST_2:
currentFrame.pushStack(Type.FLOAT_TYPE); break;
case DCONST_0:
case DCONST_1:
currentFrame.pushStack(Type.DOUBLE_TYPE); break;
case LCONST_0:
case LCONST_1:
currentFrame.pushStack(Type.LONG_TYPE); break;
case ACONST_NULL:
currentFrame.pushStack(StackInfo.AconstNullType); break;
// currentFrame.pushStack(Type.getType(Object.class)); break;
case DUP:
currentFrame.dupStack(); break;
case DUP_X1:
currentFrame.dupX1Stack(); break;
case DUP_X2:
currentFrame.dupX2Stack(); break;
case DUP2:
currentFrame.dup2Stack(); break;
case DUP2_X1:
currentFrame.dup2X1Stack(); break;
case DUP2_X2:
currentFrame.dup2X2Stack(); break;
case POP:
currentFrame.popStack(); break;
case POP2:
currentFrame.pop2Stack(); break;
case SWAP:
currentFrame.swapStack(); break;
case IADD:
case IAND:
case ISUB:
case IMUL:
case IDIV:
case IOR:
case ISHL:
case ISHR:
case IUSHR:
case IREM:
case IXOR:
currentFrame.popStackChecked(Type.INT_TYPE);
case INEG:
currentFrame.replaceStackChecked(Type.INT_TYPE,Type.INT_TYPE); break;
case LADD:
case LAND:
case LOR:
case LSUB:
case LMUL:
case LDIV:
case LREM:
case LXOR:
currentFrame.popStackChecked(Type.LONG_TYPE);
case LNEG:
currentFrame.replaceStackChecked(Type.LONG_TYPE,Type.LONG_TYPE); break;
case LSHL:
case LSHR:
case LUSHR:
currentFrame.popStackChecked(Type.INT_TYPE);
currentFrame.replaceStackChecked(Type.LONG_TYPE,Type.LONG_TYPE); break;
case DADD:
case DSUB:
case DMUL:
case DDIV:
case DREM:
currentFrame.popStackChecked(Type.DOUBLE_TYPE);
case DNEG:
currentFrame.replaceStackChecked(Type.DOUBLE_TYPE,Type.DOUBLE_TYPE); break;
case FADD:
case FSUB:
case FMUL:
case FDIV:
case FREM:
currentFrame.popStackChecked(Type.FLOAT_TYPE);
case FNEG:
currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.FLOAT_TYPE); break;
case FCMPG:
case FCMPL:
currentFrame.popStackChecked(Type.FLOAT_TYPE); currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.INT_TYPE); break;
case DCMPG:
case DCMPL:
currentFrame.popStackChecked(Type.DOUBLE_TYPE); currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.INT_TYPE); break;
case F2D:
currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.DOUBLE_TYPE); break;
case F2I:
currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.INT_TYPE); break;
case F2L:
currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.LONG_TYPE); break;
case I2B:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.BYTE_TYPE); break;
case I2C:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.CHAR_TYPE); break;
case I2D:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.DOUBLE_TYPE); break;
case I2F:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.FLOAT_TYPE); break;
case I2L:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.LONG_TYPE); break;
case I2S:
currentFrame.replaceStackChecked(Type.INT_TYPE, Type.SHORT_TYPE); break;
case L2D:
currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.DOUBLE_TYPE); break;
case L2F:
currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.FLOAT_TYPE); break;
case L2I:
currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.INT_TYPE); break;
case D2F:
currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.FLOAT_TYPE); break;
case D2I:
currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.INT_TYPE); break;
case D2L:
currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.LONG_TYPE); break;
case LCMP:
currentFrame.popStackChecked(Type.LONG_TYPE); currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.INT_TYPE); break;
case ARRAYLENGTH:
currentFrame.popStack();
currentFrame.pushStack(Type.INT_TYPE);
break;
case RETURN:
case IRETURN:
case LRETURN:
case DRETURN:
case FRETURN:
case ARETURN:
currentFrame.clearFrame();
break;
case ATHROW:
Type t = currentFrame.popStack();
currentFrame.clearStack();
currentFrame.pushStack(t);
break;
case AALOAD:
currentFrame.popStackChecked(Type.INT_TYPE);
Type arrayType = currentFrame.popStack();
currentFrame.pushStack(arrayType.getElementType());
break;
case BALOAD:
arrayLoad(Type.BYTE_TYPE);
break;
case CALOAD:
arrayLoad(Type.CHAR_TYPE);
break;
case DALOAD:
arrayLoad(Type.DOUBLE_TYPE);
break;
case FALOAD:
arrayLoad(Type.FLOAT_TYPE);
break;
case IALOAD:
arrayLoad(Type.INT_TYPE);
break;
case LALOAD:
arrayLoad(Type.LONG_TYPE);
break;
case SALOAD:
arrayLoad(Type.SHORT_TYPE);
break;
case BASTORE:
arrayStore(Type.BYTE_TYPE);
break;
case CASTORE:
arrayStore(Type.CHAR_TYPE);
break;
case DASTORE:
arrayStore(Type.DOUBLE_TYPE);
break;
case FASTORE:
arrayStore(Type.FLOAT_TYPE);
break;
case IASTORE:
arrayStore(Type.INT_TYPE);
break;
case LASTORE:
arrayStore(Type.LONG_TYPE);
break;
case SASTORE:
arrayStore(Type.SHORT_TYPE);
break;
case AASTORE:
currentFrame.popStack();
currentFrame.popStackChecked(Type.INT_TYPE);
currentFrame.popStack();
break;
case MONITORENTER:
case MONITOREXIT:
currentFrame.popStack();
break;
case NOP: break;
default: logger.debug("Unhandled: ");
}
if (logger.isDebugEnabled()) logger.debug("insn "+getOpCode(arg0));
delegate.visitInsn(arg0);
}
@Override
public void visitIntInsn(int arg0, int arg1) {
savePreviousFrame();
switch (arg0) {
case BIPUSH:
currentFrame.pushStack(Type.BYTE_TYPE); break;
case SIPUSH:
currentFrame.pushStack(Type.SHORT_TYPE); break;
case NEWARRAY:
currentFrame.replaceStackChecked(Type.INT_TYPE, getArrayType(arg1)); break;
default:
logger.debug("Unhandled: ");
}
if (logger.isDebugEnabled()) logger.debug("intInsn "+getOpCode(arg0)+" "+arg1);
delegate.visitIntInsn(arg0, arg1);
}
@Override
public void visitJumpInsn(int arg0, Label arg1) {
savePreviousFrame();
switch (arg0) {
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPNE:
currentFrame.popStack();
case Opcodes.IFEQ:
case Opcodes.IFGE:
case Opcodes.IFGT:
case Opcodes.IFLE:
case Opcodes.IFLT:
case Opcodes.IFNE:
case Opcodes.IFNONNULL:
case Opcodes.IFNULL:
currentFrame.popStack();
case Opcodes.GOTO:
forwardFrames.put(arg1, new StackInfo(currentFrame)); break;
case Opcodes.JSR:
currentFrame.pushStack(retAddressType);
forwardFrames.put(arg1, new StackInfo(currentFrame)); break;
default:
logger.debug("Unhandled: ");
}
if (logger.isDebugEnabled()) logger.debug("jumpInsn "+getOpCode(arg0)+" "+arg1);
delegate.visitJumpInsn(arg0, arg1);
}
@Override
public void visitLabel(Label arg0) {
savePreviousFrame();
if (logger.isDebugEnabled()) logger.debug("label "+arg0);
StackInfo f = forwardFrames.get(arg0);
if (f != null)
currentFrame = new StackInfo(f);
delegate.visitLabel(arg0);
}
@Override
public void visitLdcInsn(Object arg0) {
savePreviousFrame();
if (arg0 instanceof Type)
currentFrame.pushStack((Type)arg0);
else if (arg0 instanceof String)
currentFrame.pushStack(Type.getType(String.class));
else if (arg0 instanceof Float)
currentFrame.pushStack(Type.FLOAT_TYPE);
else if (arg0 instanceof Double)
currentFrame.pushStack(Type.DOUBLE_TYPE);
else if (arg0 instanceof Integer)
currentFrame.pushStack(Type.INT_TYPE);
else if (arg0 instanceof Long)
currentFrame.pushStack(Type.LONG_TYPE);
else
logger.debug("Unhandled: ");
if (logger.isDebugEnabled()) logger.debug("ldcInsn "+arg0);
delegate.visitLdcInsn(arg0);
}
@Override
public void visitLineNumber(int arg0, Label arg1) {
getLineNumber(arg1)[0] = arg0;
currentFrame.setLineNo(arg0);
delegate.visitLineNumber(arg0, arg1);
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
localVariables.add(new LocalVariable(name,desc,start,end,index));
delegate.visitLocalVariable(name, desc, signature, start, end, index);
}
@Override
public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) {
savePreviousFrame();
if (logger.isDebugEnabled()) logger.debug("lookupSwitchInsn "+arg0+" "+Arrays.toString(arg1)+" "+Arrays.toString(arg2));
delegate.visitLookupSwitchInsn(arg0, arg1, arg2);
}
@Override
public void visitMaxs(int arg0, int arg1) {
delegate.visitMaxs(arg0, arg1);
}
@Override
public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) {
savePreviousFrame();
Type deferredReturnType = deferReturnType(arg3);
switch (arg0) {
case INVOKESTATIC:
currentFrame.popStackBySignature(arg3);
if (deferredReturnType != Type.VOID_TYPE)
currentFrame.pushStack(deferredReturnType);
break;
case INVOKESPECIAL:
case INVOKEINTERFACE:
case INVOKEVIRTUAL:
currentFrame.popStackBySignature(arg3);
currentFrame.popStack();
if (deferredReturnType != Type.VOID_TYPE)
currentFrame.pushStack(deferredReturnType);
break;
default:
logger.debug("Unhandled: ");
}
if (logger.isDebugEnabled()) logger.debug("methodInsn "+getOpCode(arg0)+" "+arg1+" "+arg2+" "+arg3);
delegate.visitMethodInsn(arg0, arg1, arg2, arg3);
}
@Override
public void visitMultiANewArrayInsn(String arg0, int arg1) {
savePreviousFrame();
for (int i = 0; i < arg1; ++i)
currentFrame.popStackChecked(Type.INT_TYPE);
currentFrame.pushStack(Type.getObjectType(arg0));
if (logger.isDebugEnabled()) logger.debug("visitMultiANewArrayInsn "+arg0+" "+arg1);
delegate.visitMultiANewArrayInsn(arg0, arg1);
}
@Override
public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1,
boolean arg2) {
return delegate.visitParameterAnnotation(arg0, arg1, arg2);
}
@Override
public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label... arg3) {
savePreviousFrame();
if (logger.isDebugEnabled()) logger.debug("tableSwitchInsn "+arg0+" "+arg1+" "+arg2+" "+Arrays.asList(arg3));
delegate.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
}
@Override
public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2,
String arg3) {
if (logger.isDebugEnabled()) logger.debug("tryCatchBlock "+arg0+" "+arg1+" "+arg2+" "+arg3);
delegate.visitTryCatchBlock(arg0, arg1, arg2, arg3);
}
@Override
public void visitTypeInsn(int arg0, String arg1) {
savePreviousFrame();
Type objectType = Type.getObjectType(arg1);
switch (arg0) {
case NEW:
currentFrame.pushStack(objectType); break;
case CHECKCAST:
currentFrame.replaceStack(objectType); break;
case ANEWARRAY:
currentFrame.replaceStack(Type.getObjectType("["+objectType.getDescriptor())); break;
case INSTANCEOF:
currentFrame.replaceStack(Type.INT_TYPE); break;
default:
logger.debug("Unhandled:");
}
if (logger.isDebugEnabled()) logger.debug("typeInsn: "+getOpCode(arg0)+" "+arg1);
delegate.visitTypeInsn(arg0, arg1);
}
@Override
public void visitVarInsn(int arg0, int arg1) {
savePreviousFrame();
switch (arg0) {
case ALOAD:
currentFrame.pushStack(currentFrame.getLocal(arg1)); break;
case ASTORE:
currentFrame.setLocal(arg1, currentFrame.popStack()); break;
case FLOAD:
if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.FLOAT_TYPE))
throw new BuildStackFrameException("FLOAD expects a float, but got "+currentFrame.getLocal(arg1));
currentFrame.pushStack(currentFrame.getLocal(arg1)); break;
case FSTORE:
currentFrame.setLocal(arg1, currentFrame.popStack()); break;
case ILOAD:
if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.INT_TYPE))
throw new BuildStackFrameException("ILOAD expects an int, but got "+currentFrame.getLocal(arg1));
currentFrame.pushStack(Type.INT_TYPE); break;
case LLOAD:
if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.LONG_TYPE))
throw new BuildStackFrameException("LLOAD expects a long, but got "+currentFrame.getLocal(arg1));
currentFrame.pushStack(Type.LONG_TYPE); break;
case DLOAD:
if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.DOUBLE_TYPE))
throw new BuildStackFrameException("DLOAD expects a double, but got "+currentFrame.getLocal(arg1));
currentFrame.pushStack(Type.DOUBLE_TYPE); break;
case ISTORE:
if (!StackInfo.compatible(currentFrame.popStack(), Type.INT_TYPE))
throw new BuildStackFrameException("ISTORE expects an int, but got "+currentFrame.getLocal(arg1));
currentFrame.setLocal(arg1, Type.INT_TYPE); break;
case DSTORE:
if (!StackInfo.compatible(currentFrame.pop2Stack(), Type.DOUBLE_TYPE))
throw new BuildStackFrameException("DSTORE expects a double, but got "+currentFrame.getLocal(arg1));
currentFrame.setLocal(arg1, Type.DOUBLE_TYPE); break;
case LSTORE:
if (!StackInfo.compatible(currentFrame.pop2Stack(), Type.LONG_TYPE))
throw new BuildStackFrameException("LSTORE expects a long, but got "+currentFrame.getLocal(arg1));
currentFrame.setLocal(arg1, Type.LONG_TYPE); break;
default:
logger.debug("Unhandled:");
}
if (logger.isDebugEnabled()) logger.debug("varInsn: "+getOpCode(arg0)+" "+arg1);
delegate.visitVarInsn(arg0, arg1);
}
public static void main(String[] args) throws Exception {
File basedir = new File("C:/SVN/POLZUG-Solution-1.0-trucking/projects/gui/target/classes");
testAllClasses(basedir,basedir);
}
private static void testAllClasses(File baseDir, File dir) throws FileNotFoundException, IOException, ClassNotFoundException {
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".class");
}
});
for (File f : files) {
testClass(f, f.getAbsolutePath().substring(baseDir.getAbsolutePath().length()+1).replace(".class", "").replace("\\","."));
}
files = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File f : files) {
testAllClasses(baseDir, f);
}
}
private static void testClass(File file, final String className) throws IOException, FileNotFoundException {
ClassReader cr = new ClassReader(new FileInputStream(file));
ClassWriter cw = new ClassWriter(0);
final String cDesc = Type.getObjectType(className).getDescriptor();
ClassVisitor cv = new ClassVisitor(ASM4, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (logger.isDebugEnabled()) logger.debug("=======>"+access+" "+name+" "+desc+" "+signature);
return new BuildStackInfoAdapter(cDesc, (access&Opcodes.ACC_STATIC) > 0, name, desc, signature);
}
@Override
public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) {
if (logger.isDebugEnabled()) logger.debug("== VISIT INNER =======>"+arg0+" "+arg1+" "+arg2+" "+arg3);
super.visitInnerClass(arg0, arg1, arg2, arg3);
}
};
cr.accept(cv, 0);
}
String getOpCode(int opCode) {
for (Field f : Opcodes.class.getDeclaredFields()) {
try {
if (f.getName().startsWith("F_")
|| f.getName().startsWith("T_")
|| f.getName().startsWith("ACC_")
|| f.getName().startsWith("V1_")
)
continue;
if (f.getInt(null) == opCode) {
return f.getName();
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return "No Opcode for "+opCode;
}
String getFrameType(int frameType) {
for (Field f : Opcodes.class.getDeclaredFields()) {
try {
if (!f.getName().startsWith("F_")
)
continue;
if (f.getInt(null) == frameType) {
return f.getName();
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return "No frame type for "+frameType;
}
Type getArrayElementType(int type) {
switch (type) {
case T_BOOLEAN: return Type.BOOLEAN_TYPE;
case T_BYTE: return Type.BYTE_TYPE;
case T_CHAR: return Type.CHAR_TYPE;
case T_DOUBLE: return Type.DOUBLE_TYPE;
case T_FLOAT: return Type.FLOAT_TYPE;
case T_INT: return Type.INT_TYPE;
case T_LONG: return Type.LONG_TYPE;
case T_SHORT: return Type.SHORT_TYPE;
}
throw new BuildStackFrameException("Illegal array type code: "+type);
}
Type getArrayType(int type) {
Type t = getArrayElementType(type);
return Type.getObjectType("["+t.getDescriptor());
}
String getStackInfo(Object[] args) {
StringBuilder sb = new StringBuilder("[");
for (Object arg : args) {
if (arg == null)
sb.append("null");
else {
try {
sb.append(deferTypFromCanonicalName(arg.toString()));
} catch (ClassFormatException ex) {
sb.append(arg.toString());
}
}
sb.append(", ");
}
if (sb.length() > 1)
sb.setLength(sb.length()-2);
sb.append(']');
return sb.toString();
}
static Type deferTypFromCanonicalName(String name) {
return Type.getType(name);
}
static Type deferReturnType(String signature) {
return Type.getReturnType(signature);
}
void savePreviousFrame() {
previousFrame = new StackInfo(currentFrame);
}
void arrayLoad(Type arrayType) {
currentFrame.popStackChecked(Type.INT_TYPE);
currentFrame.replaceStack(arrayType);
}
void arrayStore(Type arrayType) {
currentFrame.popStackChecked(arrayType);
currentFrame.popStackChecked(Type.INT_TYPE);
currentFrame.popStack();
}
@Override
public StackInfo getPreviousStackInfo() {
return new StackInfo(previousFrame);
}
@Override
public StackInfo getCurrentStackInfo() {
return new StackInfo(currentFrame);
}
private int[] getLineNumber(Label l) {
int[] lineNo = lineNumbers.get(l);
if (lineNo == null) {
lineNumbers.put(l, lineNo = new int[]{-1});
}
return lineNo;
}
@Override
public String[] getLocalNames(int lineNo, int count) {
String[] names = new String[count];
outerLoop: for (int index = 0; index < count; ++index) {
names[index] = "var"+index;
for (LocalVariable var : localVariables) {
if (var.index == index && var.fromLine[0] <= lineNo && var.toLine[0] >= lineNo) {
names[index] = var.name;
continue outerLoop;
}
}
}
return names;
}
@Override
public Type[] getLocalDescriptors(int lineNo, int count) {
Type[] types = new Type[count];
outerLoop: for (int index = 0; index < count; ++index) {
for (LocalVariable var : localVariables) {
if (var.index == index && var.fromLine[0] <= lineNo && var.toLine[0] >= lineNo) {
types[index] = Type.getType(var.declaredDescriptor);
continue outerLoop;
}
}
}
return types;
}
public class LocalVariable {
public LocalVariable(String name, String declaredDescriptor, Label from, Label to, int index) {
this.name = name;
this.fromLine = getLineNumber(from);
this.toLine = getLineNumber(to);
if (this.toLine[0] == -1)
this.toLine[0] = Integer.MAX_VALUE;
this.index = index;
this.declaredDescriptor = declaredDescriptor;
}
String name;
int[] fromLine;
int[] toLine;
int index;
String declaredDescriptor;
}
}