mirror of
https://gitee.com/BDWare/common
synced 2025-01-09 17:34:16 +00:00
initial commit
This commit is contained in:
parent
016d019bc7
commit
ef46d1ac4c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
.DS_Store
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
|
59
build.gradle
Normal file
59
build.gradle
Normal 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" }
|
||||
}
|
BIN
lib/bdledger-java-sdk-20200311-SNAPSHOT.jar.bak
Normal file
BIN
lib/bdledger-java-sdk-20200311-SNAPSHOT.jar.bak
Normal file
Binary file not shown.
BIN
lib/bdledger-java-sdk-dev-200712.f6d4130c.jar.bak
Normal file
BIN
lib/bdledger-java-sdk-dev-200712.f6d4130c.jar.bak
Normal file
Binary file not shown.
BIN
lib/bdledger-java-sdk-dev-200922.1278255c.jar.bak
Normal file
BIN
lib/bdledger-java-sdk-dev-200922.1278255c.jar.bak
Normal file
Binary file not shown.
BIN
lib/bdledger-java-sdk-tb-0621.jar.bak
Normal file
BIN
lib/bdledger-java-sdk-tb-0621.jar.bak
Normal file
Binary file not shown.
BIN
lib/bdledger-java-sdk-tb-20200722.jar.bak
Normal file
BIN
lib/bdledger-java-sdk-tb-20200722.jar.bak
Normal file
Binary file not shown.
18
src/main/analysis/org/bdware/analysis/AnalysisResult.java
Normal file
18
src/main/analysis/org/bdware/analysis/AnalysisResult.java
Normal 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();
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package org.bdware.analysis;
|
||||
|
||||
public interface AnalysisTarget {
|
||||
public boolean inList();
|
||||
|
||||
public void setInList(boolean b);
|
||||
}
|
49
src/main/analysis/org/bdware/analysis/BasicBlock.java
Normal file
49
src/main/analysis/org/bdware/analysis/BasicBlock.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
581
src/main/analysis/org/bdware/analysis/CFGraph.java
Normal file
581
src/main/analysis/org/bdware/analysis/CFGraph.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/main/analysis/org/bdware/analysis/CFType.java
Normal file
10
src/main/analysis/org/bdware/analysis/CFType.java
Normal 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
|
||||
}
|
138
src/main/analysis/org/bdware/analysis/FrontCF.java
Normal file
138
src/main/analysis/org/bdware/analysis/FrontCF.java
Normal 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);
|
||||
|
||||
}
|
||||
}
|
297
src/main/analysis/org/bdware/analysis/InsnPrinter.java
Normal file
297
src/main/analysis/org/bdware/analysis/InsnPrinter.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
256
src/main/analysis/org/bdware/analysis/OpInfo.java
Normal file
256
src/main/analysis/org/bdware/analysis/OpInfo.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
31
src/main/analysis/org/bdware/analysis/gas/BFS.java
Normal file
31
src/main/analysis/org/bdware/analysis/gas/BFS.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1 @@
|
||||
package org.bdware.analysis.gas;
|
226
src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java
Normal file
226
src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
25
src/main/analysis/org/bdware/analysis/gas/DFS.java
Normal file
25
src/main/analysis/org/bdware/analysis/gas/DFS.java
Normal 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];
|
||||
}
|
||||
}
|
96
src/main/analysis/org/bdware/analysis/gas/Evaluates.java
Normal file
96
src/main/analysis/org/bdware/analysis/gas/Evaluates.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
51
src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java
Normal file
51
src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java
Normal 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();
|
||||
|
||||
}
|
||||
}
|
450
src/main/analysis/org/bdware/analysis/gas/PPCount.java
Normal file
450
src/main/analysis/org/bdware/analysis/gas/PPCount.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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];
|
||||
}
|
||||
|
||||
}
|
247
src/main/analysis/org/bdware/analysis/taint/HeapObject.java
Normal file
247
src/main/analysis/org/bdware/analysis/taint/HeapObject.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
70
src/main/analysis/org/bdware/analysis/taint/TaintBB.java
Normal file
70
src/main/analysis/org/bdware/analysis/taint/TaintBB.java
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
68
src/main/analysis/org/bdware/analysis/taint/TaintBits.java
Normal file
68
src/main/analysis/org/bdware/analysis/taint/TaintBits.java
Normal 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;
|
||||
}
|
||||
}
|
84
src/main/analysis/org/bdware/analysis/taint/TaintCFG.java
Normal file
84
src/main/analysis/org/bdware/analysis/taint/TaintCFG.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.bdware.analysis.taint;
|
||||
|
||||
public class TaintConfig {
|
||||
public static boolean isDebug = false;
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
190
src/main/analysis/org/bdware/analysis/taint/TaintResult.java
Normal file
190
src/main/analysis/org/bdware/analysis/taint/TaintResult.java
Normal 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;
|
||||
}
|
||||
}
|
54
src/main/analysis/org/bdware/analysis/taint/TaintValue.java
Normal file
54
src/main/analysis/org/bdware/analysis/taint/TaintValue.java
Normal 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;
|
||||
}
|
||||
}
|
169
src/main/asm/org/objectweb/asm/AnnotationVisitor.java
Normal file
169
src/main/asm/org/objectweb/asm/AnnotationVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
378
src/main/asm/org/objectweb/asm/AnnotationWriter.java
Normal file
378
src/main/asm/org/objectweb/asm/AnnotationWriter.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
255
src/main/asm/org/objectweb/asm/Attribute.java
Normal file
255
src/main/asm/org/objectweb/asm/Attribute.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
312
src/main/asm/org/objectweb/asm/ByteVector.java
Normal file
312
src/main/asm/org/objectweb/asm/ByteVector.java
Normal 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;
|
||||
}
|
||||
}
|
2518
src/main/asm/org/objectweb/asm/ClassReader.java
Normal file
2518
src/main/asm/org/objectweb/asm/ClassReader.java
Normal file
File diff suppressed because it is too large
Load Diff
286
src/main/asm/org/objectweb/asm/ClassVisitor.java
Normal file
286
src/main/asm/org/objectweb/asm/ClassVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
1706
src/main/asm/org/objectweb/asm/ClassWriter.java
Normal file
1706
src/main/asm/org/objectweb/asm/ClassWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
110
src/main/asm/org/objectweb/asm/Context.java
Normal file
110
src/main/asm/org/objectweb/asm/Context.java
Normal 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;
|
||||
}
|
75
src/main/asm/org/objectweb/asm/Edge.java
Normal file
75
src/main/asm/org/objectweb/asm/Edge.java
Normal 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;
|
||||
}
|
121
src/main/asm/org/objectweb/asm/FieldVisitor.java
Normal file
121
src/main/asm/org/objectweb/asm/FieldVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
273
src/main/asm/org/objectweb/asm/FieldWriter.java
Normal file
273
src/main/asm/org/objectweb/asm/FieldWriter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
1453
src/main/asm/org/objectweb/asm/Frame.java
Normal file
1453
src/main/asm/org/objectweb/asm/Frame.java
Normal file
File diff suppressed because it is too large
Load Diff
170
src/main/asm/org/objectweb/asm/Handle.java
Normal file
170
src/main/asm/org/objectweb/asm/Handle.java
Normal 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 + ')';
|
||||
}
|
||||
}
|
121
src/main/asm/org/objectweb/asm/Handler.java
Normal file
121
src/main/asm/org/objectweb/asm/Handler.java
Normal 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;
|
||||
}
|
||||
}
|
311
src/main/asm/org/objectweb/asm/Item.java
Normal file
311
src/main/asm/org/objectweb/asm/Item.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
560
src/main/asm/org/objectweb/asm/Label.java
Normal file
560
src/main/asm/org/objectweb/asm/Label.java
Normal 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);
|
||||
}
|
||||
}
|
662
src/main/asm/org/objectweb/asm/MethodVisitor.java
Normal file
662
src/main/asm/org/objectweb/asm/MethodVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
2685
src/main/asm/org/objectweb/asm/MethodWriter.java
Normal file
2685
src/main/asm/org/objectweb/asm/MethodWriter.java
Normal file
File diff suppressed because it is too large
Load Diff
360
src/main/asm/org/objectweb/asm/Opcodes.java
Normal file
360
src/main/asm/org/objectweb/asm/Opcodes.java
Normal 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; // -
|
||||
}
|
895
src/main/asm/org/objectweb/asm/Type.java
Normal file
895
src/main/asm/org/objectweb/asm/Type.java
Normal 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();
|
||||
}
|
||||
}
|
48
src/main/asm/org/objectweb/asm/attrs/package.html
Normal file
48
src/main/asm/org/objectweb/asm/attrs/package.html
Normal 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>
|
625
src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java
Normal file
625
src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java
Normal 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
|
||||
}
|
920
src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java
Normal file
920
src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java
Normal 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;
|
||||
}
|
||||
}
|
217
src/main/asm/org/objectweb/asm/commons/CodeSizeEvaluator.java
Normal file
217
src/main/asm/org/objectweb/asm/commons/CodeSizeEvaluator.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
1623
src/main/asm/org/objectweb/asm/commons/GeneratorAdapter.java
Normal file
1623
src/main/asm/org/objectweb/asm/commons/GeneratorAdapter.java
Normal file
File diff suppressed because it is too large
Load Diff
1090
src/main/asm/org/objectweb/asm/commons/InstructionAdapter.java
Normal file
1090
src/main/asm/org/objectweb/asm/commons/InstructionAdapter.java
Normal file
File diff suppressed because it is too large
Load Diff
747
src/main/asm/org/objectweb/asm/commons/JSRInlinerAdapter.java
Normal file
747
src/main/asm/org/objectweb/asm/commons/JSRInlinerAdapter.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
361
src/main/asm/org/objectweb/asm/commons/LocalVariablesSorter.java
Normal file
361
src/main/asm/org/objectweb/asm/commons/LocalVariablesSorter.java
Normal 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;
|
||||
}
|
||||
}
|
282
src/main/asm/org/objectweb/asm/commons/Method.java
Normal file
282
src/main/asm/org/objectweb/asm/commons/Method.java
Normal 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();
|
||||
}
|
||||
}
|
223
src/main/asm/org/objectweb/asm/commons/Remapper.java
Normal file
223
src/main/asm/org/objectweb/asm/commons/Remapper.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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, <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.
|
||||
* 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.
|
||||
* 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] >>> 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;
|
||||
* </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();
|
||||
}
|
||||
}
|
||||
}
|
69
src/main/asm/org/objectweb/asm/commons/SimpleRemapper.java
Normal file
69
src/main/asm/org/objectweb/asm/commons/SimpleRemapper.java
Normal 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);
|
||||
}
|
||||
}
|
96
src/main/asm/org/objectweb/asm/commons/StaticInitMerger.java
Normal file
96
src/main/asm/org/objectweb/asm/commons/StaticInitMerger.java
Normal 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
48
src/main/asm/org/objectweb/asm/commons/package.html
Normal file
48
src/main/asm/org/objectweb/asm/commons/package.html
Normal 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>
|
87
src/main/asm/org/objectweb/asm/package.html
Normal file
87
src/main/asm/org/objectweb/asm/package.html
Normal 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>
|
228
src/main/asm/org/objectweb/asm/signature/SignatureReader.java
Normal file
228
src/main/asm/org/objectweb/asm/signature/SignatureReader.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
235
src/main/asm/org/objectweb/asm/signature/SignatureVisitor.java
Normal file
235
src/main/asm/org/objectweb/asm/signature/SignatureVisitor.java
Normal 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() {
|
||||
}
|
||||
}
|
227
src/main/asm/org/objectweb/asm/signature/SignatureWriter.java
Normal file
227
src/main/asm/org/objectweb/asm/signature/SignatureWriter.java
Normal 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;
|
||||
}
|
||||
}
|
36
src/main/asm/org/objectweb/asm/signature/package.html
Normal file
36
src/main/asm/org/objectweb/asm/signature/package.html
Normal 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>
|
248
src/main/asm/org/objectweb/asm/tree/AbstractInsnNode.java
Normal file
248
src/main/asm/org/objectweb/asm/tree/AbstractInsnNode.java
Normal 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;
|
||||
}
|
||||
}
|
281
src/main/asm/org/objectweb/asm/tree/AnnotationNode.java
Normal file
281
src/main/asm/org/objectweb/asm/tree/AnnotationNode.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
345
src/main/asm/org/objectweb/asm/tree/ClassNode.java
Normal file
345
src/main/asm/org/objectweb/asm/tree/ClassNode.java
Normal 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();
|
||||
}
|
||||
}
|
108
src/main/asm/org/objectweb/asm/tree/FieldInsnNode.java
Normal file
108
src/main/asm/org/objectweb/asm/tree/FieldInsnNode.java
Normal 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);
|
||||
}
|
||||
}
|
243
src/main/asm/org/objectweb/asm/tree/FieldNode.java
Normal file
243
src/main/asm/org/objectweb/asm/tree/FieldNode.java
Normal 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();
|
||||
}
|
||||
}
|
210
src/main/asm/org/objectweb/asm/tree/FrameNode.java
Normal file
210
src/main/asm/org/objectweb/asm/tree/FrameNode.java
Normal 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;
|
||||
}
|
||||
}
|
82
src/main/asm/org/objectweb/asm/tree/IincInsnNode.java
Normal file
82
src/main/asm/org/objectweb/asm/tree/IincInsnNode.java
Normal 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);
|
||||
}
|
||||
}
|
101
src/main/asm/org/objectweb/asm/tree/InnerClassNode.java
Normal file
101
src/main/asm/org/objectweb/asm/tree/InnerClassNode.java
Normal 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);
|
||||
}
|
||||
}
|
600
src/main/asm/org/objectweb/asm/tree/InsnList.java
Normal file
600
src/main/asm/org/objectweb/asm/tree/InsnList.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
87
src/main/asm/org/objectweb/asm/tree/InsnNode.java
Normal file
87
src/main/asm/org/objectweb/asm/tree/InsnNode.java
Normal 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);
|
||||
}
|
||||
}
|
87
src/main/asm/org/objectweb/asm/tree/IntInsnNode.java
Normal file
87
src/main/asm/org/objectweb/asm/tree/IntInsnNode.java
Normal 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);
|
||||
}
|
||||
}
|
100
src/main/asm/org/objectweb/asm/tree/InvokeDynamicInsnNode.java
Normal file
100
src/main/asm/org/objectweb/asm/tree/InvokeDynamicInsnNode.java
Normal 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);
|
||||
}
|
||||
}
|
95
src/main/asm/org/objectweb/asm/tree/JumpInsnNode.java
Normal file
95
src/main/asm/org/objectweb/asm/tree/JumpInsnNode.java
Normal 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));
|
||||
}
|
||||
}
|
78
src/main/asm/org/objectweb/asm/tree/LabelNode.java
Normal file
78
src/main/asm/org/objectweb/asm/tree/LabelNode.java
Normal 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;
|
||||
}
|
||||
}
|
78
src/main/asm/org/objectweb/asm/tree/LdcInsnNode.java
Normal file
78
src/main/asm/org/objectweb/asm/tree/LdcInsnNode.java
Normal 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
Loading…
Reference in New Issue
Block a user