initial commit

This commit is contained in:
CaiHQ 2021-09-24 13:08:25 +08:00
parent 016d019bc7
commit ef46d1ac4c
338 changed files with 72735 additions and 1 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Compiled class file
*.class
.DS_Store
# Log file
*.log

59
build.gradle Normal file
View File

@ -0,0 +1,59 @@
plugins {
id 'java'
id 'java-library'
}
sourceSets {
main {
java {
srcDirs 'src/main/base', 'src/main/analysis', 'src/main/asm', 'src/main/crypto', 'src/main/entry', 'src/main/gen', 'src/main/pythongen', 'src/main/DOIP', 'src/main/config'
}
resources {
srcDir 'src/main/resources'
}
}
test {
java {
srcDir 'src/test/java'
}
resources {
srcDir 'src/test/resources'
}
}
}
dependencies {
api project(":gmhelper")
api 'berkeleydb:je:3.2.76'
api 'com.fifesoft:rsyntaxtextarea:3.1.3'
api 'commons-io:commons-io:2.11.0'
api 'io.grpc:grpc-all:1.40.1'
api 'io.netty:netty-all:4.1.52.Final'
api 'io.prometheus:simpleclient:0.12.0'
api 'org.antlr:antlr4:4.9.2'
api 'org.apache.commons:commons-lang3:3.12.0'
api 'org.apache.httpcomponents:httpclient:4.5.13'
api 'org.apache.logging.log4j:log4j-core:2.14.1'
api 'org.apache.logging.log4j:log4j-api:2.14.1'
api 'org.apache.velocity:velocity-engine-core:2.3'
api 'org.knowhowlab.osgi:sigar:1.6.5_01'
api 'org.rocksdb:rocksdbjni:6.22.1'
api fileTree(dir: 'lib', include: '*.jar')
testImplementation 'junit:junit:4.13.2'
}
tasks.processResources.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE)
task copyLibs(type: Copy) {
from configurations.runtimeClasspath
into "./build/output/libs/"
}
task copyJar(type: Copy) {
from "./build/libs/$project.name-${version}.jar"
into "./build/output/"
rename { String fileName -> "yjs.jar" }
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,18 @@
package org.bdware.analysis;
import org.objectweb.asm.tree.AbstractInsnNode;
public abstract class AnalysisResult {
public AnalysisResult() {
}
public abstract AnalysisResult merge(AbstractInsnNode insn);
public abstract void printResult();
public abstract boolean covers(AnalysisResult result);
public abstract void mergeResult(AnalysisResult r);
public abstract AnalysisResult clone();
}

View File

@ -0,0 +1,7 @@
package org.bdware.analysis;
public interface AnalysisTarget {
public boolean inList();
public void setInList(boolean b);
}

View File

@ -0,0 +1,49 @@
package org.bdware.analysis;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.tree.AbstractInsnNode;
public class BasicBlock {
public List<AbstractInsnNode> list;
public int blockID;
public int lineNum = -1;
public int insnCount;
public BasicBlock(int id) {
list = new ArrayList<>();
blockID = id;
}
public void add(AbstractInsnNode insn) {
list.add(insn);
}
public int size() {
return list.size();
}
public List<AbstractInsnNode> getInsn() {
return list;
}
boolean inList = false;
public AbstractInsnNode lastInsn() {
return list.get(list.size() - 1);
}
public void setLineNum(int line) {
lineNum = line;
}
public boolean inList() {
return inList;
}
public void setInList(boolean b) {
inList = b;
}
}

View File

@ -0,0 +1,58 @@
package org.bdware.analysis;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class BreadthFirstSearch<R extends AnalysisResult, T extends AnalysisTarget> {
public Map<T, AnalysisResult> results;
protected List<T> toAnalysis;
public abstract R execute(T t);
public abstract Collection<T> getSuc(T t);
public BreadthFirstSearch() {
results = new HashMap<T, AnalysisResult>();
}
public Map<T, AnalysisResult> analysis() {
results.clear();
T current = null;
for (int i = 0; i < toAnalysis.size(); i++) {
current = toAnalysis.get(i);
current.setInList(false);
AnalysisResult preResult = results.get(current);
AnalysisResult sucResult = execute(current);
if (preResult == null || !preResult.covers(sucResult)) {
AnalysisResult cloneResult = sucResult.clone();
if (cloneResult != null) {
results.put(current, cloneResult);
}
Collection<T> sucs = getSuc(current);
for (T next : sucs) {
if (toAnalysis.contains(next)) {
//results.remove(next);
//toAnalysis.remove(next);
}
if (!next.inList()) {
toAnalysis.add(next);
next.setInList(true);
}
}
}
}
return results;
}
public int getListLength() {
return toAnalysis.size();
}
public void setToAnalysis(List<T> l) {
toAnalysis = l;
}
}

View File

@ -0,0 +1,581 @@
package org.bdware.analysis;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import java.util.*;
public abstract class CFGraph {
private static final Logger LOGGER = LogManager.getLogger(CFGraph.class);
private final Map<BasicBlock, Set<BasicBlock>> preBlock;
private final Map<Label, BasicBlock> labelToBB;
private final Map<Label, Integer> labelOrder = new HashMap<>();
protected List<BasicBlock> basicBlocks;
protected Map<BasicBlock, Set<BasicBlock>> sucBlock;
MethodNode methodNode;
// Pass2: build edges
// type2(canThrow) and catchLabels
// type3 and target labels
// type4 and catchLabels
// private List<TryCatchBlockNode> tryCacheList;
// Pass1: build basic blocks
// create a new block when:
// 1.starts with Label(can jump)
// 2.ends with CanReturn/CanThrow Insn
// 3.ends with CanBranch(IF/Switch)
// 4.ends with MethodInvoke
// At the same time build edges between:
// type1 and pre
// type2 and endBlock
// type3 and suc
// type4 and endBlock
// type4 and suc
public CFGraph(MethodNode mn) {
basicBlocks = new ArrayList<>();
preBlock = new HashMap<>();
sucBlock = new HashMap<>();
labelToBB = new HashMap<>();
methodNode = mn;
buildBasicBlock(mn.instructions, mn.tryCatchBlocks);
}
private void addEdge(BasicBlock pre, BasicBlock suc) {
Set<BasicBlock> pres = getPreBlocks(suc);
pres.add(pre);
Set<BasicBlock> sucs = getSucBlocks(pre);
sucs.add(suc);
}
public Set<BasicBlock> getSucBlocks(BasicBlock pre) {
if (null == sucBlock.get(pre)) {
Set<BasicBlock> ret = new HashSet<>();
sucBlock.put(pre, ret);
return ret;
}
return sucBlock.get(pre);
}
public Set<BasicBlock> getPreBlocks(BasicBlock suc) {
if (preBlock.get(suc) == null) {
Set<BasicBlock> ret = new HashSet<>();
preBlock.put(suc, ret);
return ret;
}
return preBlock.get(suc);
}
public abstract BasicBlock getBasicBlock(int id);
private void buildBasicBlock(InsnList instructions, List<TryCatchBlockNode> tryCatchBlocks) {
InsnPass1Visitor visitor = new InsnPass1Visitor(Opcodes.ASM4);
visitor.currBlock = getBasicBlock(0);
basicBlocks.add(visitor.currBlock);
for (int i = 0; i < instructions.size(); i++) {
AbstractInsnNode insn = instructions.get(i);
visitor.setCurrInsn(insn);
insn.accept(visitor);
}
visitor.visitEnd();
List<BasicBlock> merged = new ArrayList<>();
for (BasicBlock bb : basicBlocks)
if (bb.list.size() > 0)
merged.add(bb);
basicBlocks = merged;
InsnPass2Visitor pass2 = new InsnPass2Visitor(Opcodes.ASM4);
pass2.tryCatchBlocks = tryCatchBlocks;
for (int i = 0; i < basicBlocks.size(); i++) {
pass2.blockid = i;
BasicBlock bb = basicBlocks.get(i);
bb.blockID = i;
if (bb.size() > 0)
if (bb.list.get(0) instanceof LabelNode) {
pass2.preLabel = ((LabelNode) bb.list.get(0)).getLabel();
}
for (AbstractInsnNode node : bb.list) {
node.accept(pass2);
}
}
int preLine = -1;
for (BasicBlock block : basicBlocks) {
if (block.lineNum != -1) {
preLine = block.lineNum;
} else
block.lineNum = preLine;
}
}
public void printSelf() {
InsnPrinter printer = new InsnPrinter(Opcodes.ASM4, System.out);
printer.setLabelOrder(getLabelOrder());
LOGGER.info("isStatic: " + ((methodNode.access & Opcodes.ACC_STATIC) > 0)
+ "\tMethod:" + methodNode.name + " " + methodNode.desc);
LOGGER.info(methodNode.maxLocals + " " + methodNode.maxStack);
StringBuilder log = new StringBuilder();
for (BasicBlock bb : basicBlocks) {
log.append("B").append(bb.blockID);
if (getSucBlocks(bb).size() > 0) {
log.append(" -->");
}
for (BasicBlock suc : getSucBlocks(bb)) {
log.append(" B").append(suc.blockID);
}
for (AbstractInsnNode an : bb.list) {
an.accept(printer);
}
log.append("\n");
}
LOGGER.info(log.substring(0, log.length() - 1));
}
public Map<Label, Integer> getLabelOrder() {
return labelOrder;
}
public BasicBlock getBasicBlockAt(int i) {
return basicBlocks.get(i);
}
public int getBasicBlockSize() {
return basicBlocks.size();
}
public MethodNode getMethodNode() {
return methodNode;
}
public BasicBlock getBasicBlockByLabel(Label l) {
return labelToBB.get(l);
}
private class InsnPass1Visitor extends MethodVisitor {
int count = 0;
AbstractInsnNode currInsn;
BasicBlock currBlock;
// -------------------------------------------------------------------------
// Normal instructions
// -------------------------------------------------------------------------
BasicBlock endBlock = getEndBlock();
public InsnPass1Visitor(int api) {
super(api);
}
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
currBlock.add(currInsn);
}
/**
* Visits a zero operand instruction.
*
* @param opcode the opcode of the instruction to be visited. This opcode is
* either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or
* MONITOREXIT.
*/
public void visitInsn(int opcode) {
currBlock.add(currInsn);
if (OpInfo.ops[opcode].canReturn()) {
addEdge(currBlock, endBlock);
currBlock = getBasicBlock(basicBlocks.size());
basicBlocks.add(currBlock);
}
}
/**
* Visits an instruction with a single int operand.
*
* @param opcode the opcode of the instruction to be visited. This opcode is
* either BIPUSH, SIPUSH or NEWARRAY.
* @param operand the operand of the instruction to be visited.<br>
* When opcode is BIPUSH, operand value should be between
* Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
* When opcode is SIPUSH, operand value should be between
* Short.MIN_VALUE and Short.MAX_VALUE.<br>
* When opcode is NEWARRAY, operand value should be one of
* {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
* {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
* {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
* {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
*/
public void visitIntInsn(int opcode, int operand) {
currBlock.add(currInsn);
}
/**
* Visits a local variable instruction. A local variable instruction is an
* instruction that loads or stores the value of a local variable.
*
* @param opcode the opcode of the local variable instruction to be visited.
* This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
* ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var the operand of the instruction to be visited. This operand is
* the index of a local variable.
*/
public void visitVarInsn(int opcode, int var) {
currBlock.add(currInsn);
}
/**
* Visits a type instruction. A type instruction is an instruction that takes
* the internal name of a class as parameter.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param type the operand of the instruction to be visited. This operand must
* be the internal name of an object or array class (see
* {@link Type#getInternalName() getInternalName}).
*/
public void visitTypeInsn(int opcode, String type) {
currBlock.add(currInsn);
}
/**
* Visits a field instruction. A field instruction is an instruction that loads
* or stores the value of a field of an object.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner the internal name of the field's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name the field's name.
* @param desc the field's descriptor (see {@link Type Type}).
*/
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
currBlock.add(currInsn);
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
*/
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
currBlock.add(currInsn);
addEdge(currBlock, endBlock);
BasicBlock nextBlock = getBasicBlock(basicBlocks.size());
addEdge(currBlock, nextBlock);
currBlock = nextBlock;
basicBlocks.add(currBlock);
// TODO add edges to try catch blocks!
}
// -------------------------------------------------------------------------
// Special instructions
// -------------------------------------------------------------------------
/**
* Visits an invokedynamic instruction.
*
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
* @param bsm the bootstrap method.
* @param bsmArgs the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long},
* {@link Double}, {@link String}, {@link Type} or {@link Handle}
* value. This method is allowed to modify the content of the
* array so a caller should expect that this array may change.
*/
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
// TODO add edges to try catch blocks!
currBlock.add(currInsn);
addEdge(currBlock, endBlock);
BasicBlock nextBlock = getBasicBlock(basicBlocks.size());
addEdge(currBlock, nextBlock);
currBlock = nextBlock;
basicBlocks.add(currBlock);
}
/**
* Visits a jump instruction. A jump instruction is an instruction that may jump
* to another instruction.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label the operand of the instruction to be visited. This operand is a
* label that designates the instruction to which the jump
* instruction may jump.
*/
public void visitJumpInsn(int opcode, Label label) {
currBlock.add(currInsn);
BasicBlock nextBlock = getBasicBlock(basicBlocks.size());
if (!OpInfo.ops[opcode].toString().contains("goto"))
addEdge(currBlock, nextBlock);
currBlock = nextBlock;
basicBlocks.add(currBlock);
}
/**
* Visits a label. A label designates the instruction that will be visited just
* after it.
*
* @param label a {@link Label Label} object.
*/
public void visitLabel(Label label) {
getLabelOrder().put(label, count++);
if (currBlock.size() > 0) {
BasicBlock pre = currBlock;
currBlock = getBasicBlock(basicBlocks.size());
basicBlocks.add(currBlock);
addEdge(pre, currBlock);
}
currBlock.add(currInsn);
labelToBB.put(label, currBlock);
}
/**
* Visits a LDC instruction. Note that new constant types may be added in future
* versions of the Java Virtual Machine. To easily detect new constant types,
* implementations of this method should check for unexpected constant types,
* like this:
*
* <pre>
* if (cst instanceof Integer) {
* // ...
* } else if (cst instanceof Float) {
* // ...
* } else if (cst instanceof Long) {
* // ...
* } else if (cst instanceof Double) {
* // ...
* } else if (cst instanceof String) {
* // ...
* } else if (cst instanceof Type) {
* int sort = ((Type) cst).getSort();
* if (sort == Type.OBJECT) {
* // ...
* } else if (sort == Type.ARRAY) {
* // ...
* } else if (sort == Type.METHOD) {
* // ...
* } else {
* // throw an exception
* }
* } else if (cst instanceof Handle) {
* // ...
* } else {
* // throw an exception
* }
* </pre>
*
* @param cst the constant to be loaded on the stack. This parameter must be a
* non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
* ARRAY sort for <tt>.class</tt> constants, for classes whose
* version is 49.0, a {@link Type} of METHOD sort or a {@link Handle}
* for MethodType and MethodHandle constants, for classes whose
* version is 51.0.
*/
public void visitLdcInsn(Object cst) {
currBlock.add(currInsn);
}
/**
* Visits an IINC instruction.
*
* @param var index of the local variable to be incremented.
* @param increment amount to increment the local variable by.
*/
public void visitIincInsn(int var, int increment) {
currBlock.add(currInsn);
}
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
/**
* Visits a TABLESWITCH instruction.
*
* @param min the minimum key value.
* @param max the maximum key value.
* @param dflt beginning of the default handler block.
* @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
*/
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
currBlock.add(currInsn);
currBlock = getBasicBlock(basicBlocks.size());
basicBlocks.add(currBlock);
}
/**
* Visits a LOOKUPSWITCH instruction.
*
* @param dflt beginning of the default handler block.
* @param keys the values of the keys.
* @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
*/
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
currBlock.add(currInsn);
currBlock = getBasicBlock(basicBlocks.size());
basicBlocks.add(currBlock);
}
/**
* Visits a MULTIANEWARRAY instruction.
*
* @param desc an array type descriptor (see {@link Type Type}).
* @param dims number of dimensions of the array to allocate.
*/
public void visitMultiANewArrayInsn(String desc, int dims) {
currBlock.add(currInsn);
}
/**
* Visits a local variable declaration.
*
* @param name the name of a local variable.
* @param desc the type descriptor of this local variable.
* @param signature the type signature of this local variable. May be
* <tt>null</tt> if the local variable type does not use
* generic types.
* @param start the first instruction corresponding to the scope of this
* local variable (inclusive).
* @param end the last instruction corresponding to the scope of this
* local variable (exclusive).
* @param index the local variable's index.
* @throws IllegalArgumentException if one of the labels has not already been
* visited by this visitor (by the
* {@link #visitLabel visitLabel} method).
*/
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
currBlock.add(currInsn);
}
/**
* Visits a line number declaration.
*
* @param line a line number. This number refers to the source file from which
* the class was compiled.
* @param start the first instruction corresponding to this line number.
* @throws IllegalArgumentException if <tt>start</tt> has not already been
* visited by this visitor (by the
* {@link #visitLabel visitLabel} method).
*/
public void visitLineNumber(int line, Label start) {
currBlock.add(currInsn);
}
public void setCurrInsn(AbstractInsnNode insn) {
currInsn = insn;
}
private BasicBlock getEndBlock() {
BasicBlock ret = getBasicBlock(-1);
Label l = new Label();
ret.add(new LabelNode(l));
labelToBB.put(l, ret);
return ret;
}
public void visitEnd() {
basicBlocks.add(endBlock);
getLabelOrder().put(((LabelNode) (endBlock.list.get(0))).getLabel(), count++);
}
}
private class InsnPass2Visitor extends MethodVisitor {
int blockid;
Label preLabel;
List<TryCatchBlockNode> tryCatchBlocks;
public InsnPass2Visitor(int api) {
super(api);
}
public void addTryCatchNodes() {
for (TryCatchBlockNode node : tryCatchBlocks) {
Label l1 = node.start.getLabel();
Label l2 = node.end.getLabel();
Label l3 = node.handler.getLabel();
if (inLabel(l1, l2, preLabel))
addEdge(labelToBB.get(preLabel), labelToBB.get(l3));
}
}
@Override
public void visitLineNumber(int line, Label start) {
BasicBlock currBlock = basicBlocks.get(blockid);
currBlock.setLineNum(line);
}
@Override
public void visitJumpInsn(int opcode, Label label) {
BasicBlock currBlock = basicBlocks.get(blockid);
BasicBlock targetBlock = labelToBB.get(label);
addEdge(currBlock, targetBlock);
}
@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
BasicBlock currBlock = basicBlocks.get(blockid);
BasicBlock targetBlock = labelToBB.get(dflt);
addEdge(currBlock, targetBlock);
for (Label label : labels) {
targetBlock = labelToBB.get(label);
addEdge(currBlock, targetBlock);
}
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
BasicBlock currBlock = basicBlocks.get(blockid);
BasicBlock targetBlock = labelToBB.get(dflt);
addEdge(currBlock, targetBlock);
for (Label label : labels) {
targetBlock = labelToBB.get(label);
addEdge(currBlock, targetBlock);
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
addTryCatchNodes();
}
private boolean inLabel(Label start, Label end, Label query) {
int s = getLabelOrder().get(start);
int e = getLabelOrder().get(end);
int m = getLabelOrder().get(query);
return (m >= s && m < e);
}
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
addTryCatchNodes();
}
public void visitInsn(int opcode) {
if (OpInfo.ops[opcode].toString().contains("throw")) {
addTryCatchNodes();
}
}
}
}

View File

@ -0,0 +1,10 @@
package org.bdware.analysis;
public interface CFType {
public static final int kInstrCanBranch = 1; // conditional or unconditional branch
public static final int kInstrCanContinue = 1 << 1; // flow can continue to next statement
public static final int kInstrCanSwitch = 1 << 2; // switch
public static final int kInstrCanThrow = 1 << 3; // could cause an exception to be thrown
public static final int kInstrCanReturn = 1 << 4; // returns, no additional statements
public static final int kInstrInvoke = 1 << 5; // a flavor of invoke
}

View File

@ -0,0 +1,138 @@
package org.bdware.analysis;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.CFGraph;
import org.bdware.analysis.InsnPrinter;
import org.bdware.analysis.OpInfo;
import org.bdware.analysis.taint.TaintBB;
import org.bdware.analysis.taint.TaintCFG;
public class FrontCF {
String methodName;
public List<FrontBB> blocks;
public List<FrontEdge> edges;
public String ret;
public String finalRet;
transient InsnPrinter printer;
transient ArrayPs ps;
static class ArrayPs extends PrintStream {
List<String> content;
public ArrayPs() throws FileNotFoundException {
super("/dev/null");
}
public void println(String str) {
if (content != null)
content.add(str);
}
}
public FrontCF(CFGraph graph) {
blocks = new ArrayList<>();
edges = new ArrayList<>();
try {
ps = new ArrayPs();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
printer = new InsnPrinter(Opcodes.ASM4, ps);
printer.setLabelOrder(graph.getLabelOrder());
}
public static class FrontBB {
String type;
String name; //BlockNumber
List<String> stmts; //BlockInstructions
String original;
String result; //preResult
String blockDep;
}
public static class EdgeLabel {
String label;
}
public static class FrontEdge {
String from, to;
EdgeLabel label;
}
public void addBB(BasicBlock bb, String original, List<Integer> ids, TaintCFG cfg) {
FrontBB fb = new FrontBB();
blocks.add(fb);
fb.name = "B" + bb.blockID;
List<AbstractInsnNode> insnList = bb.getInsn();
fb.type = "Continuous";
fb.original = original;
//added
TaintBB b = (TaintBB) bb;
//if(b.preResult != null)
//b.preResult.printResult();
fb.result = b.getResult();
if(ids == null)
fb.blockDep = "";
else{
StringBuilder sb = new StringBuilder();
//sb.append("Dependence: ");
for(Integer id : ids) {
//sb.append("B"+ id +" ");
TaintBB tb = (TaintBB) cfg.getBasicBlockAt(id);
sb.append(tb.preResult.frame.getStack(0).toReadableTaint());
}
fb.blockDep = sb.toString();
}
if (insnList != null && insnList.size() > 0) {
AbstractInsnNode lastStmt = insnList.get(insnList.size() - 1);
if (lastStmt.getOpcode() >= 0) {
OpInfo info = OpInfo.ops[lastStmt.getOpcode()];
if (info.canBranch() || info.canSwitch()) {
fb.type = "Branch";
}
}
fb.stmts = new ArrayList<String>();
ps.content = fb.stmts;
for (AbstractInsnNode node : insnList) {
node.accept(printer);
}
}
}
public void addEdge(BasicBlock bb, BasicBlock suc) {
FrontEdge edge = new FrontEdge();
List<AbstractInsnNode> insnList = bb.getInsn();
edge.label = new EdgeLabel();
edge.label.label = "e";
AbstractInsnNode lastStmt = insnList.get(insnList.size() - 1);
boolean ignore = false;
if (lastStmt.getOpcode() >= 0) {
OpInfo info = OpInfo.ops[lastStmt.getOpcode()];
if (info.canBranch() && info.toString().startsWith("if")) {
if (suc.blockID == bb.blockID + 1)
edge.label.label = "false";
else
edge.label.label = "true";
}
if (info.canThrow() && info.toString().startsWith("invoke")) {
if (suc.blockID != bb.blockID + 1) {
ignore = true;
}
}
}
edge.from = "B" + bb.blockID;
edge.to = "B" + suc.blockID;
if (!ignore)
edges.add(edge);
}
}

View File

@ -0,0 +1,297 @@
package org.bdware.analysis;
import java.io.PrintStream;
import java.util.Map;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class InsnPrinter extends MethodVisitor {
PrintStream ps;
private Map<Label, Integer> labelOrder;
public InsnPrinter(int api, PrintStream ps) {
super(api);
this.ps = ps;
// TODO Auto-generated constructor stub
}
// -------------------------------------------------------------------------
// Normal instructions
// -------------------------------------------------------------------------
/**
* Visits a zero operand instruction.
*
* @param opcode the opcode of the instruction to be visited. This opcode is
* either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or
* MONITOREXIT.
*/
public void visitInsn(int opcode) {
ps.println(OpInfo.ops[opcode].toString());
}
/**
* Visits an instruction with a single int operand.
*
* @param opcode the opcode of the instruction to be visited. This opcode is
* either BIPUSH, SIPUSH or NEWARRAY.
* @param operand the operand of the instruction to be visited.<br>
* When opcode is BIPUSH, operand value should be between
* Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
* When opcode is SIPUSH, operand value should be between
* Short.MIN_VALUE and Short.MAX_VALUE.<br>
* When opcode is NEWARRAY, operand value should be one of
* {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
* {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
* {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
* {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
*/
public void visitIntInsn(int opcode, int operand) {
ps.println(OpInfo.ops[opcode].toString() + " " + operand);
}
/**
* Visits a local variable instruction. A local variable instruction is an
* instruction that loads or stores the value of a local variable.
*
* @param opcode the opcode of the local variable instruction to be visited.
* This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
* ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var the operand of the instruction to be visited. This operand is
* the index of a local variable.
*/
public void visitVarInsn(int opcode, int var) {
ps.println(OpInfo.ops[opcode].toString() + " " + var);
}
/**
* Visits a type instruction. A type instruction is an instruction that takes
* the internal name of a class as parameter.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param type the operand of the instruction to be visited. This operand must
* be the internal name of an object or array class (see
* {@link Type#getInternalName() getInternalName}).
*/
public void visitTypeInsn(int opcode, String type) {
ps.println(OpInfo.ops[opcode].toString() + " " + type);
}
/**
* Visits a field instruction. A field instruction is an instruction that loads
* or stores the value of a field of an object.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner the internal name of the field's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name the field's name.
* @param desc the field's descriptor (see {@link Type Type}).
*/
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
ps.println(OpInfo.ops[opcode].toString() + " " + owner + " " + name + " " + desc);
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
*/
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
ps.println(OpInfo.ops[opcode].toString() + " " + owner + " " + name + " " + desc);
}
/**
* Visits an invokedynamic instruction.
*
* @param name the method's name.
* @param desc the method's descriptor (see {@link Type Type}).
* @param bsm the bootstrap method.
* @param bsmArgs the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long},
* {@link Double}, {@link String}, {@link Type} or {@link Handle}
* value. This method is allowed to modify the content of the
* array so a caller should expect that this array may change.
*/
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
ps.println(OpInfo.INVOKEDYNAMIC.toString() + " " + name + " " + desc + " HANDLE:" + bsm.toString() + " "
+ objs2Str(bsmArgs));
}
private String objs2Str(Object[] bsmArgs) {
StringBuilder sb = new StringBuilder();
for (Object obj : bsmArgs)
sb.append(obj.toString()).append(" ");
return sb.toString();
}
/**
* Visits a jump instruction. A jump instruction is an instruction that may jump
* to another instruction.
*
* @param opcode the opcode of the type instruction to be visited. This opcode
* is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label the operand of the instruction to be visited. This operand is a
* label that designates the instruction to which the jump
* instruction may jump.
*/
public void visitJumpInsn(int opcode, Label label) {
ps.println(OpInfo.ops[opcode].toString() + getLabelStr(label));
}
/**
* Visits a label. A label designates the instruction that will be visited just
* after it.
*
* @param label a {@link Label Label} object.
*/
private String getLabelStr(Label label) {
return "L" + labelOrder.get(label);
}
public void visitLabel(Label label) {
ps.println("=" + getLabelStr(label) + "=");
}
// -------------------------------------------------------------------------
// Special instructions
// -------------------------------------------------------------------------
/**
* Visits a LDC instruction. Note that new constant types may be added in future
* versions of the Java Virtual Machine. To easily detect new constant types,
* implementations of this method should check for unexpected constant types,
* like this:
*
* <pre>
* if (cst instanceof Integer) {
* // ...
* } else if (cst instanceof Float) {
* // ...
* } else if (cst instanceof Long) {
* // ...
* } else if (cst instanceof Double) {
* // ...
* } else if (cst instanceof String) {
* // ...
* } else if (cst instanceof Type) {
* int sort = ((Type) cst).getSort();
* if (sort == Type.OBJECT) {
* // ...
* } else if (sort == Type.ARRAY) {
* // ...
* } else if (sort == Type.METHOD) {
* // ...
* } else {
* // throw an exception
* }
* } else if (cst instanceof Handle) {
* // ...
* } else {
* // throw an exception
* }
* </pre>
*
* @param cst the constant to be loaded on the stack. This parameter must be a
* non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
* ARRAY sort for <tt>.class</tt> constants, for classes whose
* version is 49.0, a {@link Type} of METHOD sort or a {@link Handle}
* for MethodType and MethodHandle constants, for classes whose
* version is 51.0.
*/
public void visitLdcInsn(Object cst) {
ps.println("ldc " + cst);
}
/**
* Visits an IINC instruction.
*
* @param var index of the local variable to be incremented.
* @param increment amount to increment the local variable by.
*/
public void visitIincInsn(int var, int increment) {
ps.println("iinc " + var + " " + increment);
}
/**
* Visits a TABLESWITCH instruction.
*
* @param min the minimum key value.
* @param max the maximum key value.
* @param dflt beginning of the default handler block.
* @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
*/
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
ps.println(OpInfo.TABLESWITCH.toString() + " labels:" + getLabelStr(dflt) + " " + convertLabels(labels));
}
private String convertLabels(Label[] labels) {
StringBuilder sb = new StringBuilder();
for (Label l : labels)
sb.append(getLabelStr(l)).append(" ");
return sb.toString();
}
/**
* Visits a LOOKUPSWITCH instruction.
*
* @param dflt beginning of the default handler block.
* @param keys the values of the keys.
* @param labels beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
*/
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
ps.println(OpInfo.LOOKUPSWITCH.toString() + " labels:" + getLabelStr(dflt) + " " + convertLabels(labels));
}
/**
* Visits a MULTIANEWARRAY instruction.
*
* @param desc an array type descriptor (see {@link Type Type}).
* @param dims number of dimensions of the array to allocate.
*/
public void visitMultiANewArrayInsn(String desc, int dims) {
ps.println(OpInfo.MULTIANEWARRAY + " " + desc + " " + dims);
}
public void setLabelOrder(Map<Label, Integer> labelOrder) {
this.labelOrder = labelOrder;
}
}

View File

@ -0,0 +1,256 @@
package org.bdware.analysis;
public enum OpInfo implements CFType {
NOP(0x00, "nop", kInstrCanContinue, 0), // --
ACONST_NULL(0x01, "aconst_null", kInstrCanContinue, 1), // --
ICONST_M1(0x02, "iconst_m1", kInstrCanContinue, 1), // --
ICONST_0(0x03, "iconst_0", kInstrCanContinue, 1), // --
ICONST_1(0x04, "iconst_1", kInstrCanContinue, 1), // --
ICONST_2(0x05, "iconst_2", kInstrCanContinue, 1), // --
ICONST_3(0x06, "iconst_3", kInstrCanContinue, 1), // --
ICONST_4(0x07, "iconst_4", kInstrCanContinue, 1), // --
ICONST_5(0x08, "iconst_5", kInstrCanContinue, 1), // --
LCONST_0(0x09, "lconst_0", kInstrCanContinue, 2), // --
LCONST_1(0x0a, "lconst_1", kInstrCanContinue, 2), // --
FCONST_0(0x0b, "fconst_0", kInstrCanContinue, 1), // --
FCONST_1(0x0c, "fconst_1", kInstrCanContinue, 1), // --
FCONST_2(0x0d, "fconst_2", kInstrCanContinue, 1), // --
DCONST_0(0x0e, "dconst_0", kInstrCanContinue, 2), // --
DCONST_1(0x0f, "dconst_1", kInstrCanContinue, 2), // --
BIPUSH(0x10, "bipush", kInstrCanContinue, 1), // --
SIPUSH(0x11, "sipush", kInstrCanContinue, 1), // --
LDC(0x12, "ldc", kInstrCanContinue, 1), // --
LDC_W(0x13, "ldc_w", kInstrCanContinue, 1), // --
LDC2_W(0x14, "ldc2_w", kInstrCanContinue, 2), // --
ILOAD(0x15, "iload", kInstrCanContinue, 1), // --
LLOAD(0x16, "lload", kInstrCanContinue, 2), // --
FLOAD(0x17, "fload", kInstrCanContinue, 1), // --
DLOAD(0x18, "dload", kInstrCanContinue, 2), // --
ALOAD(0x19, "aload", kInstrCanContinue, 1), // --
ILOAD_0(0x1a, "iload_0", kInstrCanContinue, 1), // --
ILOAD_1(0x1b, "iload_1", kInstrCanContinue, 1), // --
ILOAD_2(0x1c, "iload_2", kInstrCanContinue, 1), // --
ILOAD_3(0x1d, "iload_3", kInstrCanContinue, 1), // --
LLOAD_0(0x1e, "lload_0", kInstrCanContinue, 2), // --
LLOAD_1(0x1f, "lload_1", kInstrCanContinue, 2), // --
LLOAD_2(0x20, "lload_2", kInstrCanContinue, 2), // --
LLOAD_3(0x21, "lload_3", kInstrCanContinue, 2), // --
FLOAD_0(0x22, "fload_0", kInstrCanContinue, 1), // --
FLOAD_1(0x23, "fload_1", kInstrCanContinue, 1), // --
FLOAD_2(0x24, "fload_2", kInstrCanContinue, 1), // --
FLOAD_3(0x25, "fload_3", kInstrCanContinue, 1), // --
DLOAD_0(0x26, "dload_0", kInstrCanContinue, 2), // --
DLOAD_1(0x27, "dload_1", kInstrCanContinue, 2), // --
DLOAD_2(0x28, "dload_2", kInstrCanContinue, 2), // --
DLOAD_3(0x29, "dload_3", kInstrCanContinue, 2), // --
ALOAD_0(0x2a, "aload_0", kInstrCanContinue, 1), // --
ALOAD_1(0x2b, "aload_1", kInstrCanContinue, 1), // --
ALOAD_2(0x2c, "aload_2", kInstrCanContinue, 1), // --
ALOAD_3(0x2d, "aload_3", kInstrCanContinue, 1), // --
IALOAD(0x2e, "iaload", kInstrCanContinue, -1), // --
LALOAD(0x2f, "laload", kInstrCanContinue, 0), // --
FALOAD(0x30, "faload", kInstrCanContinue, -1), // --
DALOAD(0x31, "daload", kInstrCanContinue, 0), // --
AALOAD(0x32, "aaload", kInstrCanContinue, -1), // --
BALOAD(0x33, "baload", kInstrCanContinue, -1), // --
CALOAD(0x34, "caload", kInstrCanContinue, -1), // --
SALOAD(0x35, "saload", kInstrCanContinue, -1), // --
ISTORE(0x36, "istore", kInstrCanContinue, -1), // --
LSTORE(0x37, "lstore", kInstrCanContinue, -2), // --
FSTORE(0x38, "fstore", kInstrCanContinue, -1), // --
DSTORE(0x39, "dstore", kInstrCanContinue, -2), // --
ASTORE(0x3a, "astore", kInstrCanContinue, -1), // --
ISTORE_0(0x3b, "istore_0", kInstrCanContinue, -1), // --
ISTORE_1(0x3c, "istore_1", kInstrCanContinue, -1), // --
ISTORE_2(0x3d, "istore_2", kInstrCanContinue, -1), // --
ISTORE_3(0x3e, "istore_3", kInstrCanContinue, -1), // --
LSTORE_0(0x3f, "lstore_0", kInstrCanContinue, -2), // --
LSTORE_1(0x40, "lstore_1", kInstrCanContinue, -2), // --
LSTORE_2(0x41, "lstore_2", kInstrCanContinue, -2), // --
LSTORE_3(0x42, "lstore_3", kInstrCanContinue, -2), // --
FSTORE_0(0x43, "fstore_0", kInstrCanContinue, -1), // --
FSTORE_1(0x44, "fstore_1", kInstrCanContinue, -1), // --
FSTORE_2(0x45, "fstore_2", kInstrCanContinue, -1), // --
FSTORE_3(0x46, "fstore_3", kInstrCanContinue, -1), // --
DSTORE_0(0x47, "dstore_0", kInstrCanContinue, -2), // --
DSTORE_1(0x48, "dstore_1", kInstrCanContinue, -2), // --
DSTORE_2(0x49, "dstore_2", kInstrCanContinue, -2), // --
DSTORE_3(0x4a, "dstore_3", kInstrCanContinue, -2), // --
ASTORE_0(0x4b, "astore_0", kInstrCanContinue, -1), // --
ASTORE_1(0x4c, "astore_1", kInstrCanContinue, -1), // --
ASTORE_2(0x4d, "astore_2", kInstrCanContinue, -1), // --
ASTORE_3(0x4e, "astore_3", kInstrCanContinue, -1), // --
IASTORE(0x4f, "iastore", kInstrCanContinue, -3), // --
LASTORE(0x50, "lastore", kInstrCanContinue, -4), // --
FASTORE(0x51, "fastore", kInstrCanContinue, -3), // --
DASTORE(0x52, "dastore", kInstrCanContinue, -4), // --
AASTORE(0x53, "aastore", kInstrCanContinue, -3), // --
BASTORE(0x54, "bastore", kInstrCanContinue, -3), // --
CASTORE(0x55, "castore", kInstrCanContinue, -3), // --
SASTORE(0x56, "sastore", kInstrCanContinue, -3), // --
POP(0x57, "pop", kInstrCanContinue, -1), // --
POP2(0x58, "pop2", kInstrCanContinue, -2), // --
DUP(0x59, "dup", kInstrCanContinue, 1), // --
DUP_X1(0x5a, "dup_x1", kInstrCanContinue, 1), // --
DUP_X2(0x5b, "dup_x2", kInstrCanContinue, 1), // --
DUP2(0x5c, "dup2", kInstrCanContinue, 2), // --
DUP2_X1(0x5d, "dup2_x1", kInstrCanContinue, 2), // --
DUP2_X2(0x5e, "dup2_x2", kInstrCanContinue, 2), // --
SWAP(0x5f, "swap", kInstrCanContinue, 0), // --
IADD(0x60, "iadd", kInstrCanContinue, -1), // --
LADD(0x61, "ladd", kInstrCanContinue, -2), // --
FADD(0x62, "fadd", kInstrCanContinue, -1), // --
DADD(0x63, "dadd", kInstrCanContinue, -2), // --
ISUB(0x64, "isub", kInstrCanContinue, -1), // --
LSUB(0x65, "lsub", kInstrCanContinue, -2), // --
FSUB(0x66, "fsub", kInstrCanContinue, -1), // --
DSUB(0x67, "dsub", kInstrCanContinue, -2), // --
IMUL(0x68, "imul", kInstrCanContinue, -1), // --
LMUL(0x69, "lmul", kInstrCanContinue, -2), // --
FMUL(0x6a, "fmul", kInstrCanContinue, -1), // --
DMUL(0x6b, "dmul", kInstrCanContinue, -2), // --
IDIV(0x6c, "idiv", kInstrCanContinue, -1), // --
LDIV(0x6d, "ldiv", kInstrCanContinue, -2), // --
FDIV(0x6e, "fdiv", kInstrCanContinue, -1), // --
DDIV(0x6f, "ddiv", kInstrCanContinue, -2), // --
IREM(0x70, "irem", kInstrCanContinue, -1), // --
LREM(0x71, "lrem", kInstrCanContinue, -2), // --
FREM(0x72, "frem", kInstrCanContinue, -1), // --
DREM(0x73, "drem", kInstrCanContinue, -2), // --
INEG(0x74, "ineg", kInstrCanContinue, 0), // --
LNEG(0x75, "lneg", kInstrCanContinue, 0), // --
FNEG(0x76, "fneg", kInstrCanContinue, 0), // --
DNEG(0x77, "dneg", kInstrCanContinue, 0), // --
ISHL(0x78, "ishl", kInstrCanContinue, -1), // --
LSHL(0x79, "lshl", kInstrCanContinue, -1), // --
ISHR(0x7a, "ishr", kInstrCanContinue, -1), // --
LSHR(0x7b, "lshr", kInstrCanContinue, -1), // --
IUSHR(0x7c, "iushr", kInstrCanContinue, -1), // --
LUSHR(0x7d, "lushr", kInstrCanContinue, -1), // --
IAND(0x7e, "iand", kInstrCanContinue, -1), // --
LAND(0x7f, "land", kInstrCanContinue, -2), // --
IOR(0x80, "ior", kInstrCanContinue, -1), // --
LOR(0x81, "lor", kInstrCanContinue, -2), // --
IXOR(0x82, "ixor", kInstrCanContinue, -1), // --
LXOR(0x83, "lxor", kInstrCanContinue, -2), // --
IINC(0x84, "iinc", kInstrCanContinue, 0), // --
I2L(0x85, "i2l", kInstrCanContinue, 1), // --
I2F(0x86, "i2f", kInstrCanContinue, 0), // --
I2D(0x87, "i2d", kInstrCanContinue, 1), // --
L2I(0x88, "l2i", kInstrCanContinue, -1), // --
L2F(0x89, "l2f", kInstrCanContinue, -1), // --
L2D(0x8a, "l2d", kInstrCanContinue, 0), // --
F2I(0x8b, "f2i", kInstrCanContinue, 0), // --
F2L(0x8c, "f2l", kInstrCanContinue, 1), // --
F2D(0x8d, "f2d", kInstrCanContinue, 1), // --
D2I(0x8e, "d2i", kInstrCanContinue, -1), // --
D2L(0x8f, "d2l", kInstrCanContinue, 0), // --
D2F(0x90, "d2f", kInstrCanContinue, -1), // --
I2B(0x91, "i2b", kInstrCanContinue, 0), // --
I2C(0x92, "i2c", kInstrCanContinue, 0), // --
I2S(0x93, "i2s", kInstrCanContinue, 0), // --
LCMP(0x94, "lcmp", kInstrCanContinue, -2), // --
FCMPL(0x95, "fcmpl", kInstrCanContinue, -1), // --
FCMPG(0x96, "fcmpg", kInstrCanContinue, -1), // --
DCMPL(0x97, "dcmpl", kInstrCanContinue, -3), // --
DCMPG(0x98, "dcmpg", kInstrCanContinue, -3), // --
IFEQ(0x99, "ifeq", kInstrCanBranch, -1), // --
IFNE(0x9a, "ifne", kInstrCanBranch, -1), // --
IFLT(0x9b, "iflt", kInstrCanBranch, -1), // --
IFGE(0x9c, "ifge", kInstrCanBranch, -1), // --
IFGT(0x9d, "ifgt", kInstrCanBranch, -1), // --
IFLE(0x9e, "ifle", kInstrCanBranch, -1), // --
IF_ICMPEQ(0x9f, "if_icmpeq", kInstrCanBranch, -2), // --
IF_ICMPNE(0xa0, "if_icmpne", kInstrCanBranch, -2), // --
IF_ICMPLT(0xa1, "if_icmplt", kInstrCanBranch, -2), // --
IF_ICMPGE(0xa2, "if_icmpge", kInstrCanBranch, -2), // --
IF_ICMPGT(0xa3, "if_icmpgt", kInstrCanBranch, -2), // --
IF_ICMPLE(0xa4, "if_icmple", kInstrCanBranch, -2), // --
IF_ACMPEQ(0xa5, "if_acmpeq", kInstrCanBranch, -2), // --
IF_ACMPNE(0xa6, "if_acmpne", kInstrCanBranch, -2), // --
GOTO(0xa7, "goto", kInstrCanBranch, 0), // --
JSR(0xa8, "jsr", kInstrCanContinue, 1), // ??--
RET(0xa9, "ret", kInstrCanContinue, -1), // ??--
TABLESWITCH(0xaa, "tableswitch", kInstrCanBranch, 1), // --
LOOKUPSWITCH(0xab, "lookupswitch", kInstrCanBranch, 0), // --
IRETURN(0xac, "ireturn", kInstrCanReturn, -1), // --
LRETURN(0xad, "lreturn", kInstrCanReturn, -2), // --
FRETURN(0xae, "freturn", kInstrCanReturn, -1), // --
DRETURN(0xaf, "dreturn", kInstrCanReturn, -2), // --
ARETURN(0xb0, "areturn", kInstrCanReturn, -1), // --
RETURN(0xb1, "return", kInstrCanReturn, 0), // --
GETSTATIC(0xb2, "getstatic", kInstrCanContinue, 0), // dynamic changing+ --
PUTSTATIC(0xb3, "putstatic", kInstrCanContinue, 0), // dynamic changing- --
GETFIELD(0xb4, "getfield", kInstrCanContinue, 0), // dynamic changing_+ --
PUTFIELD(0xb5, "putfield", kInstrCanContinue, 0), // dynamic changing-- --
INVOKEVIRTUAL(0xb6, "invokevirtual", kInstrInvoke | kInstrCanThrow, 0), // dynamic changing-- --
INVOKESPECIAL(0xb7, "invokespecial", kInstrInvoke | kInstrCanThrow, 0), // dynamic changing-- --
INVOKESTATIC(0xb8, "invokestatic", kInstrInvoke | kInstrCanThrow, 0), // dynamic changing-- --
INVOKEINTERFACE(0xb9, "invokeinterface", kInstrInvoke | kInstrCanThrow, 0), // dynamic changing-- --
INVOKEDYNAMIC(0xba, "invokedynamic", kInstrInvoke | kInstrCanThrow, 0), // dynamic changing-- --
NEW(0xbb, "new", kInstrCanContinue, 1), // --
NEWARRAY(0xbc, "newarray", kInstrCanContinue, 0), // --
ANEWARRAY(0xbd, "anewarray", kInstrCanContinue, 0), // --
ARRAYLENGTH(0xbe, "arraylength", kInstrCanContinue, 0), // --
ATHROW(0xbf, "athrow", kInstrCanReturn, 0), // --
CHECKCAST(0xc0, "checkcast", kInstrCanContinue, 0), // --
INSTANCEOF(0xc1, "instanceof", kInstrCanContinue, 0), // --
MONITORENTER(0xc2, "monitorenter", kInstrCanContinue, -1), // --
MONITOREXIT(0xc3, "monitorexit", kInstrCanContinue, -1), // --
WIDE(0xc4, "wide", kInstrCanContinue, 0), // --
MULTIANEWARRAY(0xc5, "multianewarray", kInstrCanContinue, 0), // dynamic changing--
IFNULL(0xc6, "ifnull", kInstrCanBranch, -1), // --
IFNONNULL(0xc7, "ifnonnull", kInstrCanBranch, -1), // --
GOTO_W(0xc8, "goto_w", kInstrCanBranch, 0), // --
JSR_W(0xc9, "jsr_w", kInstrCanContinue, 1);// ??--
public final static OpInfo ops[] = new OpInfo[256];
static {
OpInfo[] ops = OpInfo.ops;
for (OpInfo op : OpInfo.values()) {
if (op.opcode >= 0) {
ops[op.opcode] = op;
}
}
}
public boolean changeFrame;
int changeStack;
private int flags;
private String displayName;
private int opcode;
OpInfo() {
}
OpInfo(int opcode, String displayName, int branchType, int changStack) {
flags = branchType;
this.displayName = displayName;
this.opcode = opcode;
this.changeStack = changeStack;
}
public boolean canBranch() {
return 0 != (flags & kInstrCanBranch);
}
public boolean canContinue() {
return 0 != (flags & kInstrCanContinue);
}
public boolean canReturn() {
return 0 != (flags & kInstrCanReturn);
}
public boolean canSwitch() {
return 0 != (flags & kInstrCanSwitch);
}
public boolean canThrow() {
return 0 != (flags & kInstrCanThrow);
}
public String toString() {
return displayName;
}
}

View File

@ -0,0 +1,193 @@
package org.bdware.analysis.dynamic;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.OpInfo;
import org.bdware.analysis.taint.TaintBB;
import org.bdware.analysis.taint.TaintCFG;
import org.bdware.analysis.taint.TaintResult;
import org.bdware.analysis.taint.TaintValue;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.MethodNode;
import java.util.*;
public class FieldSensitiveDynamicTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
private static final Logger LOGGER = LogManager.getLogger(FieldSensitiveDynamicTaintAnalysis.class);
public static boolean isDebug = false;
TaintCFG cfg;
TracedFile tf;
int count = 0;
public FieldSensitiveDynamicTaintAnalysis(TaintCFG cfg, TracedFile tf) {
this.cfg = cfg;
this.tf = tf;
List<TaintBB> toAnalysis = new ArrayList<>();
MethodNode mn = cfg.getMethodNode();
LOGGER.info("mn: " + mn.name);
String methodDesc = mn.desc;
LOGGER.info("method desc: " + methodDesc);
methodDesc = methodDesc.replaceAll("\\).*$", ")");
LOGGER.info("method desc: " + methodDesc);
int pos = 2;
if (methodDesc.split(";").length == 3)
pos = 1;
// TODO add inputBlock!
LOGGER.info("p+++ " + pos);
TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);
b.preResult = new TaintResult();
LOGGER.info(TaintResult.nLocals);
if (TaintResult.nLocals > 2) {
for (int i = 0; i < TaintResult.nLocals; i++)
b.preResult.frame.setLocal(i, new TaintValue(1, i == pos ? 1 : 0));
}
b.preResult.ret = new TaintValue(1);
// NaiveTaintResult.printer.setLabelOrder(cfg.getLabelOrder());
toAnalysis.add(b);
b.setInList(true);
setToAnalysis(toAnalysis);
if (isDebug) {
MethodNode methodNode = cfg.getMethodNode();
LOGGER.info("Method: " + methodNode.name + " " + methodNode.desc);
LOGGER.info("Local: " + methodNode.maxLocals + " " + methodNode.maxStack);
}
}
@Override
public TaintResult execute(TaintBB t) {
return t.forwardAnalysis();
}
// Current Block is done, merge sucResult to sucBlocks!
@Override
public Collection<TaintBB> getSuc(TaintBB t) {
Set<BasicBlock> subBlock = new HashSet<>();//
if (t.list.size() > 0) {
AbstractInsnNode insn = t.lastInsn();
if (insn != null) {
OpInfo info = null;
if (insn.getOpcode() >= 0)
info = OpInfo.ops[insn.getOpcode()];
if (info == null) {
subBlock.addAll(cfg.getSucBlocks(t));
} else if (info.canThrow()) {
// subBlock.clear();
subBlock.add(cfg.getBasicBlockAt(t.blockID + 1));
} else if (OpInfo.ops[insn.getOpcode()].canBranch()) {
// subBlock.clear();
// LOGGER.info("can branch " + t.blockID);
int block = handleBranchCase(subBlock, insn, t);
subBlock.add(cfg.getBasicBlockAt(block));
} else if (OpInfo.ops[insn.getOpcode()].canSwitch()) {
subBlock.add(cfg.getBasicBlockAt(t.blockID + 1));
} else {
subBlock.addAll(cfg.getSucBlocks(t));
}
}
}
Set<TaintBB> ret = new HashSet<>();
// StringBuilder log = new StringBuilder("nextBB:");
for (BasicBlock bb : subBlock) {
// log.append("\n\t").append(bb.blockID);
TaintBB ntbb = (TaintBB) bb;
ntbb.preResult.mergeResult(t.sucResult);
ret.add(ntbb);
}
// LOGGER.info(log.toString());
return ret;
}
private int handleBranchCase(Set<BasicBlock> subBlock, AbstractInsnNode insn, TaintBB t) {
int blockid = 0;
switch (insn.getOpcode()) {
case Opcodes.IFNE:// succeeds if and only if value ≠ 0
count++;
if (tf.trans.get(0).tmToVal.get(0).get(0) != 0) {
// test first tracemark{"traceMark":0, "val":1}
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFEQ:// succeeds if and only if value = 0
if (tf.trans.get(0).tmToVal.get(0).get(0) == 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFGE:// succeeds if and only if value 0
if (tf.trans.get(0).tmToVal.get(0).get(0) >= 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFLE:// succeeds if and only if value 0
if (tf.trans.get(0).tmToVal.get(0).get(0) <= 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFLT:// succeeds if and only if value < 0
if (tf.trans.get(0).tmToVal.get(0).get(0) < 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFGT:// succeeds if and only if value > 0
if (tf.trans.get(0).tmToVal.get(0).get(0) < 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IF_ACMPEQ:// succeeds if and only if value1 = value2
case Opcodes.IF_ACMPNE:// succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPEQ:// succeeds if and only if value1 = value2
case Opcodes.IF_ICMPGE:// succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPGT:// succeeds if and only if value1 > value2
case Opcodes.IF_ICMPLE:// succeeds if and only if value1 value2
case Opcodes.IF_ICMPLT:// succeeds if and only if value1 < value2
case Opcodes.IFNONNULL:
case Opcodes.TABLESWITCH:
case Opcodes.LOOKUPSWITCH:
default:
break;
case Opcodes.GOTO:
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
}
return blockid;
}
}

View File

@ -0,0 +1,208 @@
package org.bdware.analysis.dynamic;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.OpInfo;
import org.bdware.analysis.taint.*;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.util.*;
public class NaiveDynamicTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
TaintCFG cfg;
TracedFile tf;
public static boolean isDebug = false;
int count = 0;
String functionGlobel;
public static HashMap<String, HashMap<Integer, Integer>> branchCount = new HashMap<>();
public NaiveDynamicTaintAnalysis(TaintCFG cfg, TracedFile tf) {
this.cfg = cfg;
this.tf = tf;
List<TaintBB> toAnalysis = new ArrayList<>();
MethodNode mn = cfg.getMethodNode();
String methodDesc = mn.desc;
methodDesc = methodDesc.replaceAll("\\).*$", ")");
int pos = 2;
if (methodDesc.split(";").length == 3) pos = 1;
// TODO add inputBlock!
TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);
b.preResult = new TaintResult();
int arg = cfg.argsLocal();
b.preResult.frame.setLocal(arg, new TaintValue(1, cfg.taintBits.allocate("arg" + arg)));
b.preResult.frame.setLocal(0, HeapObject.getRootObject());
cfg.executeLocal();
TaintResult.interpreter.setTaintBits(cfg.taintBits);
functionGlobel = cfg.getMethodNode().name;
branchCount.put(functionGlobel, new HashMap<Integer, Integer>());
// local0=scriptfuncion, is not tainted;
// local1=this, is not tainted;
// local2=this, is not tainted;
// NaiveTaintResult.printer.setLabelOrder(cfg.getLabelOrder());
toAnalysis.add(b);
b.setInList(true);
setToAnalysis(toAnalysis);
if (isDebug) {
System.out.println("===Method:" + cfg.getMethodNode().name + cfg.getMethodNode().desc);
System.out.println(
"===Local:"
+ cfg.getMethodNode().maxLocals
+ " "
+ cfg.getMethodNode().maxStack);
}
}
@Override
public TaintResult execute(TaintBB t) {
return t.forwardAnalysis();
}
// Current Block is done, merge sucResult to sucBlocks!
@Override
public Collection<TaintBB> getSuc(TaintBB t) {
Set<BasicBlock> subBlock = new HashSet<>(); // bug ! clear() no suc
if (t.list.size() > 0) {
AbstractInsnNode insn = t.lastInsn();
if (insn != null) {
OpInfo info = null;
if (insn.getOpcode() >= 0) info = OpInfo.ops[insn.getOpcode()];
if (info == null) {
subBlock.addAll(cfg.getSucBlocks(t));
} else if (info.canThrow()) {
callCount(insn);
subBlock.add(cfg.getBasicBlockAt(t.blockID + 1));
} else if (OpInfo.ops[insn.getOpcode()].canBranch()) {
subBlock.clear();
int block = handleBranchCase(subBlock, insn, t);
subBlock.add(cfg.getBasicBlockAt(block));
} else if (OpInfo.ops[insn.getOpcode()].canSwitch()) {
subBlock.add(cfg.getBasicBlockAt(t.blockID + 1));
} else {
subBlock.addAll(cfg.getSucBlocks(t));
}
}
}
Set<TaintBB> ret = new HashSet<>();
// System.out.print("[NaiveDynamicTaintAnalysis] nextBB:");
for (BasicBlock bb : subBlock) {
// System.out.print(" " + bb.blockID);
TaintBB ntbb = (TaintBB) bb;
ntbb.preResult.mergeResult(t.sucResult);
ret.add(ntbb);
}
// System.out.println();
return ret;
}
private void callCount(AbstractInsnNode insn) {
if (insn instanceof InvokeDynamicInsnNode) {
Object invoke = ((InvokeDynamicInsnNode) insn).bsmArgs[0];
String functionName = ((InvokeDynamicInsnNode) insn).name;
if (functionName.contains("traceif")) {
traceIfNum = (int) invoke;
if (branchCount.get(functionGlobel).containsKey(traceIfNum)) {
branchCount
.get(functionGlobel)
.put(traceIfNum, branchCount.get(functionGlobel).get(traceIfNum) + 1);
} else {
branchCount.get(functionGlobel).put(traceIfNum, 1);
}
}
}
}
int traceIfNum = 0;
private int handleBranchCase(Set<BasicBlock> subBlock, AbstractInsnNode insn, TaintBB t) {
int blockid = 0;
switch (insn.getOpcode()) {
case Opcodes.IFNE: // succeeds if and only if value ≠ 0
int ifneCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifneCount) != 0) { // test first
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFEQ: // succeeds if and only if value = 0
int ifeqCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifeqCount) == 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFGE: // succeeds if and only if value 0
int ifgeCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifgeCount) >= 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFLE: // succeeds if and only if value 0
int ifleCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifleCount) <= 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFLT: // succeeds if and only if value < 0
int ifltCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifltCount) < 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IFGT: // succeeds if and only if value > 0
int ifgtCount = branchCount.get(functionGlobel).get(traceIfNum);
if (tf.trans.get(0).tmToVal.get(traceIfNum).get(ifgtCount) < 0) {
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
} else {
blockid = t.blockID + 1;
}
return blockid;
case Opcodes.IF_ACMPEQ: // succeeds if and only if value1 = value2
case Opcodes.IF_ACMPNE: // succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPEQ: // succeeds if and only if value1 = value2
case Opcodes.IF_ICMPGE: // succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPGT: // succeeds if and only if value1 > value2
case Opcodes.IF_ICMPLE: // succeeds if and only if value1 value2
case Opcodes.IF_ICMPLT: // succeeds if and only if value1 < value2
case Opcodes.IFNONNULL:
case Opcodes.TABLESWITCH:
case Opcodes.LOOKUPSWITCH:
default:
break;
case Opcodes.GOTO:
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
blockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
}
}
return blockid;
}
}

View File

@ -0,0 +1,91 @@
package org.bdware.analysis.dynamic;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.InputStream;
import java.util.*;
public class ProgramPoint {
private static final Logger LOGGER = LogManager.getLogger(ProgramPoint.class);
List<Transaction> trans;
List<FunctionTran> functionTrans;
public ProgramPoint(InputStream in) {
Scanner sc = new Scanner(in);
trans = new ArrayList<>();
functionTrans = new ArrayList<>();
Transaction transaction = new Transaction();
FunctionTran functionTran = new FunctionTran();
transaction.tmToVal = new HashMap<>();
functionTran.ppToVal = new HashMap<>();
// TODO ignore handle transaction start
// TODO ignore handle contractID/method....
// TODO ignore handle transaction end
while (sc.hasNextLine()) {
String string = sc.nextLine().replace("[ProgramPointCounter]", "");
LOGGER.debug("[string: ]" + string);
if (string.contains("ENTER")) {
String[] strings = string.split("_");
strings = strings[1].split("[(]");
System.out.println("[stringsss: ]" + strings[0]);
functionTran.insert(strings[0], "ENTER");
}
// if (string.contains("EXIT")) {
// String[] strings = string.split("_");
// strings=strings[1].split("-");
// System.out.println("[stringsss: ]" + strings[0]);
// functionMap.put(strings[1], "EXIT");
// }
if (string.contains("traceMark")) {
JsonObject jo = JsonParser.parseString(string).getAsJsonObject();
if (jo.get("traceMark") != null) {
if (jo.get("lval") != null) {
transaction.insert(
jo.get("traceMark").getAsInt(), jo.get("lval").getAsInt());
transaction.insert(
jo.get("traceMark").getAsInt(), jo.get("rval").getAsInt());
} else {
transaction.insert(
jo.get("traceMark").getAsInt(), jo.get("val").getAsInt());
}
}
}
}
LOGGER.info(functionTran.ppToVal);
LOGGER.info(transaction.tmToVal);
sc.close();
}
static class Transaction {
Map<Integer, List<Integer>> tmToVal;
public void insert(int traceMark, int val) {
List<Integer> ret;
if (!tmToVal.containsKey(traceMark)) {
ret = new ArrayList<>();
tmToVal.put(traceMark, ret);
} else {
ret = tmToVal.get(traceMark);
}
ret.add(val);
}
}
static class FunctionTran {
Map<String, List<String>> ppToVal;
public void insert(String functionID, String val) {
List<String> ret;
if (!ppToVal.containsKey(functionID)) {
ret = new ArrayList<>();
ppToVal.put(functionID, ret);
} else {
ret = ppToVal.get(functionID);
}
ret.add(val);
}
}
}

View File

@ -0,0 +1,49 @@
package org.bdware.analysis.dynamic;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.InputStream;
import java.util.*;
public class TracedFile {
public List<Transaction> trans;
public TracedFile(InputStream in) {
Scanner sc = new Scanner(in);
trans = new ArrayList<>();
Transaction transaction = new Transaction();
transaction.tmToVal = new HashMap<Integer, List<Integer>>();
// TODO ignore handle transaction start
// TODO ignore handle contractID/method....
// TODO ignore handle transaction end
while (sc.hasNextLine()) {
JsonObject jo = JsonParser.parseString(sc.nextLine()).getAsJsonObject();
if (null != jo.get("traceMark")) {
if (null != jo.get("lval")) {
transaction.insert(jo.get("traceMark").getAsInt(), jo.get("lval").getAsInt());
transaction.insert(jo.get("traceMark").getAsInt(), jo.get("rval").getAsInt());
} else {
transaction.insert(jo.get("traceMark").getAsInt(), jo.get("val").getAsInt());
}
}
}
trans.add(transaction);
sc.close();
}
public static class Transaction {
public Map<Integer, List<Integer>> tmToVal;
public void insert(int traceMark, int val) {
List<Integer> ret;
if (!tmToVal.containsKey(traceMark)) {
ret = new ArrayList<>();
tmToVal.put(traceMark, ret);
} else {
ret = tmToVal.get(traceMark);
}
ret.add(val);
}
}
}

View File

@ -0,0 +1,94 @@
package org.bdware.analysis.example;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.taint.TaintBB;
import org.bdware.analysis.taint.TaintCFG;
import org.bdware.analysis.taint.TaintResult;
import org.bdware.analysis.taint.TaintValue;
import org.objectweb.asm.tree.MethodNode;
import java.util.*;
public class FieldSensitiveTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
private static final Logger LOGGER = LogManager.getLogger(FieldSensitiveTaintAnalysis.class);
public static boolean isDebug = false;
TaintCFG cfg;
public FieldSensitiveTaintAnalysis(TaintCFG cfg) {
this.cfg = cfg;
List<TaintBB> toAnalysis = new ArrayList<>();
/*
* NaiveTaintBB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> boolean inList NaiveTaintResult preResult NaiveTaintResult
* sucResult
*/
TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);
/*
* NaiveTaintResult<EFBFBD>еı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Frame<TaintValue> frame TaintInterpreter interpreter
* TaintValue ret InsnPrinter printer int nLocals int nStack
* NaiveTaintResult<EFBFBD>е<EFBFBD><EFBFBD> TaintValue int size boolean isTainted
* TaintInterpreter() NaiveTaintResult currentResult Frame<EFBFBD>еı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> V returnValue
* //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊvoid<EFBFBD><EFBFBD>Ϊnull V[] values //<EFBFBD>ֲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> int locals
* //<EFBFBD>ֲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĸ<EFBFBD><EFBFBD><EFBFBD> int top //<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
*/
b.preResult = new TaintResult();
// <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
int arg = cfg.argsLocal();
cfg.executeLocal();
TaintResult.interpreter.setTaintBits(cfg.taintBits);
b.preResult.frame.setLocal(arg, new TaintValue(1, cfg.taintBits.allocate("arg" + arg)));
/*
* if (NaiveTaintResult.nLocals > 2) { b.preResult.frame.setLocal(0, new
* TaintValue(1, cfg.taintBits.allocate("arg0"))); b.preResult.frame.setLocal(1,
* new TaintValue(1, cfg.taintBits.allocate("arg1")));
* b.preResult.frame.setLocal(2, new TaintValue(1,
* cfg.taintBits.allocate("arg2"))); }
*/
// .ret = TaintValue<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>size=1
b.preResult.ret = new TaintValue(1);
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>b<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD>
toAnalysis.add(b);
b.setInList(true);
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD>BreadthFirstSearch<EFBFBD><EFBFBD><EFBFBD>еĺ<EFBFBD><EFBFBD><EFBFBD>setToAnalysis<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱBreadthFirstSearch<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>toAnalysisΪ<EFBFBD><EFBFBD>ǰ<EFBFBD>Ŀ<EFBFBD><EFBFBD>б<EFBFBD>ֻ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>B0
/*
* BreadthFirstSearch<EFBFBD><EFBFBD><EFBFBD>еı<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Map<T, AnalysisResult> results; List<T>
* toAnalysis;
*/
setToAnalysis(toAnalysis);
if (isDebug) {
MethodNode methodNode = cfg.getMethodNode();
LOGGER.info("Method: " + methodNode.name + " " + methodNode.desc);
LOGGER.info("Local: " + methodNode.maxLocals + " " + methodNode.maxStack);
}
}
@Override
public TaintResult execute(TaintBB t) {
return t.forwardAnalysis();
}
// Current Block is done, merge sucResult to sucBlocks!
@Override
public Collection<TaintBB> getSuc(TaintBB t) {
// System.out.println("---------------------------------");
// System.out.println("XXXXXB" + t.blockID + " sucBlock:" +
// t.sucResult.frame2Str());
Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
Set<TaintBB> ret = new HashSet<>();
for (BasicBlock bb : subBlock) {
TaintBB ntbb = (TaintBB) bb;
ntbb.preResult.mergeResult(t.sucResult);
// System.out.println(
// "XXXXXB" + ntbb.blockID + " mergedBlock:" +
// ntbb.preResult.frame2Str() + " "
// + ntbb.preResult);
ret.add(ntbb);
}
// System.out.println("---------------------------------");
return ret;
}
}

View File

@ -0,0 +1,184 @@
package org.bdware.analysis.example;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.OpInfo;
import org.bdware.analysis.taint.*;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import java.util.*;
// 1. Dependency Analysis ..
// 2. Mulitple Source + Muliple Sink
// 3. Combine Dependency+TaintAnalysis
public class MultiSourceTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
TaintCFG cfg;
public MultiSourceTaintAnalysis(TaintCFG cfg) {
this.cfg = cfg;
List<TaintBB> toAnalysis = new ArrayList<>();
TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);
b.preResult = new TaintResult();
// Put the RootObject into the index 0 of the Local Variable Table
b.preResult.frame.setLocal(0, HeapObject.getRootObject());
// The number of parameters of this method minus one
int arg = cfg.argsLocal();
// Put the arg into the index 2 of the Local Variable Table
b.preResult.frame.setLocal(1, new TaintValue(1, cfg.taintBits.allocate("arg")));
// Find the executeContract functions and allocate taintBits
cfg.executeLocal();
TaintResult.interpreter.setTaintBits(cfg.taintBits);
b.preResult.ret = new TaintValue(1);
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
toAnalysis.add(b);
b.setInList(true);
setToAnalysis(toAnalysis);
if (TaintConfig.isDebug) {
System.out.println("===Method:" + cfg.getMethodNode().name + cfg.getMethodNode().desc);
System.out.println(
"===Local:"
+ cfg.getMethodNode().maxLocals
+ " "
+ cfg.getMethodNode().maxStack);
}
}
@Override
public TaintResult execute(TaintBB t) {
return t.forwardAnalysis();
}
@Override
public Collection<TaintBB> getSuc(TaintBB t) {
Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
Set<TaintBB> ret = new HashSet<>();
for (BasicBlock bb : subBlock) {
TaintBB ntbb = (TaintBB) bb;
if (TaintConfig.isDebug)
System.out.println(
"[MultiSoruceTaintAnalysis] B"
+ ntbb.blockID
+ " beforeMerge:"
+ ntbb.preResult.frame2Str());
ntbb.preResult.mergeResult(t.sucResult);
if (TaintConfig.isDebug)
System.out.println(
"[MultiSoruceTaintAnalysis] B"
+ ntbb.blockID
+ " afterMerge:"
+ ntbb.preResult.frame2Str());
ret.add(ntbb);
}
return ret;
}
/*
* Dependency Analysis
*/
public static Map<Integer, List<Integer>> depAnalysis(TaintCFG cfg) {
// public static Set<Integer> depAnalysis(TaintCFG cfg) {
// Step1: Find all the jump blocks
Set<Integer> depBlocks = new HashSet<>();
for (BasicBlock b : cfg.getBlocks()) {
Set<BasicBlock> suc = cfg.getSucBlocks(b);
int sucSize = suc.size();
// Get rid of some jump nodes such as "GOTO"
if (sucSize > 1) {
for (AbstractInsnNode an : b.getInsn()) {
if (an instanceof JumpInsnNode) {
int blockID = b.blockID;
depBlocks.add(blockID);
}
}
}
}
/*Step2: Traverse all the blocks, for each block, traverse all the depBlocks,
* for each depBlock, traverse all the sucBlocks,
* if all the sucBlocks are arrival from each block, then the block is dependency with the depBlock.
*/
List<BasicBlock> blocks = cfg.getBlocks();
Map<Integer, List<Integer>> map = new HashMap<>();
for (BasicBlock bb : blocks) {
List<Integer> list = new ArrayList<>();
for (int id : depBlocks) {
Set<BasicBlock> sucBlocks = cfg.getSucBlocks(cfg.getBasicBlockAt(id));
int sucSize = sucBlocks.size();
int count = 0;
for (BasicBlock sucBlock : sucBlocks) {
if (isArrival(cfg, sucBlock, bb)) count++;
}
if (count > 0 && count != sucSize) list.add(id);
}
map.put(bb.blockID, list);
}
Map<Integer, List<Integer>> returnMap = new HashMap<>();
for (Map.Entry<Integer, List<Integer>> entry : map.entrySet()) {
// System.out.print(entry.getKey() +" : ");
BasicBlock tmp = cfg.getBasicBlockAt(entry.getKey());
for (AbstractInsnNode an : tmp.getInsn()) {
int opcode;
if (an instanceof InsnNode) {
opcode = an.getOpcode();
if (OpInfo.ops[opcode].canReturn()) {
returnMap.put(entry.getKey(), entry.getValue());
}
}
}
/*
for(int i : entry.getValue())
System.out.print(i+ " ");
System.out.println();
*/
}
// add dependence to the last block
if (returnMap != null) {
List<Integer> lastBlockDep = new ArrayList<>();
for (Map.Entry<Integer, List<Integer>> entry : returnMap.entrySet()) {
List<Integer> listID = entry.getValue();
for (Integer i : listID) {
if (!lastBlockDep.contains(i)) lastBlockDep.add(i);
}
}
returnMap.put(cfg.getBasicBlockSize() - 1, lastBlockDep);
}
// TODO get value from branch block
/*
List<Integer> list = returnMap.get(cfg.getBasicBlockSize()-1);
for(int i : list) {
System.out.println(i);
TaintBB tb = (TaintBB) cfg.getBasicBlockAt(i);
System.out.println("Test:");
tb.preResult.printResult();
}
*/
return returnMap;
}
public static boolean isArrival(TaintCFG cfg, BasicBlock suc, BasicBlock bb) {
// Test
/*
if(suc.blockID == bb.blockID)
return true;
if(suc.blockID == 7 && bb.blockID == 11)
return true;
if(suc.blockID == 9 && bb.blockID == 11)
return true;
if(suc.blockID == 7 && bb.blockID == 12)
return true;
if(suc.blockID == 9 && bb.blockID == 12)
return true;
return false;
*/
if (suc.blockID == bb.blockID) return true;
DirectGraphDFS dgDFS = new DirectGraphDFS(cfg, suc);
return dgDFS.isArrival(bb);
}
}

View File

@ -0,0 +1,79 @@
package org.bdware.analysis.example;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.BreadthFirstSearch;
import org.bdware.analysis.taint.*;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.LabelNode;
import java.util.*;
public class NaiveTaintAnalysis extends BreadthFirstSearch<TaintResult, TaintBB> {
TaintCFG cfg;
public NaiveTaintAnalysis(TaintCFG cfg) {
this.cfg = cfg;
List<TaintBB> toAnalysis = new ArrayList<>();
// TODO add inputBlock!
TaintBB b = (TaintBB) cfg.getBasicBlockAt(0);
b.preResult = new TaintResult();
// local0=scriptfuncion, is not tainted;
// local1=this, is not tainted;
// local2=this, is not tainted;
if (TaintResult.nLocals > 2) {
b.preResult.frame.setLocal(0, new TaintValue(1, 0));
b.preResult.frame.setLocal(1, new TaintValue(1, 0));
b.preResult.frame.setLocal(2, new TaintValue(1, 1));
}
b.preResult.ret = new TaintValue(1);
TaintResult.printer.setLabelOrder(cfg.getLabelOrder());
toAnalysis.add(b);
b.setInList(true);
setToAnalysis(toAnalysis);
if (TaintConfig.isDebug) {
System.out.println("===Method:" + cfg.getMethodNode().name + cfg.getMethodNode().desc);
System.out.println(
"===Local:"
+ cfg.getMethodNode().maxLocals
+ " "
+ cfg.getMethodNode().maxStack);
}
}
@Override
public TaintResult execute(TaintBB t) {
return t.forwardAnalysis();
}
// Current Block is done, merge sucResult to sucBlocks!
@Override
public Collection<TaintBB> getSuc(TaintBB t) {
// System.out.println("---------------------------------");
// System.out.println("XXXXXB" + t.blockID + " sucBlock:" +
// t.sucResult.frame2Str());
Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
System.out.println("ttlist" + t.list);
System.out.println("subblock" + subBlock.size());
Set<TaintBB> ret = new HashSet<>();
AbstractInsnNode insn = t.lastInsn();
if (insn instanceof LabelNode) {
LabelNode label = ((LabelNode) insn);
System.out.println("-----");
System.out.println("label" + label.getLabel().toString());
System.out.println(cfg.getBasicBlockByLabel(label.getLabel()).blockID);
}
for (BasicBlock bb : subBlock) {
System.out.println(bb.blockID);
TaintBB ntbb = (TaintBB) bb;
ntbb.preResult.mergeResult(t.sucResult);
// System.out.println(
// "XXXXXB" + ntbb.blockID + " mergedBlock:" + ntbb.preResult.frame2Str() + " "
// + ntbb.preResult);
ret.add(ntbb);
}
// System.out.println("---------------------------------");
return ret;
}
}

View File

@ -0,0 +1,31 @@
package org.bdware.analysis.gas;
import java.util.Collection;
import java.util.List;
import org.bdware.analysis.BasicBlock;
public abstract class BFS {
protected List<BasicBlock> toAnalysis;
public abstract Collection<BasicBlock> getSuc(BasicBlock BB);
public void analysis() {
BasicBlock current = null;
for (int i = 0; i < toAnalysis.size(); i++) {
current = toAnalysis.get(i);
//current.setInList(false);
if(current.inList()) {
Collection<BasicBlock> sucs = getSuc(current);
for (BasicBlock next : sucs) {
if (!next.inList()) {
toAnalysis.add(next);
next.setInList(true);
}
}
}
}
}
public void setToAnalysis(List<BasicBlock> l) {
toAnalysis = l;
}
}

View File

@ -0,0 +1 @@
package org.bdware.analysis.gas;

View File

@ -0,0 +1,226 @@
package org.bdware.analysis.gas;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.CFGraph;
import org.bdware.analysis.OpInfo;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
public class CountProgramPoint {
public static HashMap<Integer, Map<String, Integer>> ppcount;
CFGraph actionCfg;
private String bdName;
HashMap<String, CFGraph> cfgraphMap;
String actionName;
int globalPC;
public CountProgramPoint(HashMap<String, CFGraph> cfgMap, int startPc, int endPc, String aName,
HashMap<Integer, Map<String, Integer>> ppc) {
ppcount = ppc;
cfgraphMap = cfgMap;
actionName = aName;
typeCount(startPc, endPc);
}
private HashMap<Integer, Map<String, Integer>> callCount(AbstractInsnNode insn) {
if (insn instanceof InvokeDynamicInsnNode) {
invoke = ((InvokeDynamicInsnNode) insn).bsmArgs[0];
String functionName = ((InvokeDynamicInsnNode) insn).name;
dynCount(functionName);
} else {
normalCount(insn);
}
return ppcount;
}
Object invoke = 0;
public HashMap<Integer, Map<String, Integer>> typeCount(int startPc, int endPc) {
if (startPc == 0) {
ppcount.put(startPc, new HashMap<>());
globalPC = startPc;
} else {
ppcount.put(endPc, new HashMap<>());
globalPC = endPc;
}
actionCfg = cfgraphMap.get(actionName);
int blockStart = 0, blockend = 0;
if (startPc == 0) {
blockStart = 0;
} else {
OUT: for (int j = 0; j < actionCfg.getBasicBlockSize(); j++) {
BasicBlock bb = actionCfg.getBasicBlockAt(j);
AbstractInsnNode insnNode = bb.lastInsn();
if (insnNode instanceof InvokeDynamicInsnNode) {
invoke = ((InvokeDynamicInsnNode) insnNode).bsmArgs[0];
if ((int) invoke == startPc) {
blockStart = j;
break OUT;
}
}
}
}
OUT: for (int j = 0; j < actionCfg.getBasicBlockSize(); j++) {
BasicBlock bb = actionCfg.getBasicBlockAt(j);
AbstractInsnNode insnNode = bb.lastInsn();
if (insnNode instanceof InvokeDynamicInsnNode) {
invoke = ((InvokeDynamicInsnNode) insnNode).bsmArgs[0];
if ((int) invoke == endPc) {
blockend = j;
break OUT;
}
}
}
return getInsn(blockStart, blockend);
}
private HashMap<Integer, Map<String, Integer>> getInsn(int blockStart, int blockend) {
BasicBlock t;
if (blockend == blockStart && blockStart != 0) {
System.out.println("blockend" + blockend);
t = actionCfg.getBasicBlockAt(blockend);
if (t.list.size() > 0) {
List<AbstractInsnNode> insnList = t.getInsn();
for (AbstractInsnNode insn : insnList) {
if (insn instanceof InvokeDynamicInsnNode) {
callCount(insn);
} else if (insn instanceof JumpInsnNode) {
jumpCount(insn);
} else {
normalCount(insn);
}
}
}
return ppcount;
} else if (blockend == 0) {
return ppcount;
} else if (blockend != blockStart && blockStart != 0) {
blockStart = blockStart + 1;
blockend = blockend + 1;
System.out.println(blockStart);
}
for (int i = blockStart; i < blockend; i++) {
t = actionCfg.getBasicBlockAt(i);
System.out.println("[t.blockID]" + t.blockID);
if (t.list.size() > 0) {
List<AbstractInsnNode> insnList = t.getInsn();
for (AbstractInsnNode insn : insnList) {
if (insn != null) {
OpInfo info = null;
if (insn.getOpcode() >= 0) {
info = OpInfo.ops[insn.getOpcode()];
System.out.println("[info.toString()]" + info.toString());
}
if (info == null) {
} else if (info.canThrow()) {
callCount(insn);
} else if (info.canBranch()) {
jumpCount(insn);
} else if (info.canContinue()) {
normalCount(insn);
} else if (info.canReturn()) {
normalCount(insn);
} else if (info.canSwitch()) {
normalCount(insn);
} else {
System.out.println("[info:else]" + info);
normalCount(insn);
}
}
}
}
}
return ppcount;
}
private void normalCount(AbstractInsnNode insn) {
bdName = FeeSchedule.BDInsn.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
}
private void jumpCount(AbstractInsnNode insn) {
bdName = FeeSchedule.BDjump.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
}
private void dynCount(String functionName) {
if (functionName.contains("getProp")) {
bdName = FeeSchedule.BDgetMethod.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
System.out.println(" function " + functionName);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
} else if (functionName.contains("setProp")) {
bdName = FeeSchedule.BDsetMethod.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
System.out.println(" function " + functionName);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
} else if (functionName.contains("call") && functionName.contains("Util")) {
bdName = FeeSchedule.BDcallUtil.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
System.out.println(" function " + functionName);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
} else if (functionName.contains("call") && isInnerfunction(functionName)) {
bdName = FeeSchedule.BDcallFuntion.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
System.out.println(" function " + functionName);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
} else if (functionName.contains("call")) {
bdName = FeeSchedule.BDcallUtil.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
System.out.println(" function " + functionName);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
} else {
bdName = FeeSchedule.BDInsn.name();
if (ppcount.get(globalPC).containsKey(bdName)) {
ppcount.get(globalPC).put(bdName, ppcount.get(globalPC).get(bdName) + 1);
} else {
ppcount.get(globalPC).put(bdName, 1);
}
}
}
private boolean isInnerfunction(String functionName) {
String string = functionName.split(":")[2];
if (cfgraphMap.containsKey(string)) {
return true;
} else {
return false;
}
}
}

View File

@ -0,0 +1,25 @@
package org.bdware.analysis.gas;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.CFGraph;
import java.util.Set;
public abstract class DFS {
private boolean[] marked = new boolean[2048];
public abstract Set<BasicBlock> getSuc(BasicBlock BB);
public void dfs(CFGraph cfg, BasicBlock start) {
marked[start.blockID] = true;
// System.out.println("[start.blockID]" + start.blockID);
Set<BasicBlock> sucBlocks = getSuc(start);
for (BasicBlock bb : sucBlocks) {
if (!marked[bb.blockID]) dfs(cfg, bb);
}
}
public boolean isArrival(BasicBlock end) {
return marked[end.blockID];
}
}

View File

@ -0,0 +1,96 @@
package org.bdware.analysis.gas;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Evaluates {
Map<Integer, HashMap<String, Integer>> callFunctionResult;
Map<Integer, Long> CountResult = new HashMap<>();
public Map<Integer, Long> getCallFee() {
for (Entry<Integer, HashMap<String, Integer>> c : callFunctionResult.entrySet()) {
Integer cfrKey = c.getKey();
long value = 0;
HashMap<String, Integer> map = c.getValue();
for (Entry<String, Integer> cmap : map.entrySet()) {
long fee = getValue(cmap.getKey());
value = fee * cmap.getValue() + value;
}
CountResult.put(cfrKey, value);
}
return CountResult;
}
public long getValue(String name) {
long value = 0;
switch (name) {
case "BDgetMethod":
value = FeeSchedule.BDgetMethod.getFee();
break;
case "BDsetMethod":
value = FeeSchedule.BDsetMethod.getFee();
break;
case "BDnew":
value = FeeSchedule.BDnew.getFee();
break;
case "BDcallUtil":
value = FeeSchedule.BDcallUtil.getFee();
break;
case "BDcallFuntion":
value = FeeSchedule.BDcallFuntion.getFee();
break;
case "BDcall":
value = FeeSchedule.BDcall.getFee();
break;
case "BDjump":
value = FeeSchedule.BDjump.getFee();
break;
case "BDInsn":
value = FeeSchedule.BDInsn.getFee();
break;
default:
break;
}
return value;
}
long sum;
Set<HashMap<String, Long>> set = new HashSet<>();
public void getGas(HashMap<String, Set<Map<Integer, HashMap<String, Integer>>>> branchCount) {
for (Entry<String, Set<Map<Integer, HashMap<String, Integer>>>> varInsn :
branchCount.entrySet()) {
sum = 0;
for (Map<Integer, HashMap<String, Integer>> m : varInsn.getValue()) {
blockGas(m);
}
map.put(varInsn.getKey(), sum);
}
}
private void blockGas(Map<Integer, HashMap<String, Integer>> m) {
for (Entry<Integer, HashMap<String, Integer>> map : m.entrySet()) {
for (Entry<String, Integer> insnMap : map.getValue().entrySet()) {
long value = getValue(insnMap.getKey()) * insnMap.getValue();
sum = sum + value;
}
}
}
public static HashMap<String, Long> map = new HashMap<>();
public void getInsnGas(Map<Integer, Set<Map<Integer, HashMap<String, Integer>>>> ppMap) {
for (Entry<Integer, Set<Map<Integer, HashMap<String, Integer>>>> varInsn :
ppMap.entrySet()) {
sum = 0;
for (Map<Integer, HashMap<String, Integer>> m : varInsn.getValue()) {
blockGas(m);
}
map.put(varInsn.getKey().toString(), sum);
}
}
}

View File

@ -0,0 +1,51 @@
package org.bdware.analysis.gas;
public enum FeeSchedule {
// BDaload(20L),BDstore(200L),
BDgetMethod(10L), BDsetMethod(20L), BDnew(20L),BDcallUtil(30L), BDcallFuntion(40L), BDcall(10L), BDjump(15L), BDInsn(1L);
long fee;
FeeSchedule(long value) {
fee = value;
}
public long getFee() {
return fee;
}
public long getValue(String name) {
long value=0;
switch (name) {
case "BDgetMethod":
value=BDgetMethod.getFee();
break;
case "BDsetMethod":
value= BDsetMethod.getFee();
break;
case "BDcallUtil":
value= BDcallUtil.getFee();
break;
case "BDcallFuntion":
value= BDcallFuntion.getFee();
break;
case "BDcall":
value= BDcall.getFee();
break;
case "BDjump":
value= BDjump.getFee();
break;
case "BDInsn":
value= BDInsn.getFee();
break;
default:
break;
}
return value;
}
public String getString(FeeSchedule feeName) {
return feeName.toString();
}
}

View File

@ -0,0 +1,450 @@
package org.bdware.analysis.gas;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.CFGraph;
import org.bdware.analysis.OpInfo;
import org.bdware.analysis.gas.DFS;
import org.bdware.analysis.gas.FeeSchedule;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
public class PPCount extends DFS {
CFGraph cfg;
String functionGlobel;
private String bdName;
private int globalInvoke = 0;
static List<String> functionList = new ArrayList<>();
private int globalBlockID;
public static Map<String, HashMap<String, Integer>> varInsnCount = new HashMap<>();
public static HashMap<String, Set<Map<Integer, HashMap<String, Integer>>>> branchCount =
new HashMap<>();;
public static Map<Integer, HashMap<String, Integer>> callFunction = new HashMap<>();
public static Map<Integer, HashMap<String, Integer>> BlockInsn = new HashMap<>();
public static Map<Integer, Set<Map<Integer, HashMap<String, Integer>>>> ppMap = new HashMap<>();
public HashSet<Integer> countBlock = new HashSet<>();
boolean[] isBranchBlock;
public PPCount(CFGraph cfg, int flag) {
this.cfg = cfg;
functionGlobel = cfg.getMethodNode().name;
varInsnCount.put(functionGlobel, new HashMap<>());
globalInvoke = flag;
ppMap.put(globalInvoke, new HashSet<>());
callFunction.put(flag, new HashMap<>());
List<BasicBlock> toAnalysis = new ArrayList<>();
BasicBlock b = cfg.getBasicBlockAt(0);
toAnalysis.add(b);
b.setInList(true);
// System.out.println("=========:"+cfg.getMethodNode().name);
functionList.add(cfg.getMethodNode().name);
isBranchBlock = new boolean[cfg.getBasicBlockSize()];
// setToAnalysis(toAnalysis);
}
// @Override
// public Collection<BasicBlock> getSuc(BasicBlock t) {
// System.out.println("++++++++++" + t.blockID);
// typeCount(t);
// Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
// DFS dgDFS = new DFS(cfg, t);
//
// return subBlock;
// }
@Override
public Set<BasicBlock> getSuc(BasicBlock t) {
// System.out.println("++++++++++" + t.blockID);
Set<BasicBlock> subBlock = cfg.getSucBlocks(t);
typeCount(t);
return subBlock;
}
private void typeCount(BasicBlock t) { // 一个基本块里面的所有指令
int count = 0;
countBlock.add(t.blockID);
globalBlockID = t.blockID;
BlockInsn.put(t.blockID, new HashMap<>());
List<AbstractInsnNode> insnList = t.getInsn();
OpInfo info = null;
if (t.list.size() > 0) {
for (AbstractInsnNode ab : insnList) {
if (ab != null) {
if (ab.getOpcode() >= 0) {
count++;
}
}
}
}
t.insnCount = count;
if (t.list.size() > 0) {
for (int i = 0; i < insnList.size(); i++) {
AbstractInsnNode insn = insnList.get(i);
if (insn != null) {
if (insn.getOpcode() >= 0) {
info = OpInfo.ops[insn.getOpcode()];
}
if (info == null) {
} else if (info.canThrow()) {
callCount(insn, t);
} else if (info.canBranch()) {
normalCount(insn, t);
jumpCount(insn, t);
} else if (info.canContinue() || info.canSwitch() || info.canReturn()) {
normalCount(insn, t);
}
}
}
}
addBlock(t);
removeBranch();
}
int jumpBlockid = -1;
int conBlockid = -1;
private boolean isBranch = false;
private List<Integer> globalBranch = new ArrayList<>();
private void jumpCount(AbstractInsnNode insn, BasicBlock t) {
switch (insn.getOpcode()) {
case Opcodes.IFNE: // succeeds if and only if value ≠ 0
case Opcodes.IFEQ: // succeeds if and only if value = 0
case Opcodes.IFLT: // succeeds if and only if value < 0
case Opcodes.IFLE:
case Opcodes.IFGE: // succeeds if and only if value 0
isBranch = true;
globalBranch.add(globalInvoke);
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
Map<Integer, HashMap<String, Integer>> map2 = new HashMap<>();
Set<Map<Integer, HashMap<String, Integer>>> ret = new HashSet<>();
Set<Map<Integer, HashMap<String, Integer>>> ret2 = new HashSet<>();
map.put(t.blockID, BlockInsn.get(t.blockID));
map2.put(t.blockID - 1, BlockInsn.get(t.blockID - 1));
ret.add(map);
ret.add(map2);
ret2.add(map);
ret2.add(map2);
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
jumpBlockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
branchCount.put(globalInvoke + "false" + jumpBlockid, ret);
}
conBlockid = t.blockID + 1;
branchCount.put(globalInvoke + "true" + conBlockid, ret2);
// System.out.println(branchCount);
break;
case Opcodes.IFGT: // succeeds if and only if value > 0
if (insn instanceof JumpInsnNode) {
LabelNode jump = ((JumpInsnNode) insn).label;
jumpBlockid = cfg.getBasicBlockByLabel(jump.getLabel()).blockID;
branchCount.put(globalInvoke + "false" + jumpBlockid, new HashSet<>());
}
conBlockid = t.blockID + 1;
branchCount.put(globalInvoke + "true" + conBlockid, new HashSet<>());
// System.out.println(branchCount);
break;
case Opcodes.IF_ACMPEQ: // succeeds if and only if value1 = value2
case Opcodes.IF_ACMPNE: // succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPEQ: // succeeds if and only if value1 = value2
case Opcodes.IF_ICMPGE: // succeeds if and only if value1 ≠ value2
case Opcodes.IF_ICMPGT: // succeeds if and only if value1 > value2
case Opcodes.IF_ICMPLE: // succeeds if and only if value1 value2
case Opcodes.IF_ICMPLT: // succeeds if and only if value1 < value2
case Opcodes.IFNONNULL:
case Opcodes.TABLESWITCH:
case Opcodes.LOOKUPSWITCH:
case Opcodes.GOTO:
lastBlockId = t.blockID + 1;
default:
break;
}
}
int lastBlockId = 0;
int globalBlock = 0;
private void normalCount(AbstractInsnNode insn, BasicBlock t) {
if (t.blockID != lastBlockId) {
lastBlockId = t.blockID;
globalBlock = 0;
}
OpInfo info = OpInfo.ops[insn.getOpcode()];
bdName = FeeSchedule.BDInsn.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID).put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
globalBlock++;
if (globalBranch.size() != 0) {
int gb = globalBranch.get(globalBranch.size() - 1);
if (gb == globalInvoke) {
if (globalBlock == t.insnCount && !(insn instanceof JumpInsnNode)) {
chosenBranch(t);
}
}
}
}
private void chosenBranch(BasicBlock t) {
if (globalBranch.size() != 0) {
int branch = globalBranch.get(globalBranch.size() - 1);
Set<Map<Integer, HashMap<String, Integer>>> ret = new HashSet<>();
if (isBranch && t.blockID < jumpBlockid) {
isBranchBlock[t.blockID] = true;
if (branchCount.get(branch + "true" + conBlockid) != null
&& !branchCount.get(branch + "true" + conBlockid).isEmpty()) {
ret = branchCount.get(branch + "true" + conBlockid);
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
map.put(t.blockID, BlockInsn.get(t.blockID));
ret.add(map);
branchCount.put(branch + "true" + conBlockid, ret);
} else if (branchCount.get(branch + "true" + conBlockid) != null) {
ret = branchCount.get(branch + "true" + conBlockid);
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
map.put(t.blockID, BlockInsn.get(t.blockID));
branchCount.get(branch + "true" + conBlockid).add(map);
}
} else if (isBranch && t.blockID >= jumpBlockid) {
isBranchBlock[t.blockID] = true;
if (branchCount.get(branch + "false" + jumpBlockid) != null
&& !branchCount.get(branch + "false" + jumpBlockid).isEmpty()) {
Set<Map<Integer, HashMap<String, Integer>>> list =
branchCount.get(branch + "false" + jumpBlockid);
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
map.put(t.blockID, BlockInsn.get(t.blockID));
list.add(map);
branchCount.put(branch + "false" + jumpBlockid, list);
} else if (branchCount.get(branch + "false" + jumpBlockid) != null) {
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
if (ret.isEmpty()) {
map.put(t.blockID, BlockInsn.get(t.blockID));
branchCount.get(branch + "false" + jumpBlockid).add(map);
}
}
}
}
}
int perBlockId = 0;
public void removeBranch() {
if (!globalBranch.isEmpty()) {
for (int i = 0; i < globalBranch.size(); i++) {
if (ppMap.containsKey(globalBranch.get(i))) {
ppMap.remove(globalBranch.get(i));
}
}
}
}
private void callCount(AbstractInsnNode insn, BasicBlock t) {
boolean isNewCall = false;
lastBlockId = t.blockID;
if (insn instanceof InvokeDynamicInsnNode) {
Object invoke = ((InvokeDynamicInsnNode) insn).bsmArgs[0];
String functionName = ((InvokeDynamicInsnNode) insn).name;
isNewCall = true;
if ((int) invoke > 5) {
dynCount(functionName);
globalInvoke = (int) invoke;
ppMap.put((int) invoke, new HashSet<>());
perBlockId = t.blockID;
} else {
dynCount(functionName);
}
} else {
normalCount(insn, t);
}
if (!isNewCall || t.blockID == jumpBlockid || t.blockID == conBlockid) {
branchEnd = true;
chosenBranch(t);
}
}
private void addBlock(BasicBlock t) {
if (t.list.size() > 0) {
Set<Map<Integer, HashMap<String, Integer>>> ret = new HashSet<>();
Map<Integer, HashMap<String, Integer>> map = new HashMap<>();
map.put(t.blockID, BlockInsn.get(t.blockID));
if (!isBranchBlock[t.blockID]) {
if (!ppMap.containsKey(globalInvoke)) {
ppMap.put(globalInvoke, new HashSet<>());
}
ppMap.get(globalInvoke).add(map);
}
}
}
boolean branchEnd;
private void dynCount(String functionName) {
String function = functionName.split(":")[1];
if (function.contains("getProp")) {
bdName = FeeSchedule.BDgetMethod.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
} else if (function.contains("setProp")) {
bdName = FeeSchedule.BDsetMethod.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
} else if (function.contains("new")) {
bdName = FeeSchedule.BDnew.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
} else if (function.contains("call") && functionName.split(":")[2].contains("Util")) {
bdName = FeeSchedule.BDcallUtil.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
} else if (function.contains("call") && isInnerfunction(functionName)) {
// System.out.println("[call ]" + functionName);
String methName = functionName.split(":")[2];
bdName = FeeSchedule.BDcallFuntion.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(
bdName + "," + methName,
BlockInsn.get(globalBlockID).get(bdName + "," + methName) + 1);
System.out.println(" function " + functionName);
} else {
BlockInsn.get(globalBlockID).put(bdName + "," + methName, 1);
}
} else if (function.contains("call")) {
bdName = FeeSchedule.BDcall.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
} else if (functionName.contains("traceif")) {
bdName = FeeSchedule.BDjump.name();
if (BlockInsn.get(globalBlockID).containsKey(bdName)) {
BlockInsn.get(globalBlockID)
.put(bdName, BlockInsn.get(globalBlockID).get(bdName) + 1);
} else {
BlockInsn.get(globalBlockID).put(bdName, 1);
}
}
}
private boolean isInnerfunction(String functionName) {
String string = functionName.split(":")[2];
// System.out.println("++++++++++++++" + functionName);
// System.out.println("【function】" + functionList);
if (functionList.contains(string)) {
return true;
} else {
return false;
}
}
// public static void main(String[] args) throws Exception {
// String path = "/Users/hulingxuan/git/SmartContract/output/main.yjs";
// ContractNode contractNode = null;
// YJSCompiler compiler = new YJSCompiler();
// contractNode = compiler.compile(new FileInputStream(path), null);
// engine = new DesktopEngine();
// engine.loadContract(contractNode, false);
//
// Map<String, byte[]> clzs = engine.dumpClass();
// Map<String, MethodNode> methods = new HashMap<>();
// for (byte[] clz : clzs.values()) {
// ClassNode classNode = new ClassNode();
// ClassReader cr = new ClassReader(clz);
// cr.accept(classNode, ClassReader.EXPAND_FRAMES);
// for (MethodNode mn : classNode.methods) {
// methods.put(mn.name, mn);
// }
// }
// int flag = 0;
// for (FunctionNode fn : contractNode.getFunctions()) {
// functionList.add(fn.functionName);
// MethodNode mn = methods.get(fn.functionName);
// if (mn != null) {
// CFGraph cfg = new CFGraph(mn) {
// @Override
// public BasicBlock getBasicBlock(int id) {
// return new BasicBlock(id);
// }
// };
// // cfg.getLabelOrder();
// PPCount countFee = new PPCount(cfg, flag);
//
// BasicBlock bb = cfg.getBasicBlockAt(0);
// countFee.dfs(cfg, bb);
// // cfg.printSelf();
//
// Evaluates feEvaluates = new Evaluates();
// feEvaluates.getGas(branchCount);
// feEvaluates.getInsnGas(ppMap);
// countFunction(fn.functionName, Evaluates.map);
// System.out.println("+++++++" + functionSumGas);
// System.out.println("========" + Evaluates.map);
// flag++;
// }
// }
// System.out.println(branchCount);
// System.out.println(BlockInsn);
// System.out.println(ppMap);
//
// // System.out.println(feEvaluates.getCallFee());
// }
public static HashMap<String, Long> functionSumGas = new HashMap<>();
public static void countFunction(String functionName, HashMap<String, Long> map) {
long sumTrue = 0;
long sumFalse = 0;
long sum = 0;
for (Map.Entry<String, Long> entry : map.entrySet()) {
if (entry.getKey().contains("true")) {
sumTrue = entry.getValue();
} else if (entry.getKey().contains("false")) {
sumFalse = entry.getValue();
} else {
sum += entry.getValue();
}
}
functionSumGas.put(functionName, sum);
functionSumGas.put(functionName + "true", sumTrue);
functionSumGas.put(functionName + "false", sumFalse);
}
}

View File

@ -0,0 +1,28 @@
package org.bdware.analysis.taint;
import java.util.Set;
import org.bdware.analysis.BasicBlock;
public class DirectGraphDFS {
private boolean[] marked;
public DirectGraphDFS(TaintCFG cfg, BasicBlock start) {
marked = new boolean[cfg.getBlocks().size()];
dfs(cfg, start);
}
private void dfs(TaintCFG cfg, BasicBlock start) {
marked[start.blockID] = true;
Set<BasicBlock> sucBlocks = cfg.getSucBlocks(start);
for(BasicBlock bb : sucBlocks) {
if(!marked[bb.blockID])
dfs(cfg, bb);
}
}
public boolean isArrival(BasicBlock end) {
return marked[end.blockID];
}
}

View File

@ -0,0 +1,247 @@
package org.bdware.analysis.taint;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
public class HeapObject extends TaintValue {
private Map<String, TaintValue> fields = new HashMap<String, TaintValue>();
static int allocatID = 0;
int id;
public HeapObject() {
super(1);
id = allocatID++;
}
public HeapObject(TaintValue t) {
this();
if (t != null) {
merge(t);
size = t.size;
} else {
isTainted = 0;
size = 1;
}
}
public static HeapObject getRootObject() {
HeapObject ret = new HeapObject();
ret.setProp("Global", new HeapObject());
ret.setProp("getScope", new HeapObject());
return ret;
}
@Override
public String toString() {
return countSize() + "|" + super.toString();
}
private String countSize() {
objSet = new HashSet<>();
return countSizeInternal();
}
private String countSizeInternal() {
if (objSet.contains(this))
return "{H" + id + "}";
objSet.add(this);
String ret = "{H" + id + ",";
for (String field : fields.keySet()) {
TaintValue tv = fields.get(field);
if (tv instanceof HeapObject)
ret += field + ":" + ((HeapObject) tv).countSizeInternal() + ",";
else
ret += field + ":" + tv.isTainted;
}
ret += isTainted + "}";
return ret;
}
private static HashSet<HeapObject> objSet;
public static TaintValue operate(AbstractInsnNode insn, List<? extends TaintValue> values,
TaintValue calculatedVal) {
TaintValue retVal = null;
String desc;
switch (insn.getOpcode()) {
case Opcodes.INVOKEVIRTUAL:
desc = ((MethodInsnNode) insn).owner;
if (isGetScopeObject((MethodInsnNode) insn) && values.size() != 0) {
TaintValue tv = values.get(0);
if (tv instanceof HeapObject) {
HeapObject heapObject = (HeapObject) tv;
retVal = heapObject.getProp("getScope");
if (retVal == null) {
return calculatedVal;
} else
return retVal;
}
}
break;
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE:
break;
case Opcodes.INVOKEDYNAMIC:
desc = ((InvokeDynamicInsnNode) insn).name;
desc = desc.replaceAll(".*:", "");
if (isDynGet((InvokeDynamicInsnNode) insn)) {
TaintValue tval = values.get(0);
if (tval instanceof HeapObject) {
HeapObject heapObject = (HeapObject) tval;
retVal = heapObject.getProp(desc);
if (retVal != null) {
if (TaintConfig.isDebug)
System.out.println("[HeapObject] get:" + desc + " taintVal:" + retVal);
return retVal;
} else {
if (TaintConfig.isDebug)
System.out.println("[HeapObject] get:" + desc + " taintVal: empty");
heapObject.setProp(desc, new HeapObject());
return heapObject.getProp(desc);
}
} else {
// TODO
}
} else if (isDynSet((InvokeDynamicInsnNode) insn)) {
// TaintValue tv = values.get(0);
if (TaintConfig.isDebug)
System.out.println("[HeapObject] set:" + desc + " taintVal:" + values.get(1));
TaintValue tval = values.get(0);
if (tval instanceof HeapObject) {
HeapObject heapObject = (HeapObject) tval;
// heapObject.merge(values.get(1));
heapObject.setProp(desc,
values.get(1) instanceof HeapObject ? values.get(1) : new HeapObject(values.get(1)));
} else {
HeapObject heapObject = new HeapObject(tval);
heapObject.merge(tval);
// heapObject.merge(values.get(1));
heapObject.setProp(desc, values.get(1));
}
} else {
for (TaintValue tv : values) {
if (tv instanceof HeapObject) {
calculatedVal.isTainted |= ((HeapObject) tv).wholeTaint();
}
}
}
break;
default:
}
return calculatedVal;
}
private static boolean isDynGet(InvokeDynamicInsnNode insn) {
String desc = insn.name;
if (desc.contains("getProp") && desc.contains("getMethod") && desc.contains("getElem")) {
return true;
}
return false;
}
private static boolean isDynSet(InvokeDynamicInsnNode insn) {
String desc = insn.name;
if (desc.contains("setProp") && desc.contains("setElem")) {
// System.out.println(desc);
return true;
}
return false;
}
private static boolean isGetScopeObject(MethodInsnNode insn) {
if (insn.owner.contains("wrp/jdk/nashorn/internal/runtime/ScriptFunction") && insn.name.equals("getScope"))
return true;
return false;
}
public TaintValue getProp(String str) {
return fields.get(str);
}
public TaintValue setProp(String str, TaintValue val) {
return fields.put(str, val);
}
@Override
public HeapObject clone() {
return this;
}
public HeapObject actualClone() {
ccObj = new HashMap<>();
return cloneInternal();
}
static Map<HeapObject, HeapObject> ccObj;
private HeapObject cloneInternal() {
if (ccObj.containsKey(this))
return ccObj.get(this);
HeapObject ho = new HeapObject();
ccObj.put(this, ho);
ho.isTainted = isTainted;
for (String field : fields.keySet()) {
TaintValue target = fields.get(field);
if (target instanceof HeapObject)
ho.fields.put(field, ((HeapObject) target).cloneInternal());
else
ho.fields.put(field, target.clone());
}
return ho;
}
// TODO consider the "Cite circle"
public void heapMerge(TaintValue target) {
merge(target);
if (target instanceof HeapObject) {
HeapObject targetObject = (HeapObject) target;
for (String field : targetObject.fields.keySet()) {
if (fields.containsKey(field)) {
TaintValue t2 = fields.get(field);
TaintValue target2 = targetObject.fields.get(field);
// System.out.println("[HeapObject heapMerge]:" + field);
if (t2 instanceof HeapObject) {
((HeapObject) t2).heapMerge(target2);
} else if (target2 instanceof HeapObject) {
HeapObject next = ((HeapObject) target2).clone();
next.merge(t2);
fields.put(field, next);
} else
t2.merge(target2);
} else
fields.put(field, targetObject.fields.get(field).clone());
}
}
}
public synchronized long wholeTaint() {
objSet = new HashSet<>();
return wholeTaintInternal();
}
private long wholeTaintInternal() {
if (objSet.contains(this))
return 0L;
objSet.add(this);
long ret = isTainted;
for (TaintValue tv : fields.values()) {
if (tv instanceof HeapObject)
ret |= ((HeapObject) tv).wholeTaintInternal();
else
ret |= tv.isTainted;
}
return ret;
}
}

View File

@ -0,0 +1,70 @@
package org.bdware.analysis.taint;
import java.util.List;
import org.bdware.analysis.AnalysisTarget;
import org.bdware.analysis.BasicBlock;
import org.objectweb.asm.tree.AbstractInsnNode;
public class TaintBB extends BasicBlock implements AnalysisTarget {
boolean inList = false;
public TaintBB(int id) {
super(id);
preResult = new TaintResult();
sucResult = new TaintResult();
}
public TaintResult preResult;
public TaintResult sucResult;
@Override
public boolean inList() {
return inList;
}
@Override
public void setInList(boolean b) {
inList = b;
}
public String getResult() {
return (sucResult.frame2Str() + " Ret:" + sucResult.ret.toString());
}
public String getResultWithTaintBit() {
return "Ret:" + sucResult.ret.toReadableTaint();
}
public TaintResult forwardAnalysis() {
TaintResult oldSuc = sucResult;
sucResult = (TaintResult) preResult.clone();
TaintResult currentResult = sucResult;
List<AbstractInsnNode> insns = getInsn();
if (TaintConfig.isDebug)
System.out.println("[TaintBB] Enter B" + blockID + ":" + getResult() + " size:" + insns.size());
for (int i = 0; i < insns.size(); i++) {
currentResult = (TaintResult) currentResult.merge(insns.get(i));
}
currentResult.mergeResult(oldSuc);
if (TaintConfig.isDebug)
System.out.println("[TaintBB] Leave B" + blockID + ":" + getResult() + " size:" + insns.size());
// already done.
return currentResult;
}
public AbstractInsnNode lastInsn() {
return list.get(list.size() - 1);
}
public AbstractInsnNode firstInsn() {
return list.get(0);
}
public List<AbstractInsnNode> AllInsn() {
return list;
}
}

View File

@ -0,0 +1,68 @@
package org.bdware.analysis.taint;
import java.util.HashMap;
import java.util.Map;
public class TaintBits {
Map<Long, String> data;
Map<String, Long> type2Taint;
long curr;
Map<String, String> reallocate;
int count = 0;
public TaintBits() {
curr = 1L;
data = new HashMap<>();
type2Taint = new HashMap<>();
reallocate = new HashMap<>();
}
public long allocate(String type) {
type = reallocateCall(type);
if (type2Taint.containsKey(type))
return type2Taint.get(type);
long ret = curr;
data.put(curr, type);
type2Taint.put(type, curr);
curr <<= 1;
return ret;
}
private String reallocateCall(String type) {
if (reallocate.containsKey(type))
return reallocate.get(type);
if (type.contains("dyn:call:executeContract")) {
reallocate.put(type, "executeContract" + (count++));
return reallocate.get(type);
}
return type;
}
public long getTaintValue(String type) {
type = reallocateCall(type);
if (type2Taint.containsKey(type))
return type2Taint.get(type);
return -1;
}
public String taintInfo() {
String ret = "";
long curr = this.curr >> 1;
for (; curr >= 1L;) {
ret += data.get(curr) + ", ";
curr >>= 1;
}
return ret;
}
public String parse(long isTainted) {
String ret = "";
long curr = this.curr >> 1;
for (; curr >= 1L;) {
if ((isTainted & curr) != 0)
ret += data.get(curr) + " ";
curr >>= 1;
}
return ret;
}
}

View File

@ -0,0 +1,84 @@
package org.bdware.analysis.taint;
import java.util.List;
import org.bdware.analysis.BasicBlock;
import org.bdware.analysis.CFGraph;
import org.bdware.analysis.InsnPrinter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodNode;
public class TaintCFG extends CFGraph {
public TaintBits taintBits;
public TaintCFG(MethodNode mn) {
super(mn);
taintBits = new TaintBits();
}
@Override
public BasicBlock getBasicBlock(int id) {
return new TaintBB(id);
}
public int argsLocal() {
String desc = getMethodNode().desc;
String[] parameters = desc.split("[)]");
String parameter = parameters[0];
String[] args = parameter.split("[;]");
return args.length - 1;
}
public void executeLocal() {
for (BasicBlock bb : basicBlocks) {
for (AbstractInsnNode an : bb.getInsn()) {
if (an instanceof InvokeDynamicInsnNode) {
InvokeDynamicInsnNode inDy = (InvokeDynamicInsnNode) an;
if (inDy.name.contains("dyn:call:executeContract")) {
taintBits.allocate(inDy.name + inDy.hashCode());
}
}
}
}
return;
}
public void printSelf() {
InsnPrinter printer = new InsnPrinter(Opcodes.ASM4, System.out);
printer.setLabelOrder(getLabelOrder());
System.out.println("======Method:" + getMethodNode().name + getMethodNode().desc + "=======");
System.out.println("=====TaintInfo: " + taintBits.taintInfo() + "===========");
for (BasicBlock bb : basicBlocks) {
System.out.print("==B" + bb.blockID);
if (getSucBlocks(bb).size() > 0)
System.out.print("-->");
for (BasicBlock suc : getSucBlocks(bb))
System.out.print(" B" + suc.blockID);
System.out.println("==");
TaintBB b = (TaintBB) bb;
if (b.preResult != null) {
System.out.print("前序分析结果:");
b.preResult.printResult();
//System.out.println("test:"+b.getResultWithTaintBit());
}
for (AbstractInsnNode an : bb.getInsn()) {
an.accept(printer);
}
}
}
public TaintBB getLastBlock() {
if (basicBlocks != null && basicBlocks.size() > 0)
return (TaintBB) basicBlocks.get(basicBlocks.size() - 1);
return null;
}
public List<BasicBlock> getBlocks() {
return basicBlocks;
}
}

View File

@ -0,0 +1,5 @@
package org.bdware.analysis.taint;
public class TaintConfig {
public static boolean isDebug = false;
}

View File

@ -0,0 +1,177 @@
package org.bdware.analysis.taint;
import java.util.List;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Interpreter;
public class TaintInterpreter extends Interpreter<TaintValue> {
TaintResult currentResult;
TaintBits taintBits;
public TaintInterpreter(int api) {
super(api);
}
@Override
public TaintValue newValue(Type type) {
if (type != null)
return new TaintValue(type.getSize());
return new TaintValue(1);
}
@Override
public TaintValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
TaintValue ret;
switch (insn.getOpcode()) {
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
ret = new TaintValue(2);
break;
case Opcodes.NEW:
TypeInsnNode typeNode = (TypeInsnNode) insn;
if (typeNode.desc.startsWith("wrp/jdk/nashorn/internal/scripts/JO")) {
ret = new HeapObject();
} else {
ret = new TaintValue(1);
}
break;
default:
ret = new TaintValue(1);
}
return ret;
}
@Override
public TaintValue copyOperation(AbstractInsnNode insn, TaintValue value) throws AnalyzerException {
return value;
}
@Override
public TaintValue unaryOperation(AbstractInsnNode insn, TaintValue value) throws AnalyzerException {
return value;
}
@Override
public TaintValue binaryOperation(AbstractInsnNode insn, TaintValue value1, TaintValue value2)
throws AnalyzerException {
/*
* IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD, LADD,
* FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV,
* DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR, LUSHR, IAND,
* LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE,
* PUTFIELD
*/
TaintValue ret = new TaintValue(1);
ret.isTainted = value1.isTainted | value2.isTainted;
switch (insn.getOpcode()) {
case Opcodes.DALOAD:
case Opcodes.DADD:
case Opcodes.DSUB:
case Opcodes.DMUL:
case Opcodes.DDIV:
case Opcodes.DREM:
case Opcodes.LALOAD:
case Opcodes.LADD:
case Opcodes.LSUB:
case Opcodes.LMUL:
case Opcodes.LDIV:
case Opcodes.LREM:
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.LUSHR:
case Opcodes.LAND:
case Opcodes.LXOR:
case Opcodes.LOR:
ret.size = 2;
default:
}
return ret;
}
@Override
public TaintValue ternaryOperation(AbstractInsnNode insn, TaintValue value1, TaintValue value2, TaintValue value3)
throws AnalyzerException {
// TODO
value1.isTainted |= value3.isTainted;
return value1;
}
@Override
public TaintValue naryOperation(AbstractInsnNode insn, List<? extends TaintValue> values) throws AnalyzerException {
int size = 1;
/*
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, MULTIANEWARRAY
* and INVOKEDYNAMIC
*/
String desc;
switch (insn.getOpcode()) {
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE:
desc = ((MethodInsnNode) insn).desc;
if (desc != null && (desc.charAt(desc.length() - 1) == 'D' || desc.charAt(desc.length() - 1) == 'J'))
size = 2;
break;
case Opcodes.INVOKEDYNAMIC:
desc = ((InvokeDynamicInsnNode) insn).desc;
if (desc != null && (desc.charAt(desc.length() - 1) == 'D' || desc.charAt(desc.length() - 1) == 'J'))
size = 2;
// Extra..Judgeffff x
if (((InvokeDynamicInsnNode) insn).name.startsWith("dyn:setElem|setProp:")) {
if (values.size() == 2) {
values.get(0).isTainted |= values.get(1).isTainted;
}
}
break;
default:
}
TaintValue ret = new TaintValue(size);
for (TaintValue v : values)
if (v != null)
ret.isTainted |= v.isTainted;
if (insn instanceof InvokeDynamicInsnNode) {
long taint = (taintBits.getTaintValue(((InvokeDynamicInsnNode) insn).name + insn.hashCode()));
if (taint > 0L)
ret.isTainted |= taint;
}
return HeapObject.operate(insn, values, ret);
}
@Override
public void returnOperation(AbstractInsnNode insn, TaintValue value, TaintValue expected) throws AnalyzerException {
if (value instanceof HeapObject) {
currentResult.ret.isTainted |= ((HeapObject) value).wholeTaint();
} else if (value!=null)
currentResult.ret.isTainted |= value.isTainted;
}
@Override
public TaintValue merge(TaintValue v, TaintValue w) {
TaintValue ret = new TaintValue(v.getSize());
ret.isTainted |= v.isTainted;
ret.isTainted |= w.isTainted;
return ret;
}
public void setCurrentResult(TaintResult naiveTaintResult) {
currentResult = naiveTaintResult;
}
public void setTaintBits(TaintBits tb) {
taintBits = tb;
}
}

View File

@ -0,0 +1,190 @@
package org.bdware.analysis.taint;
import org.bdware.analysis.AnalysisResult;
import org.bdware.analysis.InsnPrinter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.Frame;
public class TaintResult extends AnalysisResult {
// public HeapObject heapObejct;
public Frame<TaintValue> frame;
public TaintValue ret;
public static int nLocals = 0;
public static int nStack = 0;
public static InsnPrinter printer = new InsnPrinter(Opcodes.ASM4, System.out);
public static TaintInterpreter interpreter = new TaintInterpreter(Opcodes.ASM4);
public TaintResult() {
frame = new Frame<>(nLocals, nStack);
ret = new TaintValue(1);
ret.isTainted = 0L;
}
@Override
public AnalysisResult merge(AbstractInsnNode insn) {
interpreter.setCurrentResult(this);
try {
if (TaintConfig.isDebug && insn.getOpcode() >= 0) {
System.out.println("[TaintResult] frameStatus:" + frame2Str());
insn.accept(printer);
}
if (insn.getOpcode() < 0) {
// System.out.println("[TaintResult] MetLabel:" +
// insn.getClass().getCanonicalName());
} else
frame.execute(insn, interpreter);
if (TaintConfig.isDebug && insn.getOpcode() >= 0) {
System.out.println("[TaintResult] frameStatus:" + frame2Str());
}
} catch (AnalyzerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// we use suc instead,so we don't create new object here.
return this;
}
@Override
public void printResult() {
System.out.println("====" + frame2Str() + " Ret:" + ret.toString() + "====");
}
public String frame2Str() {
StringBuilder sb = new StringBuilder();
sb.append("Local:");
for (int i = 0; i < frame.getLocals(); i++) { // getLocals<EFBFBD><EFBFBD><EFBFBD><EFBFBD>local<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>size
TaintValue t = frame.getLocal(i);
if (t != null)
sb.append(t.toString());
else
sb.append("0--");
}
sb.append(" Stack:");
for (int i = 0; i < frame.getStackSize(); i++) { // getStackSize<EFBFBD><EFBFBD><EFBFBD><EFBFBD>stack<EFBFBD>ĵ<EFBFBD>ǰsize
TaintValue t = frame.getStack(i);
if (t != null)
sb.append(t.toString());
else
sb.append("0--");
}
return sb.toString();
}
private static boolean cover(TaintValue t1, TaintValue t2) {
// if (t2 == null || t2.isTainted == 0)
// return true;
// TODO whether is cover?
if (t1 != null && t1.isTainted != 0) {
if (t2 == null || t1.isTainted != t2.isTainted)
return true;
}
return false;
}
/*
* private static boolean isTainted(TaintValue t1) { if (t1 != null &&
* t1.isTainted) { return true; } return false; }
*/
private static boolean isTainted(TaintValue t1) {
if (t1 != null && t1.isTainted != 0) {
return true;
}
return false;
}
@Override
public boolean covers(AnalysisResult result) {
TaintResult tr = (TaintResult) result;
boolean ret = coversInternal(tr);
return ret;
// System.out.println("[NaiveTaintResult] Cover:" + ret);
// System.out.println("[NaiveTaintResult] " + frame.toString());
// System.out.println("[NaiveTaintResult] " + tr.frame.toString());
}
// preResult cover sucResult means
// preResult's taint is large or equals sucResult.
public boolean coversInternal(TaintResult tr) {
for (int i = 0; i < frame.getLocals() && i < tr.frame.getLocals(); i++)
if (cover(tr.frame.getLocal(i), frame.getLocal(i)))
return false;
// TODO why locals is not equal??
for (int i = frame.getLocals(); i < tr.frame.getLocals(); i++)
if (isTainted(tr.frame.getLocal(i)))
return false;
for (int i = 0; i < frame.getStackSize() && i < tr.frame.getStackSize(); i++)
if (cover(tr.frame.getStack(i), frame.getStack(i)))
return false;
for (int i = frame.getStackSize(); i < tr.frame.getStackSize(); i++)
if (isTainted(tr.frame.getStack(i)))
return false;
return true;
}
@Override
public void mergeResult(AnalysisResult r) {
TaintResult from = (TaintResult) r;
for (int i = 0; i < from.frame.getLocals(); i++) {
TaintValue target = from.frame.getLocal(i);
if (frame.getLocals() > i) {
TaintValue t1 = frame.getLocal(i);
if (target != null) {
if (t1 == null) {
t1 = target.clone();
frame.setLocal(i, t1);
} else {
t1.merge(target);
}
}
} else {
frame.setLocal(i, target.clone());
}
}
for (int i = 0; i < from.frame.getStackSize(); i++) {
TaintValue target = from.frame.getStack(i);
if (frame.getStackSize() > i) {
TaintValue t1 = frame.getStack(i);
if (target != null) {
if (t1 == null) {
t1 = target.clone();
frame.setStack(i, t1);
} else {
t1.merge(target);
}
}
t1.merge(from.frame.getStack(i));
} else {
if (target != null)
frame.push(target.clone());
else
frame.push(new TaintValue(1,0));
}
}
ret.merge(from.ret);
}
@Override
public AnalysisResult clone() {
TaintResult ret = new TaintResult();
ret.frame = new Frame<>(frame);
for (int i = 0; i < ret.frame.getLocals(); i++) {
TaintValue t = ret.frame.getLocal(i);
if (t != null)
ret.frame.setLocal(i, t.clone());
}
for (int i = 0; i < ret.frame.getStackSize(); i++) {
TaintValue t = ret.frame.getStack(i);
if (t != null)
ret.frame.setStack(i, t.clone());
}
ret.ret = this.ret.clone();
return ret;
}
}

View File

@ -0,0 +1,54 @@
package org.bdware.analysis.taint;
import org.objectweb.asm.tree.analysis.Value;
public class TaintValue implements Value {
public int size;
// public boolean isTainted;
public long isTainted;
public TaintValue(int size) {
this.size = size;
isTainted = 0L;
}
public TaintValue(int size, long isTainted) {
this.size = size;
this.isTainted = isTainted;
}
@Override
public int getSize() {
return size;
}
@Override
public String toString() {
String s = Long.toBinaryString(isTainted);
char[] c = s.toCharArray();
StringBuffer buf = new StringBuffer();
for (int i = 0; i < c.length; i++) {
if (c[i] == '1')
buf.append("1/");
else
buf.append("0/");
}
buf.append("--");
return buf.toString();
}
public TaintValue clone() {
TaintValue ret = new TaintValue(size);
ret.isTainted = isTainted;
return ret;
}
public String toReadableTaint() {
return TaintResult.interpreter.taintBits.parse(isTainted);
}
public void merge(TaintValue target) {
if (target != null)
isTainted |= target.isTainted;
}
}

View File

@ -0,0 +1,169 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A visitor to visit a Java annotation. The methods of this class must be
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}.
*/
protected final int api;
/**
* The annotation visitor to which this visitor must delegate method calls.
* May be null.
*/
protected AnnotationVisitor av;
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
if (api != Opcodes.ASM4) {
throw new IllegalArgumentException();
}
this.api = api;
this.av = av;
}
/**
* Visits a primitive value of the annotation.
*
* @param name
* the value name.
* @param value
* the actual value, whose type must be {@link Byte},
* {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} or OBJECT or ARRAY sort. This
* value can also be an array of byte, boolean, short, char, int,
* long, float or double values (this is equivalent to using
* {@link #visitArray visitArray} and visiting each array element
* in turn, but is more convenient).
*/
public void visit(String name, Object value) {
if (av != null) {
av.visit(name, value);
}
}
/**
* Visits an enumeration value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the enumeration class.
* @param value
* the actual enumeration value.
*/
public void visitEnum(String name, String desc, String value) {
if (av != null) {
av.visitEnum(name, desc, value);
}
}
/**
* Visits a nested annotation value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or
* <tt>null</tt> if this visitor is not interested in visiting this
* nested annotation. <i>The nested annotation value must be fully
* visited before calling other methods on this annotation
* visitor</i>.
*/
public AnnotationVisitor visitAnnotation(String name, String desc) {
if (av != null) {
return av.visitAnnotation(name, desc);
}
return null;
}
/**
* Visits an array value of the annotation. Note that arrays of primitive
* types (such as byte, boolean, short, char, int, long, float or double)
* can be passed as value to {@link #visit visit}. This is what
* {@link ClassReader} does.
*
* @param name
* the value name.
* @return a visitor to visit the actual array value elements, or
* <tt>null</tt> if this visitor is not interested in visiting these
* values. The 'name' parameters passed to the methods of this
* visitor are ignored. <i>All the array values must be visited
* before calling other methods on this annotation visitor</i>.
*/
public AnnotationVisitor visitArray(String name) {
if (av != null) {
return av.visitArray(name);
}
return null;
}
/**
* Visits the end of the annotation.
*/
public void visitEnd() {
if (av != null) {
av.visitEnd();
}
}
}

View File

@ -0,0 +1,378 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* An {@link AnnotationVisitor} that generates annotations in bytecode form.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
final class AnnotationWriter extends AnnotationVisitor
{
/**
* The class writer to which this annotation must be added.
*/
private final ClassWriter cw;
/**
* The number of values in this annotation.
*/
private int size;
/**
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
* writers used for annotation default and annotation arrays use unnamed
* values.
*/
private final boolean named;
/**
* The annotation values in bytecode form. This byte vector only contains
* the values themselves, i.e. the number of values must be stored as a
* unsigned short just before these bytes.
*/
private final ByteVector bv;
/**
* The byte vector to be used to store the number of values of this
* annotation. See {@link #bv}.
*/
private final ByteVector parent;
/**
* Where the number of values of this annotation must be stored in
* {@link #parent}.
*/
private final int offset;
/**
* Next annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter next;
/**
* Previous annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter prev;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link AnnotationWriter}.
*
* @param cw
* the class writer to which this annotation must be added.
* @param named
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
* @param bv
* where the annotation values must be stored.
* @param parent
* where the number of annotation values must be stored.
* @param offset
* where in <tt>parent</tt> the number of annotation values must
* be stored.
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset)
{
super(Opcodes.ASM4);
this.cw = cw;
this.named = named;
this.bv = bv;
this.parent = parent;
this.offset = offset;
}
// ------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final String name, final Object value)
{
++size;
if (named)
{
bv.putShort(cw.newUTF8(name));
}
if (value instanceof String)
{
bv.put12('s', cw.newUTF8((String) value));
}
else if (value instanceof Byte)
{
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
}
else if (value instanceof Boolean)
{
int v = ((Boolean) value).booleanValue() ? 1 : 0;
bv.put12('Z', cw.newInteger(v).index);
}
else if (value instanceof Character)
{
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
}
else if (value instanceof Short)
{
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
}
else if (value instanceof Type)
{
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
}
else if (value instanceof byte[])
{
byte[] v = (byte[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('B', cw.newInteger(v[i]).index);
}
}
else if (value instanceof boolean[])
{
boolean[] v = (boolean[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
}
}
else if (value instanceof short[])
{
short[] v = (short[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('S', cw.newInteger(v[i]).index);
}
}
else if (value instanceof char[])
{
char[] v = (char[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('C', cw.newInteger(v[i]).index);
}
}
else if (value instanceof int[])
{
int[] v = (int[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('I', cw.newInteger(v[i]).index);
}
}
else if (value instanceof long[])
{
long[] v = (long[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('J', cw.newLong(v[i]).index);
}
}
else if (value instanceof float[])
{
float[] v = (float[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('F', cw.newFloat(v[i]).index);
}
}
else if (value instanceof double[])
{
double[] v = (double[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++)
{
bv.put12('D', cw.newDouble(v[i]).index);
}
}
else
{
Item i = cw.newConstItem(value);
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
}
}
@Override
public void visitEnum(final String name, final String desc,
final String value)
{
++size;
// TODO add by chq! &&name!=null;
if (named && name != null)
{
bv.putShort(cw.newUTF8(name));
}
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc)
{
++size;
if (named)
{
bv.putShort(cw.newUTF8(name));
}
// write tag and type, and reserve space for values count
bv.put12('@', cw.newUTF8(desc)).putShort(0);
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
}
@Override
public AnnotationVisitor visitArray(final String name)
{
++size;
if (named)
{
bv.putShort(cw.newUTF8(name));
}
// write tag, and reserve space for array size
bv.put12('[', 0);
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
}
@Override
public void visitEnd()
{
if (parent != null)
{
byte[] data = parent.data;
data[offset] = (byte) (size >>> 8);
data[offset + 1] = (byte) size;
}
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the size of this annotation writer list.
*
* @return the size of this annotation writer list.
*/
int getSize()
{
int size = 0;
AnnotationWriter aw = this;
while (aw != null)
{
size += aw.bv.length;
aw = aw.next;
}
return size;
}
/**
* Puts the annotations of this annotation writer list into the given byte
* vector.
*
* @param out
* where the annotations must be put.
*/
void put(final ByteVector out)
{
int n = 0;
int size = 2;
AnnotationWriter aw = this;
AnnotationWriter last = null;
while (aw != null)
{
++n;
size += aw.bv.length;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
}
out.putInt(size);
out.putShort(n);
aw = last;
while (aw != null)
{
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
}
}
/**
* Puts the given annotation lists into the given byte vector.
*
* @param panns
* an array of annotation writer lists.
* @param off
* index of the first annotation to be written.
* @param out
* where the annotations must be put.
*/
static void put(final AnnotationWriter[] panns, final int off,
final ByteVector out)
{
int size = 1 + 2 * (panns.length - off);
for (int i = off; i < panns.length; ++i)
{
size += panns[i] == null ? 0 : panns[i].getSize();
}
out.putInt(size).putByte(panns.length - off);
for (int i = off; i < panns.length; ++i)
{
AnnotationWriter aw = panns[i];
AnnotationWriter last = null;
int n = 0;
while (aw != null)
{
++n;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
}
out.putShort(n);
aw = last;
while (aw != null)
{
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
}
}
}
}

View File

@ -0,0 +1,255 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A non standard class, field, method or code attribute.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class Attribute {
/**
* The type of this attribute.
*/
public final String type;
/**
* The raw value of this attribute, used only for unknown attributes.
*/
byte[] value;
/**
* The next attribute in this attribute list. May be <tt>null</tt>.
*/
Attribute next;
/**
* Constructs a new empty attribute.
*
* @param type
* the type of the attribute.
*/
protected Attribute(final String type) {
this.type = type;
}
/**
* Returns <tt>true</tt> if this type of attribute is unknown. The default
* implementation of this method always returns <tt>true</tt>.
*
* @return <tt>true</tt> if this type of attribute is unknown.
*/
public boolean isUnknown() {
return true;
}
/**
* Returns <tt>true</tt> if this type of attribute is a code attribute.
*
* @return <tt>true</tt> if this type of attribute is a code attribute.
*/
public boolean isCodeAttribute() {
return false;
}
/**
* Returns the labels corresponding to this attribute.
*
* @return the labels corresponding to this attribute, or <tt>null</tt> if
* this attribute is not a code attribute that contains labels.
*/
protected Label[] getLabels() {
return null;
}
/**
* Reads a {@link #type type} attribute. This method must return a
* <i>new</i> {@link Attribute} object, of type {@link #type type},
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
* the given class reader.
*
* @param cr
* the class that contains the attribute to be read.
* @param off
* index of the first byte of the attribute's content in
* {@link ClassReader#b cr.b}. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param len
* the length of the attribute's content.
* @param buf
* buffer to be used to call {@link ClassReader#readUTF8
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
* or {@link ClassReader#readConst readConst}.
* @param codeOff
* index of the first byte of code's attribute content in
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read
* is not a code attribute. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param labels
* the labels of the method's code, or <tt>null</tt> if the
* attribute to be read is not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the given
* bytes.
*/
protected Attribute read(final ClassReader cr, final int off,
final int len, final char[] buf, final int codeOff,
final Label[] labels) {
Attribute attr = new Attribute(type);
attr.value = new byte[len];
System.arraycopy(cr.b, off, attr.value, 0, len);
return attr;
}
/**
* Returns the byte array form of this attribute.
*
* @param cw
* the class to which this attribute must be added. This
* parameter can be used to add to the constant pool of this
* class the items that corresponds to this attribute.
* @param code
* the bytecode of the method corresponding to this code
* attribute, or <tt>null</tt> if this attribute is not a code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to this
* code attribute, or <tt>null</tt> if this attribute is not a
* code attribute.
* @param maxStack
* the maximum stack size of the method corresponding to this
* code attribute, or -1 if this attribute is not a code
* attribute.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to this code attribute, or -1 if this attribute
* is not a code attribute.
* @return the byte array form of this attribute.
*/
protected ByteVector write(final ClassWriter cw, final byte[] code,
final int len, final int maxStack, final int maxLocals) {
ByteVector v = new ByteVector();
v.data = value;
v.length = value.length;
return v;
}
/**
* Returns the length of the attribute list that begins with this attribute.
*
* @return the length of the attribute list that begins with this attribute.
*/
final int getCount() {
int count = 0;
Attribute attr = this;
while (attr != null) {
count += 1;
attr = attr.next;
}
return count;
}
/**
* Returns the size of all the attributes in this attribute list.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @return the size of all the attributes in this attribute list. This size
* includes the size of the attribute headers.
*/
final int getSize(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals) {
Attribute attr = this;
int size = 0;
while (attr != null) {
cw.newUTF8(attr.type);
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
attr = attr.next;
}
return size;
}
/**
* Writes all the attributes of this attribute list in the given byte
* vector.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @param out
* where the attributes must be written.
*/
final void put(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals, final ByteVector out) {
Attribute attr = this;
while (attr != null) {
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
out.putByteArray(b.data, 0, b.length);
attr = attr.next;
}
}
}

View File

@ -0,0 +1,312 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A dynamically extensible vector of bytes. This class is roughly equivalent to
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
*
* @author Eric Bruneton
*/
public class ByteVector {
/**
* The content of this vector.
*/
byte[] data;
/**
* Actual number of bytes in this vector.
*/
int length;
/**
* Constructs a new {@link ByteVector ByteVector} with a default initial
* size.
*/
public ByteVector() {
data = new byte[64];
}
/**
* Constructs a new {@link ByteVector ByteVector} with the given initial
* size.
*
* @param initialSize
* the initial size of the byte vector to be constructed.
*/
public ByteVector(final int initialSize) {
data = new byte[initialSize];
}
/**
* Puts a byte into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param b
* a byte.
* @return this byte vector.
*/
public ByteVector putByte(final int b) {
int length = this.length;
if (length + 1 > data.length) {
enlarge(1);
}
data[length++] = (byte) b;
this.length = length;
return this;
}
/**
* Puts two bytes into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param b1
* a byte.
* @param b2
* another byte.
* @return this byte vector.
*/
ByteVector put11(final int b1, final int b2) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) b1;
data[length++] = (byte) b2;
this.length = length;
return this;
}
/**
* Puts a short into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param s
* a short.
* @return this byte vector.
*/
public ByteVector putShort(final int s) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts a byte and a short into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b
* a byte.
* @param s
* a short.
* @return this byte vector.
*/
ByteVector put12(final int b, final int s) {
int length = this.length;
if (length + 3 > data.length) {
enlarge(3);
}
byte[] data = this.data;
data[length++] = (byte) b;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
return this;
}
/**
* Puts an int into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param i
* an int.
* @return this byte vector.
*/
public ByteVector putInt(final int i) {
int length = this.length;
if (length + 4 > data.length) {
enlarge(4);
}
byte[] data = this.data;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
return this;
}
/**
* Puts a long into this byte vector. The byte vector is automatically
* enlarged if necessary.
*
* @param l
* a long.
* @return this byte vector.
*/
public ByteVector putLong(final long l) {
int length = this.length;
if (length + 8 > data.length) {
enlarge(8);
}
byte[] data = this.data;
int i = (int) (l >>> 32);
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
i = (int) l;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param s
* a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
}
int len = length;
if (len + 2 + charLength > data.length) {
enlarge(2 + charLength);
}
byte[] data = this.data;
// optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the
// general method.
data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else {
int byteLength = i;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
byteLength++;
} else if (c > '\u07FF') {
byteLength += 3;
} else {
byteLength += 2;
}
}
if (byteLength > 65535) {
throw new IllegalArgumentException();
}
data[length] = (byte) (byteLength >>> 8);
data[length + 1] = (byte) byteLength;
if (length + 2 + byteLength > data.length) {
length = len;
enlarge(2 + byteLength);
data = this.data;
}
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else if (c > '\u07FF') {
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
data[len++] = (byte) (0x80 | c & 0x3F);
} else {
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
data[len++] = (byte) (0x80 | c & 0x3F);
}
}
break;
}
}
length = len;
return this;
}
/**
* Puts an array of bytes into this byte vector. The byte vector is
* automatically enlarged if necessary.
*
* @param b
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
* null bytes into this byte vector.
* @param off
* index of the fist byte of b that must be copied.
* @param len
* number of bytes of b that must be copied.
* @return this byte vector.
*/
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
if (length + len > data.length) {
enlarge(len);
}
if (b != null) {
System.arraycopy(b, off, data, length, len);
}
length += len;
return this;
}
/**
* Enlarge this byte vector so that it can receive n more bytes.
*
* @param size
* number of additional bytes that this byte vector should be
* able to receive.
*/
private void enlarge(final int size) {
int length1 = 2 * data.length;
int length2 = length + size;
byte[] newData = new byte[length1 > length2 ? length1 : length2];
System.arraycopy(data, 0, newData, 0, length);
data = newData;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,286 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitAttribute</tt> )* ( <tt>visitInnerClass</tt> | <tt>visitField</tt> |
* <tt>visitMethod</tt> )* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}.
*/
protected final int api;
/**
* The class visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ClassVisitor cv;
/**
* Constructs a new {@link ClassVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public ClassVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link ClassVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
if (api != Opcodes.ASM4) {
throw new IllegalArgumentException();
}
this.api = api;
this.cv = cv;
}
/**
* Visits the header of the class.
*
* @param version
* the class version.
* @param access
* the class's access flags (see {@link Opcodes}). This parameter
* also indicates if the class is deprecated.
* @param name
* the internal name of the class (see
* {@link Type#getInternalName() getInternalName}).
* @param signature
* the signature of this class. May be <tt>null</tt> if the class
* is not a generic one, and does not extend or implement generic
* classes or interfaces.
* @param superName
* the internal of name of the super class (see
* {@link Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be
* <tt>null</tt>, but only for the {@link Object} class.
* @param interfaces
* the internal names of the class's interfaces (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces);
}
}
/**
* Visits the source of the class.
*
* @param source
* the name of the source file from which the class was compiled.
* May be <tt>null</tt>.
* @param debug
* additional debug information to compute the correspondance
* between source and compiled elements of the class. May be
* <tt>null</tt>.
*/
public void visitSource(String source, String debug) {
if (cv != null) {
cv.visitSource(source, debug);
}
}
/**
* Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class.
*
* @param owner
* internal name of the enclosing class of the class.
* @param name
* the name of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
* @param desc
* the descriptor of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
*/
public void visitOuterClass(String owner, String name, String desc) {
if (cv != null) {
cv.visitOuterClass(owner, name, desc);
}
}
/**
* Visits an annotation of the class.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (cv != null) {
return cv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of the class.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (cv != null) {
cv.visitAttribute(attr);
}
}
/**
* Visits information about an inner class. This inner class is not
* necessarily a member of the class being visited.
*
* @param name
* the internal name of an inner class (see
* {@link Type#getInternalName() getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link Type#getInternalName() getInternalName}).
* May be <tt>null</tt> for not member classes.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
*/
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
if (cv != null) {
cv.visitInnerClass(name, outerName, innerName, access);
}
}
/**
* Visits a field of the class.
*
* @param access
* the field's access flags (see {@link Opcodes}). This parameter
* also indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type Type}).
* @param signature
* the field's signature. May be <tt>null</tt> if the field's
* type does not use generic types.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String} (for <tt>int</tt>,
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
* respectively). <i>This parameter is only used for static
* fields</i>. Its value is ignored for non static fields, which
* must be initialized through bytecode instructions in
* constructors or methods.
* @return a visitor to visit field annotations and attributes, or
* <tt>null</tt> if this class visitor is not interested in visiting
* these annotations and attributes.
*/
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
if (cv != null) {
return cv.visitField(access, name, desc, signature, value);
}
return null;
}
/**
* Visits a method of the class. This method <i>must</i> return a new
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
* i.e., it should not return a previously returned visitor.
*
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param signature
* the method's signature. May be <tt>null</tt> if the method
* parameters, return type and exceptions do not use generic
* types.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @return an object to visit the byte code of the method, or <tt>null</tt>
* if this class visitor is not interested in visiting the code of
* this method.
*/
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
if (cv != null) {
return cv.visitMethod(access, name, desc, signature, exceptions);
}
return null;
}
/**
* Visits the end of the class. This method, which is the last one to be
* called, is used to inform the visitor that all the fields and methods of
* the class have been visited.
*/
public void visitEnd() {
if (cv != null) {
cv.visitEnd();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* Information about a class being parsed in a {@link ClassReader}.
*
* @author Eric Bruneton
*/
class Context {
/**
* Prototypes of the attributes that must be parsed for this class.
*/
Attribute[] attrs;
/**
* The {@link ClassReader} option flags for the parsing of this class.
*/
int flags;
/**
* The buffer used to read strings.
*/
char[] buffer;
/**
* The start index of each bootstrap method.
*/
int[] bootstrapMethods;
/**
* The access flags of the method currently being parsed.
*/
int access;
/**
* The name of the method currently being parsed.
*/
String name;
/**
* The descriptor of the method currently being parsed.
*/
String desc;
/**
* The offset of the latest stack map frame that has been parsed.
*/
int offset;
/**
* The encoding of the latest stack map frame that has been parsed.
*/
int mode;
/**
* The number of locals in the latest stack map frame that has been parsed.
*/
int localCount;
/**
* The number locals in the latest stack map frame that has been parsed,
* minus the number of locals in the previous frame.
*/
int localDiff;
/**
* The local values of the latest stack map frame that has been parsed.
*/
Object[] local;
/**
* The stack size of the latest stack map frame that has been parsed.
*/
int stackCount;
/**
* The stack values of the latest stack map frame that has been parsed.
*/
Object[] stack;
}

View File

@ -0,0 +1,75 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* An edge in the control flow graph of a method body. See {@link Label Label}.
*
* @author Eric Bruneton
*/
class Edge {
/**
* Denotes a normal control flow graph edge.
*/
static final int NORMAL = 0;
/**
* Denotes a control flow graph edge corresponding to an exception handler.
* More precisely any {@link Edge} whose {@link #info} is strictly positive
* corresponds to an exception handler. The actual value of {@link #info} is
* the index, in the {@link ClassWriter} type table, of the exception that
* is catched.
*/
static final int EXCEPTION = 0x7FFFFFFF;
/**
* Information about this control flow graph edge. If
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
* stack size in the basic block from which this edge originates. This size
* is equal to the stack size at the "jump" instruction to which this edge
* corresponds, relatively to the stack size at the beginning of the
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
* this field is the kind of this control flow graph edge (i.e. NORMAL or
* EXCEPTION).
*/
int info;
/**
* The successor block of the basic block from which this edge originates.
*/
Label successor;
/**
* The next edge in the list of successors of the originating basic block.
* See {@link Label#successors successors}.
*/
Edge next;
}

View File

@ -0,0 +1,121 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
* the following order: ( <tt>visitAnnotation</tt> | <tt>visitAttribute</tt> )*
* <tt>visitEnd</tt>.
*
* @author Eric Bruneton
*/
public abstract class FieldVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}.
*/
protected final int api;
/**
* The field visitor to which this visitor must delegate method calls. May
* be null.
*/
protected FieldVisitor fv;
/**
* Constructs a new {@link FieldVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public FieldVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link FieldVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
if (api != Opcodes.ASM4) {
throw new IllegalArgumentException();
}
this.api = api;
this.fv = fv;
}
/**
* Visits an annotation of the field.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (fv != null) {
return fv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of the field.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (fv != null) {
fv.visitAttribute(attr);
}
}
/**
* Visits the end of the field. This method, which is the last one to be
* called, is used to inform the visitor that all the annotations and
* attributes of the field have been visited.
*/
public void visitEnd() {
if (fv != null) {
fv.visitEnd();
}
}
}

View File

@ -0,0 +1,273 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* An {@link FieldVisitor} that generates Java fields in bytecode form.
*
* @author Eric Bruneton
*/
final class FieldWriter extends FieldVisitor {
/**
* The class writer to which this field must be added.
*/
private final ClassWriter cw;
/**
* Access flags of this field.
*/
private final int access;
/**
* The index of the constant pool item that contains the name of this
* method.
*/
private final int name;
/**
* The index of the constant pool item that contains the descriptor of this
* field.
*/
private final int desc;
/**
* The index of the constant pool item that contains the signature of this
* field.
*/
private int signature;
/**
* The index of the constant pool item that contains the constant value of
* this field.
*/
private int value;
/**
* The runtime visible annotations of this field. May be <tt>null</tt>.
*/
private AnnotationWriter anns;
/**
* The runtime invisible annotations of this field. May be <tt>null</tt>.
*/
private AnnotationWriter ianns;
/**
* The non standard attributes of this field. May be <tt>null</tt>.
*/
private Attribute attrs;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link FieldWriter}.
*
* @param cw
* the class writer to which this field must be added.
* @param access
* the field's access flags (see {@link Opcodes}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type}).
* @param signature
* the field's signature. May be <tt>null</tt>.
* @param value
* the field's constant value. May be <tt>null</tt>.
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
super(Opcodes.ASM4);
if (cw.firstField == null) {
cw.firstField = this;
} else {
cw.lastField.fv = this;
}
cw.lastField = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (ClassReader.SIGNATURES && signature != null) {
this.signature = cw.newUTF8(signature);
}
if (value != null) {
this.value = cw.newConstItem(value).index;
}
}
// ------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
if (!ClassReader.ANNOTATIONS) {
return null;
}
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
if (visible) {
aw.next = anns;
anns = aw;
} else {
aw.next = ianns;
ianns = aw;
}
return aw;
}
@Override
public void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Returns the size of this field.
*
* @return the size of this field.
*/
int getSize() {
int size = 8;
if (value != 0) {
cw.newUTF8("ConstantValue");
size += 8;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
cw.newUTF8("Synthetic");
size += 6;
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated");
size += 6;
}
if (ClassReader.SIGNATURES && signature != 0) {
cw.newUTF8("Signature");
size += 8;
}
if (ClassReader.ANNOTATIONS && anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
}
if (ClassReader.ANNOTATIONS && ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
}
if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1);
}
return size;
}
/**
* Puts the content of this field into the given byte vector.
*
* @param out
* where the content of this field must be put.
*/
void put(final ByteVector out) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0;
if (value != 0) {
++attributeCount;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount;
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (ClassReader.SIGNATURES && signature != 0) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && anns != null) {
++attributeCount;
}
if (ClassReader.ANNOTATIONS && ianns != null) {
++attributeCount;
}
if (attrs != null) {
attributeCount += attrs.getCount();
}
out.putShort(attributeCount);
if (value != 0) {
out.putShort(cw.newUTF8("ConstantValue"));
out.putInt(2).putShort(value);
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
if (ClassReader.SIGNATURES && signature != 0) {
out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature);
}
if (ClassReader.ANNOTATIONS && anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ClassReader.ANNOTATIONS && ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A reference to a field or a method.
*
* @author Remi Forax
* @author Eric Bruneton
*/
public final class Handle {
/**
* The kind of field or method designated by this Handle. Should be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
*/
final int tag;
/**
* The internal name of the class that owns the field or method designated
* by this handle.
*/
final String owner;
/**
* The name of the field or method designated by this handle.
*/
final String name;
/**
* The descriptor of the field or method designated by this handle.
*/
final String desc;
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* handle.
*/
public Handle(int tag, String owner, String name, String desc) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.desc = desc;
}
/**
* Returns the kind of field or method designated by this handle.
*
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
*/
public int getTag() {
return tag;
}
/**
* Returns the internal name of the class that owns the field or method
* designated by this handle.
*
* @return the internal name of the class that owns the field or method
* designated by this handle.
*/
public String getOwner() {
return owner;
}
/**
* Returns the name of the field or method designated by this handle.
*
* @return the name of the field or method designated by this handle.
*/
public String getName() {
return name;
}
/**
* Returns the descriptor of the field or method designated by this handle.
*
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return desc;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Handle)) {
return false;
}
Handle h = (Handle) obj;
return tag == h.tag && owner.equals(h.owner) && name.equals(h.name)
&& desc.equals(h.desc);
}
@Override
public int hashCode() {
return tag + owner.hashCode() * name.hashCode() * desc.hashCode();
}
/**
* Returns the textual representation of this handle. The textual
* representation is:
*
* <pre>
* owner '.' name desc ' ' '(' tag ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
*/
@Override
public String toString() {
return owner + '.' + name + desc + " (" + tag + ')';
}
}

View File

@ -0,0 +1,121 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* Information about an exception handler block.
*
* @author Eric Bruneton
*/
class Handler {
/**
* Beginning of the exception handler's scope (inclusive).
*/
Label start;
/**
* End of the exception handler's scope (exclusive).
*/
Label end;
/**
* Beginning of the exception handler's code.
*/
Label handler;
/**
* Internal name of the type of exceptions handled by this handler, or
* <tt>null</tt> to catch any exceptions.
*/
String desc;
/**
* Constant pool index of the internal name of the type of exceptions
* handled by this handler, or 0 to catch any exceptions.
*/
int type;
/**
* Next exception handler block info.
*/
Handler next;
/**
* Removes the range between start and end from the given exception
* handlers.
*
* @param h
* an exception handler list.
* @param start
* the start of the range to be removed.
* @param end
* the end of the range to be removed. Maybe null.
* @return the exception handler list with the start-end range removed.
*/
static Handler remove(Handler h, Label start, Label end) {
if (h == null) {
return null;
} else {
h.next = remove(h.next, start, end);
}
int hstart = h.start.position;
int hend = h.end.position;
int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) {
if (s <= hstart) {
if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
} else {
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
g.start = end;
g.end = h.end;
g.handler = h.handler;
g.desc = h.desc;
g.type = h.type;
g.next = h.next;
h.end = start;
h.next = g;
}
}
return h;
}
}

View File

@ -0,0 +1,311 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A constant pool item. Constant pool items can be created with the 'newXXX'
* methods in the {@link ClassWriter} class.
*
* @author Eric Bruneton
*/
final class Item {
/**
* Index of this item in the constant pool.
*/
int index;
/**
* Type of this constant pool item. A single class is used to represent all
* constant pool item types, in order to minimize the bytecode size of this
* package. The value of this field is one of {@link ClassWriter#INT},
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
* {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
*
* MethodHandle constant 9 variations are stored using a range of 9 values
* from {@link ClassWriter#HANDLE_BASE} + 1 to
* {@link ClassWriter#HANDLE_BASE} + 9.
*
* Special Item types are used for Items that are stored in the ClassWriter
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
* avoid clashes with normal constant pool items in the ClassWriter constant
* pool's hash table. These special item types are
* {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
* {@link ClassWriter#TYPE_MERGED}.
*/
int type;
/**
* Value of this item, for an integer item.
*/
int intVal;
/**
* Value of this item, for a long item.
*/
long longVal;
/**
* First part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal1;
/**
* Second part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal2;
/**
* Third part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal3;
/**
* The hash code value of this constant pool item.
*/
int hashCode;
/**
* Link to another constant pool item, used for collision lists in the
* constant pool's hash table.
*/
Item next;
/**
* Constructs an uninitialized {@link Item}.
*/
Item() {
}
/**
* Constructs an uninitialized {@link Item} for constant pool element at
* given position.
*
* @param index
* index of the item to be constructed.
*/
Item(final int index) {
this.index = index;
}
/**
* Constructs a copy of the given item.
*
* @param index
* index of the item to be constructed.
* @param i
* the item that must be copied into the item to be constructed.
*/
Item(final int index, final Item i) {
this.index = index;
type = i.type;
intVal = i.intVal;
longVal = i.longVal;
strVal1 = i.strVal1;
strVal2 = i.strVal2;
strVal3 = i.strVal3;
hashCode = i.hashCode;
}
/**
* Sets this item to an integer item.
*
* @param intVal
* the value of this item.
*/
void set(final int intVal) {
this.type = ClassWriter.INT;
this.intVal = intVal;
this.hashCode = 0x7FFFFFFF & (type + intVal);
}
/**
* Sets this item to a long item.
*
* @param longVal
* the value of this item.
*/
void set(final long longVal) {
this.type = ClassWriter.LONG;
this.longVal = longVal;
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
}
/**
* Sets this item to a float item.
*
* @param floatVal
* the value of this item.
*/
void set(final float floatVal) {
this.type = ClassWriter.FLOAT;
this.intVal = Float.floatToRawIntBits(floatVal);
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
}
/**
* Sets this item to a double item.
*
* @param doubleVal
* the value of this item.
*/
void set(final double doubleVal) {
this.type = ClassWriter.DOUBLE;
this.longVal = Double.doubleToRawLongBits(doubleVal);
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
}
/**
* Sets this item to an item that do not hold a primitive value.
*
* @param type
* the type of this item.
* @param strVal1
* first part of the value of this item.
* @param strVal2
* second part of the value of this item.
* @param strVal3
* third part of the value of this item.
*/
void set(final int type, final String strVal1, final String strVal2,
final String strVal3) {
this.type = type;
this.strVal1 = strVal1;
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.CLASS:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
case ClassWriter.NAME_TYPE: {
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode());
return;
}
// ClassWriter.FIELD:
// ClassWriter.METH:
// ClassWriter.IMETH:
// ClassWriter.HANDLE_BASE + 1..9
default:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode() * strVal3.hashCode());
}
}
/**
* Sets the item to an InvokeDynamic item.
*
* @param name
* invokedynamic's name.
* @param desc
* invokedynamic's desc.
* @param bsmIndex
* zero based index into the class attribute BootrapMethods.
*/
void set(String name, String desc, int bsmIndex) {
this.type = ClassWriter.INDY;
this.longVal = bsmIndex;
this.strVal1 = name;
this.strVal2 = desc;
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
* strVal1.hashCode() * strVal2.hashCode());
}
/**
* Sets the item to a BootstrapMethod item.
*
* @param position
* position in byte in the class attribute BootrapMethods.
* @param hashCode
* hashcode of the item. This hashcode is processed from the
* hashcode of the bootstrap method and the hashcode of all
* bootstrap arguments.
*/
void set(int position, int hashCode) {
this.type = ClassWriter.BSM;
this.intVal = position;
this.hashCode = hashCode;
}
/**
* Indicates if the given item is equal to this one. <i>This method assumes
* that the two items have the same {@link #type}</i>.
*
* @param i
* the item to be compared to this one. Both items must have the
* same {@link #type}.
* @return <tt>true</tt> if the given item if equal to this one,
* <tt>false</tt> otherwise.
*/
boolean isEqualTo(final Item i) {
switch (type) {
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.CLASS:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1);
case ClassWriter.TYPE_MERGED:
case ClassWriter.LONG:
case ClassWriter.DOUBLE:
return i.longVal == longVal;
case ClassWriter.INT:
case ClassWriter.FLOAT:
return i.intVal == intVal;
case ClassWriter.TYPE_UNINIT:
return i.intVal == intVal && i.strVal1.equals(strVal1);
case ClassWriter.NAME_TYPE:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
case ClassWriter.INDY: {
return i.longVal == longVal && i.strVal1.equals(strVal1)
&& i.strVal2.equals(strVal2);
}
// case ClassWriter.FIELD:
// case ClassWriter.METH:
// case ClassWriter.IMETH:
// case ClassWriter.HANDLE_BASE + 1..9
default:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
&& i.strVal3.equals(strVal3);
}
}
}

View File

@ -0,0 +1,560 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A label represents a position in the bytecode of a method. Labels are used
* for jump, goto, and switch instructions, and for try catch blocks. A label
* designates the <i>instruction</i> that is just after. Note however that there
* can be other elements between a label and the instruction it designates (such
* as other labels, stack map frames, line numbers, etc.).
*
* @author Eric Bruneton
*/
public class Label {
/**
* Indicates if this label is only used for debug attributes. Such a label
* is not the start of a basic block, the target of a jump instruction, or
* an exception handler. It can be safely ignored in control flow graph
* analysis algorithms (for optimization purposes).
*/
static final int DEBUG = 1;
/**
* Indicates if the position of this label is known.
*/
static final int RESOLVED = 2;
/**
* Indicates if this label has been updated, after instruction resizing.
*/
static final int RESIZED = 4;
/**
* Indicates if this basic block has been pushed in the basic block stack.
* See {@link MethodWriter#visitMaxs visitMaxs}.
*/
static final int PUSHED = 8;
/**
* Indicates if this label is the target of a jump instruction, or the start
* of an exception handler.
*/
static final int TARGET = 16;
/**
* Indicates if a stack map frame must be stored for this label.
*/
static final int STORE = 32;
/**
* Indicates if this label corresponds to a reachable basic block.
*/
static final int REACHABLE = 64;
/**
* Indicates if this basic block ends with a JSR instruction.
*/
static final int JSR = 128;
/**
* Indicates if this basic block ends with a RET instruction.
*/
static final int RET = 256;
/**
* Indicates if this basic block is the start of a subroutine.
*/
static final int SUBROUTINE = 512;
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(null, ...) call.
*/
static final int VISITED = 1024;
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(!null, ...) call.
*/
static final int VISITED2 = 2048;
/**
* Field used to associate user information to a label. Warning: this field
* is used by the ASM tree package. In order to use it with the ASM tree
* package you must override the
* {@link org.objectweb.asm.tree.MethodNode#getLabelNode} method.
*/
public Object info;
/**
* Flags that indicate the status of this label.
*
* @see #DEBUG
* @see #RESOLVED
* @see #RESIZED
* @see #PUSHED
* @see #TARGET
* @see #STORE
* @see #REACHABLE
* @see #JSR
* @see #RET
*/
int status;
/**
* The line number corresponding to this label, if known.
*/
int line;
/**
* The position of this label in the code, if known.
*/
int position;
/**
* Number of forward references to this label, times two.
*/
private int referenceCount;
/**
* Informations about forward references. Each forward reference is
* described by two consecutive integers in this array: the first one is the
* position of the first byte of the bytecode instruction that contains the
* forward reference, while the second is the position of the first byte of
* the forward reference itself. In fact the sign of the first integer
* indicates if this reference uses 2 or 4 bytes, and its absolute value
* gives the position of the bytecode instruction. This array is also used
* as a bitset to store the subroutines to which a basic block belongs. This
* information is needed in {@linked MethodWriter#visitMaxs}, after all
* forward references have been resolved. Hence the same array can be used
* for both purposes without problems.
*/
private int[] srcAndRefPositions;
// ------------------------------------------------------------------------
/*
* Fields for the control flow and data flow graph analysis algorithms (used
* to compute the maximum stack size or the stack map frames). A control
* flow graph contains one node per "basic block", and one edge per "jump"
* from one basic block to another. Each node (i.e., each basic block) is
* represented by the Label object that corresponds to the first instruction
* of this basic block. Each node also stores the list of its successors in
* the graph, as a linked list of Edge objects.
*
* The control flow analysis algorithms used to compute the maximum stack
* size or the stack map frames are similar and use two steps. The first
* step, during the visit of each instruction, builds information about the
* state of the local variables and the operand stack at the end of each
* basic block, called the "output frame", <i>relatively</i> to the frame
* state at the beginning of the basic block, which is called the "input
* frame", and which is <i>unknown</i> during this step. The second step, in
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
* information about the input frame of each basic block, from the input
* state of the first basic block (known from the method signature), and by
* the using the previously computed relative output frames.
*
* The algorithm used to compute the maximum stack size only computes the
* relative output and absolute input stack heights, while the algorithm
* used to compute stack map frames computes relative output frames and
* absolute input frames.
*/
/**
* Start of the output stack relatively to the input stack. The exact
* semantics of this field depends on the algorithm that is used.
*
* When only the maximum stack size is computed, this field is the number of
* elements in the input stack.
*
* When the stack map frames are completely computed, this field is the
* offset of the first output stack element relatively to the top of the
* input stack. This offset is always negative or null. A null offset means
* that the output stack must be appended to the input stack. A -n offset
* means that the first n output stack elements must replace the top n input
* stack elements, and that the other elements must be appended to the input
* stack.
*/
int inputStackTop;
/**
* Maximum height reached by the output stack, relatively to the top of the
* input stack. This maximum is always positive or null.
*/
int outputStackMax;
/**
* Information about the input and output stack map frames of this basic
* block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
* option is used.
*/
Frame frame;
/**
* The successor of this label, in the order they are visited. This linked
* list does not include labels used for debug info only. If
* {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
* does not contain successive labels that denote the same bytecode position
* (in this case only the first label appears in this list).
*/
Label successor;
/**
* The successors of this node in the control flow graph. These successors
* are stored in a linked list of {@link Edge Edge} objects, linked to each
* other by their {@link Edge#next} field.
*/
Edge successors;
/**
* The next basic block in the basic block stack. This stack is used in the
* main loop of the fix point algorithm used in the second step of the
* control flow analysis algorithms. It is also used in
* {@link #visitSubroutine} to avoid using a recursive method.
*
* @see MethodWriter#visitMaxs
*/
Label next;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new label.
*/
public Label() {
}
// ------------------------------------------------------------------------
// Methods to compute offsets and to manage forward references
// ------------------------------------------------------------------------
/**
* Returns the offset corresponding to this label. This offset is computed
* from the start of the method's bytecode. <i>This method is intended for
* {@link Attribute} sub classes, and is normally not needed by class
* generators or adapters.</i>
*
* @return the offset corresponding to this label.
* @throws IllegalStateException
* if this label is not resolved yet.
*/
public int getOffset() {
if ((status & RESOLVED) == 0) {
throw new IllegalStateException(
"Label offset position has not been resolved yet");
}
return position;
}
/**
* Puts a reference to this label in the bytecode of a method. If the
* position of the label is known, the offset is computed and written
* directly. Otherwise, a null offset is written and a new forward reference
* is declared for this label.
*
* @param owner
* the code writer that calls this method.
* @param out
* the bytecode of the method.
* @param source
* the position of first byte of the bytecode instruction that
* contains this label.
* @param wideOffset
* <tt>true</tt> if the reference must be stored in 4 bytes, or
* <tt>false</tt> if it must be stored with 2 bytes.
* @throws IllegalArgumentException
* if this label has not been created by the given code writer.
*/
void put(final MethodWriter owner, final ByteVector out, final int source,
final boolean wideOffset) {
if ((status & RESOLVED) == 0) {
if (wideOffset) {
addReference(-1 - source, out.length);
out.putInt(-1);
} else {
addReference(source, out.length);
out.putShort(-1);
}
} else {
if (wideOffset) {
out.putInt(position - source);
} else {
out.putShort(position - source);
}
}
}
/**
* Adds a forward reference to this label. This method must be called only
* for a true forward reference, i.e. only if this label is not resolved
* yet. For backward references, the offset of the reference can be, and
* must be, computed and stored directly.
*
* @param sourcePosition
* the position of the referencing instruction. This position
* will be used to compute the offset of this forward reference.
* @param referencePosition
* the position where the offset for this forward reference must
* be stored.
*/
private void addReference(final int sourcePosition,
final int referencePosition) {
if (srcAndRefPositions == null) {
srcAndRefPositions = new int[6];
}
if (referenceCount >= srcAndRefPositions.length) {
int[] a = new int[srcAndRefPositions.length + 6];
System.arraycopy(srcAndRefPositions, 0, a, 0,
srcAndRefPositions.length);
srcAndRefPositions = a;
}
srcAndRefPositions[referenceCount++] = sourcePosition;
srcAndRefPositions[referenceCount++] = referencePosition;
}
/**
* Resolves all forward references to this label. This method must be called
* when this label is added to the bytecode of the method, i.e. when its
* position becomes known. This method fills in the blanks that where left
* in the bytecode by each forward reference previously added to this label.
*
* @param owner
* the code writer that calls this method.
* @param position
* the position of this label in the bytecode.
* @param data
* the bytecode of the method.
* @return <tt>true</tt> if a blank that was left for this label was to
* small to store the offset. In such a case the corresponding jump
* instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo
* instructions will need to be replaced with true instructions with
* wider offsets (4 bytes instead of 2). This is done in
* {@link MethodWriter#resizeInstructions}.
* @throws IllegalArgumentException
* if this label has already been resolved, or if it has not
* been created by the given code writer.
*/
boolean resolve(final MethodWriter owner, final int position,
final byte[] data) {
boolean needUpdate = false;
this.status |= RESOLVED;
this.position = position;
int i = 0;
while (i < referenceCount) {
int source = srcAndRefPositions[i++];
int reference = srcAndRefPositions[i++];
int offset;
if (source >= 0) {
offset = position - source;
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
/*
* changes the opcode of the jump instruction, in order to
* be able to find it later (see resizeInstructions in
* MethodWriter). These temporary opcodes are similar to
* jump instruction opcodes, except that the 2 bytes offset
* is unsigned (and can therefore represent values from 0 to
* 65535, which is sufficient since the size of a method is
* limited to 65535 bytes).
*/
int opcode = data[reference - 1] & 0xFF;
if (opcode <= Opcodes.JSR) {
// changes IFEQ ... JSR to opcodes 202 to 217
data[reference - 1] = (byte) (opcode + 49);
} else {
// changes IFNULL and IFNONNULL to opcodes 218 and 219
data[reference - 1] = (byte) (opcode + 20);
}
needUpdate = true;
}
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
} else {
offset = position + source + 1;
data[reference++] = (byte) (offset >>> 24);
data[reference++] = (byte) (offset >>> 16);
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
}
}
return needUpdate;
}
/**
* Returns the first label of the series to which this label belongs. For an
* isolated label or for the first label in a series of successive labels,
* this method returns the label itself. For other labels it returns the
* first label of the series.
*
* @return the first label of the series to which this label belongs.
*/
Label getFirst() {
return !ClassReader.FRAMES || frame == null ? this : frame.owner;
}
// ------------------------------------------------------------------------
// Methods related to subroutines
// ------------------------------------------------------------------------
/**
* Returns true is this basic block belongs to the given subroutine.
*
* @param id
* a subroutine id.
* @return true is this basic block belongs to the given subroutine.
*/
boolean inSubroutine(final long id) {
if ((status & Label.VISITED) != 0) {
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
}
return false;
}
/**
* Returns true if this basic block and the given one belong to a common
* subroutine.
*
* @param block
* another basic block.
* @return true if this basic block and the given one belong to a common
* subroutine.
*/
boolean inSameSubroutine(final Label block) {
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
return false;
}
for (int i = 0; i < srcAndRefPositions.length; ++i) {
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
return true;
}
}
return false;
}
/**
* Marks this basic block as belonging to the given subroutine.
*
* @param id
* a subroutine id.
* @param nbSubroutines
* the total number of subroutines in the method.
*/
void addToSubroutine(final long id, final int nbSubroutines) {
if ((status & VISITED) == 0) {
status |= VISITED;
srcAndRefPositions = new int[(nbSubroutines - 1) / 32 + 1];
}
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
}
/**
* Finds the basic blocks that belong to a given subroutine, and marks these
* blocks as belonging to this subroutine. This method follows the control
* flow graph to find all the blocks that are reachable from the current
* block WITHOUT following any JSR target.
*
* @param JSR
* a JSR block that jumps to this subroutine. If this JSR is not
* null it is added to the successor of the RET blocks found in
* the subroutine.
* @param id
* the id of this subroutine.
* @param nbSubroutines
* the total number of subroutines in the method.
*/
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
// user managed stack of labels, to avoid using a recursive method
// (recursivity can lead to stack overflow with very large methods)
Label stack = this;
while (stack != null) {
// removes a label l from the stack
Label l = stack;
stack = l.next;
l.next = null;
if (JSR != null) {
if ((l.status & VISITED2) != 0) {
continue;
}
l.status |= VISITED2;
// adds JSR to the successors of l, if it is a RET block
if ((l.status & RET) != 0) {
if (!l.inSameSubroutine(JSR)) {
Edge e = new Edge();
e.info = l.inputStackTop;
e.successor = JSR.successors.successor;
e.next = l.successors;
l.successors = e;
}
}
} else {
// if the l block already belongs to subroutine 'id', continue
if (l.inSubroutine(id)) {
continue;
}
// marks the l block as belonging to subroutine 'id'
l.addToSubroutine(id, nbSubroutines);
}
// pushes each successor of l on the stack, except JSR targets
Edge e = l.successors;
while (e != null) {
// if the l block is a JSR block, then 'l.successors.next' leads
// to the JSR target (see {@link #visitJumpInsn}) and must
// therefore not be followed
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
// pushes e.successor on the stack if it not already added
if (e.successor.next == null) {
e.successor.next = stack;
stack = e.successor;
}
}
e = e.next;
}
}
}
// ------------------------------------------------------------------------
// Overriden Object methods
// ------------------------------------------------------------------------
/**
* Returns a string representation of this label.
*
* @return a string representation of this label.
*/
@Override
public String toString() {
return "L" + System.identityHashCode(this);
}
}

View File

@ -0,0 +1,662 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* A visitor to visit a Java method. The methods of this class must be called in
* the following order: [ <tt>visitAnnotationDefault</tt> ] (
* <tt>visitAnnotation</tt> | <tt>visitParameterAnnotation</tt> |
* <tt>visitAttribute</tt> )* [ <tt>visitCode</tt> ( <tt>visitFrame</tt> |
* <tt>visit</tt><i>X</i>Insn</tt> | <tt>visitLabel</tt> |
* <tt>visitTryCatchBlock</tt> | <tt>visitLocalVariable</tt> |
* <tt>visitLineNumber</tt> )* <tt>visitMaxs</tt> ] <tt>visitEnd</tt>. In
* addition, the <tt>visit</tt><i>X</i>Insn</tt> and <tt>visitLabel</tt> methods
* must be called in the sequential order of the bytecode instructions of the
* visited code, <tt>visitTryCatchBlock</tt> must be called <i>before</i> the
* labels passed as arguments have been visited, and the
* <tt>visitLocalVariable</tt> and <tt>visitLineNumber</tt> methods must be
* called <i>after</i> the labels passed as arguments have been visited.
*
* @author Eric Bruneton
*/
public abstract class MethodVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}.
*/
protected final int api;
/**
* The method visitor to which this visitor must delegate method calls. May
* be null.
*/
protected MethodVisitor mv;
/**
* Constructs a new {@link MethodVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public MethodVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link MethodVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param mv
* the method visitor to which this visitor must delegate method
* calls. May be null.
*/
public MethodVisitor(final int api, final MethodVisitor mv) {
if (api != Opcodes.ASM4) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
}
// -------------------------------------------------------------------------
// Annotations and non standard attributes
// -------------------------------------------------------------------------
/**
* Visits the default value of this annotation interface method.
*
* @return a visitor to the visit the actual default value of this
* annotation interface method, or <tt>null</tt> if this visitor is
* not interested in visiting this default value. The 'name'
* parameters passed to the methods of this annotation visitor are
* ignored. Moreover, exacly one visit method must be called on this
* annotation visitor, followed by visitEnd.
*/
public AnnotationVisitor visitAnnotationDefault() {
if (mv != null) {
return mv.visitAnnotationDefault();
}
return null;
}
/**
* Visits an annotation of this method.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (mv != null) {
return mv.visitAnnotation(desc, visible);
}
return null;
}
/**
* Visits an annotation of a parameter this method.
*
* @param parameter
* the parameter index.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
*/
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
if (mv != null) {
return mv.visitParameterAnnotation(parameter, desc, visible);
}
return null;
}
/**
* Visits a non standard attribute of this method.
*
* @param attr
* an attribute.
*/
public void visitAttribute(Attribute attr) {
if (mv != null) {
mv.visitAttribute(attr);
}
}
/**
* Starts the visit of the method's code, if any (i.e. non abstract method).
*/
public void visitCode() {
if (mv != null) {
mv.visitCode();
}
}
/**
* Visits the current state of the local variables and operand stack
* elements. This method must(*) be called <i>just before</i> any
* instruction <b>i</b> that follows an unconditional branch instruction
* such as GOTO or THROW, that is the target of a jump instruction, or that
* starts an exception handler block. The visited types must describe the
* values of the local variables and of the operand stack elements <i>just
* before</i> <b>i</b> is executed.<br>
* <br>
* (*) this is mandatory only for classes whose version is greater than or
* equal to {@link Opcodes#V1_6 V1_6}. <br>
* <br>
* The frames of a method must be given either in expanded form, or in
* compressed form (all frames must use the same format, i.e. you must not
* mix expanded and compressed frames within a single method):
* <ul>
* <li>In expanded form, all frames must have the F_NEW type.</li>
* <li>In compressed form, frames are basically "deltas" from the state of
* the previous frame:
* <ul>
* <li>{@link Opcodes#F_SAME} representing frame with exactly the same
* locals as the previous frame and with the empty stack.</li>
* <li>{@link Opcodes#F_SAME1} representing frame with exactly the same
* locals as the previous frame and with single value on the stack (
* <code>nStack</code> is 1 and <code>stack[0]</code> contains value for the
* type of the stack item).</li>
* <li>{@link Opcodes#F_APPEND} representing frame with current locals are
* the same as the locals in the previous frame, except that additional
* locals are defined (<code>nLocal</code> is 1, 2 or 3 and
* <code>local</code> elements contains values representing added types).</li>
* <li>{@link Opcodes#F_CHOP} representing frame with current locals are the
* same as the locals in the previous frame, except that the last 1-3 locals
* are absent and with the empty stack (<code>nLocals</code> is 1, 2 or 3).</li>
* <li>{@link Opcodes#F_FULL} representing complete frame data.</li></li>
* </ul>
* </ul> <br>
* In both cases the first frame, corresponding to the method's parameters
* and access flags, is implicit and must not be visited. Also, it is
* illegal to visit two or more frames for the same code location (i.e., at
* least one instruction must be visited between two calls to visitFrame).
*
* @param type
* the type of this stack map frame. Must be
* {@link Opcodes#F_NEW} for expanded frames, or
* {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for
* compressed frames.
* @param nLocal
* the number of local variables in the visited frame.
* @param local
* the local variable types in this frame. This array must not be
* modified. Primitive types are represented by
* {@link Opcodes#TOP}, {@link Opcodes#INTEGER},
* {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are
* represented by a single element). Reference types are
* represented by String objects (representing internal names),
* and uninitialized types by Label objects (this label
* designates the NEW instruction that created this uninitialized
* value).
* @param nStack
* the number of operand stack elements in the visited frame.
* @param stack
* the operand stack types in this frame. This array must not be
* modified. Its content has the same format as the "local"
* array.
* @throws IllegalStateException
* if a frame is visited just after another one, without any
* instruction between the two (unless this frame is a
* Opcodes#F_SAME frame, in which case it is silently ignored).
*/
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack);
}
}
// -------------------------------------------------------------------------
// Normal instructions
// -------------------------------------------------------------------------
/**
* Visits a zero operand instruction.
*
* @param opcode
* the opcode of the instruction to be visited. This opcode is
* either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
* or MONITOREXIT.
*/
public void visitInsn(int opcode) {
if (mv != null) {
mv.visitInsn(opcode);
}
}
/**
* Visits an instruction with a single int operand.
*
* @param opcode
* the opcode of the instruction to be visited. This opcode is
* either BIPUSH, SIPUSH or NEWARRAY.
* @param operand
* the operand of the instruction to be visited.<br>
* When opcode is BIPUSH, operand value should be between
* Byte.MIN_VALUE and Byte.MAX_VALUE.<br>
* When opcode is SIPUSH, operand value should be between
* Short.MIN_VALUE and Short.MAX_VALUE.<br>
* When opcode is NEWARRAY, operand value should be one of
* {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR},
* {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE},
* {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT},
* {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}.
*/
public void visitIntInsn(int opcode, int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
}
/**
* Visits a local variable instruction. A local variable instruction is an
* instruction that loads or stores the value of a local variable.
*
* @param opcode
* the opcode of the local variable instruction to be visited.
* This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD,
* ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
* @param var
* the operand of the instruction to be visited. This operand is
* the index of a local variable.
*/
public void visitVarInsn(int opcode, int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
}
/**
* Visits a type instruction. A type instruction is an instruction that
* takes the internal name of a class as parameter.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param type
* the operand of the instruction to be visited. This operand
* must be the internal name of an object or array class (see
* {@link Type#getInternalName() getInternalName}).
*/
public void visitTypeInsn(int opcode, String type) {
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
}
/**
* Visits a field instruction. A field instruction is an instruction that
* loads or stores the value of a field of an object.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner
* the internal name of the field's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type Type}).
*/
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
}
/**
* Visits a method instruction. A method instruction is an instruction that
* invokes a method.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link Type#getInternalName() getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
/**
* Visits an invokedynamic instruction.
*
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long},
* {@link Double}, {@link String}, {@link Type} or {@link Handle}
* value. This method is allowed to modify the content of the
* array so a caller should expect that this array may change.
*/
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
}
/**
* Visits a jump instruction. A jump instruction is an instruction that may
* jump to another instruction.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode
* is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label
* the operand of the instruction to be visited. This operand is
* a label that designates the instruction to which the jump
* instruction may jump.
*/
public void visitJumpInsn(int opcode, Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
}
/**
* Visits a label. A label designates the instruction that will be visited
* just after it.
*
* @param label
* a {@link Label Label} object.
*/
public void visitLabel(Label label) {
if (mv != null) {
mv.visitLabel(label);
}
}
// -------------------------------------------------------------------------
// Special instructions
// -------------------------------------------------------------------------
/**
* Visits a LDC instruction. Note that new constant types may be added in
* future versions of the Java Virtual Machine. To easily detect new
* constant types, implementations of this method should check for
* unexpected constant types, like this:
*
* <pre>
* if (cst instanceof Integer) {
* // ...
* } else if (cst instanceof Float) {
* // ...
* } else if (cst instanceof Long) {
* // ...
* } else if (cst instanceof Double) {
* // ...
* } else if (cst instanceof String) {
* // ...
* } else if (cst instanceof Type) {
* int sort = ((Type) cst).getSort();
* if (sort == Type.OBJECT) {
* // ...
* } else if (sort == Type.ARRAY) {
* // ...
* } else if (sort == Type.METHOD) {
* // ...
* } else {
* // throw an exception
* }
* } else if (cst instanceof Handle) {
* // ...
* } else {
* // throw an exception
* }
* </pre>
*
* @param cst
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double}, a {@link String}, a {@link Type} of OBJECT or
* ARRAY sort for <tt>.class</tt> constants, for classes whose
* version is 49.0, a {@link Type} of METHOD sort or a
* {@link Handle} for MethodType and MethodHandle constants, for
* classes whose version is 51.0.
*/
public void visitLdcInsn(Object cst) {
if (mv != null) {
mv.visitLdcInsn(cst);
}
}
/**
* Visits an IINC instruction.
*
* @param var
* index of the local variable to be incremented.
* @param increment
* amount to increment the local variable by.
*/
public void visitIincInsn(int var, int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
}
/**
* Visits a TABLESWITCH instruction.
*
* @param min
* the minimum key value.
* @param max
* the maximum key value.
* @param dflt
* beginning of the default handler block.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
*/
public void visitTableSwitchInsn(int min, int max, Label dflt,
Label... labels) {
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
}
/**
* Visits a LOOKUPSWITCH instruction.
*
* @param dflt
* beginning of the default handler block.
* @param keys
* the values of the keys.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
*/
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
}
/**
* Visits a MULTIANEWARRAY instruction.
*
* @param desc
* an array type descriptor (see {@link Type Type}).
* @param dims
* number of dimensions of the array to allocate.
*/
public void visitMultiANewArrayInsn(String desc, int dims) {
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
}
// -------------------------------------------------------------------------
// Exceptions table entries, debug information, max stack and max locals
// -------------------------------------------------------------------------
/**
* Visits a try catch block.
*
* @param start
* beginning of the exception handler's scope (inclusive).
* @param end
* end of the exception handler's scope (exclusive).
* @param handler
* beginning of the exception handler's code.
* @param type
* internal name of the type of exceptions handled by the
* handler, or <tt>null</tt> to catch any exceptions (for
* "finally" blocks).
* @throws IllegalArgumentException
* if one of the labels has already been visited by this visitor
* (by the {@link #visitLabel visitLabel} method).
*/
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
if (mv != null) {
mv.visitTryCatchBlock(start, end, handler, type);
}
}
/**
* Visits a local variable declaration.
*
* @param name
* the name of a local variable.
* @param desc
* the type descriptor of this local variable.
* @param signature
* the type signature of this local variable. May be
* <tt>null</tt> if the local variable type does not use generic
* types.
* @param start
* the first instruction corresponding to the scope of this local
* variable (inclusive).
* @param end
* the last instruction corresponding to the scope of this local
* variable (exclusive).
* @param index
* the local variable's index.
* @throws IllegalArgumentException
* if one of the labels has not already been visited by this
* visitor (by the {@link #visitLabel visitLabel} method).
*/
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
if (mv != null) {
mv.visitLocalVariable(name, desc, signature, start, end, index);
}
}
/**
* Visits a line number declaration.
*
* @param line
* a line number. This number refers to the source file from
* which the class was compiled.
* @param start
* the first instruction corresponding to this line number.
* @throws IllegalArgumentException
* if <tt>start</tt> has not already been visited by this
* visitor (by the {@link #visitLabel visitLabel} method).
*/
public void visitLineNumber(int line, Label start) {
if (mv != null) {
mv.visitLineNumber(line, start);
}
}
/**
* Visits the maximum stack size and the maximum number of local variables
* of the method.
*
* @param maxStack
* maximum stack size of the method.
* @param maxLocals
* maximum number of local variables for the method.
*/
public void visitMaxs(int maxStack, int maxLocals) {
if (mv != null) {
mv.visitMaxs(maxStack, maxLocals);
}
}
/**
* Visits the end of the method. This method, which is the last one to be
* called, is used to inform the visitor that all the annotations and
* attributes of the method have been visited.
*/
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,360 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
/**
* Defines the JVM opcodes, access flags and array type codes. This interface
* does not define all the JVM opcodes because some opcodes are automatically
* handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
* opcodes are therefore not defined in this interface. Likewise for LDC,
* automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
* JSR_W.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public interface Opcodes {
// ASM API versions
int ASM4 = 4 << 16 | 0 << 8 | 0;
// versions
int V1_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46;
int V1_3 = 0 << 16 | 47;
int V1_4 = 0 << 16 | 48;
int V1_5 = 0 << 16 | 49;
int V1_6 = 0 << 16 | 50;
int V1_7 = 0 << 16 | 51;
int V1_8 = 0 << 16 | 52;
// access flags
int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // class, field, method
int ACC_PROTECTED = 0x0004; // class, field, method
int ACC_STATIC = 0x0008; // field, method
int ACC_FINAL = 0x0010; // class, field, method
int ACC_SUPER = 0x0020; // class
int ACC_SYNCHRONIZED = 0x0020; // method
int ACC_VOLATILE = 0x0040; // field
int ACC_BRIDGE = 0x0040; // method
int ACC_VARARGS = 0x0080; // method
int ACC_TRANSIENT = 0x0080; // field
int ACC_NATIVE = 0x0100; // method
int ACC_INTERFACE = 0x0200; // class
int ACC_ABSTRACT = 0x0400; // class, method
int ACC_STRICT = 0x0800; // method
int ACC_SYNTHETIC = 0x1000; // class, field, method
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
// ASM specific pseudo access flags
int ACC_DEPRECATED = 0x20000; // class, field, method
// types for NEWARRAY
int T_BOOLEAN = 4;
int T_CHAR = 5;
int T_FLOAT = 6;
int T_DOUBLE = 7;
int T_BYTE = 8;
int T_SHORT = 9;
int T_INT = 10;
int T_LONG = 11;
// tags for Handle
int H_GETFIELD = 1;
int H_GETSTATIC = 2;
int H_PUTFIELD = 3;
int H_PUTSTATIC = 4;
int H_INVOKEVIRTUAL = 5;
int H_INVOKESTATIC = 6;
int H_INVOKESPECIAL = 7;
int H_NEWINVOKESPECIAL = 8;
int H_INVOKEINTERFACE = 9;
// stack map frame types
/**
* Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
*/
int F_NEW = -1;
/**
* Represents a compressed frame with complete frame data.
*/
int F_FULL = 0;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that additional 1-3 locals are defined, and
* with an empty stack.
*/
int F_APPEND = 1;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that the last 1-3 locals are absent and with
* an empty stack.
*/
int F_CHOP = 2;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with an empty stack.
*/
int F_SAME = 3;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with a single value on the stack.
*/
int F_SAME1 = 4;
Integer TOP = new Integer(0);
Integer INTEGER = new Integer(1);
Integer FLOAT = new Integer(2);
Integer DOUBLE = new Integer(3);
Integer LONG = new Integer(4);
Integer NULL = new Integer(5);
Integer UNINITIALIZED_THIS = new Integer(6);
// opcodes // visit method (- = idem)
int NOP = 0; // visitInsn
int ACONST_NULL = 1; // -
int ICONST_M1 = 2; // -
int ICONST_0 = 3; // -
int ICONST_1 = 4; // -
int ICONST_2 = 5; // -
int ICONST_3 = 6; // -
int ICONST_4 = 7; // -
int ICONST_5 = 8; // -
int LCONST_0 = 9; // -
int LCONST_1 = 10; // -
int FCONST_0 = 11; // -
int FCONST_1 = 12; // -
int FCONST_2 = 13; // -
int DCONST_0 = 14; // -
int DCONST_1 = 15; // -
int BIPUSH = 16; // visitIntInsn
int SIPUSH = 17; // -
int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // -
int FLOAD = 23; // -
int DLOAD = 24; // -
int ALOAD = 25; // -
// int ILOAD_0 = 26; // -
// int ILOAD_1 = 27; // -
// int ILOAD_2 = 28; // -
// int ILOAD_3 = 29; // -
// int LLOAD_0 = 30; // -
// int LLOAD_1 = 31; // -
// int LLOAD_2 = 32; // -
// int LLOAD_3 = 33; // -
// int FLOAD_0 = 34; // -
// int FLOAD_1 = 35; // -
// int FLOAD_2 = 36; // -
// int FLOAD_3 = 37; // -
// int DLOAD_0 = 38; // -
// int DLOAD_1 = 39; // -
// int DLOAD_2 = 40; // -
// int DLOAD_3 = 41; // -
// int ALOAD_0 = 42; // -
// int ALOAD_1 = 43; // -
// int ALOAD_2 = 44; // -
// int ALOAD_3 = 45; // -
int IALOAD = 46; // visitInsn
int LALOAD = 47; // -
int FALOAD = 48; // -
int DALOAD = 49; // -
int AALOAD = 50; // -
int BALOAD = 51; // -
int CALOAD = 52; // -
int SALOAD = 53; // -
int ISTORE = 54; // visitVarInsn
int LSTORE = 55; // -
int FSTORE = 56; // -
int DSTORE = 57; // -
int ASTORE = 58; // -
// int ISTORE_0 = 59; // -
// int ISTORE_1 = 60; // -
// int ISTORE_2 = 61; // -
// int ISTORE_3 = 62; // -
// int LSTORE_0 = 63; // -
// int LSTORE_1 = 64; // -
// int LSTORE_2 = 65; // -
// int LSTORE_3 = 66; // -
// int FSTORE_0 = 67; // -
// int FSTORE_1 = 68; // -
// int FSTORE_2 = 69; // -
// int FSTORE_3 = 70; // -
// int DSTORE_0 = 71; // -
// int DSTORE_1 = 72; // -
// int DSTORE_2 = 73; // -
// int DSTORE_3 = 74; // -
// int ASTORE_0 = 75; // -
// int ASTORE_1 = 76; // -
// int ASTORE_2 = 77; // -
// int ASTORE_3 = 78; // -
int IASTORE = 79; // visitInsn
int LASTORE = 80; // -
int FASTORE = 81; // -
int DASTORE = 82; // -
int AASTORE = 83; // -
int BASTORE = 84; // -
int CASTORE = 85; // -
int SASTORE = 86; // -
int POP = 87; // -
int POP2 = 88; // -
int DUP = 89; // -
int DUP_X1 = 90; // -
int DUP_X2 = 91; // -
int DUP2 = 92; // -
int DUP2_X1 = 93; // -
int DUP2_X2 = 94; // -
int SWAP = 95; // -
int IADD = 96; // -
int LADD = 97; // -
int FADD = 98; // -
int DADD = 99; // -
int ISUB = 100; // -
int LSUB = 101; // -
int FSUB = 102; // -
int DSUB = 103; // -
int IMUL = 104; // -
int LMUL = 105; // -
int FMUL = 106; // -
int DMUL = 107; // -
int IDIV = 108; // -
int LDIV = 109; // -
int FDIV = 110; // -
int DDIV = 111; // -
int IREM = 112; // -
int LREM = 113; // -
int FREM = 114; // -
int DREM = 115; // -
int INEG = 116; // -
int LNEG = 117; // -
int FNEG = 118; // -
int DNEG = 119; // -
int ISHL = 120; // -
int LSHL = 121; // -
int ISHR = 122; // -
int LSHR = 123; // -
int IUSHR = 124; // -
int LUSHR = 125; // -
int IAND = 126; // -
int LAND = 127; // -
int IOR = 128; // -
int LOR = 129; // -
int IXOR = 130; // -
int LXOR = 131; // -
int IINC = 132; // visitIincInsn
int I2L = 133; // visitInsn
int I2F = 134; // -
int I2D = 135; // -
int L2I = 136; // -
int L2F = 137; // -
int L2D = 138; // -
int F2I = 139; // -
int F2L = 140; // -
int F2D = 141; // -
int D2I = 142; // -
int D2L = 143; // -
int D2F = 144; // -
int I2B = 145; // -
int I2C = 146; // -
int I2S = 147; // -
int LCMP = 148; // -
int FCMPL = 149; // -
int FCMPG = 150; // -
int DCMPL = 151; // -
int DCMPG = 152; // -
int IFEQ = 153; // visitJumpInsn
int IFNE = 154; // -
int IFLT = 155; // -
int IFGE = 156; // -
int IFGT = 157; // -
int IFLE = 158; // -
int IF_ICMPEQ = 159; // -
int IF_ICMPNE = 160; // -
int IF_ICMPLT = 161; // -
int IF_ICMPGE = 162; // -
int IF_ICMPGT = 163; // -
int IF_ICMPLE = 164; // -
int IF_ACMPEQ = 165; // -
int IF_ACMPNE = 166; // -
int GOTO = 167; // -
int JSR = 168; // -
int RET = 169; // visitVarInsn
int TABLESWITCH = 170; // visiTableSwitchInsn
int LOOKUPSWITCH = 171; // visitLookupSwitch
int IRETURN = 172; // visitInsn
int LRETURN = 173; // -
int FRETURN = 174; // -
int DRETURN = 175; // -
int ARETURN = 176; // -
int RETURN = 177; // -
int GETSTATIC = 178; // visitFieldInsn
int PUTSTATIC = 179; // -
int GETFIELD = 180; // -
int PUTFIELD = 181; // -
int INVOKEVIRTUAL = 182; // visitMethodInsn
int INVOKESPECIAL = 183; // -
int INVOKESTATIC = 184; // -
int INVOKEINTERFACE = 185; // -
int INVOKEDYNAMIC = 186; // visitInvokeDynamicInsn
int NEW = 187; // visitTypeInsn
int NEWARRAY = 188; // visitIntInsn
int ANEWARRAY = 189; // visitTypeInsn
int ARRAYLENGTH = 190; // visitInsn
int ATHROW = 191; // -
int CHECKCAST = 192; // visitTypeInsn
int INSTANCEOF = 193; // -
int MONITORENTER = 194; // visitInsn
int MONITOREXIT = 195; // -
// int WIDE = 196; // NOT VISITED
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // -
// int GOTO_W = 200; // -
// int JSR_W = 201; // -
}

View File

@ -0,0 +1,895 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* A Java field or method type. This class can be used to make it easier to
* manipulate type and method descriptors.
*
* @author Eric Bruneton
* @author Chris Nokleberg
*/
public class Type {
/**
* The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
*/
public static final int VOID = 0;
/**
* The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
*/
public static final int BOOLEAN = 1;
/**
* The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
*/
public static final int CHAR = 2;
/**
* The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
*/
public static final int BYTE = 3;
/**
* The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
*/
public static final int SHORT = 4;
/**
* The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
*/
public static final int INT = 5;
/**
* The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
*/
public static final int FLOAT = 6;
/**
* The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
*/
public static final int LONG = 7;
/**
* The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
*/
public static final int DOUBLE = 8;
/**
* The sort of array reference types. See {@link #getSort getSort}.
*/
public static final int ARRAY = 9;
/**
* The sort of object reference types. See {@link #getSort getSort}.
*/
public static final int OBJECT = 10;
/**
* The sort of method types. See {@link #getSort getSort}.
*/
public static final int METHOD = 11;
/**
* The <tt>void</tt> type.
*/
public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24)
| (5 << 16) | (0 << 8) | 0, 1);
/**
* The <tt>boolean</tt> type.
*/
public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>char</tt> type.
*/
public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24)
| (0 << 16) | (6 << 8) | 1, 1);
/**
* The <tt>byte</tt> type.
*/
public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24)
| (0 << 16) | (5 << 8) | 1, 1);
/**
* The <tt>short</tt> type.
*/
public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24)
| (0 << 16) | (7 << 8) | 1, 1);
/**
* The <tt>int</tt> type.
*/
public static final Type INT_TYPE = new Type(INT, null, ('I' << 24)
| (0 << 16) | (0 << 8) | 1, 1);
/**
* The <tt>float</tt> type.
*/
public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24)
| (2 << 16) | (2 << 8) | 1, 1);
/**
* The <tt>long</tt> type.
*/
public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24)
| (1 << 16) | (1 << 8) | 2, 1);
/**
* The <tt>double</tt> type.
*/
public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24)
| (3 << 16) | (3 << 8) | 2, 1);
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
/**
* The sort of this Java type.
*/
private final int sort;
/**
* A buffer containing the internal name of this Java type. This field is
* only used for reference types.
*/
private final char[] buf;
/**
* The offset of the internal name of this Java type in {@link #buf buf} or,
* for primitive types, the size, descriptor and getOpcode offsets for this
* type (byte 0 contains the size, byte 1 the descriptor, byte 2 the offset
* for IALOAD or IASTORE, byte 3 the offset for all other instructions).
*/
private final int off;
/**
* The length of the internal name of this Java type.
*/
private final int len;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructs a reference type.
*
* @param sort
* the sort of the reference type to be constructed.
* @param buf
* a buffer containing the descriptor of the previous type.
* @param off
* the offset of this descriptor in the previous buffer.
* @param len
* the length of this descriptor.
*/
private Type(final int sort, final char[] buf, final int off, final int len) {
this.sort = sort;
this.buf = buf;
this.off = off;
this.len = len;
}
/**
* Returns the Java type corresponding to the given type descriptor.
*
* @param typeDescriptor
* a field or method type descriptor.
* @return the Java type corresponding to the given type descriptor.
*/
public static Type getType(final String typeDescriptor) {
return getType(typeDescriptor.toCharArray(), 0);
}
/**
* Returns the Java type corresponding to the given internal name.
*
* @param internalName
* an internal name.
* @return the Java type corresponding to the given internal name.
*/
public static Type getObjectType(final String internalName) {
char[] buf = internalName.toCharArray();
return new Type(buf[0] == '[' ? ARRAY : OBJECT, buf, 0, buf.length);
}
/**
* Returns the Java type corresponding to the given method descriptor.
* Equivalent to <code>Type.getType(methodDescriptor)</code>.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java type corresponding to the given method descriptor.
*/
public static Type getMethodType(final String methodDescriptor) {
return getType(methodDescriptor.toCharArray(), 0);
}
/**
* Returns the Java method type corresponding to the given argument and
* return types.
*
* @param returnType
* the return type of the method.
* @param argumentTypes
* the argument types of the method.
* @return the Java type corresponding to the given argument and return
* types.
*/
public static Type getMethodType(final Type returnType,
final Type... argumentTypes) {
return getType(getMethodDescriptor(returnType, argumentTypes));
}
/**
* Returns the Java type corresponding to the given class.
*
* @param c
* a class.
* @return the Java type corresponding to the given class.
*/
public static Type getType(final Class<?> c) {
if (c.isPrimitive()) {
if (c == Integer.TYPE) {
return INT_TYPE;
} else if (c == Void.TYPE) {
return VOID_TYPE;
} else if (c == Boolean.TYPE) {
return BOOLEAN_TYPE;
} else if (c == Byte.TYPE) {
return BYTE_TYPE;
} else if (c == Character.TYPE) {
return CHAR_TYPE;
} else if (c == Short.TYPE) {
return SHORT_TYPE;
} else if (c == Double.TYPE) {
return DOUBLE_TYPE;
} else if (c == Float.TYPE) {
return FLOAT_TYPE;
} else /* if (c == Long.TYPE) */{
return LONG_TYPE;
}
} else {
return getType(getDescriptor(c));
}
}
/**
* Returns the Java method type corresponding to the given constructor.
*
* @param c
* a {@link Constructor Constructor} object.
* @return the Java method type corresponding to the given constructor.
*/
public static Type getType(final Constructor<?> c) {
return getType(getConstructorDescriptor(c));
}
/**
* Returns the Java method type corresponding to the given method.
*
* @param m
* a {@link Method Method} object.
* @return the Java method type corresponding to the given method.
*/
public static Type getType(final Method m) {
return getType(getMethodDescriptor(m));
}
/**
* Returns the Java types corresponding to the argument types of the given
* method descriptor.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java types corresponding to the argument types of the given
* method descriptor.
*/
public static Type[] getArgumentTypes(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
int off = 1;
int size = 0;
while (true) {
char car = buf[off++];
if (car == ')') {
break;
} else if (car == 'L') {
while (buf[off++] != ';') {
}
++size;
} else if (car != '[') {
++size;
}
}
Type[] args = new Type[size];
off = 1;
size = 0;
while (buf[off] != ')') {
args[size] = getType(buf, off);
off += args[size].len + (args[size].sort == OBJECT ? 2 : 0);
size += 1;
}
return args;
}
/**
* Returns the Java types corresponding to the argument types of the given
* method.
*
* @param method
* a method.
* @return the Java types corresponding to the argument types of the given
* method.
*/
public static Type[] getArgumentTypes(final Method method) {
Class<?>[] classes = method.getParameterTypes();
Type[] types = new Type[classes.length];
for (int i = classes.length - 1; i >= 0; --i) {
types[i] = getType(classes[i]);
}
return types;
}
/**
* Returns the Java type corresponding to the return type of the given
* method descriptor.
*
* @param methodDescriptor
* a method descriptor.
* @return the Java type corresponding to the return type of the given
* method descriptor.
*/
public static Type getReturnType(final String methodDescriptor) {
char[] buf = methodDescriptor.toCharArray();
return getType(buf, methodDescriptor.indexOf(')') + 1);
}
/**
* Returns the Java type corresponding to the return type of the given
* method.
*
* @param method
* a method.
* @return the Java type corresponding to the return type of the given
* method.
*/
public static Type getReturnType(final Method method) {
return getType(method.getReturnType());
}
/**
* Computes the size of the arguments and of the return value of a method.
*
* @param desc
* the descriptor of a method.
* @return the size of the arguments of the method (plus one for the
* implicit this argument), argSize, and the size of its return
* value, retSize, packed into a single int i =
* <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal to
* <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
*/
public static int getArgumentsAndReturnSizes(final String desc) {
int n = 1;
int c = 1;
while (true) {
char car = desc.charAt(c++);
if (car == ')') {
car = desc.charAt(c);
return n << 2
| (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
} else if (car == 'L') {
while (desc.charAt(c++) != ';') {
}
n += 1;
} else if (car == '[') {
while ((car = desc.charAt(c)) == '[') {
++c;
}
if (car == 'D' || car == 'J') {
n -= 1;
}
} else if (car == 'D' || car == 'J') {
n += 2;
} else {
n += 1;
}
}
}
/**
* Returns the Java type corresponding to the given type descriptor. For
* method descriptors, buf is supposed to contain nothing more than the
* descriptor itself.
*
* @param buf
* a buffer containing a type descriptor.
* @param off
* the offset of this descriptor in the previous buffer.
* @return the Java type corresponding to the given type descriptor.
*/
private static Type getType(final char[] buf, final int off) {
int len;
switch (buf[off]) {
case 'V':
return VOID_TYPE;
case 'Z':
return BOOLEAN_TYPE;
case 'C':
return CHAR_TYPE;
case 'B':
return BYTE_TYPE;
case 'S':
return SHORT_TYPE;
case 'I':
return INT_TYPE;
case 'F':
return FLOAT_TYPE;
case 'J':
return LONG_TYPE;
case 'D':
return DOUBLE_TYPE;
case '[':
len = 1;
while (buf[off + len] == '[') {
++len;
}
if (buf[off + len] == 'L') {
++len;
while (buf[off + len] != ';') {
++len;
}
}
return new Type(ARRAY, buf, off, len + 1);
case 'L':
len = 1;
while (buf[off + len] != ';') {
++len;
}
return new Type(OBJECT, buf, off + 1, len - 1);
// case '(':
default:
return new Type(METHOD, buf, off, buf.length - off);
}
}
// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
/**
* Returns the sort of this Java type.
*
* @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
* {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT},
* {@link #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE},
* {@link #ARRAY ARRAY}, {@link #OBJECT OBJECT} or {@link #METHOD
* METHOD}.
*/
public int getSort() {
return sort;
}
/**
* Returns the number of dimensions of this array type. This method should
* only be used for an array type.
*
* @return the number of dimensions of this array type.
*/
public int getDimensions() {
int i = 1;
while (buf[off + i] == '[') {
++i;
}
return i;
}
/**
* Returns the type of the elements of this array type. This method should
* only be used for an array type.
*
* @return Returns the type of the elements of this array type.
*/
public Type getElementType() {
return getType(buf, off + getDimensions());
}
/**
* Returns the binary name of the class corresponding to this type. This
* method must not be used on method types.
*
* @return the binary name of the class corresponding to this type.
*/
public String getClassName() {
switch (sort) {
case VOID:
return "void";
case BOOLEAN:
return "boolean";
case CHAR:
return "char";
case BYTE:
return "byte";
case SHORT:
return "short";
case INT:
return "int";
case FLOAT:
return "float";
case LONG:
return "long";
case DOUBLE:
return "double";
case ARRAY:
StringBuffer b = new StringBuffer(getElementType().getClassName());
for (int i = getDimensions(); i > 0; --i) {
b.append("[]");
}
return b.toString();
case OBJECT:
return new String(buf, off, len).replace('/', '.');
default:
return null;
}
}
/**
* Returns the internal name of the class corresponding to this object or
* array type. The internal name of a class is its fully qualified name (as
* returned by Class.getName(), where '.' are replaced by '/'. This method
* should only be used for an object or array type.
*
* @return the internal name of the class corresponding to this object type.
*/
public String getInternalName() {
return new String(buf, off, len);
}
/**
* Returns the argument types of methods of this type. This method should
* only be used for method types.
*
* @return the argument types of methods of this type.
*/
public Type[] getArgumentTypes() {
return getArgumentTypes(getDescriptor());
}
/**
* Returns the return type of methods of this type. This method should only
* be used for method types.
*
* @return the return type of methods of this type.
*/
public Type getReturnType() {
return getReturnType(getDescriptor());
}
/**
* Returns the size of the arguments and of the return value of methods of
* this type. This method should only be used for method types.
*
* @return the size of the arguments (plus one for the implicit this
* argument), argSize, and the size of the return value, retSize,
* packed into a single int i = <tt>(argSize << 2) | retSize</tt>
* (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
* <tt>i & 0x03</tt>).
*/
public int getArgumentsAndReturnSizes() {
return getArgumentsAndReturnSizes(getDescriptor());
}
// ------------------------------------------------------------------------
// Conversion to type descriptors
// ------------------------------------------------------------------------
/**
* Returns the descriptor corresponding to this Java type.
*
* @return the descriptor corresponding to this Java type.
*/
public String getDescriptor() {
StringBuffer buf = new StringBuffer();
getDescriptor(buf);
return buf.toString();
}
/**
* Returns the descriptor corresponding to the given argument and return
* types.
*
* @param returnType
* the return type of the method.
* @param argumentTypes
* the argument types of the method.
* @return the descriptor corresponding to the given argument and return
* types.
*/
public static String getMethodDescriptor(final Type returnType,
final Type... argumentTypes) {
StringBuffer buf = new StringBuffer();
buf.append('(');
for (int i = 0; i < argumentTypes.length; ++i) {
argumentTypes[i].getDescriptor(buf);
}
buf.append(')');
returnType.getDescriptor(buf);
return buf.toString();
}
/**
* Appends the descriptor corresponding to this Java type to the given
* string buffer.
*
* @param buf
* the string buffer to which the descriptor must be appended.
*/
private void getDescriptor(final StringBuffer buf) {
if (this.buf == null) {
// descriptor is in byte 3 of 'off' for primitive types (buf ==
// null)
buf.append((char) ((off & 0xFF000000) >>> 24));
} else if (sort == OBJECT) {
buf.append('L');
buf.append(this.buf, off, len);
buf.append(';');
} else { // sort == ARRAY || sort == METHOD
buf.append(this.buf, off, len);
}
}
// ------------------------------------------------------------------------
// Direct conversion from classes to type descriptors,
// without intermediate Type objects
// ------------------------------------------------------------------------
/**
* Returns the internal name of the given class. The internal name of a
* class is its fully qualified name, as returned by Class.getName(), where
* '.' are replaced by '/'.
*
* @param c
* an object or array class.
* @return the internal name of the given class.
*/
public static String getInternalName(final Class<?> c) {
return c.getName().replace('.', '/');
}
/**
* Returns the descriptor corresponding to the given Java type.
*
* @param c
* an object class, a primitive class or an array class.
* @return the descriptor corresponding to the given class.
*/
public static String getDescriptor(final Class<?> c) {
StringBuffer buf = new StringBuffer();
getDescriptor(buf, c);
return buf.toString();
}
/**
* Returns the descriptor corresponding to the given constructor.
*
* @param c
* a {@link Constructor Constructor} object.
* @return the descriptor of the given constructor.
*/
public static String getConstructorDescriptor(final Constructor<?> c) {
Class<?>[] parameters = c.getParameterTypes();
StringBuffer buf = new StringBuffer();
buf.append('(');
for (int i = 0; i < parameters.length; ++i) {
getDescriptor(buf, parameters[i]);
}
return buf.append(")V").toString();
}
/**
* Returns the descriptor corresponding to the given method.
*
* @param m
* a {@link Method Method} object.
* @return the descriptor of the given method.
*/
public static String getMethodDescriptor(final Method m) {
Class<?>[] parameters = m.getParameterTypes();
StringBuffer buf = new StringBuffer();
buf.append('(');
for (int i = 0; i < parameters.length; ++i) {
getDescriptor(buf, parameters[i]);
}
buf.append(')');
getDescriptor(buf, m.getReturnType());
return buf.toString();
}
/**
* Appends the descriptor of the given class to the given string buffer.
*
* @param buf
* the string buffer to which the descriptor must be appended.
* @param c
* the class whose descriptor must be computed.
*/
private static void getDescriptor(final StringBuffer buf, final Class<?> c) {
Class<?> d = c;
while (true) {
if (d.isPrimitive()) {
char car;
if (d == Integer.TYPE) {
car = 'I';
} else if (d == Void.TYPE) {
car = 'V';
} else if (d == Boolean.TYPE) {
car = 'Z';
} else if (d == Byte.TYPE) {
car = 'B';
} else if (d == Character.TYPE) {
car = 'C';
} else if (d == Short.TYPE) {
car = 'S';
} else if (d == Double.TYPE) {
car = 'D';
} else if (d == Float.TYPE) {
car = 'F';
} else /* if (d == Long.TYPE) */{
car = 'J';
}
buf.append(car);
return;
} else if (d.isArray()) {
buf.append('[');
d = d.getComponentType();
} else {
buf.append('L');
String name = d.getName();
int len = name.length();
for (int i = 0; i < len; ++i) {
char car = name.charAt(i);
buf.append(car == '.' ? '/' : car);
}
buf.append(';');
return;
}
}
}
// ------------------------------------------------------------------------
// Corresponding size and opcodes
// ------------------------------------------------------------------------
/**
* Returns the size of values of this type. This method must not be used for
* method types.
*
* @return the size of values of this type, i.e., 2 for <tt>long</tt> and
* <tt>double</tt>, 0 for <tt>void</tt> and 1 otherwise.
*/
public int getSize() {
// the size is in byte 0 of 'off' for primitive types (buf == null)
return buf == null ? (off & 0xFF) : 1;
}
/**
* Returns a JVM instruction opcode adapted to this Java type. This method
* must not be used for method types.
*
* @param opcode
* a JVM instruction opcode. This opcode must be one of ILOAD,
* ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG,
* ISHL, ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
* @return an opcode that is similar to the given opcode, but adapted to
* this Java type. For example, if this type is <tt>float</tt> and
* <tt>opcode</tt> is IRETURN, this method returns FRETURN.
*/
public int getOpcode(final int opcode) {
if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) {
// the offset for IALOAD or IASTORE is in byte 1 of 'off' for
// primitive types (buf == null)
return opcode + (buf == null ? (off & 0xFF00) >> 8 : 4);
} else {
// the offset for other instructions is in byte 2 of 'off' for
// primitive types (buf == null)
return opcode + (buf == null ? (off & 0xFF0000) >> 16 : 4);
}
}
// ------------------------------------------------------------------------
// Equals, hashCode and toString
// ------------------------------------------------------------------------
/**
* Tests if the given object is equal to this type.
*
* @param o
* the object to be compared to this type.
* @return <tt>true</tt> if the given object is equal to this type.
*/
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Type)) {
return false;
}
Type t = (Type) o;
if (sort != t.sort) {
return false;
}
if (sort >= ARRAY) {
if (len != t.len) {
return false;
}
for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
if (buf[i] != t.buf[j]) {
return false;
}
}
}
return true;
}
/**
* Returns a hash code value for this type.
*
* @return a hash code value for this type.
*/
@Override
public int hashCode() {
int hc = 13 * sort;
if (sort >= ARRAY) {
for (int i = off, end = i + len; i < end; i++) {
hc = 17 * (hc + buf[i]);
}
}
return hc;
}
/**
* Returns a string representation of this type.
*
* @return the descriptor of this type.
*/
@Override
public String toString() {
return getDescriptor();
}
}

View File

@ -0,0 +1,48 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.
-->
<body>
Provides an implementation for optional class, field and method attributes.
<p>
By default ASM strips optional attributes, in order to keep them in
the bytecode that is being readed you should pass an array of required attribute
instances to {@link org.objectweb.asm.ClassReader#accept(org.objectweb.asm.ClassVisitor, org.objectweb.asm.Attribute[], boolean) ClassReader.accept()} method.
In order to add custom attributes to the manually constructed bytecode concrete
subclasses of the {@link org.objectweb.asm.Attribute Attribute} can be passed to
the visitAttribute methods of the
{@link org.objectweb.asm.ClassVisitor ClassVisitor},
{@link org.objectweb.asm.FieldVisitor FieldVisitor} and
{@link org.objectweb.asm.MethodVisitor MethodVisitor} interfaces.
@since ASM 1.4.1
</body>
</html>

View File

@ -0,0 +1,625 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around
* advices in methods and constructors.
* <p>
* The behavior for constructors is like this:
* <ol>
*
* <li>as long as the INVOKESPECIAL for the object initialization has not been
* reached, every bytecode instruction is dispatched in the ctor code visitor</li>
*
* <li>when this one is reached, it is only added in the ctor code visitor and a
* JP invoke is added</li>
*
* <li>after that, only the other code visitor receives the instructions</li>
*
* </ol>
*
* @author Eugene Kuleshov
* @author Eric Bruneton
*/
public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
private static final Object THIS = new Object();
private static final Object OTHER = new Object();
protected int methodAccess;
protected String methodDesc;
private boolean constructor;
private boolean superInitialized;
private List<Object> stackFrame;
private Map<Label, List<Object>> branches;
/**
* Creates a new {@link AdviceAdapter}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param mv
* the method visitor to which this adapter delegates calls.
* @param access
* the method's access flags (see {@link Opcodes}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
*/
protected AdviceAdapter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc) {
super(api, mv, access, name, desc);
methodAccess = access;
methodDesc = desc;
constructor = "<init>".equals(name);
}
@Override
public void visitCode() {
mv.visitCode();
if (constructor) {
stackFrame = new ArrayList<Object>();
branches = new HashMap<Label, List<Object>>();
} else {
superInitialized = true;
onMethodEnter();
}
}
@Override
public void visitLabel(final Label label) {
mv.visitLabel(label);
if (constructor && branches != null) {
List<Object> frame = branches.get(label);
if (frame != null) {
stackFrame = frame;
branches.remove(label);
}
}
}
@Override
public void visitInsn(final int opcode) {
if (constructor) {
int s;
switch (opcode) {
case RETURN: // empty stack
onMethodExit(opcode);
break;
case IRETURN: // 1 before n/a after
case FRETURN: // 1 before n/a after
case ARETURN: // 1 before n/a after
case ATHROW: // 1 before n/a after
popValue();
onMethodExit(opcode);
break;
case LRETURN: // 2 before n/a after
case DRETURN: // 2 before n/a after
popValue();
popValue();
onMethodExit(opcode);
break;
case NOP:
case LALOAD: // remove 2 add 2
case DALOAD: // remove 2 add 2
case LNEG:
case DNEG:
case FNEG:
case INEG:
case L2D:
case D2L:
case F2I:
case I2B:
case I2C:
case I2S:
case I2F:
case ARRAYLENGTH:
break;
case ACONST_NULL:
case ICONST_M1:
case ICONST_0:
case ICONST_1:
case ICONST_2:
case ICONST_3:
case ICONST_4:
case ICONST_5:
case FCONST_0:
case FCONST_1:
case FCONST_2:
case F2L: // 1 before 2 after
case F2D:
case I2L:
case I2D:
pushValue(OTHER);
break;
case LCONST_0:
case LCONST_1:
case DCONST_0:
case DCONST_1:
pushValue(OTHER);
pushValue(OTHER);
break;
case IALOAD: // remove 2 add 1
case FALOAD: // remove 2 add 1
case AALOAD: // remove 2 add 1
case BALOAD: // remove 2 add 1
case CALOAD: // remove 2 add 1
case SALOAD: // remove 2 add 1
case POP:
case IADD:
case FADD:
case ISUB:
case LSHL: // 3 before 2 after
case LSHR: // 3 before 2 after
case LUSHR: // 3 before 2 after
case L2I: // 2 before 1 after
case L2F: // 2 before 1 after
case D2I: // 2 before 1 after
case D2F: // 2 before 1 after
case FSUB:
case FMUL:
case FDIV:
case FREM:
case FCMPL: // 2 before 1 after
case FCMPG: // 2 before 1 after
case IMUL:
case IDIV:
case IREM:
case ISHL:
case ISHR:
case IUSHR:
case IAND:
case IOR:
case IXOR:
case MONITORENTER:
case MONITOREXIT:
popValue();
break;
case POP2:
case LSUB:
case LMUL:
case LDIV:
case LREM:
case LADD:
case LAND:
case LOR:
case LXOR:
case DADD:
case DMUL:
case DSUB:
case DDIV:
case DREM:
popValue();
popValue();
break;
case IASTORE:
case FASTORE:
case AASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
case LCMP: // 4 before 1 after
case DCMPL:
case DCMPG:
popValue();
popValue();
popValue();
break;
case LASTORE:
case DASTORE:
popValue();
popValue();
popValue();
popValue();
break;
case DUP:
pushValue(peekValue());
break;
case DUP_X1:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
break;
case DUP_X2:
s = stackFrame.size();
stackFrame.add(s - 3, stackFrame.get(s - 1));
break;
case DUP2:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackFrame.add(s - 2, stackFrame.get(s - 1));
break;
case DUP2_X1:
s = stackFrame.size();
stackFrame.add(s - 3, stackFrame.get(s - 1));
stackFrame.add(s - 3, stackFrame.get(s - 1));
break;
case DUP2_X2:
s = stackFrame.size();
stackFrame.add(s - 4, stackFrame.get(s - 1));
stackFrame.add(s - 4, stackFrame.get(s - 1));
break;
case SWAP:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackFrame.remove(s);
break;
}
} else {
switch (opcode) {
case RETURN:
case IRETURN:
case FRETURN:
case ARETURN:
case LRETURN:
case DRETURN:
case ATHROW:
onMethodExit(opcode);
break;
}
}
mv.visitInsn(opcode);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
super.visitVarInsn(opcode, var);
if (constructor) {
switch (opcode) {
case ILOAD:
case FLOAD:
pushValue(OTHER);
break;
case LLOAD:
case DLOAD:
pushValue(OTHER);
pushValue(OTHER);
break;
case ALOAD:
pushValue(var == 0 ? THIS : OTHER);
break;
case ASTORE:
case ISTORE:
case FSTORE:
popValue();
break;
case LSTORE:
case DSTORE:
popValue();
popValue();
break;
}
}
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
mv.visitFieldInsn(opcode, owner, name, desc);
if (constructor) {
char c = desc.charAt(0);
boolean longOrDouble = c == 'J' || c == 'D';
switch (opcode) {
case GETSTATIC:
pushValue(OTHER);
if (longOrDouble) {
pushValue(OTHER);
}
break;
case PUTSTATIC:
popValue();
if (longOrDouble) {
popValue();
}
break;
case PUTFIELD:
popValue();
if (longOrDouble) {
popValue();
popValue();
}
break;
// case GETFIELD:
default:
if (longOrDouble) {
pushValue(OTHER);
}
}
}
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
mv.visitIntInsn(opcode, operand);
if (constructor && opcode != NEWARRAY) {
pushValue(OTHER);
}
}
@Override
public void visitLdcInsn(final Object cst) {
mv.visitLdcInsn(cst);
if (constructor) {
pushValue(OTHER);
if (cst instanceof Double || cst instanceof Long) {
pushValue(OTHER);
}
}
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
mv.visitMultiANewArrayInsn(desc, dims);
if (constructor) {
for (int i = 0; i < dims; i++) {
popValue();
}
pushValue(OTHER);
}
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
mv.visitTypeInsn(opcode, type);
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
if (constructor && opcode == NEW) {
pushValue(OTHER);
}
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
mv.visitMethodInsn(opcode, owner, name, desc);
if (constructor) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
popValue();
if (types[i].getSize() == 2) {
popValue();
}
}
switch (opcode) {
// case INVOKESTATIC:
// break;
case INVOKEINTERFACE:
case INVOKEVIRTUAL:
popValue(); // objectref
break;
case INVOKESPECIAL:
Object type = popValue(); // objectref
if (type == THIS && !superInitialized) {
onMethodEnter();
superInitialized = true;
// once super has been initialized it is no longer
// necessary to keep track of stack state
constructor = false;
}
break;
}
Type returnType = Type.getReturnType(desc);
if (returnType != Type.VOID_TYPE) {
pushValue(OTHER);
if (returnType.getSize() == 2) {
pushValue(OTHER);
}
}
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
if (constructor) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
popValue();
if (types[i].getSize() == 2) {
popValue();
}
}
Type returnType = Type.getReturnType(desc);
if (returnType != Type.VOID_TYPE) {
pushValue(OTHER);
if (returnType.getSize() == 2) {
pushValue(OTHER);
}
}
}
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
mv.visitJumpInsn(opcode, label);
if (constructor) {
switch (opcode) {
case IFEQ:
case IFNE:
case IFLT:
case IFGE:
case IFGT:
case IFLE:
case IFNULL:
case IFNONNULL:
popValue();
break;
case IF_ICMPEQ:
case IF_ICMPNE:
case IF_ICMPLT:
case IF_ICMPGE:
case IF_ICMPGT:
case IF_ICMPLE:
case IF_ACMPEQ:
case IF_ACMPNE:
popValue();
popValue();
break;
case JSR:
pushValue(OTHER);
break;
}
addBranch(label);
}
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
if (constructor) {
popValue();
addBranches(dflt, labels);
}
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
if (constructor) {
popValue();
addBranches(dflt, labels);
}
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
super.visitTryCatchBlock(start, end, handler, type);
if (constructor && !branches.containsKey(handler)) {
List<Object> stackFrame = new ArrayList<Object>();
stackFrame.add(OTHER);
branches.put(handler, stackFrame);
}
}
private void addBranches(final Label dflt, final Label[] labels) {
addBranch(dflt);
for (int i = 0; i < labels.length; i++) {
addBranch(labels[i]);
}
}
private void addBranch(final Label label) {
if (branches.containsKey(label)) {
return;
}
branches.put(label, new ArrayList<Object>(stackFrame));
}
private Object popValue() {
return stackFrame.remove(stackFrame.size() - 1);
}
private Object peekValue() {
return stackFrame.get(stackFrame.size() - 1);
}
private void pushValue(final Object o) {
stackFrame.add(o);
}
/**
* Called at the beginning of the method or after super class class call in
* the constructor. <br>
* <br>
*
* <i>Custom code can use or change all the local variables, but should not
* change state of the stack.</i>
*/
protected void onMethodEnter() {
}
/**
* Called before explicit exit from the method using either return or throw.
* Top element on the stack contains the return value or exception instance.
* For example:
*
* <pre>
* public void onMethodExit(int opcode) {
* if(opcode==RETURN) {
* visitInsn(ACONST_NULL);
* } else if(opcode==ARETURN || opcode==ATHROW) {
* dup();
* } else {
* if(opcode==LRETURN || opcode==DRETURN) {
* dup2();
* } else {
* dup();
* }
* box(Type.getReturnType(this.methodDesc));
* }
* visitIntInsn(SIPUSH, opcode);
* visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
* }
*
* // an actual call back method
* public static void onExit(Object param, int opcode) {
* ...
* </pre>
*
* <br>
* <br>
*
* <i>Custom code can use or change all the local variables, but should not
* change state of the stack.</i>
*
* @param opcode
* one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
* or ATHROW
*
*/
protected void onMethodExit(int opcode) {
}
// TODO onException, onMethodCall
}

View File

@ -0,0 +1,920 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* A {@link MethodVisitor} that keeps track of stack map frame changes between
* {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
* adapter must be used with the
* {@link org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each
* visit<i>X</i> instruction delegates to the next visitor in the chain, if any,
* and then simulates the effect of this instruction on the stack map frame,
* represented by {@link #locals} and {@link #stack}. The next visitor in the
* chain can get the state of the stack map frame <i>before</i> each instruction
* by reading the value of these fields in its visit<i>X</i> methods (this
* requires a reference to the AnalyzerAdapter that is before it in the chain).
* If this adapter is used with a class that does not contain stack map table
* attributes (i.e., pre Java 6 classes) then this adapter may not be able to
* compute the stack map frame for each instruction. In this case no exception
* is thrown but the {@link #locals} and {@link #stack} fields will be null for
* these instructions.
*
* @author Eric Bruneton
*/
public class AnalyzerAdapter extends MethodVisitor {
/**
* <code>List</code> of the local variable slots for current execution
* frame. Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names), and uninitialized types
* by Label objects (this label designates the NEW instruction that created
* this uninitialized value). This field is <tt>null</tt> for unreachable
* instructions.
*/
public List<Object> locals;
/**
* <code>List</code> of the operand stack slots for current execution frame.
* Primitive types are represented by {@link Opcodes#TOP},
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
* two elements, the second one being TOP). Reference types are represented
* by String objects (representing internal names), and uninitialized types
* by Label objects (this label designates the NEW instruction that created
* this uninitialized value). This field is <tt>null</tt> for unreachable
* instructions.
*/
public List<Object> stack;
/**
* The labels that designate the next instruction to be visited. May be
* <tt>null</tt>.
*/
private List<Label> labels;
/**
* Information about uninitialized types in the current execution frame.
* This map associates internal names to Label objects. Each label
* designates a NEW instruction that created the currently uninitialized
* types, and the associated internal name represents the NEW operand, i.e.
* the final, initialized type value.
*/
public Map<Object, Object> uninitializedTypes;
/**
* The maximum stack size of this method.
*/
private int maxStack;
/**
* The maximum number of local variables of this method.
*/
private int maxLocals;
/**
* The owner's class name.
*/
private String owner;
/**
* Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
* version.
*
* @param owner
* the owner's class name.
* @param access
* the method's access flags (see {@link Opcodes}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls. May
* be <tt>null</tt>.
*/
public AnalyzerAdapter(final String owner, final int access,
final String name, final String desc, final MethodVisitor mv) {
this(Opcodes.ASM4, owner, access, name, desc, mv);
}
/**
* Creates a new {@link AnalyzerAdapter}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param owner
* the owner's class name.
* @param access
* the method's access flags (see {@link Opcodes}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls. May
* be <tt>null</tt>.
*/
protected AnalyzerAdapter(final int api, final String owner,
final int access, final String name, final String desc,
final MethodVisitor mv) {
super(api, mv);
this.owner = owner;
locals = new ArrayList<Object>();
stack = new ArrayList<Object>();
uninitializedTypes = new HashMap<Object, Object>();
if ((access & Opcodes.ACC_STATIC) == 0) {
if ("<init>".equals(name)) {
locals.add(Opcodes.UNINITIALIZED_THIS);
} else {
locals.add(owner);
}
}
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; ++i) {
Type type = types[i];
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
locals.add(Opcodes.INTEGER);
break;
case Type.FLOAT:
locals.add(Opcodes.FLOAT);
break;
case Type.LONG:
locals.add(Opcodes.LONG);
locals.add(Opcodes.TOP);
break;
case Type.DOUBLE:
locals.add(Opcodes.DOUBLE);
locals.add(Opcodes.TOP);
break;
case Type.ARRAY:
locals.add(types[i].getDescriptor());
break;
// case Type.OBJECT:
default:
locals.add(types[i].getInternalName());
}
}
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
if (type != Opcodes.F_NEW) { // uncompressed frame
throw new IllegalStateException(
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
}
if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack);
}
if (this.locals != null) {
this.locals.clear();
this.stack.clear();
} else {
this.locals = new ArrayList<Object>();
this.stack = new ArrayList<Object>();
}
visitFrameTypes(nLocal, local, this.locals);
visitFrameTypes(nStack, stack, this.stack);
maxStack = Math.max(maxStack, this.stack.size());
}
private static void visitFrameTypes(final int n, final Object[] types,
final List<Object> result) {
for (int i = 0; i < n; ++i) {
Object type = types[i];
result.add(type);
if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
result.add(Opcodes.TOP);
}
}
}
@Override
public void visitInsn(final int opcode) {
if (mv != null) {
mv.visitInsn(opcode);
}
execute(opcode, 0, null);
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
|| opcode == Opcodes.ATHROW) {
this.locals = null;
this.stack = null;
}
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
execute(opcode, operand, null);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
execute(opcode, var, null);
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
if (opcode == Opcodes.NEW) {
if (labels == null) {
Label l = new Label();
labels = new ArrayList<Label>(3);
labels.add(l);
if (mv != null) {
mv.visitLabel(l);
}
}
for (int i = 0; i < labels.size(); ++i) {
uninitializedTypes.put(labels.get(i), type);
}
}
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
execute(opcode, 0, type);
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
execute(opcode, 0, desc);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
if (this.locals == null) {
labels = null;
return;
}
pop(desc);
if (opcode != Opcodes.INVOKESTATIC) {
Object t = pop();
if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
Object u;
if (t == Opcodes.UNINITIALIZED_THIS) {
u = this.owner;
} else {
u = uninitializedTypes.get(t);
}
for (int i = 0; i < locals.size(); ++i) {
if (locals.get(i) == t) {
locals.set(i, u);
}
}
for (int i = 0; i < stack.size(); ++i) {
if (stack.get(i) == t) {
stack.set(i, u);
}
}
}
}
pushDesc(desc);
labels = null;
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
if (this.locals == null) {
labels = null;
return;
}
pop(desc);
pushDesc(desc);
labels = null;
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
execute(opcode, 0, null);
if (opcode == Opcodes.GOTO) {
this.locals = null;
this.stack = null;
}
}
@Override
public void visitLabel(final Label label) {
if (mv != null) {
mv.visitLabel(label);
}
if (labels == null) {
labels = new ArrayList<Label>(3);
}
labels.add(label);
}
@Override
public void visitLdcInsn(final Object cst) {
if (mv != null) {
mv.visitLdcInsn(cst);
}
if (this.locals == null) {
labels = null;
return;
}
if (cst instanceof Integer) {
push(Opcodes.INTEGER);
} else if (cst instanceof Long) {
push(Opcodes.LONG);
push(Opcodes.TOP);
} else if (cst instanceof Float) {
push(Opcodes.FLOAT);
} else if (cst instanceof Double) {
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
} else if (cst instanceof String) {
push("java/lang/String");
} else if (cst instanceof Type) {
int sort = ((Type) cst).getSort();
if (sort == Type.OBJECT || sort == Type.ARRAY) {
push("java/lang/Class");
} else if (sort == Type.METHOD) {
push("java/lang/invoke/MethodType");
} else {
throw new IllegalArgumentException();
}
} else if (cst instanceof Handle) {
push("java/lang/invoke/MethodHandle");
} else {
throw new IllegalArgumentException();
}
labels = null;
}
@Override
public void visitIincInsn(final int var, final int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
execute(Opcodes.IINC, var, null);
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
execute(Opcodes.TABLESWITCH, 0, null);
this.locals = null;
this.stack = null;
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
execute(Opcodes.LOOKUPSWITCH, 0, null);
this.locals = null;
this.stack = null;
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
execute(Opcodes.MULTIANEWARRAY, dims, desc);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
if (mv != null) {
this.maxStack = Math.max(this.maxStack, maxStack);
this.maxLocals = Math.max(this.maxLocals, maxLocals);
mv.visitMaxs(this.maxStack, this.maxLocals);
}
}
// ------------------------------------------------------------------------
private Object get(final int local) {
maxLocals = Math.max(maxLocals, local);
return local < locals.size() ? locals.get(local) : Opcodes.TOP;
}
private void set(final int local, final Object type) {
maxLocals = Math.max(maxLocals, local);
while (local >= locals.size()) {
locals.add(Opcodes.TOP);
}
locals.set(local, type);
}
private void push(final Object type) {
stack.add(type);
maxStack = Math.max(maxStack, stack.size());
}
private void pushDesc(final String desc) {
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
switch (desc.charAt(index)) {
case 'V':
return;
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
push(Opcodes.INTEGER);
return;
case 'F':
push(Opcodes.FLOAT);
return;
case 'J':
push(Opcodes.LONG);
push(Opcodes.TOP);
return;
case 'D':
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
return;
case '[':
if (index == 0) {
push(desc);
} else {
push(desc.substring(index, desc.length()));
}
break;
// case 'L':
default:
if (index == 0) {
push(desc.substring(1, desc.length() - 1));
} else {
push(desc.substring(index + 1, desc.length() - 1));
}
}
}
private Object pop() {
return stack.remove(stack.size() - 1);
}
private void pop(final int n) {
int size = stack.size();
int end = size - n;
for (int i = size - 1; i >= end; --i) {
stack.remove(i);
}
}
private void pop(final String desc) {
char c = desc.charAt(0);
if (c == '(') {
int n = 0;
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; ++i) {
n += types[i].getSize();
}
pop(n);
} else if (c == 'J' || c == 'D') {
pop(2);
} else {
pop(1);
}
}
private void execute(final int opcode, final int iarg, final String sarg) {
if (this.locals == null) {
labels = null;
return;
}
Object t1, t2, t3, t4;
switch (opcode) {
case Opcodes.NOP:
case Opcodes.INEG:
case Opcodes.LNEG:
case Opcodes.FNEG:
case Opcodes.DNEG:
case Opcodes.I2B:
case Opcodes.I2C:
case Opcodes.I2S:
case Opcodes.GOTO:
case Opcodes.RETURN:
break;
case Opcodes.ACONST_NULL:
push(Opcodes.NULL);
break;
case Opcodes.ICONST_M1:
case Opcodes.ICONST_0:
case Opcodes.ICONST_1:
case Opcodes.ICONST_2:
case Opcodes.ICONST_3:
case Opcodes.ICONST_4:
case Opcodes.ICONST_5:
case Opcodes.BIPUSH:
case Opcodes.SIPUSH:
push(Opcodes.INTEGER);
break;
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
push(Opcodes.LONG);
push(Opcodes.TOP);
break;
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
push(Opcodes.FLOAT);
break;
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
break;
case Opcodes.ILOAD:
case Opcodes.FLOAD:
case Opcodes.ALOAD:
push(get(iarg));
break;
case Opcodes.LLOAD:
case Opcodes.DLOAD:
push(get(iarg));
push(Opcodes.TOP);
break;
case Opcodes.IALOAD:
case Opcodes.BALOAD:
case Opcodes.CALOAD:
case Opcodes.SALOAD:
pop(2);
push(Opcodes.INTEGER);
break;
case Opcodes.LALOAD:
case Opcodes.D2L:
pop(2);
push(Opcodes.LONG);
push(Opcodes.TOP);
break;
case Opcodes.FALOAD:
pop(2);
push(Opcodes.FLOAT);
break;
case Opcodes.DALOAD:
case Opcodes.L2D:
pop(2);
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
break;
case Opcodes.AALOAD:
pop(1);
t1 = pop();
if (t1 instanceof String) {
pushDesc(((String) t1).substring(1));
} else {
push("java/lang/Object");
}
break;
case Opcodes.ISTORE:
case Opcodes.FSTORE:
case Opcodes.ASTORE:
t1 = pop();
set(iarg, t1);
if (iarg > 0) {
t2 = get(iarg - 1);
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
set(iarg - 1, Opcodes.TOP);
}
}
break;
case Opcodes.LSTORE:
case Opcodes.DSTORE:
pop(1);
t1 = pop();
set(iarg, t1);
set(iarg + 1, Opcodes.TOP);
if (iarg > 0) {
t2 = get(iarg - 1);
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
set(iarg - 1, Opcodes.TOP);
}
}
break;
case Opcodes.IASTORE:
case Opcodes.BASTORE:
case Opcodes.CASTORE:
case Opcodes.SASTORE:
case Opcodes.FASTORE:
case Opcodes.AASTORE:
pop(3);
break;
case Opcodes.LASTORE:
case Opcodes.DASTORE:
pop(4);
break;
case Opcodes.POP:
case Opcodes.IFEQ:
case Opcodes.IFNE:
case Opcodes.IFLT:
case Opcodes.IFGE:
case Opcodes.IFGT:
case Opcodes.IFLE:
case Opcodes.IRETURN:
case Opcodes.FRETURN:
case Opcodes.ARETURN:
case Opcodes.TABLESWITCH:
case Opcodes.LOOKUPSWITCH:
case Opcodes.ATHROW:
case Opcodes.MONITORENTER:
case Opcodes.MONITOREXIT:
case Opcodes.IFNULL:
case Opcodes.IFNONNULL:
pop(1);
break;
case Opcodes.POP2:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPGE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
case Opcodes.LRETURN:
case Opcodes.DRETURN:
pop(2);
break;
case Opcodes.DUP:
t1 = pop();
push(t1);
push(t1);
break;
case Opcodes.DUP_X1:
t1 = pop();
t2 = pop();
push(t1);
push(t2);
push(t1);
break;
case Opcodes.DUP_X2:
t1 = pop();
t2 = pop();
t3 = pop();
push(t1);
push(t3);
push(t2);
push(t1);
break;
case Opcodes.DUP2:
t1 = pop();
t2 = pop();
push(t2);
push(t1);
push(t2);
push(t1);
break;
case Opcodes.DUP2_X1:
t1 = pop();
t2 = pop();
t3 = pop();
push(t2);
push(t1);
push(t3);
push(t2);
push(t1);
break;
case Opcodes.DUP2_X2:
t1 = pop();
t2 = pop();
t3 = pop();
t4 = pop();
push(t2);
push(t1);
push(t4);
push(t3);
push(t2);
push(t1);
break;
case Opcodes.SWAP:
t1 = pop();
t2 = pop();
push(t1);
push(t2);
break;
case Opcodes.IADD:
case Opcodes.ISUB:
case Opcodes.IMUL:
case Opcodes.IDIV:
case Opcodes.IREM:
case Opcodes.IAND:
case Opcodes.IOR:
case Opcodes.IXOR:
case Opcodes.ISHL:
case Opcodes.ISHR:
case Opcodes.IUSHR:
case Opcodes.L2I:
case Opcodes.D2I:
case Opcodes.FCMPL:
case Opcodes.FCMPG:
pop(2);
push(Opcodes.INTEGER);
break;
case Opcodes.LADD:
case Opcodes.LSUB:
case Opcodes.LMUL:
case Opcodes.LDIV:
case Opcodes.LREM:
case Opcodes.LAND:
case Opcodes.LOR:
case Opcodes.LXOR:
pop(4);
push(Opcodes.LONG);
push(Opcodes.TOP);
break;
case Opcodes.FADD:
case Opcodes.FSUB:
case Opcodes.FMUL:
case Opcodes.FDIV:
case Opcodes.FREM:
case Opcodes.L2F:
case Opcodes.D2F:
pop(2);
push(Opcodes.FLOAT);
break;
case Opcodes.DADD:
case Opcodes.DSUB:
case Opcodes.DMUL:
case Opcodes.DDIV:
case Opcodes.DREM:
pop(4);
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
break;
case Opcodes.LSHL:
case Opcodes.LSHR:
case Opcodes.LUSHR:
pop(3);
push(Opcodes.LONG);
push(Opcodes.TOP);
break;
case Opcodes.IINC:
set(iarg, Opcodes.INTEGER);
break;
case Opcodes.I2L:
case Opcodes.F2L:
pop(1);
push(Opcodes.LONG);
push(Opcodes.TOP);
break;
case Opcodes.I2F:
pop(1);
push(Opcodes.FLOAT);
break;
case Opcodes.I2D:
case Opcodes.F2D:
pop(1);
push(Opcodes.DOUBLE);
push(Opcodes.TOP);
break;
case Opcodes.F2I:
case Opcodes.ARRAYLENGTH:
case Opcodes.INSTANCEOF:
pop(1);
push(Opcodes.INTEGER);
break;
case Opcodes.LCMP:
case Opcodes.DCMPL:
case Opcodes.DCMPG:
pop(4);
push(Opcodes.INTEGER);
break;
case Opcodes.JSR:
case Opcodes.RET:
throw new RuntimeException("JSR/RET are not supported");
case Opcodes.GETSTATIC:
pushDesc(sarg);
break;
case Opcodes.PUTSTATIC:
pop(sarg);
break;
case Opcodes.GETFIELD:
pop(1);
pushDesc(sarg);
break;
case Opcodes.PUTFIELD:
pop(sarg);
pop();
break;
case Opcodes.NEW:
push(labels.get(0));
break;
case Opcodes.NEWARRAY:
pop();
switch (iarg) {
case Opcodes.T_BOOLEAN:
pushDesc("[Z");
break;
case Opcodes.T_CHAR:
pushDesc("[C");
break;
case Opcodes.T_BYTE:
pushDesc("[B");
break;
case Opcodes.T_SHORT:
pushDesc("[S");
break;
case Opcodes.T_INT:
pushDesc("[I");
break;
case Opcodes.T_FLOAT:
pushDesc("[F");
break;
case Opcodes.T_DOUBLE:
pushDesc("[D");
break;
// case Opcodes.T_LONG:
default:
pushDesc("[J");
break;
}
break;
case Opcodes.ANEWARRAY:
pop();
pushDesc("[" + Type.getObjectType(sarg));
break;
case Opcodes.CHECKCAST:
pop();
pushDesc(Type.getObjectType(sarg).getDescriptor());
break;
// case Opcodes.MULTIANEWARRAY:
default:
pop(iarg);
pushDesc(sarg);
break;
}
labels = null;
}
}

View File

@ -0,0 +1,217 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link MethodVisitor} that can be used to approximate method size.
*
* @author Eugene Kuleshov
*/
public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
private int minSize;
private int maxSize;
public CodeSizeEvaluator(final MethodVisitor mv) {
this(Opcodes.ASM4, mv);
}
protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
super(api, mv);
}
public int getMinSize() {
return this.minSize;
}
public int getMaxSize() {
return this.maxSize;
}
@Override
public void visitInsn(final int opcode) {
minSize += 1;
maxSize += 1;
if (mv != null) {
mv.visitInsn(opcode);
}
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
if (opcode == SIPUSH) {
minSize += 3;
maxSize += 3;
} else {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
}
@Override
public void visitVarInsn(final int opcode, final int var) {
if (var < 4 && opcode != RET) {
minSize += 1;
maxSize += 1;
} else if (var >= 256) {
minSize += 4;
maxSize += 4;
} else {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
if (opcode == INVOKEINTERFACE) {
minSize += 5;
maxSize += 5;
} else {
minSize += 3;
maxSize += 3;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc);
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
minSize += 5;
maxSize += 5;
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
minSize += 3;
if (opcode == GOTO || opcode == JSR) {
maxSize += 5;
} else {
maxSize += 8;
}
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
}
@Override
public void visitLdcInsn(final Object cst) {
if (cst instanceof Long || cst instanceof Double) {
minSize += 3;
maxSize += 3;
} else {
minSize += 2;
maxSize += 3;
}
if (mv != null) {
mv.visitLdcInsn(cst);
}
}
@Override
public void visitIincInsn(final int var, final int increment) {
if (var > 255 || increment > 127 || increment < -128) {
minSize += 6;
maxSize += 6;
} else {
minSize += 3;
maxSize += 3;
}
if (mv != null) {
mv.visitIincInsn(var, increment);
}
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
minSize += 13 + labels.length * 4;
maxSize += 16 + labels.length * 4;
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
minSize += 9 + keys.length * 8;
maxSize += 12 + keys.length * 8;
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
minSize += 4;
maxSize += 4;
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,747 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.JumpInsnNode;
import org.objectweb.asm.tree.LabelNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.LookupSwitchInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TableSwitchInsnNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
/**
* A {@link org.objectweb.asm.MethodVisitor} that removes JSR instructions and
* inlines the referenced subroutines.
*
* <b>Explanation of how it works</b> TODO
*
* @author Niko Matsakis
*/
public class JSRInlinerAdapter extends MethodNode implements Opcodes {
private static final boolean LOGGING = false;
/**
* For each label that is jumped to by a JSR, we create a BitSet instance.
*/
private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
/**
* This subroutine instance denotes the line of execution that is not
* contained within any subroutine; i.e., the "subroutine" that is executing
* when a method first begins.
*/
private final BitSet mainSubroutine = new BitSet();
/**
* This BitSet contains the index of every instruction that belongs to more
* than one subroutine. This should not happen often.
*/
final BitSet dualCitizens = new BitSet();
/**
* Creates a new JSRInliner. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
* version.
*
* @param mv
* the <code>MethodVisitor</code> to send the resulting inlined
* method code to (use <code>null</code> for none).
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type}).
* @param signature
* the method's signature. May be <tt>null</tt>.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public JSRInlinerAdapter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
final String[] exceptions) {
this(Opcodes.ASM4, mv, access, name, desc, signature, exceptions);
}
/**
* Creates a new JSRInliner.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param mv
* the <code>MethodVisitor</code> to send the resulting inlined
* method code to (use <code>null</code> for none).
* @param access
* the method's access flags (see {@link Opcodes}). This
* parameter also indicates if the method is synthetic and/or
* deprecated.
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link Type}).
* @param signature
* the method's signature. May be <tt>null</tt>.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
super(api, access, name, desc, signature, exceptions);
this.mv = mv;
}
/**
* Detects a JSR instruction and sets a flag to indicate we will need to do
* inlining.
*/
@Override
public void visitJumpInsn(final int opcode, final Label lbl) {
super.visitJumpInsn(opcode, lbl);
LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
subroutineHeads.put(ln, new BitSet());
}
}
/**
* If any JSRs were seen, triggers the inlining process. Otherwise, forwards
* the byte codes untouched.
*/
@Override
public void visitEnd() {
if (!subroutineHeads.isEmpty()) {
markSubroutines();
if (LOGGING) {
log(mainSubroutine.toString());
Iterator<BitSet> it = subroutineHeads.values().iterator();
while (it.hasNext()) {
BitSet sub = it.next();
log(sub.toString());
}
}
emitCode();
}
// Forward the translate opcodes on if appropriate:
if (mv != null) {
accept(mv);
}
}
/**
* Walks the method and determines which internal subroutine(s), if any,
* each instruction is a method of.
*/
private void markSubroutines() {
BitSet anyvisited = new BitSet();
// First walk the main subroutine and find all those instructions which
// can be reached without invoking any JSR at all
markSubroutineWalk(mainSubroutine, 0, anyvisited);
// Go through the head of each subroutine and find any nodes reachable
// to that subroutine without following any JSR links.
for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
.entrySet().iterator(); it.hasNext();) {
Map.Entry<LabelNode, BitSet> entry = it.next();
LabelNode lab = entry.getKey();
BitSet sub = entry.getValue();
int index = instructions.indexOf(lab);
markSubroutineWalk(sub, index, anyvisited);
}
}
/**
* Performs a depth first search walking the normal byte code path starting
* at <code>index</code>, and adding each instruction encountered into the
* subroutine <code>sub</code>. After this walk is complete, iterates over
* the exception handlers to ensure that we also include those byte codes
* which are reachable through an exception that may be thrown during the
* execution of the subroutine. Invoked from <code>markSubroutines()</code>.
*
* @param sub
* the subroutine whose instructions must be computed.
* @param index
* an instruction of this subroutine.
* @param anyvisited
* indexes of the already visited instructions, i.e. marked as
* part of this subroutine or any previously computed subroutine.
*/
private void markSubroutineWalk(final BitSet sub, final int index,
final BitSet anyvisited) {
if (LOGGING) {
log("markSubroutineWalk: sub=" + sub + " index=" + index);
}
// First find those instructions reachable via normal execution
markSubroutineWalkDFS(sub, index, anyvisited);
// Now, make sure we also include any applicable exception handlers
boolean loop = true;
while (loop) {
loop = false;
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
.hasNext();) {
TryCatchBlockNode trycatch = it.next();
if (LOGGING) {
// TODO use of default toString().
log("Scanning try/catch " + trycatch);
}
// If the handler has already been processed, skip it.
int handlerindex = instructions.indexOf(trycatch.handler);
if (sub.get(handlerindex)) {
continue;
}
int startindex = instructions.indexOf(trycatch.start);
int endindex = instructions.indexOf(trycatch.end);
int nextbit = sub.nextSetBit(startindex);
if (nextbit != -1 && nextbit < endindex) {
if (LOGGING) {
log("Adding exception handler: " + startindex + '-'
+ endindex + " due to " + nextbit + " handler "
+ handlerindex);
}
markSubroutineWalkDFS(sub, handlerindex, anyvisited);
loop = true;
}
}
}
}
/**
* Performs a simple DFS of the instructions, assigning each to the
* subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
* by <code>markSubroutineWalk()</code>.
*
* @param sub
* the subroutine whose instructions must be computed.
* @param index
* an instruction of this subroutine.
* @param anyvisited
* indexes of the already visited instructions, i.e. marked as
* part of this subroutine or any previously computed subroutine.
*/
private void markSubroutineWalkDFS(final BitSet sub, int index,
final BitSet anyvisited) {
while (true) {
AbstractInsnNode node = instructions.get(index);
// don't visit a node twice
if (sub.get(index)) {
return;
}
sub.set(index);
// check for those nodes already visited by another subroutine
if (anyvisited.get(index)) {
dualCitizens.set(index);
if (LOGGING) {
log("Instruction #" + index + " is dual citizen.");
}
}
anyvisited.set(index);
if (node.getType() == AbstractInsnNode.JUMP_INSN
&& node.getOpcode() != JSR) {
// we do not follow recursively called subroutines here; but any
// other sort of branch we do follow
JumpInsnNode jnode = (JumpInsnNode) node;
int destidx = instructions.indexOf(jnode.label);
markSubroutineWalkDFS(sub, destidx, anyvisited);
}
if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
int destidx = instructions.indexOf(tsnode.dflt);
markSubroutineWalkDFS(sub, destidx, anyvisited);
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
LabelNode l = tsnode.labels.get(i);
destidx = instructions.indexOf(l);
markSubroutineWalkDFS(sub, destidx, anyvisited);
}
}
if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
int destidx = instructions.indexOf(lsnode.dflt);
markSubroutineWalkDFS(sub, destidx, anyvisited);
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
LabelNode l = lsnode.labels.get(i);
destidx = instructions.indexOf(l);
markSubroutineWalkDFS(sub, destidx, anyvisited);
}
}
// check to see if this opcode falls through to the next instruction
// or not; if not, return.
switch (instructions.get(index).getOpcode()) {
case GOTO:
case RET:
case TABLESWITCH:
case LOOKUPSWITCH:
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
case RETURN:
case ATHROW:
/*
* note: this either returns from this subroutine, or a parent
* subroutine which invoked it
*/
return;
}
// Use tail recursion here in the form of an outer while loop to
// avoid our stack growing needlessly:
index++;
// We implicitly assumed above that execution can always fall
// through to the next instruction after a JSR. But a subroutine may
// never return, in which case the code after the JSR is unreachable
// and can be anything. In particular, it can seem to fall off the
// end of the method, so we must handle this case here (we could
// instead detect whether execution can return or not from a JSR,
// but this is more complicated).
if (index >= instructions.size()) {
return;
}
}
}
/**
* Creates the new instructions, inlining each instantiation of each
* subroutine until the code is fully elaborated.
*/
private void emitCode() {
LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
// Create an instantiation of the "root" subroutine, which is just the
// main routine
worklist.add(new Instantiation(null, mainSubroutine));
// Emit instantiations of each subroutine we encounter, including the
// main subroutine
InsnList newInstructions = new InsnList();
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
while (!worklist.isEmpty()) {
Instantiation inst = worklist.removeFirst();
emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
newLocalVariables);
}
instructions = newInstructions;
tryCatchBlocks = newTryCatchBlocks;
localVariables = newLocalVariables;
}
/**
* Emits one instantiation of one subroutine, specified by
* <code>instant</code>. May add new instantiations that are invoked by this
* one to the <code>worklist</code> parameter, and new try/catch blocks to
* <code>newTryCatchBlocks</code>.
*
* @param instant
* the instantiation that must be performed.
* @param worklist
* list of the instantiations that remain to be done.
* @param newInstructions
* the instruction list to which the instantiated code must be
* appended.
* @param newTryCatchBlocks
* the exception handler list to which the instantiated handlers
* must be appended.
*/
private void emitSubroutine(final Instantiation instant,
final List<Instantiation> worklist, final InsnList newInstructions,
final List<TryCatchBlockNode> newTryCatchBlocks,
final List<LocalVariableNode> newLocalVariables) {
LabelNode duplbl = null;
if (LOGGING) {
log("--------------------------------------------------------");
log("Emitting instantiation of subroutine " + instant.subroutine);
}
// Emit the relevant instructions for this instantiation, translating
// labels and jump targets as we go:
for (int i = 0, c = instructions.size(); i < c; i++) {
AbstractInsnNode insn = instructions.get(i);
Instantiation owner = instant.findOwner(i);
// Always remap labels:
if (insn.getType() == AbstractInsnNode.LABEL) {
// Translate labels into their renamed equivalents.
// Avoid adding the same label more than once. Note
// that because we own this instruction the gotoTable
// and the rangeTable will always agree.
LabelNode ilbl = (LabelNode) insn;
LabelNode remap = instant.rangeLabel(ilbl);
if (LOGGING) {
// TODO use of default toString().
log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
}
if (remap != duplbl) {
newInstructions.add(remap);
duplbl = remap;
}
continue;
}
// We don't want to emit instructions that were already
// emitted by a subroutine higher on the stack. Note that
// it is still possible for a given instruction to be
// emitted twice because it may belong to two subroutines
// that do not invoke each other.
if (owner != instant) {
continue;
}
if (LOGGING) {
log("Emitting inst #" + i);
}
if (insn.getOpcode() == RET) {
// Translate RET instruction(s) to a jump to the return label
// for the appropriate instantiation. The problem is that the
// subroutine may "fall through" to the ret of a parent
// subroutine; therefore, to find the appropriate ret label we
// find the lowest subroutine on the stack that claims to own
// this instruction. See the class javadoc comment for an
// explanation on why this technique is safe (note: it is only
// safe if the input is verifiable).
LabelNode retlabel = null;
for (Instantiation p = instant; p != null; p = p.previous) {
if (p.subroutine.get(i)) {
retlabel = p.returnLabel;
}
}
if (retlabel == null) {
// This is only possible if the mainSubroutine owns a RET
// instruction, which should never happen for verifiable
// code.
throw new RuntimeException("Instruction #" + i
+ " is a RET not owned by any subroutine");
}
newInstructions.add(new JumpInsnNode(GOTO, retlabel));
} else if (insn.getOpcode() == JSR) {
LabelNode lbl = ((JumpInsnNode) insn).label;
BitSet sub = subroutineHeads.get(lbl);
Instantiation newinst = new Instantiation(instant, sub);
LabelNode startlbl = newinst.gotoLabel(lbl);
if (LOGGING) {
log(" Creating instantiation of subr " + sub);
}
// Rather than JSRing, we will jump to the inline version and
// push NULL for what was once the return value. This hack
// allows us to avoid doing any sort of data flow analysis to
// figure out which instructions manipulate the old return value
// pointer which is now known to be unneeded.
newInstructions.add(new InsnNode(ACONST_NULL));
newInstructions.add(new JumpInsnNode(GOTO, startlbl));
newInstructions.add(newinst.returnLabel);
// Insert this new instantiation into the queue to be emitted
// later.
worklist.add(newinst);
} else {
newInstructions.add(insn.clone(instant));
}
}
// Emit try/catch blocks that are relevant to this method.
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
.hasNext();) {
TryCatchBlockNode trycatch = it.next();
if (LOGGING) {
// TODO use of default toString().
log("try catch block original labels=" + trycatch.start + '-'
+ trycatch.end + "->" + trycatch.handler);
}
final LabelNode start = instant.rangeLabel(trycatch.start);
final LabelNode end = instant.rangeLabel(trycatch.end);
// Ignore empty try/catch regions
if (start == end) {
if (LOGGING) {
log(" try catch block empty in this subroutine");
}
continue;
}
final LabelNode handler = instant.gotoLabel(trycatch.handler);
if (LOGGING) {
// TODO use of default toString().
log(" try catch block new labels=" + start + '-' + end + "->"
+ handler);
}
if (start == null || end == null || handler == null) {
throw new RuntimeException("Internal error!");
}
newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
trycatch.type));
}
for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
.hasNext();) {
LocalVariableNode lvnode = it.next();
if (LOGGING) {
log("local var " + lvnode.name);
}
final LabelNode start = instant.rangeLabel(lvnode.start);
final LabelNode end = instant.rangeLabel(lvnode.end);
if (start == end) {
if (LOGGING) {
log(" local variable empty in this sub");
}
continue;
}
newLocalVariables.add(new LocalVariableNode(lvnode.name,
lvnode.desc, lvnode.signature, start, end, lvnode.index));
}
}
private static void log(final String str) {
System.err.println(str);
}
/**
* A class that represents an instantiation of a subroutine. Each
* instantiation has an associate "stack" --- which is a listing of those
* instantiations that were active when this particular instance of this
* subroutine was invoked. Each instantiation also has a map from the
* original labels of the program to the labels appropriate for this
* instantiation, and finally a label to return to.
*/
private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
/**
* Previous instantiations; the stack must be statically predictable to
* be inlinable.
*/
final Instantiation previous;
/**
* The subroutine this is an instantiation of.
*/
public final BitSet subroutine;
/**
* This table maps Labels from the original source to Labels pointing at
* code specific to this instantiation, for use in remapping try/catch
* blocks,as well as gotos.
*
* Note that in the presence of dual citizens instructions, that is,
* instructions which belong to more than one subroutine due to the
* merging of control flow without a RET instruction, we will map the
* target label of a GOTO to the label used by the instantiation lowest
* on the stack. This avoids code duplication during inlining in most
* cases.
*
* @see #findOwner(int)
*/
public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
/**
* All returns for this instantiation will be mapped to this label
*/
public final LabelNode returnLabel;
Instantiation(final Instantiation prev, final BitSet sub) {
previous = prev;
subroutine = sub;
for (Instantiation p = prev; p != null; p = p.previous) {
if (p.subroutine == sub) {
throw new RuntimeException("Recursive invocation of " + sub);
}
}
// Determine the label to return to when this subroutine terminates
// via RET: note that the main subroutine never terminates via RET.
if (prev != null) {
returnLabel = new LabelNode();
} else {
returnLabel = null;
}
// Each instantiation will remap the labels from the code above to
// refer to its particular copy of its own instructions. Note that
// we collapse labels which point at the same instruction into one:
// this is fairly common as we are often ignoring large chunks of
// instructions, so what were previously distinct labels become
// duplicates.
LabelNode duplbl = null;
for (int i = 0, c = instructions.size(); i < c; i++) {
AbstractInsnNode insn = instructions.get(i);
if (insn.getType() == AbstractInsnNode.LABEL) {
LabelNode ilbl = (LabelNode) insn;
if (duplbl == null) {
// if we already have a label pointing at this spot,
// don't recreate it.
duplbl = new LabelNode();
}
// Add an entry in the rangeTable for every label
// in the original code which points at the next
// instruction of our own to be emitted.
rangeTable.put(ilbl, duplbl);
} else if (findOwner(i) == this) {
// We will emit this instruction, so clear the 'duplbl' flag
// since the next Label will refer to a distinct
// instruction.
duplbl = null;
}
}
}
/**
* Returns the "owner" of a particular instruction relative to this
* instantiation: the owner referes to the Instantiation which will emit
* the version of this instruction that we will execute.
*
* Typically, the return value is either <code>this</code> or
* <code>null</code>. <code>this</code> indicates that this
* instantiation will generate the version of this instruction that we
* will execute, and <code>null</code> indicates that this instantiation
* never executes the given instruction.
*
* Sometimes, however, an instruction can belong to multiple
* subroutines; this is called a "dual citizen" instruction (though it
* may belong to more than 2 subroutines), and occurs when multiple
* subroutines branch to common points of control. In this case, the
* owner is the subroutine that appears lowest on the stack, and which
* also owns the instruction in question.
*
* @param i
* the index of the instruction in the original code
* @return the "owner" of a particular instruction relative to this
* instantiation.
*/
public Instantiation findOwner(final int i) {
if (!subroutine.get(i)) {
return null;
}
if (!dualCitizens.get(i)) {
return this;
}
Instantiation own = this;
for (Instantiation p = previous; p != null; p = p.previous) {
if (p.subroutine.get(i)) {
own = p;
}
}
return own;
}
/**
* Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
* translating it from a Label in the original code, to a Label in the
* inlined code that is appropriate for use by an instruction that
* branched to the original label.
*
* @param l
* The label we will be translating
* @return a label for use by a branch instruction in the inlined code
* @see #rangeLabel
*/
public LabelNode gotoLabel(final LabelNode l) {
// owner should never be null, because owner is only null
// if an instruction cannot be reached from this subroutine
Instantiation owner = findOwner(instructions.indexOf(l));
return owner.rangeTable.get(l);
}
/**
* Looks up the label <code>l</code> in the <code>rangeTable</code>,
* thus translating it from a Label in the original code, to a Label in
* the inlined code that is appropriate for use by an try/catch or
* variable use annotation.
*
* @param l
* The label we will be translating
* @return a label for use by a try/catch or variable annotation in the
* original code
* @see #rangeTable
*/
public LabelNode rangeLabel(final LabelNode l) {
return rangeTable.get(l);
}
// AbstractMap implementation
@Override
public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
return null;
}
@Override
public LabelNode get(final Object o) {
return gotoLabel((LabelNode) o);
}
}
}

View File

@ -0,0 +1,361 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
* A {@link MethodVisitor} that renumbers local variables in their order of
* appearance. This adapter allows one to easily add new local variables to a
* method. It may be used by inheriting from this class, but the preferred way
* of using it is via delegation: the next visitor in the chain can indeed add
* new locals when needed by calling {@link #newLocal} on this adapter (this
* requires a reference back to this {@link LocalVariablesSorter}).
*
* @author Chris Nokleberg
* @author Eugene Kuleshov
* @author Eric Bruneton
*/
public class LocalVariablesSorter extends MethodVisitor {
private static final Type OBJECT_TYPE = Type
.getObjectType("java/lang/Object");
/**
* Mapping from old to new local variable indexes. A local variable at index
* i of size 1 is remapped to 'mapping[2*i]', while a local variable at
* index i of size 2 is remapped to 'mapping[2*i+1]'.
*/
private int[] mapping = new int[40];
/**
* Array used to store stack map local variable types after remapping.
*/
private Object[] newLocals = new Object[20];
/**
* Index of the first local variable, after formal parameters.
*/
protected final int firstLocal;
/**
* Index of the next local variable to be created by {@link #newLocal}.
*/
protected int nextLocal;
/**
* Indicates if at least one local variable has moved due to remapping.
*/
private boolean changed;
/**
* Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
* this constructor</i>. Instead, they must use the
* {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
*
* @param access
* access flags of the adapted method.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls.
*/
public LocalVariablesSorter(final int access, final String desc,
final MethodVisitor mv) {
this(Opcodes.ASM4, access, desc, mv);
}
/**
* Creates a new {@link LocalVariablesSorter}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param access
* access flags of the adapted method.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls.
*/
protected LocalVariablesSorter(final int api, final int access,
final String desc, final MethodVisitor mv) {
super(api, mv);
Type[] args = Type.getArgumentTypes(desc);
nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
for (int i = 0; i < args.length; i++) {
nextLocal += args[i].getSize();
}
firstLocal = nextLocal;
}
@Override
public void visitVarInsn(final int opcode, final int var) {
Type type;
switch (opcode) {
case Opcodes.LLOAD:
case Opcodes.LSTORE:
type = Type.LONG_TYPE;
break;
case Opcodes.DLOAD:
case Opcodes.DSTORE:
type = Type.DOUBLE_TYPE;
break;
case Opcodes.FLOAD:
case Opcodes.FSTORE:
type = Type.FLOAT_TYPE;
break;
case Opcodes.ILOAD:
case Opcodes.ISTORE:
type = Type.INT_TYPE;
break;
default:
// case Opcodes.ALOAD:
// case Opcodes.ASTORE:
// case RET:
type = OBJECT_TYPE;
break;
}
mv.visitVarInsn(opcode, remap(var, type));
}
@Override
public void visitIincInsn(final int var, final int increment) {
mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
mv.visitMaxs(maxStack, nextLocal);
}
@Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
final int index) {
int newIndex = remap(index, Type.getType(desc));
mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
if (type != Opcodes.F_NEW) { // uncompressed frame
throw new IllegalStateException(
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
}
if (!changed) { // optimization for the case where mapping = identity
mv.visitFrame(type, nLocal, local, nStack, stack);
return;
}
// creates a copy of newLocals
Object[] oldLocals = new Object[newLocals.length];
System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
updateNewLocals(newLocals);
// copies types from 'local' to 'newLocals'
// 'newLocals' already contains the variables added with 'newLocal'
int index = 0; // old local variable index
int number = 0; // old local variable number
for (; number < nLocal; ++number) {
Object t = local[number];
int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
if (t != Opcodes.TOP) {
Type typ = OBJECT_TYPE;
if (t == Opcodes.INTEGER) {
typ = Type.INT_TYPE;
} else if (t == Opcodes.FLOAT) {
typ = Type.FLOAT_TYPE;
} else if (t == Opcodes.LONG) {
typ = Type.LONG_TYPE;
} else if (t == Opcodes.DOUBLE) {
typ = Type.DOUBLE_TYPE;
} else if (t instanceof String) {
typ = Type.getObjectType((String) t);
}
setFrameLocal(remap(index, typ), t);
}
index += size;
}
// removes TOP after long and double types as well as trailing TOPs
index = 0;
number = 0;
for (int i = 0; index < newLocals.length; ++i) {
Object t = newLocals[index++];
if (t != null && t != Opcodes.TOP) {
newLocals[i] = t;
number = i + 1;
if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
index += 1;
}
} else {
newLocals[i] = Opcodes.TOP;
}
}
// visits remapped frame
mv.visitFrame(type, number, newLocals, nStack, stack);
// restores original value of 'newLocals'
newLocals = oldLocals;
}
// -------------
/**
* Creates a new local variable of the given type.
*
* @param type
* the type of the local variable to be created.
* @return the identifier of the newly created local variable.
*/
public int newLocal(final Type type) {
Object t;
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
t = Opcodes.INTEGER;
break;
case Type.FLOAT:
t = Opcodes.FLOAT;
break;
case Type.LONG:
t = Opcodes.LONG;
break;
case Type.DOUBLE:
t = Opcodes.DOUBLE;
break;
case Type.ARRAY:
t = type.getDescriptor();
break;
// case Type.OBJECT:
default:
t = type.getInternalName();
break;
}
int local = newLocalMapping(type);
setLocalType(local, type);
setFrameLocal(local, t);
changed = true;
return local;
}
/**
* Notifies subclasses that a new stack map frame is being visited. The
* array argument contains the stack map frame types corresponding to the
* local variables added with {@link #newLocal}. This method can update
* these types in place for the stack map frame being visited. The default
* implementation of this method does nothing, i.e. a local variable added
* with {@link #newLocal} will have the same type in all stack map frames.
* But this behavior is not always the desired one, for instance if a local
* variable is added in the middle of a try/catch block: the frame for the
* exception handler should have a TOP type for this new local.
*
* @param newLocals
* the stack map frame types corresponding to the local variables
* added with {@link #newLocal} (and null for the others). The
* format of this array is the same as in
* {@link MethodVisitor#visitFrame}, except that long and double
* types use two slots. The types for the current stack map frame
* must be updated in place in this array.
*/
protected void updateNewLocals(Object[] newLocals) {
}
/**
* Notifies subclasses that a local variable has been added or remapped. The
* default implementation of this method does nothing.
*
* @param local
* a local variable identifier, as returned by {@link #newLocal
* newLocal()}.
* @param type
* the type of the value being stored in the local variable.
*/
protected void setLocalType(final int local, final Type type) {
}
private void setFrameLocal(final int local, final Object type) {
int l = newLocals.length;
if (local >= l) {
Object[] a = new Object[Math.max(2 * l, local + 1)];
System.arraycopy(newLocals, 0, a, 0, l);
newLocals = a;
}
newLocals[local] = type;
}
private int remap(final int var, final Type type) {
if (var + type.getSize() <= firstLocal) {
return var;
}
int key = 2 * var + type.getSize() - 1;
int size = mapping.length;
if (key >= size) {
int[] newMapping = new int[Math.max(2 * size, key + 1)];
System.arraycopy(mapping, 0, newMapping, 0, size);
mapping = newMapping;
}
int value = mapping[key];
if (value == 0) {
value = newLocalMapping(type);
setLocalType(value, type);
mapping[key] = value + 1;
} else {
value--;
}
if (value != var) {
changed = true;
}
return value;
}
protected int newLocalMapping(final Type type) {
int local = nextLocal;
nextLocal += type.getSize();
return local;
}
}

View File

@ -0,0 +1,282 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.HashMap;
import java.util.Map;
import org.objectweb.asm.Type;
/**
* A named method descriptor.
*
* @author Juozas Baliuka
* @author Chris Nokleberg
* @author Eric Bruneton
*/
public class Method {
/**
* The method name.
*/
private final String name;
/**
* The method descriptor.
*/
private final String desc;
/**
* Maps primitive Java type names to their descriptors.
*/
private static final Map<String, String> DESCRIPTORS;
static {
DESCRIPTORS = new HashMap<String, String>();
DESCRIPTORS.put("void", "V");
DESCRIPTORS.put("byte", "B");
DESCRIPTORS.put("char", "C");
DESCRIPTORS.put("double", "D");
DESCRIPTORS.put("float", "F");
DESCRIPTORS.put("int", "I");
DESCRIPTORS.put("long", "J");
DESCRIPTORS.put("short", "S");
DESCRIPTORS.put("boolean", "Z");
}
/**
* Creates a new {@link Method}.
*
* @param name
* the method's name.
* @param desc
* the method's descriptor.
*/
public Method(final String name, final String desc) {
this.name = name;
this.desc = desc;
}
/**
* Creates a new {@link Method}.
*
* @param name
* the method's name.
* @param returnType
* the method's return type.
* @param argumentTypes
* the method's argument types.
*/
public Method(final String name, final Type returnType,
final Type[] argumentTypes) {
this(name, Type.getMethodDescriptor(returnType, argumentTypes));
}
/**
* Creates a new {@link Method}.
*
* @param m
* a java.lang.reflect method descriptor
* @return a {@link Method} corresponding to the given Java method
* declaration.
*/
public static Method getMethod(java.lang.reflect.Method m) {
return new Method(m.getName(), Type.getMethodDescriptor(m));
}
/**
* Creates a new {@link Method}.
*
* @param c
* a java.lang.reflect constructor descriptor
* @return a {@link Method} corresponding to the given Java constructor
* declaration.
*/
public static Method getMethod(java.lang.reflect.Constructor<?> c) {
return new Method("<init>", Type.getConstructorDescriptor(c));
}
/**
* Returns a {@link Method} corresponding to the given Java method
* declaration.
*
* @param method
* a Java method declaration, without argument names, of the form
* "returnType name (argumentType1, ... argumentTypeN)", where
* the types are in plain Java (e.g. "int", "float",
* "java.util.List", ...). Classes of the java.lang package can
* be specified by their unqualified name; all other classes
* names must be fully qualified.
* @return a {@link Method} corresponding to the given Java method
* declaration.
* @throws IllegalArgumentException
* if <code>method</code> could not get parsed.
*/
public static Method getMethod(final String method)
throws IllegalArgumentException {
return getMethod(method, false);
}
/**
* Returns a {@link Method} corresponding to the given Java method
* declaration.
*
* @param method
* a Java method declaration, without argument names, of the form
* "returnType name (argumentType1, ... argumentTypeN)", where
* the types are in plain Java (e.g. "int", "float",
* "java.util.List", ...). Classes of the java.lang package may
* be specified by their unqualified name, depending on the
* defaultPackage argument; all other classes names must be fully
* qualified.
* @param defaultPackage
* true if unqualified class names belong to the default package,
* or false if they correspond to java.lang classes. For instance
* "Object" means "Object" if this option is true, or
* "java.lang.Object" otherwise.
* @return a {@link Method} corresponding to the given Java method
* declaration.
* @throws IllegalArgumentException
* if <code>method</code> could not get parsed.
*/
public static Method getMethod(final String method,
final boolean defaultPackage) throws IllegalArgumentException {
int space = method.indexOf(' ');
int start = method.indexOf('(', space) + 1;
int end = method.indexOf(')', start);
if (space == -1 || start == -1 || end == -1) {
throw new IllegalArgumentException();
}
String returnType = method.substring(0, space);
String methodName = method.substring(space + 1, start - 1).trim();
StringBuffer sb = new StringBuffer();
sb.append('(');
int p;
do {
String s;
p = method.indexOf(',', start);
if (p == -1) {
s = map(method.substring(start, end).trim(), defaultPackage);
} else {
s = map(method.substring(start, p).trim(), defaultPackage);
start = p + 1;
}
sb.append(s);
} while (p != -1);
sb.append(')');
sb.append(map(returnType, defaultPackage));
return new Method(methodName, sb.toString());
}
private static String map(final String type, final boolean defaultPackage) {
if ("".equals(type)) {
return type;
}
StringBuffer sb = new StringBuffer();
int index = 0;
while ((index = type.indexOf("[]", index) + 1) > 0) {
sb.append('[');
}
String t = type.substring(0, type.length() - sb.length() * 2);
String desc = DESCRIPTORS.get(t);
if (desc != null) {
sb.append(desc);
} else {
sb.append('L');
if (t.indexOf('.') < 0) {
if (!defaultPackage) {
sb.append("java/lang/");
}
sb.append(t);
} else {
sb.append(t.replace('.', '/'));
}
sb.append(';');
}
return sb.toString();
}
/**
* Returns the name of the method described by this object.
*
* @return the name of the method described by this object.
*/
public String getName() {
return name;
}
/**
* Returns the descriptor of the method described by this object.
*
* @return the descriptor of the method described by this object.
*/
public String getDescriptor() {
return desc;
}
/**
* Returns the return type of the method described by this object.
*
* @return the return type of the method described by this object.
*/
public Type getReturnType() {
return Type.getReturnType(desc);
}
/**
* Returns the argument types of the method described by this object.
*
* @return the argument types of the method described by this object.
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(desc);
}
@Override
public String toString() {
return name + desc;
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof Method)) {
return false;
}
Method other = (Method) o;
return name.equals(other.name) && desc.equals(other.desc);
}
@Override
public int hashCode() {
return name.hashCode() ^ desc.hashCode();
}
}

View File

@ -0,0 +1,223 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
import org.objectweb.asm.signature.SignatureWriter;
/**
* A class responsible for remapping types and names. Subclasses can override
* the following methods:
*
* <ul>
* <li>{@link #map(String)} - map type</li>
* <li>{@link #mapFieldName(String, String, String)} - map field name</li>
* <li>{@link #mapMethodName(String, String, String)} - map method name</li>
* </ul>
*
* @author Eugene Kuleshov
*/
public abstract class Remapper {
public String mapDesc(String desc) {
Type t = Type.getType(desc);
switch (t.getSort()) {
case Type.ARRAY:
String s = mapDesc(t.getElementType().getDescriptor());
for (int i = 0; i < t.getDimensions(); ++i) {
s = '[' + s;
}
return s;
case Type.OBJECT:
String newType = map(t.getInternalName());
if (newType != null) {
return 'L' + newType + ';';
}
}
return desc;
}
private Type mapType(Type t) {
switch (t.getSort()) {
case Type.ARRAY:
String s = mapDesc(t.getElementType().getDescriptor());
for (int i = 0; i < t.getDimensions(); ++i) {
s = '[' + s;
}
return Type.getType(s);
case Type.OBJECT:
s = map(t.getInternalName());
return s != null ? Type.getObjectType(s) : t;
case Type.METHOD:
return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
}
return t;
}
public String mapType(String type) {
if (type == null) {
return null;
}
return mapType(Type.getObjectType(type)).getInternalName();
}
public String[] mapTypes(String[] types) {
String[] newTypes = null;
boolean needMapping = false;
for (int i = 0; i < types.length; i++) {
String type = types[i];
String newType = map(type);
if (newType != null && newTypes == null) {
newTypes = new String[types.length];
if (i > 0) {
System.arraycopy(types, 0, newTypes, 0, i);
}
needMapping = true;
}
if (needMapping) {
newTypes[i] = newType == null ? type : newType;
}
}
return needMapping ? newTypes : types;
}
public String mapMethodDesc(String desc) {
if ("()V".equals(desc)) {
return desc;
}
Type[] args = Type.getArgumentTypes(desc);
StringBuffer s = new StringBuffer("(");
for (int i = 0; i < args.length; i++) {
s.append(mapDesc(args[i].getDescriptor()));
}
Type returnType = Type.getReturnType(desc);
if (returnType == Type.VOID_TYPE) {
s.append(")V");
return s.toString();
}
s.append(')').append(mapDesc(returnType.getDescriptor()));
return s.toString();
}
public Object mapValue(Object value) {
if (value instanceof Type) {
return mapType((Type) value);
}
if (value instanceof Handle) {
Handle h = (Handle) value;
return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
h.getOwner(), h.getName(), h.getDesc()),
mapMethodDesc(h.getDesc()));
}
return value;
}
/**
*
* @param typeSignature
* true if signature is a FieldTypeSignature, such as the
* signature parameter of the ClassVisitor.visitField or
* MethodVisitor.visitLocalVariable methods
*/
public String mapSignature(String signature, boolean typeSignature) {
if (signature == null) {
return null;
}
SignatureReader r = new SignatureReader(signature);
SignatureWriter w = new SignatureWriter();
SignatureVisitor a = createRemappingSignatureAdapter(w);
if (typeSignature) {
r.acceptType(a);
} else {
r.accept(a);
}
return w.toString();
}
protected SignatureVisitor createRemappingSignatureAdapter(
SignatureVisitor v) {
return new RemappingSignatureAdapter(v, this);
}
/**
* Map method name to the new name. Subclasses can override.
*
* @param owner
* owner of the method.
* @param name
* name of the method.
* @param desc
* descriptor of the method.
* @return new name of the method
*/
public String mapMethodName(String owner, String name, String desc) {
return name;
}
/**
* Map invokedynamic method name to the new name. Subclasses can override.
*
* @param name
* name of the invokedynamic.
* @param desc
* descriptor of the invokedynamic.
* @return new invokdynamic name.
*/
public String mapInvokeDynamicMethodName(String name, String desc) {
return name;
}
/**
* Map field name to the new name. Subclasses can override.
*
* @param owner
* owner of the field.
* @param name
* name of the field
* @param desc
* descriptor of the field
* @return new name of the field.
*/
public String mapFieldName(String owner, String name, String desc) {
return name;
}
/**
* Map type name to the new name. Subclasses can override.
*/
public String map(String typeName) {
return typeName;
}
}

View File

@ -0,0 +1,79 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
/**
* An {@link AnnotationVisitor} adapter for type remapping.
*
* @author Eugene Kuleshov
*/
public class RemappingAnnotationAdapter extends AnnotationVisitor {
protected final Remapper remapper;
public RemappingAnnotationAdapter(final AnnotationVisitor av,
final Remapper remapper) {
this(Opcodes.ASM4, av, remapper);
}
protected RemappingAnnotationAdapter(final int api,
final AnnotationVisitor av, final Remapper remapper) {
super(api, av);
this.remapper = remapper;
}
@Override
public void visit(String name, Object value) {
av.visit(name, remapper.mapValue(value));
}
@Override
public void visitEnum(String name, String desc, String value) {
av.visitEnum(name, remapper.mapDesc(desc), value);
}
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
return v == null ? null : (v == av ? this
: new RemappingAnnotationAdapter(v, remapper));
}
@Override
public AnnotationVisitor visitArray(String name) {
AnnotationVisitor v = av.visitArray(name);
return v == null ? null : (v == av ? this
: new RemappingAnnotationAdapter(v, remapper));
}
}

View File

@ -0,0 +1,126 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link ClassVisitor} for type remapping.
*
* @author Eugene Kuleshov
*/
public class RemappingClassAdapter extends ClassVisitor {
protected final Remapper remapper;
protected String className;
public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
this(Opcodes.ASM4, cv, remapper);
}
protected RemappingClassAdapter(final int api, final ClassVisitor cv,
final Remapper remapper) {
super(api, cv);
this.remapper = remapper;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
this.className = name;
super.visit(version, access, remapper.mapType(name), remapper
.mapSignature(signature, false), remapper.mapType(superName),
interfaces == null ? null : remapper.mapTypes(interfaces));
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av;
av = super.visitAnnotation(remapper.mapDesc(desc), visible);
return av == null ? null : createRemappingAnnotationAdapter(av);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
FieldVisitor fv = super.visitField(access,
remapper.mapFieldName(className, name, desc),
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
remapper.mapValue(value));
return fv == null ? null : createRemappingFieldAdapter(fv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
String newDesc = remapper.mapMethodDesc(desc);
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
className, name, desc), newDesc, remapper.mapSignature(
signature, false),
exceptions == null ? null : remapper.mapTypes(exceptions));
return mv == null ? null : createRemappingMethodAdapter(access,
newDesc, mv);
}
@Override
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
// TODO should innerName be changed?
super.visitInnerClass(remapper.mapType(name), outerName == null ? null
: remapper.mapType(outerName), innerName, access);
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
super.visitOuterClass(remapper.mapType(owner), name == null ? null
: remapper.mapMethodName(owner, name, desc),
desc == null ? null : remapper.mapMethodDesc(desc));
}
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
return new RemappingFieldAdapter(fv, remapper);
}
protected MethodVisitor createRemappingMethodAdapter(int access,
String newDesc, MethodVisitor mv) {
return new RemappingMethodAdapter(access, newDesc, mv, remapper);
}
protected AnnotationVisitor createRemappingAnnotationAdapter(
AnnotationVisitor av) {
return new RemappingAnnotationAdapter(av, remapper);
}
}

View File

@ -0,0 +1,62 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link FieldVisitor} adapter for type remapping.
*
* @author Eugene Kuleshov
*/
public class RemappingFieldAdapter extends FieldVisitor {
private final Remapper remapper;
public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
this(Opcodes.ASM4, fv, remapper);
}
protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
final Remapper remapper) {
super(api, fv);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
}
}

View File

@ -0,0 +1,161 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link LocalVariablesSorter} for type mapping.
*
* @author Eugene Kuleshov
*/
public class RemappingMethodAdapter extends LocalVariablesSorter {
protected final Remapper remapper;
public RemappingMethodAdapter(final int access, final String desc,
final MethodVisitor mv, final Remapper remapper) {
this(Opcodes.ASM4, access, desc, mv, remapper);
}
protected RemappingMethodAdapter(final int api, final int access,
final String desc, final MethodVisitor mv, final Remapper remapper) {
super(api, access, desc, mv);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor av = mv.visitAnnotationDefault();
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = mv.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
AnnotationVisitor av = mv.visitParameterAnnotation(parameter,
remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
}
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
remapEntries(nStack, stack));
}
private Object[] remapEntries(int n, Object[] entries) {
for (int i = 0; i < n; i++) {
if (entries[i] instanceof String) {
Object[] newEntries = new Object[n];
if (i > 0) {
System.arraycopy(entries, 0, newEntries, 0, i);
}
do {
Object t = entries[i];
newEntries[i++] = t instanceof String ? remapper
.mapType((String) t) : t;
} while (i < n);
return newEntries;
}
}
return entries;
}
@Override
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
super.visitFieldInsn(opcode, remapper.mapType(owner),
remapper.mapFieldName(owner, name, desc),
remapper.mapDesc(desc));
}
@Override
public void visitMethodInsn(int opcode, String owner, String name,
String desc) {
super.visitMethodInsn(opcode, remapper.mapType(owner),
remapper.mapMethodName(owner, name, desc),
remapper.mapMethodDesc(desc));
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
for (int i = 0; i < bsmArgs.length; i++) {
bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
}
super.visitInvokeDynamicInsn(
remapper.mapInvokeDynamicMethodName(name, desc),
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
bsmArgs);
}
@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, remapper.mapType(type));
}
@Override
public void visitLdcInsn(Object cst) {
super.visitLdcInsn(remapper.mapValue(cst));
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null
: remapper.mapType(type));
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
super.visitLocalVariable(name, remapper.mapDesc(desc),
remapper.mapSignature(signature, true), start, end, index);
}
}

View File

@ -0,0 +1,155 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.signature.SignatureVisitor;
/**
* A {@link SignatureVisitor} adapter for type mapping.
*
* @author Eugene Kuleshov
*/
public class RemappingSignatureAdapter extends SignatureVisitor {
private final SignatureVisitor v;
private final Remapper remapper;
private String className;
public RemappingSignatureAdapter(final SignatureVisitor v,
final Remapper remapper) {
this(Opcodes.ASM4, v, remapper);
}
protected RemappingSignatureAdapter(final int api,
final SignatureVisitor v, final Remapper remapper) {
super(api);
this.v = v;
this.remapper = remapper;
}
@Override
public void visitClassType(String name) {
className = name;
v.visitClassType(remapper.mapType(name));
}
@Override
public void visitInnerClassType(String name) {
String remappedOuter = remapper.mapType(className) + '$';
className = className + '$' + name;
String remappedName = remapper.mapType(className);
int index = remappedName.startsWith(remappedOuter) ? remappedOuter
.length() : remappedName.lastIndexOf('$') + 1;
v.visitInnerClassType(remappedName.substring(index));
}
@Override
public void visitFormalTypeParameter(String name) {
v.visitFormalTypeParameter(name);
}
@Override
public void visitTypeVariable(String name) {
v.visitTypeVariable(name);
}
@Override
public SignatureVisitor visitArrayType() {
v.visitArrayType();
return this;
}
@Override
public void visitBaseType(char descriptor) {
v.visitBaseType(descriptor);
}
@Override
public SignatureVisitor visitClassBound() {
v.visitClassBound();
return this;
}
@Override
public SignatureVisitor visitExceptionType() {
v.visitExceptionType();
return this;
}
@Override
public SignatureVisitor visitInterface() {
v.visitInterface();
return this;
}
@Override
public SignatureVisitor visitInterfaceBound() {
v.visitInterfaceBound();
return this;
}
@Override
public SignatureVisitor visitParameterType() {
v.visitParameterType();
return this;
}
@Override
public SignatureVisitor visitReturnType() {
v.visitReturnType();
return this;
}
@Override
public SignatureVisitor visitSuperclass() {
v.visitSuperclass();
return this;
}
@Override
public void visitTypeArgument() {
v.visitTypeArgument();
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
v.visitTypeArgument(wildcard);
return this;
}
@Override
public void visitEnd() {
v.visitEnd();
}
}

View File

@ -0,0 +1,515 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
* A {@link ClassVisitor} that adds a serial version unique identifier to a
* class if missing. Here is typical usage of this class:
*
* <pre>
* ClassWriter cw = new ClassWriter(...);
* ClassVisitor sv = new SerialVersionUIDAdder(cw);
* ClassVisitor ca = new MyClassAdapter(sv);
* new ClassReader(orginalClass).accept(ca, false);
* </pre>
* <p>
* The SVUID algorithm can be found <a href=
* "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
* >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
*
* <pre>
* The serialVersionUID is computed using the signature of a stream of bytes
* that reflect the class definition. The National Institute of Standards and
* Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
* signature for the stream. The first two 32-bit quantities are used to form a
* 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
* types to a sequence of bytes. The values input to the stream are defined by
* the Java Virtual Machine (VM) specification for classes.
*
* The sequence of items in the stream is as follows:
*
* 1. The class name written using UTF encoding.
* 2. The class modifiers written as a 32-bit integer.
* 3. The name of each interface sorted by name written using UTF encoding.
* 4. For each field of the class sorted by field name (except private static
* and private transient fields):
* 1. The name of the field in UTF encoding.
* 2. The modifiers of the field written as a 32-bit integer.
* 3. The descriptor of the field in UTF encoding
* 5. If a class initializer exists, write out the following:
* 1. The name of the method, &lt;clinit&gt;, in UTF encoding.
* 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
* written as a 32-bit integer.
* 3. The descriptor of the method, ()V, in UTF encoding.
* 6. For each non-private constructor sorted by method name and signature:
* 1. The name of the method, &lt;init&gt;, in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 7. For each non-private method sorted by method name and signature:
* 1. The name of the method in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 8. The SHA-1 algorithm is executed on the stream of bytes produced by
* DataOutputStream and produces five 32-bit values sha[0..4].
*
* 9. The hash value is assembled from the first and second 32-bit values of
* the SHA-1 message digest. If the result of the message digest, the five
* 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
* sha, the hash value would be computed as follows:
*
* long hash = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) |
* ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8 |
* ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 |
* ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 24 |
* ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 |
* ((sha[1] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 40 |
* ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 |
* ((sha[1] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
* </pre>
*
* @author Rajendra Inamdar, Vishal Vishnoi
*/
public class SerialVersionUIDAdder extends ClassVisitor {
/**
* Collection of fields. (except private static and private transient
* fields)
*/
private final Collection<Item> svuidFields;
/**
* Collection of non-private constructors.
*/
private final Collection<Item> svuidConstructors;
/**
* Collection of non-private methods.
*/
private final Collection<Item> svuidMethods;
/**
* Flag that indicates if we need to compute SVUID.
*/
private boolean computeSVUID;
/**
* Set to true if the class already has SVUID.
*/
private boolean hasSVUID;
/**
* Classes access flags.
*/
private int access;
/**
* Internal name of the class
*/
private String name;
/**
* Interfaces implemented by the class.
*/
private String[] interfaces;
/**
* Set to true if the class has static initializer.
*/
private boolean hasStaticInitializer;
/**
* Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
* this constructor</i>. Instead, they must use the
* {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
*
* @param cv a {@link ClassVisitor} to which this visitor will delegate
* calls.
*/
public SerialVersionUIDAdder(final ClassVisitor cv) {
this(Opcodes.ASM4, cv);
}
/**
* Creates a new {@link SerialVersionUIDAdder}.
*
* @param api the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param cv a {@link ClassVisitor} to which this visitor will delegate
* calls.
*/
protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
super(api, cv);
svuidFields = new ArrayList<>();
svuidConstructors = new ArrayList<>();
svuidMethods = new ArrayList<>();
}
// ------------------------------------------------------------------------
// Overriden methods
// ------------------------------------------------------------------------
/**
* Sorts the items in the collection and writes it to the data output stream
*
* @param itemCollection collection of items
* @param dos a <code>DataOutputStream</code> value
* @param dotted a <code>boolean</code> value
* @throws IOException if an error occurs
*/
private static void writeItems(final Collection<Item> itemCollection,
final DataOutput dos, final boolean dotted) throws IOException {
int size = itemCollection.size();
Item[] items = itemCollection.toArray(new Item[size]);
Arrays.sort(items);
for (int i = 0; i < size; i++) {
dos.writeUTF(items[i].name);
dos.writeInt(items[i].access);
dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
: items[i].desc);
}
}
/*
* Visit class header and get class name, access , and interfaces
* information (step 1,2, and 3) for SVUID computation.
*/
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
if (computeSVUID) {
this.name = name;
this.access = access;
this.interfaces = interfaces;
}
super.visit(version, access, name, signature, superName, interfaces);
}
/*
* Visit the methods and get constructor and method information (step 5 and
* 7). Also determine if there is a class initializer (step 6).
*/
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
if (computeSVUID) {
if ("<clinit>".equals(name)) {
hasStaticInitializer = true;
}
/*
* Remembers non private constructors and methods for SVUID
* computation For constructor and method modifiers, only the
* ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
* ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
* are used.
*/
int mods = access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
| Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
// all non private methods
if ((access & Opcodes.ACC_PRIVATE) == 0) {
if ("<init>".equals(name)) {
svuidConstructors.add(new Item(name, mods, desc));
} else if (!"<clinit>".equals(name)) {
svuidMethods.add(new Item(name, mods, desc));
}
}
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
/*
* Gets class field information for step 4 of the algorithm. Also determines
* if the class already has a SVUID.
*/
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
if (computeSVUID) {
if ("serialVersionUID".equals(name)) {
// since the class already has SVUID, we won't be computing it.
computeSVUID = false;
hasSVUID = true;
}
/*
* Remember field for SVUID computation For field modifiers, only
* the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
* ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
* computing serialVersionUID values.
*/
if ((access & Opcodes.ACC_PRIVATE) == 0
|| (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
int mods = access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
svuidFields.add(new Item(name, mods, desc));
}
}
return super.visitField(access, name, desc, signature, value);
}
/**
* Handle a bizarre special case. Nested classes (static classes declared
* inside another class) that are protected have their access bit set to
* public in their class files to deal with some odd reflection situation.
* Our SVUID computation must do as the JVM does and ignore access bits in
* the class file in favor of the access bits InnerClass attribute.
*/
@Override
public void visitInnerClass(final String aname, final String outerName,
final String innerName, final int attr_access) {
if ((name != null) && name.equals(aname)) {
this.access = attr_access;
}
super.visitInnerClass(aname, outerName, innerName, attr_access);
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/*
* Add the SVUID if class doesn't have one
*/
@Override
public void visitEnd() {
// compute SVUID and add it to the class
if (computeSVUID && !hasSVUID) {
try {
addSVUID(computeSVUID());
} catch (Throwable e) {
throw new RuntimeException("Error while computing SVUID for "
+ name, e);
}
}
super.visitEnd();
}
/**
* Returns true if the class already has a SVUID field. The result of this
* method is only valid when visitEnd is or has been called.
*
* @return true if the class already has a SVUID field.
*/
public boolean hasSVUID() {
return hasSVUID;
}
protected void addSVUID(long svuid) {
FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
+ Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
if (null != fv) {
fv.visitEnd();
}
}
/**
* Computes and returns the value of SVUID.
*
* @return Returns the serial version UID
* @throws IOException if an I/O error occurs
*/
protected long computeSVUID() throws IOException {
ByteArrayOutputStream bos;
DataOutputStream dos = null;
long svuid = 0;
try {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
/*
* 1. The class name written using UTF encoding.
*/
dos.writeUTF(name.replace('/', '.'));
/*
* 2. The class modifiers written as a 32-bit integer.
*/
dos.writeInt(access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
| Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
/*
* 3. The name of each interface sorted by name written using UTF
* encoding.
*/
Arrays.sort(interfaces);
for (String anInterface : interfaces) {
dos.writeUTF(anInterface.replace('/', '.'));
}
/*
* 4. For each field of the class sorted by field name (except
* private static and private transient fields):
*
* 1. The name of the field in UTF encoding. 2. The modifiers of the
* field written as a 32-bit integer. 3. The descriptor of the field
* in UTF encoding
*
* Note that field signatures are not dot separated. Method and
* constructor signatures are dot separated. Go figure...
*/
writeItems(svuidFields, dos, false);
/*
* 5. If a class initializer exists, write out the following: 1. The
* name of the method, <clinit>, in UTF encoding. 2. The modifier of
* the method, java.lang.reflect.Modifier.STATIC, written as a
* 32-bit integer. 3. The descriptor of the method, ()V, in UTF
* encoding.
*/
if (hasStaticInitializer) {
dos.writeUTF("<clinit>");
dos.writeInt(Opcodes.ACC_STATIC);
dos.writeUTF("()V");
} // if..
/*
* 6. For each non-private constructor sorted by method name and
* signature: 1. The name of the method, <init>, in UTF encoding. 2.
* The modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems(svuidConstructors, dos, true);
/*
* 7. For each non-private method sorted by method name and
* signature: 1. The name of the method in UTF encoding. 2. The
* modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems(svuidMethods, dos, true);
dos.flush();
/*
* 8. The SHA-1 algorithm is executed on the stream of bytes
* produced by DataOutputStream and produces five 32-bit values
* sha[0..4].
*/
byte[] hashBytes = computeSHAdigest(bos.toByteArray());
/*
* 9. The hash value is assembled from the first and second 32-bit
* values of the SHA-1 message digest. If the result of the message
* digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
* five int values named sha, the hash value would be computed as
* follows:
*
* long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
* << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
* 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
* 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
* 56;
*/
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
}
} finally {
// close the stream (if open)
if (dos != null) {
dos.close();
}
}
return svuid;
}
/**
* Returns the SHA-1 message digest of the given value.
*
* @param value the value whose SHA message digest must be computed.
* @return the SHA-1 message digest of the given value.
*/
protected byte[] computeSHAdigest(final byte[] value) {
try {
return MessageDigest.getInstance("SHA").digest(value);
} catch (Exception e) {
throw new UnsupportedOperationException(e.toString());
}
}
// ------------------------------------------------------------------------
// Inner classes
// ------------------------------------------------------------------------
private static class Item implements Comparable<Item> {
final String name;
final int access;
final String desc;
Item(final String name, final int access, final String desc) {
this.name = name;
this.access = access;
this.desc = desc;
}
public int compareTo(final Item other) {
int retVal = name.compareTo(other.name);
if (retVal == 0) {
retVal = desc.compareTo(other.desc);
}
return retVal;
}
@Override
public boolean equals(final Object o) {
if (o instanceof Item) {
return compareTo((Item) o) == 0;
}
return false;
}
@Override
public int hashCode() {
return (name + desc).hashCode();
}
}
}

View File

@ -0,0 +1,69 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.Collections;
import java.util.Map;
/**
* A {@link Remapper} using a {@link Map} to define its mapping.
*
* @author Eugene Kuleshov
*/
public class SimpleRemapper extends Remapper {
private final Map<String, String> mapping;
public SimpleRemapper(Map<String, String> mapping) {
this.mapping = mapping;
}
public SimpleRemapper(String oldName, String newName) {
this.mapping = Collections.singletonMap(oldName, newName);
}
@Override
public String mapMethodName(String owner, String name, String desc) {
String s = map(owner + '.' + name + desc);
return s == null ? name : s;
}
@Override
public String mapFieldName(String owner, String name, String desc) {
String s = map(owner + '.' + name);
return s == null ? name : s;
}
@Override
public String map(String key) {
return mapping.get(key);
}
}

View File

@ -0,0 +1,96 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A {@link ClassVisitor} that merges clinit methods into a single one.
*
* @author Eric Bruneton
*/
public class StaticInitMerger extends ClassVisitor {
private String name;
private MethodVisitor clinit;
private final String prefix;
private int counter;
public StaticInitMerger(final String prefix, final ClassVisitor cv) {
this(Opcodes.ASM4, prefix, cv);
}
protected StaticInitMerger(final int api, final String prefix,
final ClassVisitor cv) {
super(api, cv);
this.prefix = prefix;
}
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
cv.visit(version, access, name, signature, superName, interfaces);
this.name = name;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv;
if ("<clinit>".equals(name)) {
int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
String n = prefix + counter++;
mv = cv.visitMethod(a, n, desc, signature, exceptions);
if (clinit == null) {
clinit = cv.visitMethod(a, name, desc, null, null);
}
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc);
} else {
mv = cv.visitMethod(access, name, desc, signature, exceptions);
}
return mv;
}
@Override
public void visitEnd() {
if (clinit != null) {
clinit.visitInsn(Opcodes.RETURN);
clinit.visitMaxs(0, 0);
}
cv.visitEnd();
}
}

View File

@ -0,0 +1,57 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import org.objectweb.asm.Label;
/**
* A code generator for switch statements.
*
* @author Juozas Baliuka
* @author Chris Nokleberg
* @author Eric Bruneton
*/
public interface TableSwitchGenerator {
/**
* Generates the code for a switch case.
*
* @param key
* the switch case key.
* @param end
* a label that corresponds to the end of the switch statement.
*/
void generateCase(int key, Label end);
/**
* Generates the code for the default switch case.
*/
void generateDefault();
}

View File

@ -0,0 +1,92 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.commons;
import java.util.Collections;
import java.util.Comparator;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TryCatchBlockNode;
/**
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
* are sorted in a method innermost-to-outermost. This allows the programmer to
* add handlers without worrying about ordering them correctly with respect to
* existing, in-code handlers.
*
* Behavior is only defined for properly-nested handlers. If any "try" blocks
* overlap (something that isn't possible in Java code) then this may not do
* what you want. In fact, this adapter just sorts by the length of the "try"
* block, taking advantage of the fact that a given try block must be larger
* than any block it contains).
*
* @author Adrian Sampson
*/
public class TryCatchBlockSorter extends MethodNode {
public TryCatchBlockSorter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
final String[] exceptions) {
this(Opcodes.ASM4, mv, access, name, desc, signature, exceptions);
}
protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
super(api, access, name, desc, signature, exceptions);
this.mv = mv;
}
@Override
public void visitEnd() {
// Compares TryCatchBlockNodes by the length of their "try" block.
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
}
private int blockLength(TryCatchBlockNode block) {
int startidx = instructions.indexOf(block.start);
int endidx = instructions.indexOf(block.end);
return endidx - startidx;
}
};
Collections.sort(tryCatchBlocks, comp);
if (mv != null) {
accept(mv);
}
}
}

View File

@ -0,0 +1,48 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.
-->
<body>
Provides some useful class and method adapters. <i>The preferred way of using
these adapters is by chaining them together and to custom adapters (instead of
inheriting from them)</i>. Indeed this approach provides more combination
possibilities than inheritance. For instance, suppose you want to implement an
adapter MyAdapter than needs sorted local variables and intermediate stack map
frame values taking into account the local variables sort. By using inheritance,
this would require MyAdapter to extend AnalyzerAdapter, itself extending
LocalVariablesSorter. But AnalyzerAdapter is not a subclass of
LocalVariablesSorter, so this is not possible. On the contrary, by using
delegation, you can make LocalVariablesSorter delegate to AnalyzerAdapter,
itself delegating to MyAdapter. In this case AnalyzerAdapter computes
intermediate frames based on the output of LocalVariablesSorter, and MyAdapter
can add new locals by calling the newLocal method on LocalVariablesSorter, and
can get the stack map frame state before each instruction by reading the locals
and stack fields in AnalyzerAdapter (this requires references from MyAdapter
back to LocalVariablesSorter and AnalyzerAdapter).
</body>

View File

@ -0,0 +1,87 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.
-->
<body>
Provides a small and fast bytecode manipulation framework.
<p>
The <a href="http://www.objectweb.org/asm">ASM</a> framework is organized
around the {@link org.objectweb.asm.ClassVisitor ClassVisitor},
{@link org.objectweb.asm.FieldVisitor FieldVisitor},
{@link org.objectweb.asm.MethodVisitor MethodVisitor} and
{@link org.objectweb.asm.AnnotationVisitor AnnotationVisitor} abstract classes,
which allow one to visit the fields, methods and annotations of a class,
including the bytecode instructions of each method.
<p>
In addition to these main abstract classes, ASM provides a {@link
org.objectweb.asm.ClassReader ClassReader} class, that can parse an
existing class and make a given visitor visit it. ASM also provides
a {@link org.objectweb.asm.ClassWriter ClassWriter} class, which is
a visitor that generates Java class files.
<p>
In order to generate a class from scratch, only the {@link
org.objectweb.asm.ClassWriter ClassWriter} class is necessary. Indeed,
in order to generate a class, one must just call its visit<i>Xxx</i>
methods with the appropriate arguments to generate the desired fields
and methods. See the "helloworld" example in the ASM distribution for
more details about class generation.
<p>
In order to modify existing classes, one must use a {@link
org.objectweb.asm.ClassReader ClassReader} class to analyze
the original class, a class modifier, and a {@link org.objectweb.asm.ClassWriter
ClassWriter} to construct the modified class. The class modifier
is just a {@link org.objectweb.asm.ClassVisitor ClassVisitor}
that delegates most of the work to another {@link org.objectweb.asm.ClassVisitor
ClassVisitor}, but that sometimes changes some parameter values,
or call additional methods, in order to implement the desired
modification process. In order to make it easier to implement such
class modifiers, the {@link org.objectweb.asm.ClassVisitor
ClassVisitor} and {@link org.objectweb.asm.MethodVisitor MethodVisitor}
classes delegate by default all the method calls they receive to an
optional visitor. See the "adapt" example in the ASM
distribution for more details about class modification.
<p>
The size of the core ASM library, <tt>asm.jar</tt>, is only 45KB, which is much
smaller than the size of the
<a href="http://jakarta.apache.org/bcel">BCEL</a> library (504KB), and than the
size of the
<a href="http://serp.sourceforge.net">SERP</a> library (150KB). ASM is also
much faster than these tools. Indeed the overhead of a load time class
transformation process is of the order of 60% with ASM, 700% or more with BCEL,
and 1100% or more with SERP (see the <tt>test/perf</tt> directory in the ASM
distribution)!
@since ASM 1.3
</body>
</html>

View File

@ -0,0 +1,228 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.signature;
/**
* A type signature parser to make a signature visitor visit an existing
* signature.
*
* @author Thomas Hallgren
* @author Eric Bruneton
*/
public class SignatureReader {
/**
* The signature to be read.
*/
private final String signature;
/**
* Constructs a {@link SignatureReader} for the given signature.
*
* @param signature
* A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or
* <i>FieldTypeSignature</i>.
*/
public SignatureReader(final String signature) {
this.signature = signature;
}
/**
* Makes the given visitor visit the signature of this
* {@link SignatureReader}. This signature is the one specified in the
* constructor (see {@link #SignatureReader(String) SignatureReader}). This
* method is intended to be called on a {@link SignatureReader} that was
* created using a <i>ClassSignature</i> (such as the <code>signature</code>
* parameter of the {@link org.objectweb.asm.ClassVisitor#visit
* ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the
* <code>signature</code> parameter of the
* {@link org.objectweb.asm.ClassVisitor#visitMethod
* ClassVisitor.visitMethod} method).
*
* @param v
* the visitor that must visit this signature.
*/
public void accept(final SignatureVisitor v) {
String signature = this.signature;
int len = signature.length();
int pos;
char c;
if (signature.charAt(0) == '<') {
pos = 2;
do {
int end = signature.indexOf(':', pos);
v.visitFormalTypeParameter(signature.substring(pos - 1, end));
pos = end + 1;
c = signature.charAt(pos);
if (c == 'L' || c == '[' || c == 'T') {
pos = parseType(signature, pos, v.visitClassBound());
}
while ((c = signature.charAt(pos++)) == ':') {
pos = parseType(signature, pos, v.visitInterfaceBound());
}
} while (c != '>');
} else {
pos = 0;
}
if (signature.charAt(pos) == '(') {
pos++;
while (signature.charAt(pos) != ')') {
pos = parseType(signature, pos, v.visitParameterType());
}
pos = parseType(signature, pos + 1, v.visitReturnType());
while (pos < len) {
pos = parseType(signature, pos + 1, v.visitExceptionType());
}
} else {
pos = parseType(signature, pos, v.visitSuperclass());
while (pos < len) {
pos = parseType(signature, pos, v.visitInterface());
}
}
}
/**
* Makes the given visitor visit the signature of this
* {@link SignatureReader}. This signature is the one specified in the
* constructor (see {@link #SignatureReader(String) SignatureReader}). This
* method is intended to be called on a {@link SignatureReader} that was
* created using a <i>FieldTypeSignature</i>, such as the
* <code>signature</code> parameter of the
* {@link org.objectweb.asm.ClassVisitor#visitField ClassVisitor.visitField}
* or {@link org.objectweb.asm.MethodVisitor#visitLocalVariable
* MethodVisitor.visitLocalVariable} methods.
*
* @param v
* the visitor that must visit this signature.
*/
public void acceptType(final SignatureVisitor v) {
parseType(this.signature, 0, v);
}
/**
* Parses a field type signature and makes the given visitor visit it.
*
* @param signature
* a string containing the signature that must be parsed.
* @param pos
* index of the first character of the signature to parsed.
* @param v
* the visitor that must visit this signature.
* @return the index of the first character after the parsed signature.
*/
private static int parseType(final String signature, int pos,
final SignatureVisitor v) {
char c;
int start, end;
boolean visited, inner;
String name;
switch (c = signature.charAt(pos++)) {
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'F':
case 'J':
case 'D':
case 'V':
v.visitBaseType(c);
return pos;
case '[':
return parseType(signature, pos, v.visitArrayType());
case 'T':
end = signature.indexOf(';', pos);
v.visitTypeVariable(signature.substring(pos, end));
return end + 1;
default: // case 'L':
start = pos;
visited = false;
inner = false;
for (;;) {
switch (c = signature.charAt(pos++)) {
case '.':
case ';':
if (!visited) {
name = signature.substring(start, pos - 1);
if (inner) {
v.visitInnerClassType(name);
} else {
v.visitClassType(name);
}
}
if (c == ';') {
v.visitEnd();
return pos;
}
start = pos;
visited = false;
inner = true;
break;
case '<':
name = signature.substring(start, pos - 1);
if (inner) {
v.visitInnerClassType(name);
} else {
v.visitClassType(name);
}
visited = true;
top: for (;;) {
switch (c = signature.charAt(pos)) {
case '>':
break top;
case '*':
++pos;
v.visitTypeArgument();
break;
case '+':
case '-':
pos = parseType(signature, pos + 1,
v.visitTypeArgument(c));
break;
default:
pos = parseType(signature, pos,
v.visitTypeArgument('='));
break;
}
}
}
}
}
}
}

View File

@ -0,0 +1,235 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.signature;
import org.objectweb.asm.Opcodes;
/**
* A visitor to visit a generic signature. The methods of this interface must be
* called in one of the three following orders (the last one is the only valid
* order for a {@link SignatureVisitor} that is returned by a method of this
* interface):
* <ul>
* <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt>
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
* <tt>visitSuperClass</tt> <tt>visitInterface</tt>* )</li>
* <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt>
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
* <tt>visitParameterType</tt>* <tt>visitReturnType</tt>
* <tt>visitExceptionType</tt>* )</li>
* <li><i>TypeSignature</i> = <tt>visitBaseType</tt> |
* <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | (
* <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
* <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt>
* ) )</li>
* </ul>
*
* @author Thomas Hallgren
* @author Eric Bruneton
*/
public abstract class SignatureVisitor {
/**
* Wildcard for an "extends" type argument.
*/
public final static char EXTENDS = '+';
/**
* Wildcard for a "super" type argument.
*/
public final static char SUPER = '-';
/**
* Wildcard for a normal type argument.
*/
public final static char INSTANCEOF = '=';
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}.
*/
protected final int api;
/**
* Constructs a new {@link SignatureVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public SignatureVisitor(final int api) {
this.api = api;
}
/**
* Visits a formal type parameter.
*
* @param name
* the name of the formal parameter.
*/
public void visitFormalTypeParameter(String name) {
}
/**
* Visits the class bound of the last visited formal type parameter.
*
* @return a non null visitor to visit the signature of the class bound.
*/
public SignatureVisitor visitClassBound() {
return this;
}
/**
* Visits an interface bound of the last visited formal type parameter.
*
* @return a non null visitor to visit the signature of the interface bound.
*/
public SignatureVisitor visitInterfaceBound() {
return this;
}
/**
* Visits the type of the super class.
*
* @return a non null visitor to visit the signature of the super class
* type.
*/
public SignatureVisitor visitSuperclass() {
return this;
}
/**
* Visits the type of an interface implemented by the class.
*
* @return a non null visitor to visit the signature of the interface type.
*/
public SignatureVisitor visitInterface() {
return this;
}
/**
* Visits the type of a method parameter.
*
* @return a non null visitor to visit the signature of the parameter type.
*/
public SignatureVisitor visitParameterType() {
return this;
}
/**
* Visits the return type of the method.
*
* @return a non null visitor to visit the signature of the return type.
*/
public SignatureVisitor visitReturnType() {
return this;
}
/**
* Visits the type of a method exception.
*
* @return a non null visitor to visit the signature of the exception type.
*/
public SignatureVisitor visitExceptionType() {
return this;
}
/**
* Visits a signature corresponding to a primitive type.
*
* @param descriptor
* the descriptor of the primitive type, or 'V' for <tt>void</tt>
* .
*/
public void visitBaseType(char descriptor) {
}
/**
* Visits a signature corresponding to a type variable.
*
* @param name
* the name of the type variable.
*/
public void visitTypeVariable(String name) {
}
/**
* Visits a signature corresponding to an array type.
*
* @return a non null visitor to visit the signature of the array element
* type.
*/
public SignatureVisitor visitArrayType() {
return this;
}
/**
* Starts the visit of a signature corresponding to a class or interface
* type.
*
* @param name
* the internal name of the class or interface.
*/
public void visitClassType(String name) {
}
/**
* Visits an inner class.
*
* @param name
* the local name of the inner class in its enclosing class.
*/
public void visitInnerClassType(String name) {
}
/**
* Visits an unbounded type argument of the last visited class or inner
* class type.
*/
public void visitTypeArgument() {
}
/**
* Visits a type argument of the last visited class or inner class type.
*
* @param wildcard
* '+', '-' or '='.
* @return a non null visitor to visit the signature of the type argument.
*/
public SignatureVisitor visitTypeArgument(char wildcard) {
return this;
}
/**
* Ends the visit of a signature corresponding to a class or interface type.
*/
public void visitEnd() {
}
}

View File

@ -0,0 +1,227 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.signature;
import org.objectweb.asm.Opcodes;
/**
* A signature visitor that generates signatures in string format.
*
* @author Thomas Hallgren
* @author Eric Bruneton
*/
public class SignatureWriter extends SignatureVisitor {
/**
* Buffer used to construct the signature.
*/
private final StringBuffer buf = new StringBuffer();
/**
* Indicates if the signature contains formal type parameters.
*/
private boolean hasFormals;
/**
* Indicates if the signature contains method parameter types.
*/
private boolean hasParameters;
/**
* Stack used to keep track of class types that have arguments. Each element
* of this stack is a boolean encoded in one bit. The top of the stack is
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
* /2.
*/
private int argumentStack;
/**
* Constructs a new {@link SignatureWriter} object.
*/
public SignatureWriter() {
super(Opcodes.ASM4);
}
// ------------------------------------------------------------------------
// Implementation of the SignatureVisitor interface
// ------------------------------------------------------------------------
@Override
public void visitFormalTypeParameter(final String name) {
if (!hasFormals) {
hasFormals = true;
buf.append('<');
}
buf.append(name);
buf.append(':');
}
@Override
public SignatureVisitor visitClassBound() {
return this;
}
@Override
public SignatureVisitor visitInterfaceBound() {
buf.append(':');
return this;
}
@Override
public SignatureVisitor visitSuperclass() {
endFormals();
return this;
}
@Override
public SignatureVisitor visitInterface() {
return this;
}
@Override
public SignatureVisitor visitParameterType() {
endFormals();
if (!hasParameters) {
hasParameters = true;
buf.append('(');
}
return this;
}
@Override
public SignatureVisitor visitReturnType() {
endFormals();
if (!hasParameters) {
buf.append('(');
}
buf.append(')');
return this;
}
@Override
public SignatureVisitor visitExceptionType() {
buf.append('^');
return this;
}
@Override
public void visitBaseType(final char descriptor) {
buf.append(descriptor);
}
@Override
public void visitTypeVariable(final String name) {
buf.append('T');
buf.append(name);
buf.append(';');
}
@Override
public SignatureVisitor visitArrayType() {
buf.append('[');
return this;
}
@Override
public void visitClassType(final String name) {
buf.append('L');
buf.append(name);
argumentStack *= 2;
}
@Override
public void visitInnerClassType(final String name) {
endArguments();
buf.append('.');
buf.append(name);
argumentStack *= 2;
}
@Override
public void visitTypeArgument() {
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
}
buf.append('*');
}
@Override
public SignatureVisitor visitTypeArgument(final char wildcard) {
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
}
if (wildcard != '=') {
buf.append(wildcard);
}
return this;
}
@Override
public void visitEnd() {
endArguments();
buf.append(';');
}
/**
* Returns the signature that was built by this signature writer.
*
* @return the signature that was built by this signature writer.
*/
@Override
public String toString() {
return buf.toString();
}
// ------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
/**
* Ends the formal type parameters section of the signature.
*/
private void endFormals() {
if (hasFormals) {
hasFormals = false;
buf.append('>');
}
}
/**
* Ends the type arguments of a class or inner class type.
*/
private void endArguments() {
if (argumentStack % 2 != 0) {
buf.append('>');
}
argumentStack /= 2;
}
}

View File

@ -0,0 +1,36 @@
<html>
<!--
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.
-->
<body>
Provides support for type signatures.
@since ASM 2.0
</body>
</html>

View File

@ -0,0 +1,248 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a bytecode instruction. <i>An instruction can appear
* at most once in at most one {@link InsnList} at a time</i>.
*
* @author Eric Bruneton
*/
public abstract class AbstractInsnNode {
/**
* The type of {@link InsnNode} instructions.
*/
public static final int INSN = 0;
/**
* The type of {@link IntInsnNode} instructions.
*/
public static final int INT_INSN = 1;
/**
* The type of {@link VarInsnNode} instructions.
*/
public static final int VAR_INSN = 2;
/**
* The type of {@link TypeInsnNode} instructions.
*/
public static final int TYPE_INSN = 3;
/**
* The type of {@link FieldInsnNode} instructions.
*/
public static final int FIELD_INSN = 4;
/**
* The type of {@link MethodInsnNode} instructions.
*/
public static final int METHOD_INSN = 5;
/**
* The type of {@link InvokeDynamicInsnNode} instructions.
*/
public static final int INVOKE_DYNAMIC_INSN = 6;
/**
* The type of {@link JumpInsnNode} instructions.
*/
public static final int JUMP_INSN = 7;
/**
* The type of {@link LabelNode} "instructions".
*/
public static final int LABEL = 8;
/**
* The type of {@link LdcInsnNode} instructions.
*/
public static final int LDC_INSN = 9;
/**
* The type of {@link IincInsnNode} instructions.
*/
public static final int IINC_INSN = 10;
/**
* The type of {@link TableSwitchInsnNode} instructions.
*/
public static final int TABLESWITCH_INSN = 11;
/**
* The type of {@link LookupSwitchInsnNode} instructions.
*/
public static final int LOOKUPSWITCH_INSN = 12;
/**
* The type of {@link MultiANewArrayInsnNode} instructions.
*/
public static final int MULTIANEWARRAY_INSN = 13;
/**
* The type of {@link FrameNode} "instructions".
*/
public static final int FRAME = 14;
/**
* The type of {@link LineNumberNode} "instructions".
*/
public static final int LINE = 15;
/**
* The opcode of this instruction.
*/
protected int opcode;
/**
* Previous instruction in the list to which this instruction belongs.
*/
AbstractInsnNode prev;
/**
* Next instruction in the list to which this instruction belongs.
*/
AbstractInsnNode next;
/**
* Index of this instruction in the list to which it belongs. The value of
* this field is correct only when {@link InsnList#cache} is not null. A
* value of -1 indicates that this instruction does not belong to any
* {@link InsnList}.
*/
int index;
/**
* Constructs a new {@link AbstractInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed.
*/
protected AbstractInsnNode(final int opcode) {
this.opcode = opcode;
this.index = -1;
}
/**
* Returns the opcode of this instruction.
*
* @return the opcode of this instruction.
*/
public int getOpcode() {
return opcode;
}
/**
* Returns the type of this instruction.
*
* @return the type of this instruction, i.e. one the constants defined in
* this class.
*/
public abstract int getType();
/**
* Returns the previous instruction in the list to which this instruction
* belongs, if any.
*
* @return the previous instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
*/
public AbstractInsnNode getPrevious() {
return prev;
}
/**
* Returns the next instruction in the list to which this instruction
* belongs, if any.
*
* @return the next instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
*/
public AbstractInsnNode getNext() {
return next;
}
/**
* Makes the given code visitor visit this instruction.
*
* @param cv
* a code visitor.
*/
public abstract void accept(final MethodVisitor cv);
/**
* Returns a copy of this instruction.
*
* @param labels
* a map from LabelNodes to cloned LabelNodes.
* @return a copy of this instruction. The returned instruction does not
* belong to any {@link InsnList}.
*/
public abstract AbstractInsnNode clone(
final Map<LabelNode, LabelNode> labels);
/**
* Returns the clone of the given label.
*
* @param label
* a label.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @return the clone of the given label.
*/
static LabelNode clone(final LabelNode label,
final Map<LabelNode, LabelNode> map) {
return map.get(label);
}
/**
* Returns the clones of the given labels.
*
* @param labels
* a list of labels.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @return the clones of the given labels.
*/
static LabelNode[] clone(final List<LabelNode> labels,
final Map<LabelNode, LabelNode> map) {
LabelNode[] clones = new LabelNode[labels.size()];
for (int i = 0; i < clones.length; ++i) {
clones[i] = map.get(labels.get(i));
}
return clones;
}
}

View File

@ -0,0 +1,281 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;
//import cn.edu.pku.dpartner.comm.api.context.DelayLogger;
/**
* A node that represents an annotationn.
*
* @author Eric Bruneton
*/
public class AnnotationNode extends AnnotationVisitor
{
/**
* The class descriptor of the annotation class.
*/
public String desc;
/**
* The name value pairs of this annotation. Each name value pair is stored
* as two consecutive elements in the list. The name is a {@link String},
* and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Float},
* {@link Double}, {@link String} or {@link org.objectweb.asm.Type}, or an
* two elements String array (for enumeration values), a
* {@link AnnotationNode}, or a {@link List} of values of one of the
* preceding types. The list may be <tt>null</tt> if there is no name value
* pair.
*/
public List<Object> values;
/**
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #AnnotationNode(int, String)} version.
*
* @param desc
* the class descriptor of the annotation class.
*/
public AnnotationNode(final String desc)
{
this(Opcodes.ASM4, desc);
}
/**
* Constructs a new {@link AnnotationNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param desc
* the class descriptor of the annotation class.
*/
public AnnotationNode(final int api, final String desc)
{
super(api);
this.desc = desc;
}
/**
* Constructs a new {@link AnnotationNode} to visit an array value.
*
* @param values
* where the visited values must be stored.
*/
AnnotationNode(final List<Object> values)
{
super(Opcodes.ASM4);
this.values = values;
}
// ------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final String name, final Object value)
{
if (values == null)
{
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null)
{
values.add(name);
}
// else
// {
// System.out.println("[AnnotationNode] desc is null!");
// values.add("");
// }
values.add(value);
}
@Override
public void visitEnum(final String name, final String desc,
final String value)
{
if (values == null)
{
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null)
{
values.add(name);
}
values.add(new String[]
{ desc, value });
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc)
{
if (values == null)
{
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null)
{
values.add(name);
}
AnnotationNode annotation = new AnnotationNode(desc);
values.add(annotation);
return annotation;
}
@Override
public AnnotationVisitor visitArray(final String name)
{
if (values == null)
{
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null)
{
values.add(name);
}
List<Object> array = new ArrayList<Object>();
values.add(array);
return new AnnotationNode(array);
}
@Override
public void visitEnd()
{
}
// ------------------------------------------------------------------------
// Accept methods
// ------------------------------------------------------------------------
/**
* Checks that this annotation node is compatible with the given ASM API
* version. This methods checks that this node, and all its nodes
* recursively, do not contain elements that were introduced in more recent
* versions of the ASM API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4}.
*/
public void check(final int api)
{
// nothing to do
}
/**
* Makes the given visitor visit this annotation.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
*/
public void accept(final AnnotationVisitor av)
{
if (av != null)
{
if (values != null)
{
for (int i = 0; i < values.size(); i += 2)
{
if (values.get(i) == null)
{
System.out
.println("[AnnotationNode] name is null!!!!!");
// DelayLogger.logValue(values);
System.out.flush();
try
{
Thread.sleep(2000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String name = (String) values.get(i);
Object value = values.get(i + 1);
accept(av, name, value);
}
}
av.visitEnd();
}
}
/**
* Makes the given visitor visit a given annotation value.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
* @param name
* the value name.
* @param value
* the actual value.
*/
static void accept(final AnnotationVisitor av, final String name,
final Object value)
{
if (av != null)
{
if (value instanceof String[])
{
String[] typeconst = (String[]) value;
av.visitEnum(name, typeconst[0], typeconst[1]);
}
else if (value instanceof AnnotationNode)
{
AnnotationNode an = (AnnotationNode) value;
an.accept(av.visitAnnotation(name, an.desc));
}
else if (value instanceof List)
{
AnnotationVisitor v = av.visitArray(name);
List<?> array = (List<?>) value;
for (int j = 0; j < array.size(); ++j)
{
accept(v, null, array.get(j));
}
v.visitEnd();
}
else
{
av.visit(name, value);
}
}
}
}

View File

@ -0,0 +1,345 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a class.
*
* @author Eric Bruneton
*/
public class ClassNode extends ClassVisitor {
/**
* The class version.
*/
public int version;
/**
* The class's access flags (see {@link org.objectweb.asm.Opcodes}). This
* field also indicates if the class is deprecated.
*/
public int access;
/**
* The internal name of the class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String name;
/**
* The signature of the class. May be <tt>null</tt>.
*/
public String signature;
/**
* The internal of name of the super class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
* only for the {@link Object} class.
*/
public String superName;
/**
* The internal names of the class's interfaces (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). This
* list is a list of {@link String} objects.
*/
public List<String> interfaces;
/**
* The name of the source file from which this class was compiled. May be
* <tt>null</tt>.
*/
public String sourceFile;
/**
* Debug information to compute the correspondence between source and
* compiled elements of the class. May be <tt>null</tt>.
*/
public String sourceDebug;
/**
* The internal name of the enclosing class of the class. May be
* <tt>null</tt>.
*/
public String outerClass;
/**
* The name of the method that contains the class, or <tt>null</tt> if the
* class is not enclosed in a method.
*/
public String outerMethod;
/**
* The descriptor of the method that contains the class, or <tt>null</tt> if
* the class is not enclosed in a method.
*/
public String outerMethodDesc;
/**
* The runtime visible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
* The non standard attributes of this class. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.Attribute
*/
public List<Attribute> attrs;
/**
* Informations about the inner classes of this class. This list is a list
* of {@link InnerClassNode} objects.
*
* @associates org.objectweb.asm.tree.InnerClassNode
*/
public List<InnerClassNode> innerClasses;
/**
* The fields of this class. This list is a list of {@link FieldNode}
* objects.
*
* @associates org.objectweb.asm.tree.FieldNode
*/
public List<FieldNode> fields;
/**
* The methods of this class. This list is a list of {@link MethodNode}
* objects.
*
* @associates org.objectweb.asm.tree.MethodNode
*/
public List<MethodNode> methods;
/**
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
*/
public ClassNode() {
this(Opcodes.ASM4);
}
/**
* Constructs a new {@link ClassNode}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
*/
public ClassNode(final int api) {
super(api);
this.interfaces = new ArrayList<String>();
this.innerClasses = new ArrayList<InnerClassNode>();
this.fields = new ArrayList<FieldNode>();
this.methods = new ArrayList<MethodNode>();
}
// ------------------------------------------------------------------------
// Implementation of the ClassVisitor abstract class
// ------------------------------------------------------------------------
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = name;
this.signature = signature;
this.superName = superName;
if (interfaces != null) {
this.interfaces.addAll(Arrays.asList(interfaces));
}
}
@Override
public void visitSource(final String file, final String debug) {
sourceFile = file;
sourceDebug = debug;
}
@Override
public void visitOuterClass(final String owner, final String name,
final String desc) {
outerClass = owner;
outerMethod = name;
outerMethodDesc = desc;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}
@Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
}
@Override
public void visitInnerClass(final String name, final String outerName,
final String innerName, final int access) {
InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
access);
innerClasses.add(icn);
}
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
FieldNode fn = new FieldNode(access, name, desc, signature, value);
fields.add(fn);
return fn;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodNode mn = new MethodNode(access, name, desc, signature,
exceptions);
methods.add(mn);
return mn;
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Accept method
// ------------------------------------------------------------------------
/**
* Checks that this class node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4}.
*/
public void check(final int api) {
// nothing to do
}
/**
* Makes the given class visitor visit this class.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
// visits header
String[] interfaces = new String[this.interfaces.size()];
this.interfaces.toArray(interfaces);
cv.visit(version, access, name, signature, superName, interfaces);
// visits source
if (sourceFile != null || sourceDebug != null) {
cv.visitSource(sourceFile, sourceDebug);
}
// visits outer class
if (outerClass != null) {
cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
}
// visits attributes
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
cv.visitAttribute(attrs.get(i));
}
// visits inner classes
for (i = 0; i < innerClasses.size(); ++i) {
innerClasses.get(i).accept(cv);
}
// visits fields
for (i = 0; i < fields.size(); ++i) {
fields.get(i).accept(cv);
}
// visits methods
for (i = 0; i < methods.size(); ++i) {
methods.get(i).accept(cv);
}
// visits end
cv.visitEnd();
}
}

View File

@ -0,0 +1,108 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a field instruction. A field instruction is an
* instruction that loads or stores the value of a field of an object.
*
* @author Eric Bruneton
*/
public class FieldInsnNode extends AbstractInsnNode {
/**
* The internal name of the field's owner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String owner;
/**
* The field's name.
*/
public String name;
/**
* The field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* Constructs a new {@link FieldInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner
* the internal name of the field's owner class (see
* {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public FieldInsnNode(final int opcode, final String owner,
final String name, final String desc) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be GETSTATIC,
* PUTSTATIC, GETFIELD or PUTFIELD.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return FIELD_INSN;
}
@Override
public void accept(final MethodVisitor cv) {
cv.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new FieldInsnNode(opcode, owner, name, desc);
}
}

View File

@ -0,0 +1,243 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a field.
*
* @author Eric Bruneton
*/
public class FieldNode extends FieldVisitor {
/**
* The field's access flags (see {@link org.objectweb.asm.Opcodes}). This
* field also indicates if the field is synthetic and/or deprecated.
*/
public int access;
/**
* The field's name.
*/
public String name;
/**
* The field's descriptor (see {@link org.objectweb.asm.Type}).
*/
public String desc;
/**
* The field's signature. May be <tt>null</tt>.
*/
public String signature;
/**
* The field's initial value. This field, which may be <tt>null</tt> if the
* field does not have an initial value, must be an {@link Integer}, a
* {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
*/
public Object value;
/**
* The runtime visible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
public List<AnnotationNode> invisibleAnnotations;
/**
* The non standard attributes of this field. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates org.objectweb.asm.Attribute
*/
public List<Attribute> attrs;
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
*
* @param access
* the field's access flags (see
* {@link org.objectweb.asm.Opcodes}). This parameter also
* indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) {
this(Opcodes.ASM4, access, name, desc, signature, value);
}
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}.
* @param access
* the field's access flags (see
* {@link org.objectweb.asm.Opcodes}). This parameter also
* indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public FieldNode(final int api, final int access, final String name,
final String desc, final String signature, final Object value) {
super(api);
this.access = access;
this.name = name;
this.desc = desc;
this.signature = signature;
this.value = value;
}
// ------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(an);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
}
return an;
}
@Override
public void visitAttribute(final Attribute attr) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
}
@Override
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Accept methods
// ------------------------------------------------------------------------
/**
* Checks that this field node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
*
* @param api
* an ASM API version. Must be one of {@link Opcodes#ASM4}.
*/
public void check(final int api) {
// nothing to do
}
/**
* Makes the given class visitor visit this field.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
if (fv == null) {
return;
}
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
fv.visitAttribute(attrs.get(i));
}
fv.visitEnd();
}
}

View File

@ -0,0 +1,210 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents a stack map frame. These nodes are pseudo instruction
* nodes in order to be inserted in an instruction list. In fact these nodes
* must(*) be inserted <i>just before</i> any instruction node <b>i</b> that
* follows an unconditionnal branch instruction such as GOTO or THROW, that is
* the target of a jump instruction, or that starts an exception handler block.
* The stack map frame types must describe the values of the local variables and
* of the operand stack elements <i>just before</i> <b>i</b> is executed. <br>
* <br>
* (*) this is mandatory only for classes whose version is greater than or equal
* to {@link Opcodes#V1_6 V1_6}.
*
* @author Eric Bruneton
*/
public class FrameNode extends AbstractInsnNode {
/**
* The type of this frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
*/
public int type;
/**
* The types of the local variables of this stack map frame. Elements of
* this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
*/
public List<Object> local;
/**
* The types of the operand stack elements of this stack map frame. Elements
* of this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
*/
public List<Object> stack;
private FrameNode() {
super(-1);
}
/**
* Constructs a new {@link FrameNode}.
*
* @param type
* the type of this frame. Must be {@link Opcodes#F_NEW} for
* expanded frames, or {@link Opcodes#F_FULL},
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP},
* {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND},
* {@link Opcodes#F_SAME1} for compressed frames.
* @param nLocal
* number of local variables of this stack map frame.
* @param local
* the types of the local variables of this stack map frame.
* Elements of this list can be Integer, String or LabelNode
* objects (for primitive, reference and uninitialized types
* respectively - see {@link MethodVisitor}).
* @param nStack
* number of operand stack elements of this stack map frame.
* @param stack
* the types of the operand stack elements of this stack map
* frame. Elements of this list can be Integer, String or
* LabelNode objects (for primitive, reference and uninitialized
* types respectively - see {@link MethodVisitor}).
*/
public FrameNode(final int type, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
super(-1);
this.type = type;
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
this.local = asList(nLocal, local);
this.stack = asList(nStack, stack);
break;
case Opcodes.F_APPEND:
this.local = asList(nLocal, local);
break;
case Opcodes.F_CHOP:
this.local = Arrays.asList(new Object[nLocal]);
break;
case Opcodes.F_SAME:
break;
case Opcodes.F_SAME1:
this.stack = asList(1, stack);
break;
}
}
@Override
public int getType() {
return FRAME;
}
/**
* Makes the given visitor visit this stack map frame.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
mv.visitFrame(type, local.size(), asArray(local), stack.size(),
asArray(stack));
break;
case Opcodes.F_APPEND:
mv.visitFrame(type, local.size(), asArray(local), 0, null);
break;
case Opcodes.F_CHOP:
mv.visitFrame(type, local.size(), null, 0, null);
break;
case Opcodes.F_SAME:
mv.visitFrame(type, 0, null, 0, null);
break;
case Opcodes.F_SAME1:
mv.visitFrame(type, 0, null, 1, asArray(stack));
break;
}
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
FrameNode clone = new FrameNode();
clone.type = type;
if (local != null) {
clone.local = new ArrayList<Object>();
for (int i = 0; i < local.size(); ++i) {
Object l = local.get(i);
if (l instanceof LabelNode) {
l = labels.get(l);
}
clone.local.add(l);
}
}
if (stack != null) {
clone.stack = new ArrayList<Object>();
for (int i = 0; i < stack.size(); ++i) {
Object s = stack.get(i);
if (s instanceof LabelNode) {
s = labels.get(s);
}
clone.stack.add(s);
}
}
return clone;
}
// ------------------------------------------------------------------------
private static List<Object> asList(final int n, final Object[] o) {
return Arrays.asList(o).subList(0, n);
}
private static Object[] asArray(final List<Object> l) {
Object[] objs = new Object[l.size()];
for (int i = 0; i < objs.length; ++i) {
Object o = l.get(i);
if (o instanceof LabelNode) {
o = ((LabelNode) o).getLabel();
}
objs[i] = o;
}
return objs;
}
}

View File

@ -0,0 +1,82 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an IINC instruction.
*
* @author Eric Bruneton
*/
public class IincInsnNode extends AbstractInsnNode {
/**
* Index of the local variable to be incremented.
*/
public int var;
/**
* Amount to increment the local variable by.
*/
public int incr;
/**
* Constructs a new {@link IincInsnNode}.
*
* @param var
* index of the local variable to be incremented.
* @param incr
* increment amount to increment the local variable by.
*/
public IincInsnNode(final int var, final int incr) {
super(Opcodes.IINC);
this.var = var;
this.incr = incr;
}
@Override
public int getType() {
return IINC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIincInsn(var, incr);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new IincInsnNode(var, incr);
}
}

View File

@ -0,0 +1,101 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import org.objectweb.asm.ClassVisitor;
/**
* A node that represents an inner class.
*
* @author Eric Bruneton
*/
public class InnerClassNode {
/**
* The internal name of an inner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
public String name;
/**
* The internal name of the class to which the inner class belongs (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
*/
public String outerName;
/**
* The (simple) name of the inner class inside its enclosing class. May be
* <tt>null</tt> for anonymous inner classes.
*/
public String innerName;
/**
* The access flags of the inner class as originally declared in the
* enclosing class.
*/
public int access;
/**
* Constructs a new {@link InnerClassNode}.
*
* @param name
* the internal name of an inner class (see
* {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link org.objectweb.asm.Type#getInternalName()
* getInternalName}). May be <tt>null</tt>.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
*/
public InnerClassNode(final String name, final String outerName,
final String innerName, final int access) {
this.name = name;
this.outerName = outerName;
this.innerName = innerName;
this.access = access;
}
/**
* Makes the given class visitor visit this inner class.
*
* @param cv
* a class visitor.
*/
public void accept(final ClassVisitor cv) {
cv.visitInnerClass(name, outerName, innerName, access);
}
}

View File

@ -0,0 +1,600 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import org.objectweb.asm.MethodVisitor;
/**
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This
* implementation is not thread safe</i>.
*/
public class InsnList {
/**
* The number of instructions in this list.
*/
private int size;
/**
* The first instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode first;
/**
* The last instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode last;
/**
* A cache of the instructions of this list. This cache is used to improve
* the performance of the {@link #get} method.
*/
AbstractInsnNode[] cache;
/**
* Returns the number of instructions in this list.
*
* @return the number of instructions in this list.
*/
public int size() {
return size;
}
/**
* Returns the first instruction in this list.
*
* @return the first instruction in this list, or <tt>null</tt> if the list
* is empty.
*/
public AbstractInsnNode getFirst() {
return first;
}
/**
* Returns the last instruction in this list.
*
* @return the last instruction in this list, or <tt>null</tt> if the list
* is empty.
*/
public AbstractInsnNode getLast() {
return last;
}
/**
* Returns the instruction whose index is given. This method builds a cache
* of the instructions in this list to avoid scanning the whole list each
* time it is called. Once the cache is built, this method run in constant
* time. This cache is invalidated by all the methods that modify the list.
*
* @param index
* the index of the instruction that must be returned.
* @return the instruction whose index is given.
* @throws IndexOutOfBoundsException
* if (index < 0 || index >= size()).
*/
public AbstractInsnNode get(final int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
if (cache == null) {
cache = toArray();
}
return cache[index];
}
/**
* Returns <tt>true</tt> if the given instruction belongs to this list. This
* method always scans the instructions of this list until it finds the
* given instruction or reaches the end of the list.
*
* @param insn
* an instruction.
* @return <tt>true</tt> if the given instruction belongs to this list.
*/
public boolean contains(final AbstractInsnNode insn) {
AbstractInsnNode i = first;
while (i != null && i != insn) {
i = i.next;
}
return i != null;
}
/**
* Returns the index of the given instruction in this list. This method
* builds a cache of the instruction indexes to avoid scanning the whole
* list each time it is called. Once the cache is built, this method run in
* constant time. The cache is invalidated by all the methods that modify
* the list.
*
* @param insn
* an instruction <i>of this list</i>.
* @return the index of the given instruction in this list. <i>The result of
* this method is undefined if the given instruction does not belong
* to this list</i>. Use {@link #contains contains} to test if an
* instruction belongs to an instruction list or not.
*/
public int indexOf(final AbstractInsnNode insn) {
if (cache == null) {
cache = toArray();
}
return insn.index;
}
/**
* Makes the given visitor visit all of the instructions in this list.
*
* @param mv
* the method visitor that must visit the instructions.
*/
public void accept(final MethodVisitor mv) {
AbstractInsnNode insn = first;
while (insn != null) {
insn.accept(mv);
insn = insn.next;
}
}
/**
* Returns an iterator over the instructions in this list.
*
* @return an iterator over the instructions in this list.
*/
public ListIterator<AbstractInsnNode> iterator() {
return iterator(0);
}
/**
* Returns an iterator over the instructions in this list.
*
* @return an iterator over the instructions in this list.
*/
@SuppressWarnings("unchecked")
public ListIterator<AbstractInsnNode> iterator(int index) {
return new InsnListIterator(index);
}
/**
* Returns an array containing all of the instructions in this list.
*
* @return an array containing all of the instructions in this list.
*/
public AbstractInsnNode[] toArray() {
int i = 0;
AbstractInsnNode elem = first;
AbstractInsnNode[] insns = new AbstractInsnNode[size];
while (elem != null) {
insns[i] = elem;
elem.index = i++;
elem = elem.next;
}
return insns;
}
/**
* Replaces an instruction of this list with another instruction.
*
* @param location
* an instruction <i>of this list</i>.
* @param insn
* another instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void set(final AbstractInsnNode location, final AbstractInsnNode insn) {
AbstractInsnNode next = location.next;
insn.next = next;
if (next != null) {
next.prev = insn;
} else {
last = insn;
}
AbstractInsnNode prev = location.prev;
insn.prev = prev;
if (prev != null) {
prev.next = insn;
} else {
first = insn;
}
if (cache != null) {
int index = location.index;
cache[index] = insn;
insn.index = index;
} else {
insn.index = 0; // insn now belongs to an InsnList
}
location.index = -1; // i no longer belongs to an InsnList
location.prev = null;
location.next = null;
}
/**
* Adds the given instruction to the end of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void add(final AbstractInsnNode insn) {
++size;
if (last == null) {
first = insn;
last = insn;
} else {
last.next = insn;
insn.prev = last;
}
last = insn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Adds the given instructions to the end of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
*/
public void add(final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
if (last == null) {
first = insns.first;
last = insns.last;
} else {
AbstractInsnNode elem = insns.first;
last.next = elem;
elem.prev = last;
last = insns.last;
}
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction at the begining of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
*/
public void insert(final AbstractInsnNode insn) {
++size;
if (first == null) {
first = insn;
last = insn;
} else {
first.prev = insn;
insn.next = first;
}
first = insn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions at the begining of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
*/
public void insert(final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
if (first == null) {
first = insns.first;
last = insns.last;
} else {
AbstractInsnNode elem = insns.last;
first.prev = elem;
elem.next = first;
first = insns.first;
}
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
*/
public void insert(final AbstractInsnNode location,
final AbstractInsnNode insn) {
++size;
AbstractInsnNode next = location.next;
if (next == null) {
last = insn;
} else {
next.prev = insn;
}
location.next = insn;
insn.next = next;
insn.prev = location;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
*/
public void insert(final AbstractInsnNode location, final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode next = location.next;
if (next == null) {
last = ilast;
} else {
next.prev = ilast;
}
location.next = ifirst;
ilast.next = next;
ifirst.prev = location;
cache = null;
insns.removeAll(false);
}
/**
* Inserts the given instruction before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
*/
public void insertBefore(final AbstractInsnNode location,
final AbstractInsnNode insn) {
++size;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = insn;
} else {
prev.next = insn;
}
location.prev = insn;
insn.next = location;
insn.prev = prev;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
}
/**
* Inserts the given instructions before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
*/
public void insertBefore(final AbstractInsnNode location,
final InsnList insns) {
if (insns.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = ifirst;
} else {
prev.next = ifirst;
}
location.prev = ilast;
ilast.next = location;
ifirst.prev = prev;
cache = null;
insns.removeAll(false);
}
/**
* Removes the given instruction from this list.
*
* @param insn
* the instruction <i>of this list</i> that must be removed.
*/
public void remove(final AbstractInsnNode insn) {
--size;
AbstractInsnNode next = insn.next;
AbstractInsnNode prev = insn.prev;
if (next == null) {
if (prev == null) {
first = null;
last = null;
} else {
prev.next = null;
last = prev;
}
} else {
if (prev == null) {
first = next;
next.prev = null;
} else {
prev.next = next;
next.prev = prev;
}
}
cache = null;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
}
/**
* Removes all of the instructions of this list.
*
* @param mark
* if the instructions must be marked as no longer belonging to
* any {@link InsnList}.
*/
void removeAll(final boolean mark) {
if (mark) {
AbstractInsnNode insn = first;
while (insn != null) {
AbstractInsnNode next = insn.next;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
insn = next;
}
}
size = 0;
first = null;
last = null;
cache = null;
}
/**
* Removes all of the instructions of this list.
*/
public void clear() {
removeAll(false);
}
/**
* Reset all labels in the instruction list. This method should be called
* before reusing same instructions list between several
* <code>ClassWriter</code>s.
*/
public void resetLabels() {
AbstractInsnNode insn = first;
while (insn != null) {
if (insn instanceof LabelNode) {
((LabelNode) insn).resetLabel();
}
insn = insn.next;
}
}
// this class is not generified because it will create bridges
private final class InsnListIterator implements ListIterator {
AbstractInsnNode next;
AbstractInsnNode prev;
InsnListIterator(int index) {
if (index == size()) {
next = null;
prev = getLast();
} else {
next = get(index);
prev = next.prev;
}
}
public boolean hasNext() {
return next != null;
}
public Object next() {
if (next == null) {
throw new NoSuchElementException();
}
AbstractInsnNode result = next;
prev = result;
next = result.next;
return result;
}
public void remove() {
InsnList.this.remove(prev);
prev = prev.prev;
}
public boolean hasPrevious() {
return prev != null;
}
public Object previous() {
AbstractInsnNode result = prev;
next = result;
prev = result.prev;
return result;
}
public int nextIndex() {
if (next == null) {
return size();
}
if (cache == null) {
cache = toArray();
}
return next.index;
}
public int previousIndex() {
if (prev == null) {
return -1;
}
if (cache == null) {
cache = toArray();
}
return prev.index;
}
public void add(Object o) {
InsnList.this.insertBefore(next, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
}
public void set(Object o) {
InsnList.this.set(next.prev, (AbstractInsnNode) o);
prev = (AbstractInsnNode) o;
}
}
}

View File

@ -0,0 +1,87 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a zero operand instruction.
*
* @author Eric Bruneton
*/
public class InsnNode extends AbstractInsnNode {
/**
* Constructs a new {@link InsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
* or MONITOREXIT.
*/
public InsnNode(final int opcode) {
super(opcode);
}
@Override
public int getType() {
return INSN;
}
/**
* Makes the given visitor visit this instruction.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
mv.visitInsn(opcode);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new InsnNode(opcode);
}
}

View File

@ -0,0 +1,87 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents an instruction with a single int operand.
*
* @author Eric Bruneton
*/
public class IntInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction.
*/
public int operand;
/**
* Constructs a new {@link IntInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be BIPUSH, SIPUSH or NEWARRAY.
* @param operand
* the operand of the instruction to be constructed.
*/
public IntInsnNode(final int opcode, final int operand) {
super(opcode);
this.operand = operand;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be BIPUSH, SIPUSH
* or NEWARRAY.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return INT_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIntInsn(opcode, operand);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new IntInsnNode(opcode, operand);
}
}

View File

@ -0,0 +1,100 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an invokedynamic instruction.
*
* @author Remi Forax
*/
public class InvokeDynamicInsnNode extends AbstractInsnNode {
/**
* Invokedynamic name.
*/
public String name;
/**
* Invokedynamic descriptor.
*/
public String desc;
/**
* Bootstrap method
*/
public Handle bsm;
/**
* Bootstrap constant arguments
*/
public Object[] bsmArgs;
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name
* invokedynamic name.
* @param desc
* invokedynamic descriptor (see {@link org.objectweb.asm.Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the boostrap constant arguments.
*/
public InvokeDynamicInsnNode(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = desc;
this.bsm = bsm;
this.bsmArgs = bsmArgs;
}
@Override
public int getType() {
return INVOKE_DYNAMIC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs);
}
}

View File

@ -0,0 +1,95 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
/**
* A node that represents a jump instruction. A jump instruction is an
* instruction that may jump to another instruction.
*
* @author Eric Bruneton
*/
public class JumpInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is a label that designates
* the instruction to which this instruction may jump.
*/
public LabelNode label;
/**
* Constructs a new {@link JumpInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label
* the operand of the instruction to be constructed. This operand
* is a label that designates the instruction to which the jump
* instruction may jump.
*/
public JumpInsnNode(final int opcode, final LabelNode label) {
super(opcode);
this.label = label;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be IFEQ, IFNE,
* IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT,
* IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
* JSR, IFNULL or IFNONNULL.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
}
@Override
public int getType() {
return JUMP_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitJumpInsn(opcode, label.getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new JumpInsnNode(opcode, clone(label, labels));
}
}

View File

@ -0,0 +1,78 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
/**
* An {@link AbstractInsnNode} that encapsulates a {@link Label}.
*/
public class LabelNode extends AbstractInsnNode {
private Label label;
public LabelNode() {
super(-1);
}
public LabelNode(final Label label) {
super(-1);
this.label = label;
}
@Override
public int getType() {
return LABEL;
}
public Label getLabel() {
if (label == null) {
label = new Label();
}
return label;
}
@Override
public void accept(final MethodVisitor cv) {
cv.visitLabel(getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return labels.get(this);
}
public void resetLabel() {
label = null;
}
}

View File

@ -0,0 +1,78 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* 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.objectweb.asm.tree;
import java.util.Map;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
/**
* A node that represents an LDC instruction.
*
* @author Eric Bruneton
*/
public class LdcInsnNode extends AbstractInsnNode {
/**
* The constant to be loaded on the stack. This parameter must be a non null
* {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a
* {@link String} or a {@link org.objectweb.asm.Type}.
*/
public Object cst;
/**
* Constructs a new {@link LdcInsnNode}.
*
* @param cst
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
*/
public LdcInsnNode(final Object cst) {
super(Opcodes.LDC);
this.cst = cst;
}
@Override
public int getType() {
return LDC_INSN;
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitLdcInsn(cst);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new LdcInsnNode(cst);
}
}

Some files were not shown because too many files have changed in this diff Show More