/* Software Name : AsmDex
* Version : 1.0
*
* Copyright © 2012 France Télécom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.ow2.asmdex.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.ow2.asmdex.AnnotationVisitor;
import org.ow2.asmdex.MethodVisitor;
import org.ow2.asmdex.structureCommon.Label;
/**
* A {@link MethodVisitor} that prints the AsmDex code that generates the Methods it
* visits.
*
* @author Julien Névo, based on the ASM Framework.
*/
public class AsmDexifierMethodVisitor extends MethodVisitor {
private final AsmDexPrinter pr;
/**
* Map linking a Label to its name.
*/
private HashMap<Label, String> labelNames = new HashMap<Label, String>();
/**
* Constructs a new {@link AsmDexifierMethodVisitor} object.
*
* @param api api level
* @param nbTabulations number of spaces
*/
public AsmDexifierMethodVisitor(int api, final int nbTabulations) {
super(api);
pr = new AsmDexPrinter();
pr.currentTabulation = nbTabulations;
}
// ------------------------------------------------
// Visitor Methods.
// ------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
pr.addTabulation();
pr.addText("{\n");
pr.addTabulation();
pr.addText("\tav0 = mv.visitAnnotation(");
pr.addConstant(desc, true);
pr.addBoolean(visible, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
AsmDexifierAnnotationVisitor av = new AsmDexifierAnnotationVisitor(api, 0, pr.currentTabulation + 1);
pr.addTextToList(av.getTextComponent());
pr.addTabulation();
pr.addText("}\n");
pr.closeText();
return av;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
pr.addTabulation();
pr.addText("{\n");
pr.addTabulation();
pr.addText("\tav0 = mv.visitAnnotationDefault();");
pr.addEOL();
pr.closeText();
AsmDexifierAnnotationVisitor av = new AsmDexifierAnnotationVisitor(api, 0, pr.currentTabulation + 1);
pr.addTextToList(av.getTextComponent());
pr.addTabulation();
pr.addText("}\n");
pr.closeText();
return av;
}
@Override
public void visitArrayLengthInsn(int destinationRegister, int arrayReferenceBearing) {
pr.addTabulation();
pr.addText("mv.visitArrayLengthInsn(");
pr.addNumber(destinationRegister, true);
pr.addNumber(arrayReferenceBearing, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitArrayOperationInsn(int opcode, int valueRegister,
int arrayRegister, int indexRegister) {
pr.addTabulation();
pr.addText("mv.visitArrayOperationInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(valueRegister, true);
pr.addNumber(arrayRegister, true);
pr.addNumber(indexRegister, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitAttribute(Object attr) {
// Ignored by AsmDex.
}
@Override
public void visitCode() {
pr.addTabulation();
pr.addText("mv.visitCode();\n");
pr.closeText();
}
@Override
public void visitEnd() {
pr.addTabulation();
pr.addText("mv.visitEnd();\n");
pr.closeText();
}
@Override
public void visitFieldInsn(int opcode, String owner, String name,
String desc, int valueRegister, int objectRegister) {
pr.addTabulation();
pr.addText("mv.visitFieldInsn(");
pr.addOpcode(opcode, true);
pr.addConstant(owner, true);
pr.addConstant(name, true);
pr.addConstant(desc, true);
pr.addNumber(valueRegister, true);
pr.addNumber(objectRegister, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitFillArrayDataInsn(int arrayReference, Object[] arrayData) {
pr.addTabulation();
pr.addText("mv.visitFillArrayDataInsn(");
pr.addNumber(arrayReference, true);
pr.addConstant(arrayData, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
// Ignored by AsmDex.
}
@Override
public void visitInsn(int opcode) {
pr.addTabulation();
pr.addText("mv.visitInsn(");
pr.addOpcode(opcode, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitIntInsn(int opcode, int register) {
pr.addTabulation();
pr.addText("mv.visitIntInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(register, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitJumpInsn(int opcode, Label label, int registerA,
int registerB) {
String name = declareLabel(label);
pr.addTabulation();
pr.addText("mv.visitJumpInsn(");
pr.addOpcode(opcode, true);
pr.addText(name, true);
pr.addNumber(registerA, true);
pr.addNumber(registerB, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitLabel(Label label) {
String name = declareLabel(label);
pr.addTabulation();
pr.addText("mv.visitLabel(" + name + ");\n");
pr.closeText();
}
@Override
public void visitLineNumber(int line, Label start) {
String name = declareLabel(start);
pr.addTabulation();
pr.addText("mv.visitLineNumber(");
pr.addNumber(line, true);
pr.addText(name + ");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
String nameStart = declareLabel(start);
String nameEnd = declareLabel(end);
pr.addTabulation();
pr.addText("mv.visitLocalVariable(");
pr.addConstant(name, true);
pr.addConstant(desc, true);
pr.addConstant(signature, true);
pr.addText(nameStart, true);
pr.addText(nameEnd, true);
pr.addNumber(index, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, List<Label> ends, List<Label> restarts, int index) {
String nameStart = declareLabel(start);
List<String> nameEnds = declareLabelsToList(ends);
List<String> nameRestarts = declareLabelsToList(restarts);
pr.addTabulation();
pr.addText("mv.visitLocalVariable(");
pr.addConstant(name, true);
pr.addConstant(desc, true);
pr.addConstant(signature, true);
pr.addText(nameStart, true);
pr.addStringArrayList(nameEnds, true);
pr.addStringArrayList(nameRestarts, true);
pr.addNumber(index, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitLookupSwitchInsn(int register, Label dflt, int[] keys,
Label[] labels) {
String nameDefault = declareLabel(dflt);
String[] nameLabels = declareLabels(labels);
pr.addTabulation();
pr.addText("mv.visitLookupSwitchInsn(");
pr.addNumber(register, true);
pr.addText(nameDefault, true);
pr.addConstant(keys, true);
pr.addLabelArray(nameLabels, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
pr.addTabulation();
pr.addText("mv.visitMaxs(");
pr.addNumber(maxStack, true);
pr.addNumber(maxLocals, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc, int[] arguments) {
pr.addTabulation();
pr.addText("mv.visitMethodInsn(");
pr.addOpcode(opcode, true);
pr.addConstant(owner, true);
pr.addConstant(name, true);
pr.addConstant(desc, true);
pr.addConstant(arguments, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitMultiANewArrayInsn(String desc, int[] registers) {
pr.addTabulation();
pr.addText("mv.visitMultiANewArrayInsn(");
pr.addConstant(desc, true);
pr.addConstant(registers, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitOperationInsn(int opcode, int destinationRegister,
int firstSourceRegister, int secondSourceRegister, int value) {
pr.addTabulation();
pr.addText("mv.visitOperationInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(destinationRegister, true);
pr.addNumber(firstSourceRegister, true);
pr.addNumber(secondSourceRegister, true);
pr.addNumber(value, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
pr.addTabulation();
pr.addText("{\n");
pr.addTabulation();
pr.addText("\tav0 = mv.visitParameterAnnotation(");
pr.addNumber(parameter, true);
pr.addConstant(desc, true);
pr.addBoolean(visible, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
AsmDexifierAnnotationVisitor av = new AsmDexifierAnnotationVisitor(api, 0, pr.currentTabulation + 1);
pr.addTextToList(av.getTextComponent());
pr.addTabulation();
pr.addText("}\n");
pr.closeText();
return av;
}
@Override
public void visitParameters(String[] parameters) {
pr.addTabulation();
pr.addText("mv.visitParameters(");
pr.addConstant(parameters, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitStringInsn(int opcode, int destinationRegister, String string) {
pr.addTabulation();
pr.addText("mv.visitStringInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(destinationRegister, true);
pr.addConstant(string, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitTableSwitchInsn(int register, int min, int max,
Label dflt, Label[] labels) {
String nameDefault = declareLabel(dflt);
String[] nameLabels = declareLabels(labels);
pr.addTabulation();
pr.addText("mv.visitTableSwitchInsn(");
pr.addNumber(register, true);
pr.addNumber(min, true);
pr.addNumber(max, true);
pr.addText(nameDefault, true);
pr.addLabelArray(nameLabels, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
String nameStart = declareLabel(start);
String nameEnd = declareLabel(end);
String nameHandler = declareLabel(handler);
pr.addTabulation();
pr.addText("mv.visitTryCatchBlock(");
pr.addText(nameStart, true);
pr.addText(nameEnd, true);
pr.addText(nameHandler, true);
pr.addConstant(type, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitTypeInsn(int opcode, int destinationRegister,
int referenceBearingRegister, int sizeRegister, String type) {
pr.addTabulation();
pr.addText("mv.visitTypeInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(destinationRegister, true);
pr.addNumber(referenceBearingRegister, true);
pr.addNumber(sizeRegister, true);
pr.addConstant(type, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitVarInsn(int opcode, int destinationRegister, int var) {
pr.addTabulation();
pr.addText("mv.visitVarInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(destinationRegister, true);
pr.addNumber(var, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
@Override
public void visitVarInsn(int opcode, int destinationRegister, long var) {
pr.addTabulation();
pr.addText("mv.visitVarInsn(");
pr.addOpcode(opcode, true);
pr.addNumber(destinationRegister, true);
pr.addNumber(var, false);
pr.addText(");");
pr.addEOL();
pr.closeText();
}
// ------------------------------------------------
// Private Methods.
// ------------------------------------------------
/**
* Appends a declaration of the given label to current text. This
* declaration is of the form "Label lXXX = new Label();". Does nothing if
* the given label has already been declared, or if the Label is Null.
*
* @param label a Label. May be Null.
* @return the name of the Label, whether it existed or had been just created.
*/
private String declareLabel(final Label label) {
String name = null;
if (label != null) {
if (!labelNames.containsKey(label)) {
pr.addTabulation();
name = "l" + labelNames.size();
labelNames.put(label, name);
pr.addText("Label " + name + " = new Label();\n");
} else {
name = (String)labelNames.get(label);
}
}
return name;
}
/**
* Appends a declaration of the given label to current text. This
* declaration is of the form "Label lXXX = new Label();". Does nothing if
* the given label has already been declared.
*
* @param labels the Labels.
* @return the name of the Labels, whether it existed or had been just created.
*/
private String[] declareLabels(final Label[] labels) {
String[] names = new String[labels.length];
int i = 0;
for (Label label : labels) {
names[i] = declareLabel(label);
i++;
}
return names;
}
/**
* Appends a declaration of the given label to current text. This
* declaration is of the form "Label lXXX = new Label();". Does nothing if
* the given label has already been declared.
* May be Null.
*
* @param labels the Labels, or Null.
* @return the name of the Labels, whether it existed or had been just created, or Null.
*/
private List<String> declareLabelsToList(final List<Label> labels) {
List<String> names = null;
if (labels != null) {
names = new ArrayList<String>(labels.size());
for (Label label : labels) {
names.add(declareLabel(label));
}
}
return names;
}
/**
* Returns the Text Component this element holds.
* @return the Text Component this element holds.
*/
public TextComponent getTextComponent() {
return pr.getTextComponent();
}
}