Mercurial > hg > icedrobot > daneel
view src/main/java/org/icedrobot/daneel/rewriter/PatchMethodVisitor.java @ 109:cf71c6ab82fc
Add a flag daneel.verify to enable post verification of DEX to bytecode translation
author | forax |
---|---|
date | Fri, 01 Apr 2011 11:15:49 +0200 |
parents | 2711ac37fdfb |
children | b375045a6197 |
line wrap: on
line source
/* * Daneel - Dalvik to Java bytecode compiler * Copyright (C) 2011 IcedRobot team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * This file is subject to the "Classpath" exception: * * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. * * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under terms * of your choice, provided that you also meet, for each linked independent * module, the terms and conditions of the license of that module. An * independent module is a module which is not derived from or based on * this library. If you modify this library, you may extend this exception * to your version of the library, but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. */ package org.icedrobot.daneel.rewriter; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.Label; //import org.objectweb.asm.MethodHandle; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.MethodNode; /** * A method visitor which is able to patch some of its instruction. To avoid the * overhead of always storing all instructions in memory, to patch at least one * instruction, the {@link #setPatchMode() patch mode} must be activated. * * By default, this method visitor delegates to the underlying method visitor * but if the {@link #setPatchMode() patch mode} is activated, all new * instructions are stored and dumped when {@link #visitMaxs(int, int)} is * called. * * So if the patch mode is activated, one can get the last instruction * {@link #getLastInsnNode()}, remember it, and replace it later using * {@link #patch(AbstractInsnNode, AbstractInsnNode)} with another instruction. * * The methods {@link #getLastInsnNode()} and * {@link #patch(AbstractInsnNode, AbstractInsnNode)} can only be called is the * patch mode is activated. After a call to {@link #visitMaxs(int, int)}, the * patch mode is deactivated. */ public class PatchMethodVisitor implements MethodVisitor { private final MethodVisitor mv; private MethodNode methodNode; public PatchMethodVisitor(MethodVisitor mv) { this.mv = mv; } @Override public AnnotationVisitor visitAnnotationDefault() { return mv.visitAnnotationDefault(); } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return mv.visitAnnotation(desc, visible); } @Override public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { return mv.visitParameterAnnotation(parameter, desc, visible); } @Override public void visitAttribute(Attribute attr) { mv.visitAttribute(attr); } @Override public void visitCode() { mv.visitCode(); } private MethodVisitor mv() { return (methodNode == null) ? mv : methodNode; } /** * Switch to patch mode. If the patch mode is already activated, this method * does nothing. */ public void setPatchMode() { if (methodNode == null) { methodNode = new MethodNode(); } } public AbstractInsnNode getLastInsnNode() { if (methodNode == null) { throw new IllegalStateException("patchMode is not activated"); } return methodNode.instructions.getLast(); } public void addNode(AbstractInsnNode node) { if (methodNode == null) { throw new IllegalStateException("patchMode is not activated"); } methodNode.instructions.add(node); } public void patch(AbstractInsnNode node, AbstractInsnNode newNode) { if (methodNode == null) { throw new IllegalStateException("patchMode is not activated"); } methodNode.instructions.set(node, newNode); } @Override public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { mv().visitFrame(type, nLocal, local, nStack, stack); } @Override public void visitInsn(int opcode) { mv().visitInsn(opcode); } @Override public void visitIntInsn(int opcode, int operand) { mv().visitIntInsn(opcode, operand); } @Override public void visitVarInsn(int opcode, int var) { mv().visitVarInsn(opcode, var); } @Override public void visitTypeInsn(int opcode, String type) { mv().visitTypeInsn(opcode, type); } @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { mv().visitFieldInsn(opcode, owner, name, desc); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { mv().visitMethodInsn(opcode, owner, name, desc); } // @Override // public void visitInvokeDynamicInsn( // String name, // String desc, // MethodHandle bsm, // Object... bsmArgs) { // mv().visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); // } @Override public void visitJumpInsn(int opcode, Label label) { mv().visitJumpInsn(opcode, label); } @Override public void visitLabel(Label label) { mv().visitLabel(label); } @Override public void visitLdcInsn(Object cst) { mv().visitLdcInsn(cst); } @Override public void visitIincInsn(int var, int increment) { mv().visitIincInsn(var, increment); } @Override public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { mv().visitTableSwitchInsn(min, max, dflt, labels); } @Override public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { mv().visitLookupSwitchInsn(dflt, keys, labels); } @Override public void visitMultiANewArrayInsn(String desc, int dims) { mv().visitMultiANewArrayInsn(desc, dims); } @Override public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { mv().visitTryCatchBlock(start, end, handler, type); } @Override public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) { mv.visitLocalVariable(name, desc, signature, start, end, index); } @Override public void visitLineNumber(int line, Label start) { mv().visitLineNumber(line, start); } @Override public void visitMaxs(int maxStack, int maxLocals) { if (methodNode != null) { final MethodVisitor mv = this.mv; for (AbstractInsnNode insn = methodNode.instructions.getFirst(); insn != null; insn = insn .getNext()) { insn.accept(mv); } methodNode = null; } mv.visitMaxs(maxStack, maxLocals); } @Override public void visitEnd() { mv.visitEnd(); } }