//Copyright 2006-2007 Acelet Corporation. All rights reserved.
package limpidlog.asm1;
import java.io.*;
import java.net.*;
import java.util.*;
import limpidlog.org.objectweb.asm.Label;
import limpidlog.org.objectweb.asm.MethodAdapter;
import limpidlog.org.objectweb.asm.MethodVisitor;
import limpidlog.org.objectweb.asm.Opcodes;
import limpidlog.org.objectweb.asm.Type;
import limpidlog.lib.Events;
import limpidlog.lib.Options;
/**
* @author Wei Jiang
*/
public class MyMethodAdapter extends MethodAdapter implements Events, Opcodes {
int access;
String methodName;
String descriptor;
String classNameWithSlash;
String sourceFileName;
Vector memberFieldVector;
Hashtable lineVariableHashtable;
Vector labelVector;
String classNameWithDot;
Type[] argumentTypes;
boolean isStatic;
boolean isInnerClass;
String methodFullName;
Type typeOfObject = Type.getType(Object.class);
boolean containsDebugInfo = false;
int localVarIndexMax;
String defaultWhere;
String functionDescForObject = "(Ljava/lang/Object;)Llimpidlog/log/Log;";
String functionDescForString = "(Ljava/lang/String;)Llimpidlog/log/Log;";
int numberOfMemberFields;
int currentLine = 0;
int lineNumberVisit = 0;
int labelIndex = 1;
Vector localVariableVector;
protected MyMethodAdapter(MethodVisitor mv, int access, String methodName, String descriptor,
String classNameWithSlash, String sourceFileName,
Vector memberFieldVector, Vector labelVector, Hashtable lineVariableHashtable) {
super(mv);
this.access = access;
this.methodName = methodName;
this.descriptor = descriptor;
this.classNameWithSlash = classNameWithSlash;
this.sourceFileName = sourceFileName;
this.memberFieldVector = memberFieldVector;
this.labelVector = labelVector;
this.lineVariableHashtable = lineVariableHashtable;
if (Options.debug)
System.out.println("MyMethodAdapter.<init>: " +
" access="+access+
" methodName="+methodName+
" descriptor="+descriptor+
" classNameWithSlash="+classNameWithSlash+
" sourceFileName="+sourceFileName+
" memberFieldVector="+memberFieldVector+
" labelVector="+labelVector+
" lineVariableHashtable="+lineVariableHashtable);
classNameWithDot = classNameWithSlash.replace('/', '.');
methodFullName = classNameWithDot + "." + methodName;
argumentTypes = Type.getArgumentTypes(descriptor);
defaultWhere = methodFullName + "(" + sourceFileName + ")";
numberOfMemberFields = memberFieldVector.size();
isStatic = ((access & Opcodes.ACC_STATIC) > 0);
String baseName = classNameWithSlash.substring(classNameWithSlash.lastIndexOf("/") + 1);
String theName = sourceFileName.substring(0, sourceFileName.indexOf("."));
if (theName.equals(baseName) == false)
isInnerClass = true;
if (Options.debug)
System.out.println("MyMethodAdapter.<init>: " +
" classNameWithDot="+classNameWithDot+
" methodFullName="+methodFullName+
" argumentTypes="+argumentTypes+
" defaultWhere="+defaultWhere+
" numberOfMemberFields="+numberOfMemberFields+
" isStatic="+isStatic+
" baseName="+baseName+
" theName="+theName+
" isInnerClass="+isInnerClass);
}
protected void addArgument() {
if (Options.logOnArgument == false)
return;
int argIndex = 0;
if (isStatic == false) {
argIndex++;
}
for (int index = 0; index < argumentTypes.length; index++) {
String variableName = getLocalVariableName(argIndex);
if (variableName == null)
continue;
Type type = argumentTypes[index];
int opcode = type.getOpcode(Opcodes.ILOAD);
String functionDesc = makeFunctionType(type);
super.visitLdcInsn(variableName);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addName", functionDescForString);
super.visitVarInsn(opcode, argIndex);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addValue", functionDesc);
argIndex += type.getSize();
}
}
protected String getLocalVariableName(int index) {
if (Options.useLocalVariableName == false) {
return "#" + index;
}
if (localVariableVector != null) {
for (int i = 0; i < localVariableVector.size(); i++) {
LocalVariable localVariable = (LocalVariable) localVariableVector.get(i);
if (index == localVariable.index)
return localVariable.name;
}
}
return null;
}
protected Type getTypeFromOpcode(int opcode) {
switch (opcode) {
case Opcodes.ISTORE:
return Type.INT_TYPE;
case Opcodes.LSTORE:
return Type.LONG_TYPE;
case Opcodes.FSTORE:
return Type.FLOAT_TYPE;
case Opcodes.DSTORE:
return Type.DOUBLE_TYPE;
case Opcodes.ASTORE:
default:
return typeOfObject;
}
}
protected String makeFunctionType(String type) {
if (type.equals("Z") ||
type.equals("B") ||
type.equals("C") ||
type.equals("D") ||
type.equals("F") ||
type.equals("I") ||
type.equals("J") ||
type.equals("S") ||
type.equals("[Z") ||
type.equals("[B") ||
type.equals("[C") ||
type.equals("[D") ||
type.equals("[F") ||
type.equals("[I") ||
type.equals("[J") ||
type.equals("[S"))
;
else
type = "Ljava/lang/Object;";
return "(" + type +")Llimpidlog/log/Log;";
}
protected String makeFunctionType(Type type) {
String desc = type.getDescriptor();
return makeFunctionType(desc);
}
protected String makeWhere(int lineNumber) {
return methodFullName + "(" + sourceFileName + ":" + lineNumber + ")";
}
protected void onField(int opcode, String owner, String name, String desc) {
if (currentLine == 0) //generated code, like class$(Person.java:0)
return;
if (name.equals("this") || name.startsWith("this$") || isInnerClass)
return;
String functionDesc = makeFunctionType(desc);
super.visitTypeInsn(NEW, "limpidlog/log/Log");
super.visitInsn(DUP);
super.visitLdcInsn(makeWhere(currentLine));
super.visitLdcInsn(EVENT_FIELD);
super.visitMethodInsn(INVOKESPECIAL, "limpidlog/log/Log", "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V");
super.visitLdcInsn(name);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addName", functionDescForString);
int readOpcode = GETSTATIC;
if (opcode == PUTFIELD) {
super.visitVarInsn(ALOAD, 0);
readOpcode = GETFIELD;
}
super.visitFieldInsn(readOpcode, owner, name, desc);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addValue", functionDesc);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
}
protected void onIncrease(int var, int increament) {
if (currentLine == 0) //generated code, like class$(Person.java:0)
return;
String variableName = "#" + var;
String functionDesc = "(I)Llimpidlog/log/Log;";
super.visitTypeInsn(NEW, "limpidlog/log/Log");
super.visitInsn(DUP);
super.visitLdcInsn(makeWhere(currentLine));
super.visitLdcInsn(EVENT_INCREASE);
super.visitMethodInsn(INVOKESPECIAL, "limpidlog/log/Log", "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V");
super.visitLdcInsn(variableName);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addName", functionDescForString);
super.visitVarInsn(ILOAD, var);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addValue", functionDesc);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
}
protected void onLabel(Label label) {
if (labelIndex < labelVector.size()) {
Label aLabel = (Label) labelVector.get(labelIndex++);
localVariableVector = (Vector) lineVariableHashtable.get(aLabel);
}
}
protected void onLineNumber(int line, Label start) {
containsDebugInfo = true;
currentLine = line;
super.visitTypeInsn(NEW, "limpidlog/log/Log");
super.visitInsn(DUP);
super.visitLdcInsn(makeWhere(line));
super.visitLdcInsn(EVENT_LINE);
super.visitMethodInsn(INVOKESPECIAL, "limpidlog/log/Log", "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V");
lineNumberVisit++;
if ((methodName.equals("<clinit>") || methodName.equals("<init>"))) {
if (lineNumberVisit == 2)
addArgument();
} else if (lineNumberVisit == 1) {
addArgument();
}
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
}
protected void onReturn(Type type) {
if (currentLine == 0) //generated code, like class$(Person.java:0)
return;
if (localVariableVector != null)
localVarIndexMax = localVariableVector.size();
else
localVarIndexMax = 1;
String functionDesc = null;
if (type != null) {
super.visitVarInsn(type.getOpcode(ISTORE), localVarIndexMax);
functionDesc = makeFunctionType(type);
}
super.visitTypeInsn(NEW, "limpidlog/log/Log");
super.visitInsn(DUP);
super.visitLdcInsn(makeWhere(currentLine));
super.visitLdcInsn(EVENT_RETURN);
super.visitMethodInsn(INVOKESPECIAL, "limpidlog/log/Log", "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V");
if (type != null) {
super.visitLdcInsn(EVENT_RETURN);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addName", functionDescForString);
super.visitVarInsn(type.getOpcode(ILOAD), localVarIndexMax);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addValue", functionDesc);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
super.visitVarInsn(type.getOpcode(ILOAD), localVarIndexMax);
} else
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
}
protected void onStore(int opcode, int var) {
if (currentLine == 0) //generated code, like class$(Person.java:0)
return;
String variableName = getLocalVariableName(var);
if (variableName == null)
return;
Type type = getTypeFromOpcode(opcode);
String functionDesc = makeFunctionType(type);
super.visitTypeInsn(NEW, "limpidlog/log/Log");
super.visitInsn(DUP);
super.visitLdcInsn(makeWhere(currentLine));
super.visitLdcInsn(EVENT_STORE);
super.visitMethodInsn(INVOKESPECIAL, "limpidlog/log/Log", "<init>",
"(Ljava/lang/String;Ljava/lang/String;)V");
super.visitLdcInsn(variableName);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addName", functionDescForString);
super.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "addValue", functionDesc);
super.visitMethodInsn(INVOKEVIRTUAL, "limpidlog/log/Log", "log", "()V");
}
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
super.visitFieldInsn(opcode, owner, name, desc);
if (Options.logOnField) {
if ((opcode == PUTSTATIC) || (opcode == PUTFIELD)) {
if (owner.equals(classNameWithSlash))
onField(opcode, owner, name, desc);
}
}
}
public void visitIincInsn(int var, int increment) {
super.visitIincInsn(var, increment);
if (Options.logOnIncrease)
onIncrease(var, increment);
}
public void visitInsn(int opcode) {
if (Options.logOnReturn) {
switch (opcode) {
case RETURN:
onReturn(null);
break;
case ARETURN:
onReturn(typeOfObject);
break;
case DRETURN:
onReturn(Type.DOUBLE_TYPE);
break;
case FRETURN:
onReturn(Type.FLOAT_TYPE);
break;
case IRETURN:
onReturn(Type.INT_TYPE);
break;
case LRETURN:
onReturn(Type.LONG_TYPE);
break;
}
}
super.visitInsn(opcode);
}
public void visitLabel(Label label) {
super.visitLabel(label);
onLabel(label);
}
public void visitLineNumber(int line, Label start) {
super.visitLineNumber(line, start);
onLineNumber(line, start);
}
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack + 4, maxLocals + 2);
}
public void visitVarInsn(int opcode, int var) {
super.visitVarInsn(opcode, var);
if (Options.logOnStore) {
if (opcode == ISTORE || opcode == LSTORE || opcode == FSTORE || opcode == DSTORE ||
opcode == ASTORE) {
onStore(opcode, var);
}
}
}
}