mirror of
				https://gitee.com/BDWare/common
				synced 2025-10-31 12:52: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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user