use of jodd.asm.EmptyClassVisitor in project jodd by oblac.
the class ProxettaMethodBuilder method createProxyMethod.
/**
* Creates proxy methods over target method, For each matched proxy, new proxy method is created
* by taking advice bytecode and replaces usages of {@link jodd.proxetta.ProxyTarget}.
* <p>
* Invocation chain example: {@code name -> name$p0 -> name$p1 -> name$p4 -> super}.
*/
public void createProxyMethod(final TargetMethodData td) {
final ProxyAspectData aspectData = td.getProxyData();
int access = td.msign.getAccessFlags();
access &= ~ACC_NATIVE;
access &= ~ACC_ABSTRACT;
access = ProxettaAsmUtil.makePrivateFinalAccess(access);
final MethodVisitor mv = wd.dest.visitMethod(access, td.methodName(), td.msign.getDescription(), null, null);
mv.visitCode();
//*** VISIT ADVICE - called for each aspect and each method
aspectData.getAdviceClassReader().accept(new EmptyClassVisitor() {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (!name.equals(executeMethodName)) {
return null;
}
return new HistoryMethodAdapter(mv) {
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (owner.equals(aspectData.adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectData.aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitVarInsn(int opcode, int var) {
var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
if (proxyInfoRequested) {
proxyInfoRequested = false;
if (opcode == ASTORE) {
ProxyTargetReplacement.info(mv, td.msign, var);
}
}
// [F1]
super.visitVarInsn(opcode, var);
}
@Override
public void visitIincInsn(int var, int increment) {
var += (var == 0 ? 0 : td.msign.getAllArgumentsSize());
// [F1]
super.visitIincInsn(var, increment);
}
@Override
public void visitInsn(int opcode) {
if (opcode == ARETURN) {
visitReturn(mv, td.msign, true);
return;
}
if (traceNext) {
if ((opcode == POP) || (opcode == POP2)) {
// [F3] - invoke invoked without assignment
return;
}
}
super.visitInsn(opcode);
}
@SuppressWarnings({ "ParameterNameDiffersFromOverriddenParameter" })
@Override
public void visitMethodInsn(int opcode, String string, String mname, String mdesc, boolean isInterface) {
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE) || (opcode == INVOKESPECIAL)) {
if (string.equals(aspectData.adviceReference)) {
string = wd.thisReference;
mname = adviceMethodName(mname, aspectData.aspectIndex);
}
} else if (opcode == INVOKESTATIC) {
if (string.equals(aspectData.adviceReference)) {
string = wd.thisReference;
mname = adviceMethodName(mname, aspectData.aspectIndex);
} else if (string.endsWith('/' + TARGET_CLASS_NAME)) {
if (isInvokeMethod(mname, mdesc)) {
// [R7]
if (td.isLastMethodInChain()) {
if (!wd.isWrapper()) {
// PROXY
loadSpecialMethodArguments(mv, td.msign);
mv.visitMethodInsn(INVOKESPECIAL, wd.superReference, td.msign.getMethodName(), td.msign.getDescription(), isInterface);
} else {
// WRAPPER
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, wd.thisReference, wd.wrapperRef, wd.wrapperType);
loadVirtualMethodArguments(mv, td.msign);
if (wd.wrapInterface) {
mv.visitMethodInsn(INVOKEINTERFACE, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), true);
} else {
mv.visitMethodInsn(INVOKEVIRTUAL, wd.wrapperType.substring(1, wd.wrapperType.length() - 1), td.msign.getMethodName(), td.msign.getDescription(), isInterface);
}
}
// [F4]
prepareReturnValue(mv, td.msign, aspectData.maxLocalVarOffset);
traceNext = true;
} else {
// calls next proxy method
loadSpecialMethodArguments(mv, td.msign);
mv.visitMethodInsn(INVOKESPECIAL, wd.thisReference, td.nextMethodName(), td.msign.getDescription(), isInterface);
visitReturn(mv, td.msign, false);
}
return;
}
if (isArgumentsCountMethod(mname, mdesc)) {
// [R2]
ProxyTargetReplacement.argumentsCount(mv, td.msign);
return;
}
if (isArgumentTypeMethod(mname, mdesc)) {
// [R3]
int argIndex = this.getArgumentIndex();
ProxyTargetReplacement.argumentType(mv, td.msign, argIndex);
return;
}
if (isArgumentMethod(mname, mdesc)) {
// [R4]
int argIndex = this.getArgumentIndex();
ProxyTargetReplacement.argument(mv, td.msign, argIndex);
return;
}
if (isSetArgumentMethod(mname, mdesc)) {
// [R5]
int argIndex = this.getArgumentIndex();
checkArgumentIndex(td.msign, argIndex);
mv.visitInsn(POP);
storeMethodArgumentFromObject(mv, td.msign, argIndex);
return;
}
if (isCreateArgumentsArrayMethod(mname, mdesc)) {
// [R6]
ProxyTargetReplacement.createArgumentsArray(mv, td.msign);
return;
}
if (isCreateArgumentsClassArrayMethod(mname, mdesc)) {
// [R11]
ProxyTargetReplacement.createArgumentsClassArray(mv, td.msign);
return;
}
if (isTargetMethod(mname, mdesc)) {
// [R9.1]
mv.visitVarInsn(ALOAD, 0);
return;
}
if (isTargetClassMethod(mname, mdesc)) {
// [R9]
ProxyTargetReplacement.targetClass(mv, td.msign);
//ProxyTargetReplacement.targetClass(mv, wd.superReference);
return;
}
if (isTargetMethodNameMethod(mname, mdesc)) {
// [R10]
ProxyTargetReplacement.targetMethodName(mv, td.msign);
return;
}
if (isTargetMethodSignatureMethod(mname, mdesc)) {
ProxyTargetReplacement.targetMethodSignature(mv, td.msign);
return;
}
if (isTargetMethodDescriptionMethod(mname, mdesc)) {
ProxyTargetReplacement.targetMethodDescription(mv, td.msign);
return;
}
if (isInfoMethod(mname, mdesc)) {
// we are NOT replacing info() here! First, we need to figure out
// what is the operand for the very next ASTORE instructions
// since we need to create an object and store it in this
// register - and reuse it, in replacement code.
//ProxyTargetReplacement.info(mv, td.msign);
proxyInfoRequested = true;
return;
}
if (isReturnTypeMethod(mname, mdesc)) {
// [R11]
ProxyTargetReplacement.returnType(mv, td.msign);
return;
}
if (isReturnValueMethod(mname, mdesc)) {
castToReturnType(mv, td.msign);
return;
}
if (isTargetMethodAnnotationMethod(mname, mdesc)) {
String[] args = getLastTwoStringArguments();
// pop current two args
mv.visitInsn(POP);
mv.visitInsn(POP);
ProxyTargetReplacement.targetMethodAnnotation(mv, td.msign, args);
return;
}
if (isTargetClassAnnotationMethod(mname, mdesc)) {
String[] args = getLastTwoStringArguments();
// pop current two args
mv.visitInsn(POP);
mv.visitInsn(POP);
ProxyTargetReplacement.targetClassAnnotation(mv, td.msign.getClassInfo(), args);
return;
}
}
}
super.visitMethodInsn(opcode, string, mname, mdesc, isInterface);
}
};
}
}, 0);
}
use of jodd.asm.EmptyClassVisitor in project jodd by oblac.
the class ProxyAspectData method readAdviceData.
// ---------------------------------------------------------------- read
/**
* Parse advice class to gather some advice data. Should be called before any advice use.
* Must be called only *once* per advice.
*/
private void readAdviceData() {
if (ready) {
return;
}
adviceClassReader.accept(new EmptyClassVisitor() {
/**
* Stores advice reference.
*/
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
adviceReference = name;
super.visit(version, access, name, signature, superName, interfaces);
}
/**
* Prevents advice to have inner classes.
*/
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (outerName.equals(adviceReference)) {
throw new ProxettaException("Proxetta doesn't allow inner classes in/for advice: " + advice.getName());
}
super.visitInnerClass(name, outerName, innerName, access);
}
/**
* Clones advices fields to destination.
*/
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
// [A5]
wd.dest.visitField(access, adviceFieldName(name, aspectIndex), desc, signature, value);
return super.visitField(access, name, desc, signature, value);
}
/**
* Copies advices methods to destination.
*/
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals(CLINIT)) {
// [A6]
if (!desc.equals(DESC_VOID)) {
throw new ProxettaException("Invalid static initialization block description for advice: " + advice.getName());
}
name = clinitMethodName + methodDivider + aspectIndex;
access |= AsmUtil.ACC_PRIVATE | AsmUtil.ACC_FINAL;
wd.addAdviceClinitMethod(name);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if (opcode == INVOKESTATIC) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// [F6]
if (owner.equals(adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
} else if (name.equals(INIT)) {
// [A7]
if (!desc.equals(DESC_VOID)) {
throw new ProxettaException("Advices can have only default constructors. Invalid advice: " + advice.getName());
}
name = initMethodName + methodDivider + aspectIndex;
access = ProxettaAsmUtil.makePrivateFinalAccess(access);
wd.addAdviceInitMethod(name);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
// used to detect and to ignore the first super call()
int state;
@Override
public void visitVarInsn(int opcode, int var) {
// [F7]
if ((state == 0) && (opcode == ALOAD) && (var == 0)) {
state++;
return;
}
super.visitVarInsn(opcode, var);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if ((state == 1) && (opcode == INVOKESPECIAL)) {
state++;
return;
}
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
} else if (opcode == INVOKESTATIC) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// [F7]
if (owner.equals(adviceReference)) {
// [F5]
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
} else // other methods
if (!name.equals(executeMethodName)) {
name = adviceMethodName(name, aspectIndex);
return new MethodAdapter(wd.dest.visitMethod(access, name, desc, signature, exceptions)) {
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean isInterface) {
if ((opcode == INVOKEVIRTUAL) || (opcode == INVOKEINTERFACE)) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
} else if (opcode == INVOKESTATIC || opcode == INVOKESPECIAL) {
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceMethodName(name, aspectIndex);
}
}
super.visitMethodInsn(opcode, owner, name, desc, isInterface);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
// replace field references
if (owner.equals(adviceReference)) {
owner = wd.thisReference;
name = adviceFieldName(name, aspectIndex);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
};
}
//return new MethodAdapter(new EmptyMethodVisitor()) { // toask may we replace this with the following code?
return new EmptyMethodVisitor() {
@Override
public void visitVarInsn(int opcode, int var) {
if (isStoreOpcode(opcode)) {
if (var > maxLocalVarOffset) {
// find max local var offset
maxLocalVarOffset = var;
}
}
super.visitVarInsn(opcode, var);
}
};
// return super.visitMethod(access, name, desc, signature, exceptions);
}
}, 0);
// increment offset by 2 because var on last index may be a dword value
maxLocalVarOffset += 2;
ready = true;
}
Aggregations