package openeye.asm.injectors;
import com.google.common.base.Throwables;
import com.google.common.collect.Maps;
import java.util.Map;
import openeye.Log;
import openeye.asm.CallHack;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
public class ExceptionHandlerInjector extends MethodVisitor {
private final Method callTarget;
private final Type callHackType;
private final String[] excNames;
private final Map<Label, String> excLabels = Maps.newIdentityHashMap();
private final String excType;
int currentLabel;
private boolean skipHandlers;
public ExceptionHandlerInjector(MethodVisitor mv, String excType, String... excNames) {
super(Opcodes.ASM5, mv);
this.excNames = excNames;
this.excType = excType;
try {
callHackType = Type.getType(CallHack.class);
callTarget = Method.getMethod(CallHack.class.getMethod("callForSilentException", Throwable.class, String.class));
} catch (Throwable t) {
throw Throwables.propagate(t);
}
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
super.visitTryCatchBlock(start, end, handler, type);
if (!skipHandlers && excType.equals(type)) {
try {
String name = excNames[currentLabel++];
excLabels.put(handler, name);
} catch (ArrayIndexOutOfBoundsException e) {
Log.warn("Invalid method structure, more than two exception handlers. Aborting");
skipHandlers = true;
}
}
}
@Override
public void visitLabel(Label label) {
super.visitLabel(label);
if (!skipHandlers) {
String name = excLabels.get(label);
if (name != null) addHandler(name);
}
}
private void addHandler(String location) {
Log.debug("Adding handler for '%s'", location);
super.visitInsn(Opcodes.DUP);
super.visitLdcInsn(location);
super.visitMethodInsn(Opcodes.INVOKESTATIC, callHackType.getInternalName(), callTarget.getName(), callTarget.getDescriptor(), false);
}
}