From 2f4253929316277267db95d51136cf1454a147d6 Mon Sep 17 00:00:00 2001 From: "Frank.R.Wu" Date: Thu, 15 Jun 2023 11:08:09 +0800 Subject: [PATCH] build: config spotless plugin and reformat code --- build.gradle | 19 +- shardingsphere_eclipse_formatter.xml | 431 - .../org/bdware/analysis/AnalysisResult.java | 15 +- .../org/bdware/analysis/AnalysisTarget.java | 4 +- .../org/bdware/analysis/BasicBlock.java | 56 +- .../bdware/analysis/BreadthFirstSearch.java | 82 +- .../analysis/org/bdware/analysis/CFGraph.java | 264 +- .../analysis/org/bdware/analysis/CFType.java | 12 +- .../analysis/org/bdware/analysis/FrontCF.java | 222 +- .../org/bdware/analysis/InsnPrinter.java | 495 +- .../analysis/org/bdware/analysis/OpInfo.java | 487 +- .../FieldSensitiveDynamicTaintAnalysis.java | 13 +- .../dynamic/NaiveDynamicTaintAnalysis.java | 18 +- .../bdware/analysis/dynamic/ProgramPoint.java | 24 +- .../example/FieldSensitiveTaintAnalysis.java | 22 +- .../example/MultiSourceTaintAnalysis.java | 75 +- .../analysis/example/NaiveTaintAnalysis.java | 7 +- .../analysis/org/bdware/analysis/gas/BFS.java | 47 +- .../org/bdware/analysis/gas/CostDetail.java | 2 +- .../analysis/gas/CountProgramPoint.java | 388 +- .../analysis/org/bdware/analysis/gas/DFS.java | 3 +- .../org/bdware/analysis/gas/Evaluates.java | 22 +- .../org/bdware/analysis/gas/FeeSchedule.java | 83 +- .../org/bdware/analysis/gas/PPCount.java | 136 +- .../bdware/analysis/taint/DirectGraphDFS.java | 40 +- .../org/bdware/analysis/taint/HeapObject.java | 421 +- .../org/bdware/analysis/taint/TaintBB.java | 102 +- .../org/bdware/analysis/taint/TaintBits.java | 110 +- .../org/bdware/analysis/taint/TaintCFG.java | 123 +- .../bdware/analysis/taint/TaintConfig.java | 2 +- .../analysis/taint/TaintInterpreter.java | 302 +- .../bdware/analysis/taint/TaintResult.java | 330 +- .../org/bdware/analysis/taint/TaintValue.java | 82 +- .../org/objectweb/asm/AnnotationVisitor.java | 131 +- .../org/objectweb/asm/AnnotationWriter.java | 605 +- src/main/asm/org/objectweb/asm/Attribute.java | 214 +- .../asm/org/objectweb/asm/ByteVector.java | 124 +- .../asm/org/objectweb/asm/ClassReader.java | 4513 ++--- .../asm/org/objectweb/asm/ClassVisitor.java | 262 +- .../asm/org/objectweb/asm/ClassWriter.java | 717 +- src/main/asm/org/objectweb/asm/Context.java | 48 +- src/main/asm/org/objectweb/asm/Edge.java | 69 +- .../asm/org/objectweb/asm/FieldVisitor.java | 86 +- .../asm/org/objectweb/asm/FieldWriter.java | 85 +- src/main/asm/org/objectweb/asm/Frame.java | 1220 +- src/main/asm/org/objectweb/asm/Handle.java | 100 +- src/main/asm/org/objectweb/asm/Handler.java | 62 +- src/main/asm/org/objectweb/asm/Item.java | 255 +- src/main/asm/org/objectweb/asm/Label.java | 348 +- .../asm/org/objectweb/asm/MethodVisitor.java | 558 +- .../asm/org/objectweb/asm/MethodWriter.java | 1364 +- src/main/asm/org/objectweb/asm/Opcodes.java | 72 +- src/main/asm/org/objectweb/asm/Type.java | 455 +- .../objectweb/asm/commons/AdviceAdapter.java | 627 +- .../asm/commons/AnalyzerAdapter.java | 1002 +- .../asm/commons/CodeSizeEvaluator.java | 60 +- .../asm/commons/GeneratorAdapter.java | 908 +- .../asm/commons/InstructionAdapter.java | 1104 +- .../asm/commons/JSRInlinerAdapter.java | 369 +- .../asm/commons/LocalVariablesSorter.java | 245 +- .../asm/org/objectweb/asm/commons/Method.java | 131 +- .../org/objectweb/asm/commons/Remapper.java | 126 +- .../commons/RemappingAnnotationAdapter.java | 55 +- .../asm/commons/RemappingClassAdapter.java | 90 +- .../asm/commons/RemappingFieldAdapter.java | 48 +- .../asm/commons/RemappingMethodAdapter.java | 97 +- .../commons/RemappingSignatureAdapter.java | 53 +- .../asm/commons/SerialVersionUIDAdder.java | 221 +- .../objectweb/asm/commons/SimpleRemapper.java | 42 +- .../asm/commons/StaticInitMerger.java | 52 +- .../asm/commons/TableSwitchGenerator.java | 48 +- .../asm/commons/TryCatchBlockSorter.java | 69 +- .../asm/signature/SignatureReader.java | 235 +- .../asm/signature/SignatureVisitor.java | 128 +- .../asm/signature/SignatureWriter.java | 51 +- .../objectweb/asm/tree/AbstractInsnNode.java | 104 +- .../objectweb/asm/tree/AnnotationNode.java | 431 +- .../asm/org/objectweb/asm/tree/ClassNode.java | 150 +- .../org/objectweb/asm/tree/FieldInsnNode.java | 72 +- .../asm/org/objectweb/asm/tree/FieldNode.java | 150 +- .../asm/org/objectweb/asm/tree/FrameNode.java | 185 +- .../org/objectweb/asm/tree/IincInsnNode.java | 50 +- .../objectweb/asm/tree/InnerClassNode.java | 86 +- .../asm/org/objectweb/asm/tree/InsnList.java | 187 +- .../asm/org/objectweb/asm/tree/InsnNode.java | 72 +- .../org/objectweb/asm/tree/IntInsnNode.java | 54 +- .../asm/tree/InvokeDynamicInsnNode.java | 60 +- .../org/objectweb/asm/tree/JumpInsnNode.java | 72 +- .../asm/org/objectweb/asm/tree/LabelNode.java | 44 +- .../org/objectweb/asm/tree/LdcInsnNode.java | 57 +- .../objectweb/asm/tree/LineNumberNode.java | 57 +- .../objectweb/asm/tree/LocalVariableNode.java | 81 +- .../asm/tree/LookupSwitchInsnNode.java | 66 +- .../objectweb/asm/tree/MethodInsnNode.java | 75 +- .../org/objectweb/asm/tree/MethodNode.java | 264 +- .../asm/tree/MultiANewArrayInsnNode.java | 50 +- .../asm/tree/TableSwitchInsnNode.java | 68 +- .../objectweb/asm/tree/TryCatchBlockNode.java | 68 +- .../org/objectweb/asm/tree/TypeInsnNode.java | 63 +- .../org/objectweb/asm/tree/VarInsnNode.java | 70 +- .../objectweb/asm/tree/analysis/Analyzer.java | 249 +- .../asm/tree/analysis/AnalyzerException.java | 50 +- .../asm/tree/analysis/BasicInterpreter.java | 529 +- .../asm/tree/analysis/BasicValue.java | 60 +- .../asm/tree/analysis/BasicVerifier.java | 594 +- .../objectweb/asm/tree/analysis/Frame.java | 1305 +- .../asm/tree/analysis/Interpreter.java | 246 +- .../asm/tree/analysis/SimpleVerifier.java | 162 +- .../objectweb/asm/tree/analysis/SmallSet.java | 45 +- .../asm/tree/analysis/SourceInterpreter.java | 169 +- .../asm/tree/analysis/SourceValue.java | 54 +- .../asm/tree/analysis/Subroutine.java | 50 +- .../objectweb/asm/tree/analysis/Value.java | 42 +- .../org/objectweb/asm/util/ASMifiable.java | 56 +- .../asm/org/objectweb/asm/util/ASMifier.java | 249 +- .../asm/util/CheckAnnotationAdapter.java | 73 +- .../objectweb/asm/util/CheckClassAdapter.java | 326 +- .../objectweb/asm/util/CheckFieldAdapter.java | 64 +- .../asm/util/CheckMethodAdapter.java | 622 +- .../asm/util/CheckSignatureAdapter.java | 95 +- .../asm/org/objectweb/asm/util/Printer.java | 247 +- .../org/objectweb/asm/util/Textifiable.java | 56 +- .../asm/org/objectweb/asm/util/Textifier.java | 245 +- .../asm/util/TraceAnnotationVisitor.java | 57 +- .../objectweb/asm/util/TraceClassVisitor.java | 111 +- .../objectweb/asm/util/TraceFieldVisitor.java | 51 +- .../asm/util/TraceMethodVisitor.java | 90 +- .../asm/util/TraceSignatureVisitor.java | 61 +- .../objectweb/asm/xml/ASMContentHandler.java | 237 +- .../asm/org/objectweb/asm/xml/Processor.java | 304 +- .../asm/org/objectweb/asm/xml/SAXAdapter.java | 41 +- .../asm/xml/SAXAnnotationAdapter.java | 82 +- .../objectweb/asm/xml/SAXClassAdapter.java | 90 +- .../org/objectweb/asm/xml/SAXCodeAdapter.java | 125 +- .../objectweb/asm/xml/SAXFieldAdapter.java | 41 +- .../org/bdware/sc/ComponedContractResult.java | 40 +- src/main/base/org/bdware/sc/ContractPort.java | 6 +- .../base/org/bdware/sc/ContractPrinter.java | 2 +- .../base/org/bdware/sc/ContractResult.java | 6 +- src/main/base/org/bdware/sc/JSEngine.java | 6 +- src/main/base/org/bdware/sc/Jedion.java | 74 +- .../org/bdware/sc/codec/DelimiterCodec.java | 4 +- .../sc/codec/LengthFieldBasedFrameCodec.java | 10 +- .../codec/LengthFieldBasedFrameEncoder.java | 2 +- .../bdware/sc/compiler/PermissionStub.java | 2 +- .../sc/compiler/PermissionStubGenerator.java | 11 +- .../bdware/sc/compiler/YJSErrorListener.java | 19 +- .../base/org/bdware/sc/conn/ByteUtil.java | 10 +- .../base/org/bdware/sc/conn/Description.java | 2 +- .../base/org/bdware/sc/conn/EventHandler.java | 2 +- .../base/org/bdware/sc/conn/MsgHandler.java | 7 +- .../org/bdware/sc/conn/ResultCallback.java | 7 +- .../org/bdware/sc/conn/ServiceServer.java | 60 +- .../base/org/bdware/sc/conn/SocketGet.java | 114 +- .../base/org/bdware/sc/conn/SyncResult.java | 27 +- src/main/base/org/bdware/sc/encrypt/AES.java | 38 +- .../org/bdware/sc/encrypt/HardwareInfo.java | 21 +- src/main/base/org/bdware/sc/encrypt/RSA.java | 72 +- src/main/base/org/bdware/sc/event/REvent.java | 11 +- .../base/org/bdware/sc/gen/PYGenerator.java | 180 +- .../base/org/bdware/sc/get/GetMessage.java | 5 +- .../base/org/bdware/sc/node/ContractNode.java | 33 +- .../base/org/bdware/sc/node/FunctionNode.java | 4 +- .../org/bdware/sc/node/InterfaceNode.java | 2 +- .../base/org/bdware/sc/node/LogLocation.java | 2 +- src/main/base/org/bdware/sc/node/LogType.java | 2 +- .../base/org/bdware/sc/node/MockConfig.java | 7 +- .../base/org/bdware/sc/node/Permission.java | 17 +- src/main/base/org/bdware/sc/node/YjsType.java | 5 +- src/main/base/org/bdware/sc/py/PYEntry.java | 26 +- src/main/base/org/bdware/sc/py/PYLoader.java | 3 +- .../org/bdware/sc/py/utils/HttpClient.java | 10 +- .../base/org/bdware/sc/redo/TransRecord.java | 91 +- .../org/bdware/sc/units/RequestCache.java | 8 +- .../base/org/bdware/sc/util/FileUtil.java | 2 +- .../base/org/bdware/sc/util/HashUtil.java | 10 +- src/main/base/org/bdware/sc/util/LRUList.java | 3 +- .../base/org/bdware/sc/util/VersionUtil.java | 5 +- .../sc/visitor/ContractDependencyVisitor.java | 8 +- .../org/bdware/sc/visitor/ContractReader.java | 26 +- .../sc/visitor/FunctionDependencyVisitor.java | 6 +- .../org/bdware/sc/visitor/FunctionReader.java | 23 +- .../bdware/sc/visitor/InterfaceReader.java | 4 +- .../entry/org/bdware/sc/ContractStatus.java | 4 +- src/main/entry/org/bdware/sc/SCAPI.java | 29 +- src/main/entry/org/bdware/sc/YJSPacker.java | 32 +- .../org/bdware/sc/bean/ContractDesp.java | 2 +- .../org/bdware/sc/bean/ContractExecType.java | 9 +- .../org/bdware/sc/bean/ContractRequest.java | 9 +- .../org/bdware/sc/bean/ContractStartInfo.java | 10 +- .../org/bdware/sc/bean/DefaultJoinRule.java | 4 +- .../org/bdware/sc/bean/DoipOperationInfo.java | 10 +- .../org/bdware/sc/bean/FunctionDesp.java | 3 +- .../org/bdware/sc/bean/ProjectConfig.java | 5 +- .../org/bdware/sc/bean/SM2Verifiable.java | 15 +- src/main/entry/org/bdware/sc/db/CMTables.java | 18 +- .../entry/org/bdware/sc/db/FIFOCache.java | 7 +- .../org/bdware/sc/db/KeyValueRocksDBUtil.java | 34 +- .../bdware/sc/db/MultiIndexTimeDBUtil.java | 9 +- .../sc/db/MultiIndexTimeRocksDBUtil.java | 19 +- .../entry/org/bdware/sc/db/TimeDBUtil.java | 26 +- .../org/bdware/sc/db/TimeRocksDBUtil.java | 29 +- .../org/bdware/sc/http/HttpPostForm.java | 6 +- .../entry/org/bdware/sc/http/HttpUtil.java | 29 +- .../sc/index/LenVarTimeSerialIndex.java | 13 +- .../org/bdware/sc/index/TimeSerialIndex.java | 27 +- .../org/bdware/sc/packer/AvatarHelper.java | 10 +- .../entry/org/bdware/sc/packer/JarPacker.java | 9 +- .../bdware/sc/parser/JavaScriptBaseLexer.java | 23 +- .../sc/parser/JavaScriptBaseParser.java | 27 +- .../org/bdware/sc/parser/JavaScriptLexer.java | 1570 +- .../gen/org/bdware/sc/parser/YJSParser.java | 16776 +++++++++------- .../sc/parser/YJSParserBaseListener.java | 3691 ++-- .../sc/parser/YJSParserBaseVisitor.java | 2275 ++- .../bdware/sc/parser/YJSParserListener.java | 2903 +-- .../bdware/sc/parser/YJSParserVisitor.java | 1684 +- .../bdware/sc/commParser/BDLedger/Block.java | 58 +- .../sc/commParser/BDLedger/Transaction.java | 4 +- .../bdware/sc/commParser/LocalLogAdapter.java | 8 +- .../bdware/sc/commParser/Transaction_bak.java | 5 +- .../sc/commParser/XuperChainAdapter.java | 26 +- .../org/bdware/sc/common/Transaction.java | 6 +- .../MultiIndextTimeRocksDBUtilTest.java | 3 +- ...ieldSensitiveDynamicTaintAnalysisTest.java | 9 +- .../analysis/dynamic/test/TracedFileTest.java | 2 +- .../test/FieldSensitiveTaintAnalysisTest.java | 3 +- .../org/bdware/analysis/test/CFGraphTest.java | 3 +- .../java/org/bdware/sc/AvatarHelperTest.java | 4 +- .../java/org/bdware/sc/LedgerUtilTest.java | 24 +- src/test/java/org/bdware/sc/SockGetTest.java | 6 +- .../bdware/sc/bean/ContractRequestTest.java | 6 +- .../bdware/sc/bean/test/EnumDecodeTest2.java | 2 +- .../bdware/sc/boundary/utils/SM2UtilTest.java | 108 +- .../sc/db/MultiIndexTimeDBUtilTest.java | 9 +- .../sc/encrypt/test/HardwareInfoTest.java | 4 +- .../org/bdware/sc/units/ByteArrayTest.java | 3 +- .../java/org/bdware/sc/util/UtilTest.java | 5 +- .../org/bdware/sc/util/versionUtiltest.java | 8 +- 238 files changed, 31053 insertions(+), 30607 deletions(-) delete mode 100644 shardingsphere_eclipse_formatter.xml diff --git a/build.gradle b/build.gradle index e8af3d5..de37eb4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,3 @@ -buildscript { - dependencies { - classpath "com.diffplug.spotless:spotless-plugin-gradle:4.5.1" - } -} - plugins { id 'java' id 'java-library' @@ -12,18 +6,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '4.0.2' } -apply plugin: "com.diffplug.gradle.spotless" - -spotless { - java { - removeUnusedImports() - eclipse().configFile('shardingsphere_eclipse_formatter.xml') - target fileTree('.') { - include '**/*.java' - } - } -} -//tasks.compileJava.dependsOn(spotlessJavaApply) +apply from: '../spotless.gradle' shadowJar { classifier = "jar" diff --git a/shardingsphere_eclipse_formatter.xml b/shardingsphere_eclipse_formatter.xml deleted file mode 100644 index 675ae1f..0000000 --- a/shardingsphere_eclipse_formatter.xml +++ /dev/null @@ -1,431 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/analysis/org/bdware/analysis/AnalysisResult.java b/src/main/analysis/org/bdware/analysis/AnalysisResult.java index bdbc01a..6b2c980 100644 --- a/src/main/analysis/org/bdware/analysis/AnalysisResult.java +++ b/src/main/analysis/org/bdware/analysis/AnalysisResult.java @@ -3,16 +3,15 @@ package org.bdware.analysis; import org.objectweb.asm.tree.AbstractInsnNode; public abstract class AnalysisResult { - public AnalysisResult() { - } + public AnalysisResult() {} - public abstract AnalysisResult merge(AbstractInsnNode insn); + public abstract AnalysisResult merge(AbstractInsnNode insn); - public abstract void printResult(); + public abstract void printResult(); - public abstract boolean covers(AnalysisResult result); + public abstract boolean covers(AnalysisResult result); - public abstract void mergeResult(AnalysisResult r); + public abstract void mergeResult(AnalysisResult r); - public abstract AnalysisResult clone(); -} \ No newline at end of file + public abstract AnalysisResult clone(); +} diff --git a/src/main/analysis/org/bdware/analysis/AnalysisTarget.java b/src/main/analysis/org/bdware/analysis/AnalysisTarget.java index 0a8465d..7bf3f7b 100644 --- a/src/main/analysis/org/bdware/analysis/AnalysisTarget.java +++ b/src/main/analysis/org/bdware/analysis/AnalysisTarget.java @@ -1,7 +1,7 @@ package org.bdware.analysis; public interface AnalysisTarget { - public boolean inList(); + public boolean inList(); - public void setInList(boolean b); + public void setInList(boolean b); } diff --git a/src/main/analysis/org/bdware/analysis/BasicBlock.java b/src/main/analysis/org/bdware/analysis/BasicBlock.java index 4d31245..788385a 100644 --- a/src/main/analysis/org/bdware/analysis/BasicBlock.java +++ b/src/main/analysis/org/bdware/analysis/BasicBlock.java @@ -6,44 +6,44 @@ import java.util.List; import org.objectweb.asm.tree.AbstractInsnNode; public class BasicBlock { - public List list; - public int blockID; - public int lineNum = -1; + public List list; + public int blockID; + public int lineNum = -1; public int insnCount; public BasicBlock(int id) { - list = new ArrayList<>(); - blockID = id; - } + list = new ArrayList<>(); + blockID = id; + } - public void add(AbstractInsnNode insn) { - list.add(insn); - } + public void add(AbstractInsnNode insn) { + list.add(insn); + } - public int size() { + public int size() { - return list.size(); - } + return list.size(); + } - public List getInsn() { - return list; - } + public List getInsn() { + return list; + } - boolean inList = false; + boolean inList = false; - public AbstractInsnNode lastInsn() { - return list.get(list.size() - 1); - } + public AbstractInsnNode lastInsn() { + return list.get(list.size() - 1); + } - public void setLineNum(int line) { - lineNum = line; - } + public void setLineNum(int line) { + lineNum = line; + } - public boolean inList() { - return inList; - } + public boolean inList() { + return inList; + } - public void setInList(boolean b) { - inList = b; - } + public void setInList(boolean b) { + inList = b; + } } diff --git a/src/main/analysis/org/bdware/analysis/BreadthFirstSearch.java b/src/main/analysis/org/bdware/analysis/BreadthFirstSearch.java index 20a040d..db5374b 100644 --- a/src/main/analysis/org/bdware/analysis/BreadthFirstSearch.java +++ b/src/main/analysis/org/bdware/analysis/BreadthFirstSearch.java @@ -6,53 +6,53 @@ import java.util.List; import java.util.Map; public abstract class BreadthFirstSearch { - public Map results; - protected List toAnalysis; + public Map results; + protected List toAnalysis; - public abstract R execute(T t); + public abstract R execute(T t); - public abstract Collection getSuc(T t); + public abstract Collection getSuc(T t); - public BreadthFirstSearch() { - results = new HashMap(); - } + public BreadthFirstSearch() { + results = new HashMap(); + } - public Map 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); + public Map 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 sucs = getSuc(current); - for (T next : sucs) { + if (preResult == null || !preResult.covers(sucResult)) { + AnalysisResult cloneResult = sucResult.clone(); + if (cloneResult != null) { + results.put(current, cloneResult); + } + Collection 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; - } + 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 int getListLength() { + return toAnalysis.size(); + } - public void setToAnalysis(List l) { - toAnalysis = l; - } + public void setToAnalysis(List l) { + toAnalysis = l; + } } diff --git a/src/main/analysis/org/bdware/analysis/CFGraph.java b/src/main/analysis/org/bdware/analysis/CFGraph.java index 5648ff3..6f8a5b9 100644 --- a/src/main/analysis/org/bdware/analysis/CFGraph.java +++ b/src/main/analysis/org/bdware/analysis/CFGraph.java @@ -19,7 +19,7 @@ public abstract class CFGraph { // type2(canThrow) and catchLabels // type3 and target labels // type4 and catchLabels -// private List tryCacheList; + // private List tryCacheList; // Pass1: build basic blocks // create a new block when: // 1.starts with Label(can jump) @@ -110,8 +110,8 @@ public abstract class CFGraph { 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("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) { @@ -171,21 +171,17 @@ public abstract class CFGraph { /** * 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. + * @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); @@ -199,77 +195,75 @@ public abstract class CFGraph { /** * 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 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.
- * When opcode is BIPUSH, operand value should be between - * Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between - * Short.MIN_VALUE and Short.MAX_VALUE.
- * 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}. + * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and + * Byte.MAX_VALUE.
+ * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and + * Short.MAX_VALUE.
+ * 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. + * 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. + * @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. + * 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}). + * @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. + * 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}). + * @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. + * 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}). + * @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); @@ -288,16 +282,16 @@ public abstract class CFGraph { /** * 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. + * @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) { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { // TODO add edges to try catch blocks! currBlock.add(currInsn); @@ -309,16 +303,14 @@ public abstract class CFGraph { } /** - * Visits a jump instruction. A jump instruction is an instruction that may jump - * to another instruction. + * 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. + * @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); @@ -331,8 +323,7 @@ public abstract class CFGraph { } /** - * Visits a label. A label designates the instruction that will be visited just - * after it. + * Visits a label. A label designates the instruction that will be visited just after it. * * @param label a {@link Label Label} object. */ @@ -349,47 +340,45 @@ public abstract class CFGraph { } /** - * 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: + * 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: * *
          * 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
-         *    }
+         *     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
+         *     // throw an exception
          * }
          * 
* - * @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 .class 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. + * @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 .class + * 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); @@ -398,7 +387,7 @@ public abstract class CFGraph { /** * Visits an IINC instruction. * - * @param var index of the local variable to be incremented. + * @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) { @@ -411,11 +400,11 @@ public abstract class CFGraph { /** * 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. labels[i] is the - * beginning of the handler block for the min + i key. + * @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. labels[i] is the beginning of + * the handler block for the min + i key. */ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { currBlock.add(currInsn); @@ -426,10 +415,10 @@ public abstract class CFGraph { /** * 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. labels[i] is the - * beginning of the handler block for the keys[i] key. + * @param dflt beginning of the default handler block. + * @param keys the values of the keys. + * @param labels beginnings of the handler blocks. labels[i] is the beginning of + * the handler block for the keys[i] key. */ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { currBlock.add(currInsn); @@ -450,33 +439,31 @@ public abstract class CFGraph { /** * 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 - * null 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). + * @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 null 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) { + 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 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 start has not already been - * visited by this visitor (by the - * {@link #visitLabel visitLabel} method). + * @throws IllegalArgumentException if start has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public void visitLineNumber(int line, Label start) { currBlock.add(currInsn); @@ -557,7 +544,8 @@ public abstract class CFGraph { } @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { addTryCatchNodes(); } diff --git a/src/main/analysis/org/bdware/analysis/CFType.java b/src/main/analysis/org/bdware/analysis/CFType.java index 82bd336..ddd174c 100644 --- a/src/main/analysis/org/bdware/analysis/CFType.java +++ b/src/main/analysis/org/bdware/analysis/CFType.java @@ -1,10 +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 + 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 } diff --git a/src/main/analysis/org/bdware/analysis/FrontCF.java b/src/main/analysis/org/bdware/analysis/FrontCF.java index e7cfb43..4712dbf 100644 --- a/src/main/analysis/org/bdware/analysis/FrontCF.java +++ b/src/main/analysis/org/bdware/analysis/FrontCF.java @@ -8,131 +8,127 @@ 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 blocks; - public List edges; - public String ret; - public String finalRet; - transient InsnPrinter printer; - transient ArrayPs ps; + String methodName; + public List blocks; + public List edges; + public String ret; + public String finalRet; + transient InsnPrinter printer; + transient ArrayPs ps; - static class ArrayPs extends PrintStream { - List content; + static class ArrayPs extends PrintStream { + List content; - public ArrayPs() throws FileNotFoundException { - super("/dev/null"); - } + public ArrayPs() throws FileNotFoundException { + super("/dev/null"); + } - public void println(String str) { - if (content != null) - content.add(str); - } - } + 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 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 stmts; //BlockInstructions - String original; - String result; //preResult - String blockDep; - } + public static class FrontBB { + String type; + String name; // BlockNumber + List stmts; // BlockInstructions + String original; + String result; // preResult + String blockDep; + } - public static class EdgeLabel { - String label; - } + public static class EdgeLabel { + String label; + } - public static class FrontEdge { - String from, to; - EdgeLabel label; - } + public static class FrontEdge { + String from, to; + EdgeLabel label; + } - public void addBB(BasicBlock bb, String original, List ids, TaintCFG cfg) { - FrontBB fb = new FrontBB(); - blocks.add(fb); - fb.name = "B" + bb.blockID; - List 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(); - ps.content = fb.stmts; - for (AbstractInsnNode node : insnList) { - node.accept(printer); - } - } - } + public void addBB(BasicBlock bb, String original, List ids, TaintCFG cfg) { + FrontBB fb = new FrontBB(); + blocks.add(fb); + fb.name = "B" + bb.blockID; + List insnList = bb.getInsn(); + fb.type = "Continuous"; + fb.original = original; - public void addEdge(BasicBlock bb, BasicBlock suc) { - FrontEdge edge = new FrontEdge(); - List 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); + // 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(); + ps.content = fb.stmts; + for (AbstractInsnNode node : insnList) { + node.accept(printer); + } + } + } - } + public void addEdge(BasicBlock bb, BasicBlock suc) { + FrontEdge edge = new FrontEdge(); + List 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); + + } } diff --git a/src/main/analysis/org/bdware/analysis/InsnPrinter.java b/src/main/analysis/org/bdware/analysis/InsnPrinter.java index 7079c8e..7311027 100644 --- a/src/main/analysis/org/bdware/analysis/InsnPrinter.java +++ b/src/main/analysis/org/bdware/analysis/InsnPrinter.java @@ -10,288 +10,275 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; public class InsnPrinter extends MethodVisitor { - PrintStream ps; - private Map labelOrder; + PrintStream ps; + private Map labelOrder; - public InsnPrinter(int api, PrintStream ps) { - super(api); - this.ps = ps; - // TODO Auto-generated constructor stub - } - // ------------------------------------------------------------------------- - // Normal instructions - // ------------------------------------------------------------------------- + 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 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.
- * When opcode is BIPUSH, operand value should be between - * Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between - * Short.MIN_VALUE and Short.MAX_VALUE.
- * 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 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.
+ * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and + * Byte.MAX_VALUE.
+ * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and + * Short.MAX_VALUE.
+ * 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 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 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 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 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)); + /** + * 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(); - } + 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 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); - } + /** + * 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) + "="); + public void visitLabel(Label label) { + ps.println("=" + getLabelStr(label) + "="); - } + } - // ------------------------------------------------------------------------- - // Special instructions - // ------------------------------------------------------------------------- + // ------------------------------------------------------------------------- + // 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: - * - *
-	 * 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
-	 * }
-	 * 
- * - * @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 .class 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 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: + * + *
+     * 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
+     * }
+     * 
+ * + * @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 .class 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 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. labels[i] is the - * beginning of the handler block for the min + i key. - */ - public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { - ps.println(OpInfo.TABLESWITCH.toString() + " labels:" + getLabelStr(dflt) + " " + convertLabels(labels)); + /** + * 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. labels[i] is the beginning of the + * handler block for the min + i 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(); - } + 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. labels[i] is the - * beginning of the handler block for the keys[i] key. - */ - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - ps.println(OpInfo.LOOKUPSWITCH.toString() + " labels:" + getLabelStr(dflt) + " " + convertLabels(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. labels[i] is the beginning of the + * handler block for the keys[i] 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); - } + /** + * 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 labelOrder) { - this.labelOrder = labelOrder; - } + public void setLabelOrder(Map labelOrder) { + this.labelOrder = labelOrder; + } } diff --git a/src/main/analysis/org/bdware/analysis/OpInfo.java b/src/main/analysis/org/bdware/analysis/OpInfo.java index 676746d..5abd145 100644 --- a/src/main/analysis/org/bdware/analysis/OpInfo.java +++ b/src/main/analysis/org/bdware/analysis/OpInfo.java @@ -1,256 +1,257 @@ 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]; + 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);// ??-- - 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; + public final static OpInfo ops[] = new OpInfo[256]; - OpInfo() { - } + 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(int opcode, String displayName, int branchType, int changStack) { - flags = branchType; - this.displayName = displayName; - this.opcode = opcode; - this.changeStack = changeStack; - } + OpInfo() {} - public boolean canBranch() { - return 0 != (flags & kInstrCanBranch); - } + OpInfo(int opcode, String displayName, int branchType, int changStack) { + flags = branchType; + this.displayName = displayName; + this.opcode = opcode; + this.changeStack = changeStack; + } - public boolean canContinue() { - return 0 != (flags & kInstrCanContinue); - } + public boolean canBranch() { + return 0 != (flags & kInstrCanBranch); + } - public boolean canReturn() { - return 0 != (flags & kInstrCanReturn); - } + public boolean canContinue() { + return 0 != (flags & kInstrCanContinue); + } - public boolean canSwitch() { - return 0 != (flags & kInstrCanSwitch); - } + public boolean canReturn() { + return 0 != (flags & kInstrCanReturn); + } - public boolean canThrow() { - return 0 != (flags & kInstrCanThrow); - } - + public boolean canSwitch() { + return 0 != (flags & kInstrCanSwitch); + } - public String toString() { - return displayName; - } + public boolean canThrow() { + return 0 != (flags & kInstrCanThrow); + } + + + public String toString() { + return displayName; + } } diff --git a/src/main/analysis/org/bdware/analysis/dynamic/FieldSensitiveDynamicTaintAnalysis.java b/src/main/analysis/org/bdware/analysis/dynamic/FieldSensitiveDynamicTaintAnalysis.java index 7c94c2e..208b059 100644 --- a/src/main/analysis/org/bdware/analysis/dynamic/FieldSensitiveDynamicTaintAnalysis.java +++ b/src/main/analysis/org/bdware/analysis/dynamic/FieldSensitiveDynamicTaintAnalysis.java @@ -18,7 +18,8 @@ import org.objectweb.asm.tree.MethodNode; import java.util.*; public class FieldSensitiveDynamicTaintAnalysis extends BreadthFirstSearch { - private static final Logger LOGGER = LogManager.getLogger(FieldSensitiveDynamicTaintAnalysis.class); + private static final Logger LOGGER = + LogManager.getLogger(FieldSensitiveDynamicTaintAnalysis.class); public static boolean isDebug = false; TaintCFG cfg; TracedFile tf; @@ -79,8 +80,8 @@ public class FieldSensitiveDynamicTaintAnalysis extends BreadthFirstSearch ret = new HashSet<>(); -// StringBuilder log = new StringBuilder("nextBB:"); + // StringBuilder log = new StringBuilder("nextBB:"); for (BasicBlock bb : subBlock) { -// log.append("\n\t").append(bb.blockID); + // log.append("\n\t").append(bb.blockID); TaintBB ntbb = (TaintBB) bb; ntbb.preResult.mergeResult(t.sucResult); ret.add(ntbb); } -// LOGGER.info(log.toString()); + // LOGGER.info(log.toString()); return ret; } diff --git a/src/main/analysis/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysis.java b/src/main/analysis/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysis.java index 48d6402..2530f94 100644 --- a/src/main/analysis/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysis.java +++ b/src/main/analysis/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysis.java @@ -27,7 +27,8 @@ public class NaiveDynamicTaintAnalysis extends BreadthFirstSearch= 0) info = OpInfo.ops[insn.getOpcode()]; + if (insn.getOpcode() >= 0) + info = OpInfo.ops[insn.getOpcode()]; if (info == null) { subBlock.addAll(cfg.getSucBlocks(t)); } else if (info.canThrow()) { @@ -104,9 +103,8 @@ public class NaiveDynamicTaintAnalysis extends BreadthFirstSearch toAnalysis = new ArrayList<>(); /* - * NaiveTaintBB������ boolean inList NaiveTaintResult preResult NaiveTaintResult - * sucResult + * NaiveTaintBB������ boolean inList NaiveTaintResult preResult NaiveTaintResult sucResult */ TaintBB b = (TaintBB) cfg.getBasicBlockAt(0); /* - * NaiveTaintResult�еı����� Frame frame TaintInterpreter interpreter - * TaintValue ret InsnPrinter printer int nLocals int nStack - * NaiveTaintResult�е��ࣺ TaintValue int size boolean isTainted - * TaintInterpreter() NaiveTaintResult currentResult Frame�еı����� V returnValue - * //���������ķ������ͣ����Ϊvoid��Ϊnull V[] values //�ֲ������Ͳ����� int locals + * NaiveTaintResult�еı����� Frame frame TaintInterpreter interpreter TaintValue + * ret InsnPrinter printer int nLocals int nStack NaiveTaintResult�е��ࣺ TaintValue int size + * boolean isTainted TaintInterpreter() NaiveTaintResult currentResult Frame�еı����� V + * returnValue //���������ķ������ͣ����Ϊvoid��Ϊnull V[] values //�ֲ������Ͳ����� int locals * //�ֲ������ĸ��� int top //������ջ��Ԫ�ظ��� */ b.preResult = new TaintResult(); @@ -40,10 +38,9 @@ public class FieldSensitiveTaintAnalysis extends BreadthFirstSearch 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, + * 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������size=1 @@ -54,8 +51,7 @@ public class FieldSensitiveTaintAnalysis extends BreadthFirstSearch results; List - * toAnalysis; + * BreadthFirstSearch���еı����� Map results; List toAnalysis; */ setToAnalysis(toAnalysis); if (isDebug) { diff --git a/src/main/analysis/org/bdware/analysis/example/MultiSourceTaintAnalysis.java b/src/main/analysis/org/bdware/analysis/example/MultiSourceTaintAnalysis.java index c5f468e..b0852fb 100644 --- a/src/main/analysis/org/bdware/analysis/example/MultiSourceTaintAnalysis.java +++ b/src/main/analysis/org/bdware/analysis/example/MultiSourceTaintAnalysis.java @@ -37,11 +37,8 @@ public class MultiSourceTaintAnalysis extends BreadthFirstSearch blocks = cfg.getBlocks(); Map> map = new HashMap<>(); @@ -108,9 +100,11 @@ public class MultiSourceTaintAnalysis extends BreadthFirstSearch 0 && count != sucSize) list.add(id); + if (count > 0 && count != sucSize) + list.add(id); } map.put(bb.blockID, list); } @@ -129,10 +123,8 @@ public class MultiSourceTaintAnalysis extends BreadthFirstSearch> entry : returnMap.entrySet()) { List listID = entry.getValue(); for (Integer i : listID) { - if (!lastBlockDep.contains(i)) lastBlockDep.add(i); + if (!lastBlockDep.contains(i)) + lastBlockDep.add(i); } } returnMap.put(cfg.getBasicBlockSize() - 1, lastBlockDep); @@ -149,14 +142,10 @@ public class MultiSourceTaintAnalysis extends BreadthFirstSearch 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(); - } - */ + * List 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; } @@ -164,20 +153,14 @@ public class MultiSourceTaintAnalysis extends BreadthFirstSearch 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); + System.out.println("===Local:" + cfg.getMethodNode().maxLocals + " " + + cfg.getMethodNode().maxStack); } } diff --git a/src/main/analysis/org/bdware/analysis/gas/BFS.java b/src/main/analysis/org/bdware/analysis/gas/BFS.java index 235b945..c4dc62e 100644 --- a/src/main/analysis/org/bdware/analysis/gas/BFS.java +++ b/src/main/analysis/org/bdware/analysis/gas/BFS.java @@ -6,26 +6,29 @@ import java.util.List; import org.bdware.analysis.BasicBlock; public abstract class BFS { - protected List toAnalysis; - public abstract Collection 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 sucs = getSuc(current); - for (BasicBlock next : sucs) { - if (!next.inList()) { - toAnalysis.add(next); - next.setInList(true); - } - } - } - } - } - public void setToAnalysis(List l) { - toAnalysis = l; - } - + protected List toAnalysis; + + public abstract Collection 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 sucs = getSuc(current); + for (BasicBlock next : sucs) { + if (!next.inList()) { + toAnalysis.add(next); + next.setInList(true); + } + } + } + } + } + + public void setToAnalysis(List l) { + toAnalysis = l; + } + } diff --git a/src/main/analysis/org/bdware/analysis/gas/CostDetail.java b/src/main/analysis/org/bdware/analysis/gas/CostDetail.java index 9fa2113..a09a521 100644 --- a/src/main/analysis/org/bdware/analysis/gas/CostDetail.java +++ b/src/main/analysis/org/bdware/analysis/gas/CostDetail.java @@ -1 +1 @@ -package org.bdware.analysis.gas; \ No newline at end of file +package org.bdware.analysis.gas; diff --git a/src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java b/src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java index 5652de5..2a8181b 100644 --- a/src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java +++ b/src/main/analysis/org/bdware/analysis/gas/CountProgramPoint.java @@ -12,215 +12,215 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.JumpInsnNode; public class CountProgramPoint { - public static HashMap> ppcount; - CFGraph actionCfg; - private String bdName; - HashMap cfgraphMap; - String actionName; - int globalPC; + public static HashMap> ppcount; + CFGraph actionCfg; + private String bdName; + HashMap cfgraphMap; + String actionName; + int globalPC; - public CountProgramPoint(HashMap cfgMap, int startPc, int endPc, String aName, - HashMap> ppc) { - ppcount = ppc; - cfgraphMap = cfgMap; - actionName = aName; - typeCount(startPc, endPc); - } + public CountProgramPoint(HashMap cfgMap, int startPc, int endPc, String aName, + HashMap> ppc) { + ppcount = ppc; + cfgraphMap = cfgMap; + actionName = aName; + typeCount(startPc, endPc); + } - private HashMap> callCount(AbstractInsnNode insn) { - if (insn instanceof InvokeDynamicInsnNode) { - invoke = ((InvokeDynamicInsnNode) insn).bsmArgs[0]; - String functionName = ((InvokeDynamicInsnNode) insn).name; - dynCount(functionName); - } else { - normalCount(insn); - } - return ppcount; - } + private HashMap> 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; + Object invoke = 0; - public HashMap> 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; - } - } - } + public HashMap> 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); + return getInsn(blockStart, blockend); - } + } - private HashMap> 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 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 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) { + private HashMap> 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 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 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); - } - } - } - } + } 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; - } + } + 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 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 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); - } + 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); - } - } + } 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; - } - } + private boolean isInnerfunction(String functionName) { + String string = functionName.split(":")[2]; + if (cfgraphMap.containsKey(string)) { + return true; + } else { + return false; + } + } } diff --git a/src/main/analysis/org/bdware/analysis/gas/DFS.java b/src/main/analysis/org/bdware/analysis/gas/DFS.java index 60d1812..2b2dc62 100644 --- a/src/main/analysis/org/bdware/analysis/gas/DFS.java +++ b/src/main/analysis/org/bdware/analysis/gas/DFS.java @@ -15,7 +15,8 @@ public abstract class DFS { // System.out.println("[start.blockID]" + start.blockID); Set sucBlocks = getSuc(start); for (BasicBlock bb : sucBlocks) { - if (!marked[bb.blockID]) dfs(cfg, bb); + if (!marked[bb.blockID]) + dfs(cfg, bb); } } diff --git a/src/main/analysis/org/bdware/analysis/gas/Evaluates.java b/src/main/analysis/org/bdware/analysis/gas/Evaluates.java index 2c797cd..0882cc1 100644 --- a/src/main/analysis/org/bdware/analysis/gas/Evaluates.java +++ b/src/main/analysis/org/bdware/analysis/gas/Evaluates.java @@ -20,7 +20,7 @@ public class Evaluates { long fee = getValue(cmap.getKey()); value = fee * cmap.getValue() + value; } - CountResult.put(cfrKey, value); + CountResult.put(cfrKey, value); } return CountResult; } @@ -62,14 +62,14 @@ public class Evaluates { Set> set = new HashSet<>(); public void getGas(HashMap>>> branchCount) { - for (Entry>>> varInsn : - branchCount.entrySet()) { - sum = 0; - for (Map> m : varInsn.getValue()) { - blockGas(m); - } - map.put(varInsn.getKey(), sum); + for (Entry>>> varInsn : branchCount + .entrySet()) { + sum = 0; + for (Map> m : varInsn.getValue()) { + blockGas(m); } + map.put(varInsn.getKey(), sum); + } } private void blockGas(Map> m) { @@ -84,13 +84,13 @@ public class Evaluates { public static HashMap map = new HashMap<>(); public void getInsnGas(Map>>> ppMap) { - for (Entry>>> varInsn : - ppMap.entrySet()) { + for (Entry>>> varInsn : ppMap + .entrySet()) { sum = 0; for (Map> m : varInsn.getValue()) { blockGas(m); } map.put(varInsn.getKey().toString(), sum); - } + } } } diff --git a/src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java b/src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java index bad8086..c980ae1 100644 --- a/src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java +++ b/src/main/analysis/org/bdware/analysis/gas/FeeSchedule.java @@ -1,51 +1,52 @@ 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); + // BDaload(20L),BDstore(200L), + BDgetMethod(10L), BDsetMethod(20L), BDnew(20L), BDcallUtil(30L), BDcallFuntion(40L), BDcall( + 10L), BDjump(15L), BDInsn(1L); - long fee; + long fee; - FeeSchedule(long value) { - fee = value; - } + FeeSchedule(long value) { + fee = value; + } - public long getFee() { - return fee; - } + 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 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(); + public String getString(FeeSchedule feeName) { + return feeName.toString(); - } + } } diff --git a/src/main/analysis/org/bdware/analysis/gas/PPCount.java b/src/main/analysis/org/bdware/analysis/gas/PPCount.java index c39a887..c9bc675 100644 --- a/src/main/analysis/org/bdware/analysis/gas/PPCount.java +++ b/src/main/analysis/org/bdware/analysis/gas/PPCount.java @@ -11,12 +11,8 @@ 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; @@ -49,7 +45,7 @@ public class PPCount extends DFS { BasicBlock b = cfg.getBasicBlockAt(0); toAnalysis.add(b); b.setInList(true); -// System.out.println("=========:"+cfg.getMethodNode().name); + // System.out.println("=========:"+cfg.getMethodNode().name); functionList.add(cfg.getMethodNode().name); isBranchBlock = new boolean[cfg.getBasicBlockSize()]; // setToAnalysis(toAnalysis); @@ -302,44 +298,42 @@ public class PPCount extends DFS { 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); + 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); + 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); + 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); + 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); + // 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); + 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); @@ -348,16 +342,16 @@ public class PPCount extends DFS { } 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); + 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); + BlockInsn.get(globalBlockID).put(bdName, + BlockInsn.get(globalBlockID).get(bdName) + 1); } else { BlockInsn.get(globalBlockID).put(bdName, 1); } @@ -366,8 +360,8 @@ public class PPCount extends DFS { private boolean isInnerfunction(String functionName) { String string = functionName.split(":")[2]; - // System.out.println("++++++++++++++" + functionName); - // System.out.println("【function】" + functionList); + // System.out.println("++++++++++++++" + functionName); + // System.out.println("【function】" + functionList); if (functionList.contains(string)) { return true; } else { @@ -375,57 +369,57 @@ public class PPCount extends DFS { } } - // 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); + // 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 clzs = engine.dumpClass(); - // Map 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); + // Map clzs = engine.dumpClass(); + // Map 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(); + // 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); + // 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()); - // } + // // System.out.println(feEvaluates.getCallFee()); + // } public static HashMap functionSumGas = new HashMap<>(); diff --git a/src/main/analysis/org/bdware/analysis/taint/DirectGraphDFS.java b/src/main/analysis/org/bdware/analysis/taint/DirectGraphDFS.java index 3dcdf70..ec10e4d 100644 --- a/src/main/analysis/org/bdware/analysis/taint/DirectGraphDFS.java +++ b/src/main/analysis/org/bdware/analysis/taint/DirectGraphDFS.java @@ -5,24 +5,24 @@ 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 sucBlocks = cfg.getSucBlocks(start); - for(BasicBlock bb : sucBlocks) { - if(!marked[bb.blockID]) - dfs(cfg, bb); - } - } - - public boolean isArrival(BasicBlock end) { - return marked[end.blockID]; - } - + 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 sucBlocks = cfg.getSucBlocks(start); + for (BasicBlock bb : sucBlocks) { + if (!marked[bb.blockID]) + dfs(cfg, bb); + } + } + + public boolean isArrival(BasicBlock end) { + return marked[end.blockID]; + } + } diff --git a/src/main/analysis/org/bdware/analysis/taint/HeapObject.java b/src/main/analysis/org/bdware/analysis/taint/HeapObject.java index ccee54d..9653b56 100644 --- a/src/main/analysis/org/bdware/analysis/taint/HeapObject.java +++ b/src/main/analysis/org/bdware/analysis/taint/HeapObject.java @@ -11,237 +11,240 @@ import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.InvokeDynamicInsnNode; public class HeapObject extends TaintValue { - private Map fields = new HashMap(); - static int allocatID = 0; - int id; + private Map fields = new HashMap(); + static int allocatID = 0; + int id; - public HeapObject() { - super(1); - id = allocatID++; - } + 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 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; - } + 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(); - } + @Override + public String toString() { + return countSize() + "|" + super.toString(); + } - private String countSize() { - objSet = new HashSet<>(); - return countSizeInternal(); - } + 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 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 objSet; + private static HashSet objSet; - public static TaintValue operate(AbstractInsnNode insn, List 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; + public static TaintValue operate(AbstractInsnNode insn, List 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 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 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; - } + 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 getProp(String str) { + return fields.get(str); + } - public TaintValue setProp(String str, TaintValue val) { - return fields.put(str, val); - } + public TaintValue setProp(String str, TaintValue val) { + return fields.put(str, val); + } - @Override - public HeapObject clone() { - return this; - } + @Override + public HeapObject clone() { + return this; + } - public HeapObject actualClone() { - ccObj = new HashMap<>(); - return cloneInternal(); - } + public HeapObject actualClone() { + ccObj = new HashMap<>(); + return cloneInternal(); + } - static Map ccObj; + static Map 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; - } + 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); + // 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()); + } else + fields.put(field, targetObject.fields.get(field).clone()); - } - } - } + } + } + } - public synchronized long wholeTaint() { - objSet = new HashSet<>(); - return wholeTaintInternal(); - } + 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; - } + 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; + } } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintBB.java b/src/main/analysis/org/bdware/analysis/taint/TaintBB.java index d7949fd..5b22994 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintBB.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintBB.java @@ -7,64 +7,68 @@ import org.bdware.analysis.BasicBlock; import org.objectweb.asm.tree.AbstractInsnNode; public class TaintBB extends BasicBlock implements AnalysisTarget { - boolean inList = false; + boolean inList = false; - public TaintBB(int id) { - super(id); - preResult = new TaintResult(); - sucResult = new TaintResult(); - } + public TaintBB(int id) { + super(id); + preResult = new TaintResult(); + sucResult = new TaintResult(); + } - public TaintResult preResult; - public TaintResult sucResult; + public TaintResult preResult; + public TaintResult sucResult; - @Override - public boolean inList() { - return inList; - } + @Override + public boolean inList() { + return inList; + } - @Override - public void setInList(boolean b) { - inList = b; - } - - public String getResult() { - return (sucResult.frame2Str() + " Ret:" + sucResult.ret.toString()); - } + @Override + public void setInList(boolean b) { + inList = b; + } - public String getResultWithTaintBit() { - return "Ret:" + sucResult.ret.toReadableTaint(); - } + public String getResult() { + return (sucResult.frame2Str() + " Ret:" + sucResult.ret.toString()); + } - public TaintResult forwardAnalysis() { - TaintResult oldSuc = sucResult; - sucResult = (TaintResult) preResult.clone(); - TaintResult currentResult = sucResult; - List insns = getInsn(); - if (TaintConfig.isDebug) - System.out.println("[TaintBB] Enter B" + blockID + ":" + getResult() + " size:" + insns.size()); + public String getResultWithTaintBit() { + return "Ret:" + sucResult.ret.toReadableTaint(); + } - for (int i = 0; i < insns.size(); i++) { - currentResult = (TaintResult) currentResult.merge(insns.get(i)); - } - currentResult.mergeResult(oldSuc); + public TaintResult forwardAnalysis() { + TaintResult oldSuc = sucResult; + sucResult = (TaintResult) preResult.clone(); + TaintResult currentResult = sucResult; + List insns = getInsn(); + if (TaintConfig.isDebug) + System.out.println( + "[TaintBB] Enter B" + blockID + ":" + getResult() + " size:" + insns.size()); - if (TaintConfig.isDebug) - System.out.println("[TaintBB] Leave B" + blockID + ":" + getResult() + " size:" + insns.size()); - // already done. - return currentResult; - } + 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 AllInsn() { + return list; + } - public AbstractInsnNode lastInsn() { - return list.get(list.size() - 1); - } - public AbstractInsnNode firstInsn() { - return list.get(0); - } - public List AllInsn() { - return list; - } - } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintBits.java b/src/main/analysis/org/bdware/analysis/taint/TaintBits.java index 331d179..81b32b3 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintBits.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintBits.java @@ -4,65 +4,65 @@ import java.util.HashMap; import java.util.Map; public class TaintBits { - Map data; - Map type2Taint; - long curr; - Map reallocate; - int count = 0; + Map data; + Map type2Taint; + long curr; + Map reallocate; + int count = 0; - public TaintBits() { - curr = 1L; - data = new HashMap<>(); - type2Taint = new HashMap<>(); - reallocate = new HashMap<>(); - } + 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; - } + 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; - } + 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 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 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; - } + 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; + } } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintCFG.java b/src/main/analysis/org/bdware/analysis/taint/TaintCFG.java index 4a62cb8..4a04572 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintCFG.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintCFG.java @@ -11,74 +11,75 @@ import org.objectweb.asm.tree.InvokeDynamicInsnNode; import org.objectweb.asm.tree.MethodNode; public class TaintCFG extends CFGraph { - public TaintBits taintBits; + public TaintBits taintBits; - public TaintCFG(MethodNode mn) { - super(mn); - taintBits = new TaintBits(); - } + public TaintCFG(MethodNode mn) { + super(mn); + taintBits = new TaintBits(); + } - @Override - public BasicBlock getBasicBlock(int id) { - return new TaintBB(id); - } + @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 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 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()); - } + 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); - } - } + 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 getBlocks() { - return basicBlocks; - } + public TaintBB getLastBlock() { + if (basicBlocks != null && basicBlocks.size() > 0) + return (TaintBB) basicBlocks.get(basicBlocks.size() - 1); + return null; + } + + public List getBlocks() { + return basicBlocks; + } } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintConfig.java b/src/main/analysis/org/bdware/analysis/taint/TaintConfig.java index e51392a..4bcc5fa 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintConfig.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintConfig.java @@ -1,5 +1,5 @@ package org.bdware.analysis.taint; public class TaintConfig { - public static boolean isDebug = false; + public static boolean isDebug = false; } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintInterpreter.java b/src/main/analysis/org/bdware/analysis/taint/TaintInterpreter.java index c29ab7a..df20943 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintInterpreter.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintInterpreter.java @@ -12,166 +12,172 @@ import org.objectweb.asm.tree.analysis.AnalyzerException; import org.objectweb.asm.tree.analysis.Interpreter; public class TaintInterpreter extends Interpreter { - TaintResult currentResult; - TaintBits taintBits; + TaintResult currentResult; + TaintBits taintBits; - public TaintInterpreter(int api) { - super(api); + 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 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 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 copyOperation(AbstractInsnNode insn, TaintValue value) + throws AnalyzerException { + return value; + } - @Override - public TaintValue unaryOperation(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 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 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 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; + @Override + public TaintValue naryOperation(AbstractInsnNode insn, List 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())); + // 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); - } + 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 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; - } + @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 setCurrentResult(TaintResult naiveTaintResult) { + currentResult = naiveTaintResult; + } - public void setTaintBits(TaintBits tb) { - taintBits = tb; - } -} \ No newline at end of file + public void setTaintBits(TaintBits tb) { + taintBits = tb; + } +} diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintResult.java b/src/main/analysis/org/bdware/analysis/taint/TaintResult.java index e3025c0..5601c11 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintResult.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintResult.java @@ -8,183 +8,183 @@ import org.objectweb.asm.tree.analysis.AnalyzerException; import org.objectweb.asm.tree.analysis.Frame; public class TaintResult extends AnalysisResult { - // public HeapObject heapObejct; - public Frame 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 HeapObject heapObejct; + public Frame 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; - } + 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()); + @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; - } - + } 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����local�����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����stack�ĵ�ǰsize - TaintValue t = frame.getStack(i); - if (t != null) - sb.append(t.toString()); - else - sb.append("0--"); - } - return sb.toString(); - } + @Override + public void printResult() { + System.out.println("====" + frame2Str() + " Ret:" + ret.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; - } + public String frame2Str() { + StringBuilder sb = new StringBuilder(); + sb.append("Local:"); + for (int i = 0; i < frame.getLocals(); i++) { // getLocals����local�����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����stack�ĵ�ǰsize + TaintValue t = frame.getStack(i); + if (t != null) + sb.append(t.toString()); + else + sb.append("0--"); + } + return sb.toString(); + } - /* - * 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; - } + 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; + } - @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()); - } + /* + * 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; + } - // 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 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()); + } - @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()); - } - } + // 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; + } - 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); - } - } + @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()); + } + } - 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); - } + 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); + } + } - @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; - } + 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; + } } diff --git a/src/main/analysis/org/bdware/analysis/taint/TaintValue.java b/src/main/analysis/org/bdware/analysis/taint/TaintValue.java index d01e7df..7ee8e0c 100644 --- a/src/main/analysis/org/bdware/analysis/taint/TaintValue.java +++ b/src/main/analysis/org/bdware/analysis/taint/TaintValue.java @@ -3,52 +3,52 @@ 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 int size; + // public boolean isTainted; + public long isTainted; - public TaintValue(int size) { - this.size = size; - isTainted = 0L; - } + public TaintValue(int size) { + this.size = size; + isTainted = 0L; + } - public TaintValue(int size, long isTainted) { - this.size = size; - this.isTainted = isTainted; - } + public TaintValue(int size, long isTainted) { + this.size = size; + this.isTainted = isTainted; + } - @Override - public int getSize() { - return size; - } + @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(); - } + @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 TaintValue clone() { + TaintValue ret = new TaintValue(size); + ret.isTainted = isTainted; + return ret; + } - public String toReadableTaint() { - return TaintResult.interpreter.taintBits.parse(isTainted); - } + public String toReadableTaint() { + return TaintResult.interpreter.taintBits.parse(isTainted); + } - public void merge(TaintValue target) { - if (target != null) - isTainted |= target.isTainted; - } + public void merge(TaintValue target) { + if (target != null) + isTainted |= target.isTainted; + } } diff --git a/src/main/asm/org/objectweb/asm/AnnotationVisitor.java b/src/main/asm/org/objectweb/asm/AnnotationVisitor.java index 3c8a740..2eaa156 100644 --- a/src/main/asm/org/objectweb/asm/AnnotationVisitor.java +++ b/src/main/asm/org/objectweb/asm/AnnotationVisitor.java @@ -1,38 +1,30 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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: ( visit | visitEnum | - * visitAnnotation | visitArray )* visitEnd. + * A visitor to visit a Java annotation. The methods of this class must be called in the following + * order: ( visit | visitEnum | visitAnnotation | visitArray )* + * visitEnd. * * @author Eric Bruneton * @author Eugene Kuleshov @@ -40,23 +32,21 @@ package org.objectweb.asm; public abstract class AnnotationVisitor { /** - * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4}. + * 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. + * 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}. + * @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); @@ -65,12 +55,10 @@ public abstract class AnnotationVisitor { /** * 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. + * @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) { @@ -83,17 +71,13 @@ public abstract class AnnotationVisitor { /** * 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). + * @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) { @@ -104,12 +88,9 @@ public abstract class AnnotationVisitor { /** * 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. + * @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) { @@ -120,15 +101,12 @@ public abstract class AnnotationVisitor { /** * 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 - * null if this visitor is not interested in visiting this - * nested annotation. The nested annotation value must be fully - * visited before calling other methods on this annotation - * visitor. + * @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 null if this + * visitor is not interested in visiting this nested annotation. The nested + * annotation value must be fully visited before calling other methods on this + * annotation visitor. */ public AnnotationVisitor visitAnnotation(String name, String desc) { if (av != null) { @@ -138,18 +116,15 @@ public abstract class AnnotationVisitor { } /** - * 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. + * 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 - * null if this visitor is not interested in visiting these - * values. The 'name' parameters passed to the methods of this - * visitor are ignored. All the array values must be visited - * before calling other methods on this annotation visitor. + * @param name the value name. + * @return a visitor to visit the actual array value elements, or null if this visitor + * is not interested in visiting these values. The 'name' parameters passed to the + * methods of this visitor are ignored. All the array values must be visited before + * calling other methods on this annotation visitor. */ public AnnotationVisitor visitArray(String name) { if (av != null) { diff --git a/src/main/asm/org/objectweb/asm/AnnotationWriter.java b/src/main/asm/org/objectweb/asm/AnnotationWriter.java index 4cfa633..2a99aee 100644 --- a/src/main/asm/org/objectweb/asm/AnnotationWriter.java +++ b/src/main/asm/org/objectweb/asm/AnnotationWriter.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -35,344 +27,267 @@ package org.objectweb.asm; * @author Eric Bruneton * @author Eugene Kuleshov */ -final class AnnotationWriter extends AnnotationVisitor -{ +final class AnnotationWriter extends AnnotationVisitor { - /** - * The class writer to which this annotation must be added. - */ - private final ClassWriter cw; + /** + * The class writer to which this annotation must be added. + */ + private final ClassWriter cw; - /** - * The number of values in this annotation. - */ - private int size; + /** + * The number of values in this annotation. + */ + private int size; - /** - * true if values are named, false otherwise. Annotation - * writers used for annotation default and annotation arrays use unnamed - * values. - */ - private final boolean named; + /** + * true if values are named, false 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 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; + /** + * 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; + /** + * 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; + /** + * 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; + /** + * Previous annotation writer. This field is used to store annotation lists. + */ + AnnotationWriter prev; - // ------------------------------------------------------------------------ - // Constructor - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ - /** - * Constructs a new {@link AnnotationWriter}. - * - * @param cw - * the class writer to which this annotation must be added. - * @param named - * true if values are named, false 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 parent 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; - } + /** + * Constructs a new {@link AnnotationWriter}. + * + * @param cw the class writer to which this annotation must be added. + * @param named true if values are named, false 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 parent 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 - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ + // 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 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 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 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 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; - } - } + @Override + public void visitEnd() { + if (parent != null) { + byte[] data = parent.data; + data[offset] = (byte) (size >>> 8); + data[offset + 1] = (byte) size; + } + } - // ------------------------------------------------------------------------ - // Utility methods - // ------------------------------------------------------------------------ + // ------------------------------------------------------------------------ + // 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; - } + /** + * 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 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; - } - } - } + /** + * 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; + } + } + } } diff --git a/src/main/asm/org/objectweb/asm/Attribute.java b/src/main/asm/org/objectweb/asm/Attribute.java index 8a2a882..c7d8df9 100644 --- a/src/main/asm/org/objectweb/asm/Attribute.java +++ b/src/main/asm/org/objectweb/asm/Attribute.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -55,16 +47,15 @@ public class Attribute { /** * Constructs a new empty attribute. * - * @param type - * the type of the attribute. + * @param type the type of the attribute. */ protected Attribute(final String type) { this.type = type; } /** - * Returns true if this type of attribute is unknown. The default - * implementation of this method always returns true. + * Returns true if this type of attribute is unknown. The default implementation of + * this method always returns true. * * @return true if this type of attribute is unknown. */ @@ -84,47 +75,36 @@ public class Attribute { /** * Returns the labels corresponding to this attribute. * - * @return the labels corresponding to this attribute, or null if - * this attribute is not a code attribute that contains labels. + * @return the labels corresponding to this attribute, or null 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 - * new {@link Attribute} object, of type {@link #type type}, - * corresponding to the len bytes starting at the given offset, in - * the given class reader. + * Reads a {@link #type type} attribute. This method must return a new {@link Attribute} + * object, of type {@link #type type}, corresponding to the len 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 null if the - * attribute to be read is not a code attribute. - * @return a new {@link Attribute} object corresponding to the given - * bytes. + * @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 null if the attribute to be read + * is not a code attribute. + * @return a new {@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) { + 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); @@ -134,30 +114,20 @@ public class Attribute { /** * 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 null if this attribute is not a code - * attributes. - * @param len - * the length of the bytecode of the method corresponding to this - * code attribute, or null 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. + * @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 null + * if this attribute is not a code attributes. + * @param len the length of the bytecode of the method corresponding to this code attribute, or + * null 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) { + 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; @@ -182,30 +152,21 @@ public class Attribute { /** * 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 null if these attributes are not code - * attributes. - * @param len - * the length of the bytecode of the method corresponding to - * these code attributes, or null 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. + * @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 + * null if these attributes are not code attributes. + * @param len the length of the bytecode of the method corresponding to these code attributes, + * or null 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) { + 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) { @@ -217,33 +178,22 @@ public class Attribute { } /** - * Writes all the attributes of this attribute list in the given byte - * vector. + * 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 null if these attributes are not code - * attributes. - * @param len - * the length of the bytecode of the method corresponding to - * these code attributes, or null 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. + * @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 + * null if these attributes are not code attributes. + * @param len the length of the bytecode of the method corresponding to these code attributes, + * or null 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) { + 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); diff --git a/src/main/asm/org/objectweb/asm/ByteVector.java b/src/main/asm/org/objectweb/asm/ByteVector.java index f1e2da1..b0d3d05 100644 --- a/src/main/asm/org/objectweb/asm/ByteVector.java +++ b/src/main/asm/org/objectweb/asm/ByteVector.java @@ -1,37 +1,29 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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. + * 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 */ @@ -48,30 +40,25 @@ public class ByteVector { int length; /** - * Constructs a new {@link ByteVector ByteVector} with a default initial - * size. + * 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. + * Constructs a new {@link ByteVector ByteVector} with the given initial size. * - * @param initialSize - * the initial size of the byte vector to be constructed. + * @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. + * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary. * - * @param b - * a byte. + * @param b a byte. * @return this byte vector. */ public ByteVector putByte(final int b) { @@ -85,13 +72,10 @@ public class ByteVector { } /** - * Puts two bytes into this byte vector. The byte vector is automatically - * enlarged if necessary. + * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary. * - * @param b1 - * a byte. - * @param b2 - * another byte. + * @param b1 a byte. + * @param b2 another byte. * @return this byte vector. */ ByteVector put11(final int b1, final int b2) { @@ -107,11 +91,9 @@ public class ByteVector { } /** - * Puts a short into this byte vector. The byte vector is automatically - * enlarged if necessary. + * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary. * - * @param s - * a short. + * @param s a short. * @return this byte vector. */ public ByteVector putShort(final int s) { @@ -127,13 +109,11 @@ public class ByteVector { } /** - * Puts a byte and a short into this byte vector. The byte vector is - * automatically enlarged if necessary. + * 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. + * @param b a byte. + * @param s a short. * @return this byte vector. */ ByteVector put12(final int b, final int s) { @@ -150,11 +130,9 @@ public class ByteVector { } /** - * Puts an int into this byte vector. The byte vector is automatically - * enlarged if necessary. + * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary. * - * @param i - * an int. + * @param i an int. * @return this byte vector. */ public ByteVector putInt(final int i) { @@ -172,11 +150,9 @@ public class ByteVector { } /** - * Puts a long into this byte vector. The byte vector is automatically - * enlarged if necessary. + * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary. * - * @param l - * a long. + * @param l a long. * @return this byte vector. */ public ByteVector putLong(final long l) { @@ -200,11 +176,10 @@ public class ByteVector { } /** - * Puts an UTF8 string into this byte vector. The byte vector is - * automatically enlarged if necessary. + * 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. + * @param s a String whose UTF8 encoded length must be less than 65536. * @return this byte vector. */ public ByteVector putUTF8(final String s) { @@ -272,16 +247,13 @@ public class ByteVector { } /** - * Puts an array of bytes into this byte vector. The byte vector is - * automatically enlarged if necessary. + * 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 null to put len - * 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. + * @param b an array of bytes. May be null to put len 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) { @@ -298,9 +270,7 @@ public class ByteVector { /** * 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. + * @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; diff --git a/src/main/asm/org/objectweb/asm/ClassReader.java b/src/main/asm/org/objectweb/asm/ClassReader.java index 5341e0d..0510363 100644 --- a/src/main/asm/org/objectweb/asm/ClassReader.java +++ b/src/main/asm/org/objectweb/asm/ClassReader.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -33,2486 +25,2001 @@ import java.io.IOException; import java.io.InputStream; /** - * A Java class parser to make a {@link ClassVisitor} visit an existing class. - * This class parses a byte array conforming to the Java class file format and - * calls the appropriate visit methods of a given class visitor for each field, - * method and bytecode instruction encountered. + * A Java class parser to make a {@link ClassVisitor} visit an existing class. This class parses a + * byte array conforming to the Java class file format and calls the appropriate visit methods of a + * given class visitor for each field, method and bytecode instruction encountered. * * @author Eric Bruneton * @author Eugene Kuleshov */ -public class ClassReader -{ - - /** - * True to enable signatures support. - */ - static final boolean SIGNATURES = true; - - /** - * True to enable annotations support. - */ - static final boolean ANNOTATIONS = true; - - /** - * True to enable stack map frames support. - */ - static final boolean FRAMES = true; - - /** - * True to enable bytecode writing support. - */ - static final boolean WRITER = true; - - /** - * True to enable JSR_W and GOTO_W support. - */ - static final boolean RESIZE = true; - - /** - * Flag to skip method code. If this class is set CODE - * attribute won't be visited. This can be used, for example, to retrieve - * annotations for methods and method parameters. - */ - public static final int SKIP_CODE = 1; - - /** - * Flag to skip the debug information in the class. If this flag is set the - * debug information of the class is not visited, i.e. the - * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and - * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be - * called. - */ - public static final int SKIP_DEBUG = 2; - - /** - * Flag to skip the stack map frames in the class. If this flag is set the - * stack map frames of the class is not visited, i.e. the - * {@link MethodVisitor#visitFrame visitFrame} method will not be called. - * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is - * used: it avoids visiting frames that will be ignored and recomputed from - * scratch in the class writer. - */ - public static final int SKIP_FRAMES = 4; - - /** - * Flag to expand the stack map frames. By default stack map frames are - * visited in their original format (i.e. "expanded" for classes whose - * version is less than V1_6, and "compressed" for the other classes). If - * this flag is set, stack map frames are always visited in expanded format - * (this option adds a decompression/recompression step in ClassReader and - * ClassWriter which degrades performances quite a lot). - */ - public static final int EXPAND_FRAMES = 8; - - /** - * The class to be parsed. The content of this array must not be - * modified. This field is intended for {@link Attribute} sub classes, and - * is normally not needed by class generators or adapters. - */ - public final byte[] b; - - /** - * The start index of each constant pool item in {@link #b b}, plus one. The - * one byte offset skips the constant pool item tag that indicates its type. - */ - private final int[] items; - - /** - * The String objects corresponding to the CONSTANT_Utf8 items. This cache - * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, - * which GREATLY improves performances (by a factor 2 to 3). This caching - * strategy could be extended to all constant pool items, but its benefit - * would not be so great for these items (because they are much less - * expensive to parse than CONSTANT_Utf8 items). - */ - private final String[] strings; - - /** - * Maximum length of the strings contained in the constant pool of the - * class. - */ - private final int maxStringLength; - - /** - * Start index of the class header information (access, name...) in - * {@link #b b}. - */ - public final int header; - - // ------------------------------------------------------------------------ - // Constructors - // ------------------------------------------------------------------------ - - /** - * Constructs a new {@link ClassReader} object. - * - * @param b - * the bytecode of the class to be read. - */ - public ClassReader(final byte[] b) - { - this(b, 0, b.length); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param b - * the bytecode of the class to be read. - * @param off - * the start offset of the class data. - * @param len - * the length of the class data. - */ - public ClassReader(final byte[] b, final int off, final int len) - { - this.b = b; - // checks the class version - if (readShort(off + 6) > Opcodes.V1_8) - { - throw new IllegalArgumentException(); - } - // parses the constant pool - items = new int[readUnsignedShort(off + 8)]; - int n = items.length; - strings = new String[n]; - int max = 0; - int index = off + 10; - for (int i = 1; i < n; ++i) - { - items[i] = index + 1; - int size; - switch (b[index]) - { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - case ClassWriter.INT: - case ClassWriter.FLOAT: - case ClassWriter.NAME_TYPE: - case ClassWriter.INDY: - size = 5; - break; - case ClassWriter.LONG: - case ClassWriter.DOUBLE: - size = 9; - ++i; - break; - case ClassWriter.UTF8: - size = 3 + readUnsignedShort(index + 1); - if (size > max) - { - max = size; - } - break; - case ClassWriter.HANDLE: - size = 4; - break; - // case ClassWriter.CLASS: - // case ClassWriter.STR: - // case ClassWriter.MTYPE - default: - size = 3; - break; - } - index += size; - } - maxStringLength = max; - // the class header information starts just after the constant pool - header = index; - } - - /** - * Returns the class's access flags (see {@link Opcodes}). This value may - * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 - * and those flags are represented by attributes. - * - * @return the class access flags - * - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public int getAccess() - { - return readUnsignedShort(header); - } - - /** - * Returns the internal name of the class (see - * {@link Type#getInternalName() getInternalName}). - * - * @return the internal class name - * - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getClassName() - { - return readClass(header + 2, new char[maxStringLength]); - } - - /** - * Returns the internal of name of the super class (see - * {@link Type#getInternalName() getInternalName}). For interfaces, the - * super class is {@link Object}. - * - * @return the internal name of super class, or null for - * {@link Object} class. - * - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String getSuperName() - { - return readClass(header + 4, new char[maxStringLength]); - } - - /** - * Returns the internal names of the class's interfaces (see - * {@link Type#getInternalName() getInternalName}). - * - * @return the array of internal names for all implemented interfaces or - * null. - * - * @see ClassVisitor#visit(int, int, String, String, String, String[]) - */ - public String[] getInterfaces() - { - int index = header + 6; - int n = readUnsignedShort(index); - String[] interfaces = new String[n]; - if (n > 0) - { - char[] buf = new char[maxStringLength]; - for (int i = 0; i < n; ++i) - { - index += 2; - interfaces[i] = readClass(index, buf); - } - } - return interfaces; - } - - /** - * Copies the constant pool data into the given {@link ClassWriter}. Should - * be called before the {@link #accept(ClassVisitor,int)} method. - * - * @param classWriter - * the {@link ClassWriter} to copy constant pool into. - */ - void copyPool(final ClassWriter classWriter) - { - char[] buf = new char[maxStringLength]; - int ll = items.length; - Item[] items2 = new Item[ll]; - for (int i = 1; i < ll; i++) - { - int index = items[i]; - int tag = b[index - 1]; - Item item = new Item(i); - int nameType; - switch (tag) - { - case ClassWriter.FIELD: - case ClassWriter.METH: - case ClassWriter.IMETH: - nameType = items[readUnsignedShort(index + 2)]; - item.set(tag, readClass(index, buf), readUTF8(nameType, buf), - readUTF8(nameType + 2, buf)); - break; - case ClassWriter.INT: - item.set(readInt(index)); - break; - case ClassWriter.FLOAT: - item.set(Float.intBitsToFloat(readInt(index))); - break; - case ClassWriter.NAME_TYPE: - item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), - null); - break; - case ClassWriter.LONG: - item.set(readLong(index)); - ++i; - break; - case ClassWriter.DOUBLE: - item.set(Double.longBitsToDouble(readLong(index))); - ++i; - break; - case ClassWriter.UTF8: - { - String s = strings[i]; - if (s == null) - { - index = items[i]; - s = strings[i] = readUTF(index + 2, - readUnsignedShort(index), buf); - } - item.set(tag, s, null, null); - break; - } - case ClassWriter.HANDLE: - { - int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; - nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; - item.set(ClassWriter.HANDLE_BASE + readByte(index), - readClass(fieldOrMethodRef, buf), - readUTF8(nameType, buf), readUTF8(nameType + 2, buf)); - break; - } - case ClassWriter.INDY: - if (classWriter.bootstrapMethods == null) - { - copyBootstrapMethods(classWriter, items2, buf); - } - nameType = items[readUnsignedShort(index + 2)]; - item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), - readUnsignedShort(index)); - break; - // case ClassWriter.STR: - // case ClassWriter.CLASS: - // case ClassWriter.MTYPE - default: - item.set(tag, readUTF8(index, buf), null, null); - break; - } - - int index2 = item.hashCode % items2.length; - item.next = items2[index2]; - items2[index2] = item; - } - - int off = items[1] - 1; - classWriter.pool.putByteArray(b, off, header - off); - classWriter.items = items2; - classWriter.threshold = (int) (0.75d * ll); - classWriter.index = ll; - } - - /** - * Copies the bootstrap method data into the given {@link ClassWriter}. - * Should be called before the {@link #accept(ClassVisitor,int)} method. - * - * @param classWriter - * the {@link ClassWriter} to copy bootstrap methods into. - */ - private void copyBootstrapMethods(final ClassWriter classWriter, - final Item[] items, final char[] c) - { - // finds the "BootstrapMethods" attribute - int u = getAttributes(); - boolean found = false; - for (int i = readUnsignedShort(u); i > 0; --i) - { - String attrName = readUTF8(u + 2, c); - if ("BootstrapMethods".equals(attrName)) - { - found = true; - break; - } - u += 6 + readInt(u + 4); - } - if (!found) - { - return; - } - // copies the bootstrap methods in the class writer - int boostrapMethodCount = readUnsignedShort(u + 8); - for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) - { - int position = v - u - 10; - int hashCode = readConst(readUnsignedShort(v), c).hashCode(); - for (int k = readUnsignedShort(v + 2); k > 0; --k) - { - hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); - v += 2; - } - v += 4; - Item item = new Item(j); - item.set(position, hashCode & 0x7FFFFFFF); - int index = item.hashCode % items.length; - item.next = items[index]; - items[index] = item; - } - int attrSize = readInt(u + 4); - ByteVector bootstrapMethods = new ByteVector(attrSize + 62); - bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); - classWriter.bootstrapMethodsCount = boostrapMethodCount; - classWriter.bootstrapMethods = bootstrapMethods; - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param is - * an input stream from which to read the class. - * @throws IOException - * if a problem occurs during reading. - */ - public ClassReader(final InputStream is) throws IOException - { - this(readClass(is, false)); - } - - /** - * Constructs a new {@link ClassReader} object. - * - * @param name - * the binary qualified name of the class to be read. - * @throws IOException - * if an exception occurs during reading. - */ - public ClassReader(final String name) throws IOException - { - this(readClass( - ClassLoader.getSystemResourceAsStream(name.replace('.', '/') - + ".class"), true)); - } - - /** - * Reads the bytecode of a class. - * - * @param is - * an input stream from which to read the class. - * @param close - * true to close the input stream after reading. - * @return the bytecode read from the given input stream. - * @throws IOException - * if a problem occurs during reading. - */ - private static byte[] readClass(final InputStream is, boolean close) - throws IOException - { - if (is == null) - { - throw new IOException("Class not found"); - } - try - { - byte[] b = new byte[is.available()]; - int len = 0; - while (true) - { - int n = is.read(b, len, b.length - len); - if (n == -1) - { - if (len < b.length) - { - byte[] c = new byte[len]; - System.arraycopy(b, 0, c, 0, len); - b = c; - } - return b; - } - len += n; - if (len == b.length) - { - int last = is.read(); - if (last < 0) - { - return b; - } - byte[] c = new byte[b.length + 1000]; - System.arraycopy(b, 0, c, 0, len); - c[len++] = (byte) last; - b = c; - } - } - } - finally - { - if (close) - { - is.close(); - } - } - } - - // ------------------------------------------------------------------------ - // Public methods - // ------------------------------------------------------------------------ - - /** - * Makes the given visitor visit the Java class of this {@link ClassReader} - * . This class is the one specified in the constructor (see - * {@link #ClassReader(byte[]) ClassReader}). - * - * @param classVisitor - * the visitor that must visit this class. - * @param flags - * option flags that can be used to modify the default behavior - * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} - * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. - */ - public void accept(final ClassVisitor classVisitor, final int flags) - { - accept(classVisitor, new Attribute[0], flags); - } - - /** - * Makes the given visitor visit the Java class of this {@link ClassReader}. - * This class is the one specified in the constructor (see - * {@link #ClassReader(byte[]) ClassReader}). - * - * @param classVisitor - * the visitor that must visit this class. - * @param attrs - * prototypes of the attributes that must be parsed during the - * visit of the class. Any attribute whose type is not equal to - * the type of one the prototypes will not be parsed: its byte - * array value will be passed unchanged to the ClassWriter. - * This may corrupt it if this value contains references to - * the constant pool, or has syntactic or semantic links with a - * class element that has been transformed by a class adapter - * between the reader and the writer. - * @param flags - * option flags that can be used to modify the default behavior - * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} - * , {@link #SKIP_FRAMES}, {@link #SKIP_CODE}. - */ - public void accept(final ClassVisitor classVisitor, - final Attribute[] attrs, final int flags) - { - int u = header; // current offset in the class file - char[] c = new char[maxStringLength]; // buffer used to read strings - - Context context = new Context(); - context.attrs = attrs; - context.flags = flags; - context.buffer = c; - - // reads the class declaration - int access = readUnsignedShort(u); - String name = readClass(u + 2, c); - String superClass = readClass(u + 4, c); - String[] interfaces = new String[readUnsignedShort(u + 6)]; - u += 8; - for (int i = 0; i < interfaces.length; ++i) - { - interfaces[i] = readClass(u, c); - u += 2; - } - - // reads the class attributes - String signature = null; - String sourceFile = null; - String sourceDebug = null; - String enclosingOwner = null; - String enclosingName = null; - String enclosingDesc = null; - int anns = 0; - int ianns = 0; - int innerClasses = 0; - Attribute attributes = null; - - u = getAttributes(); - for (int i = readUnsignedShort(u); i > 0; --i) - { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("SourceFile".equals(attrName)) - { - sourceFile = readUTF8(u + 8, c); - } - else if ("InnerClasses".equals(attrName)) - { - innerClasses = u + 8; - } - else if ("EnclosingMethod".equals(attrName)) - { - enclosingOwner = readClass(u + 8, c); - int item = readUnsignedShort(u + 10); - if (item != 0) - { - enclosingName = readUTF8(items[item], c); - enclosingDesc = readUTF8(items[item] + 2, c); - } - } - else if (SIGNATURES && "Signature".equals(attrName)) - { - signature = readUTF8(u + 8, c); - } - else if (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) - { - anns = u + 8; - } - else if ("Deprecated".equals(attrName)) - { - access |= Opcodes.ACC_DEPRECATED; - } - else if ("Synthetic".equals(attrName)) - { - access |= Opcodes.ACC_SYNTHETIC - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } - else if ("SourceDebugExtension".equals(attrName)) - { - int len = readInt(u + 4); - sourceDebug = readUTF(u + 8, len, new char[len]); - } - else if (ANNOTATIONS - && "RuntimeInvisibleAnnotations".equals(attrName)) - { - ianns = u + 8; - } - else if ("BootstrapMethods".equals(attrName)) - { - int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; - for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) - { - bootstrapMethods[j] = v; - v += 2 + readUnsignedShort(v + 2) << 1; - } - context.bootstrapMethods = bootstrapMethods; - } - else - { - Attribute attr = readAttribute(attrs, attrName, u + 8, - readInt(u + 4), c, -1, null); - if (attr != null) - { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - - // visits the class declaration - classVisitor.visit(readInt(items[1] - 7), access, name, signature, - superClass, interfaces); - - // visits the source and debug info - if ((flags & SKIP_DEBUG) == 0 - && (sourceFile != null || sourceDebug != null)) - { - classVisitor.visitSource(sourceFile, sourceDebug); - } - - // visits the outer class - if (enclosingOwner != null) - { - classVisitor.visitOuterClass(enclosingOwner, enclosingName, - enclosingDesc); - } - - // visits the class annotations - if (ANNOTATIONS && anns != 0) - { - for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - classVisitor.visitAnnotation(readUTF8(v, c), true)); - } - } - if (ANNOTATIONS && ianns != 0) - { - for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - classVisitor.visitAnnotation(readUTF8(v, c), false)); - } - } - - // visits the attributes - while (attributes != null) - { - Attribute attr = attributes.next; - attributes.next = null; - classVisitor.visitAttribute(attributes); - attributes = attr; - } - - // visits the inner classes - if (innerClasses != 0) - { - int v = innerClasses + 2; - for (int i = readUnsignedShort(innerClasses); i > 0; --i) - { - classVisitor.visitInnerClass(readClass(v, c), - readClass(v + 2, c), readUTF8(v + 4, c), - readUnsignedShort(v + 6)); - v += 8; - } - } - - // visits the fields and methods - u = header + 10 + 2 * interfaces.length; - for (int i = readUnsignedShort(u - 2); i > 0; --i) - { - u = readField(classVisitor, context, u); - } - u += 2; - for (int i = readUnsignedShort(u - 2); i > 0; --i) - { - u = readMethod(classVisitor, context, u); - } - - // visits the end of the class - classVisitor.visitEnd(); - } - - /** - * Reads a field and makes the given visitor visit it. - * - * @param classVisitor - * the visitor that must visit the field. - * @param context - * information about the class being parsed. - * @param u - * the start offset of the field in the class file. - * @return the offset of the first byte following the field in the class. - */ - private int readField(final ClassVisitor classVisitor, - final Context context, int u) - { - // reads the field declaration - char[] c = context.buffer; - int access = readUnsignedShort(u); - String name = readUTF8(u + 2, c); - String desc = readUTF8(u + 4, c); - u += 6; - - // reads the field attributes - String signature = null; - int anns = 0; - int ianns = 0; - Object value = null; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) - { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("ConstantValue".equals(attrName)) - { - int item = readUnsignedShort(u + 8); - value = item == 0 ? null : readConst(item, c); - } - else if (SIGNATURES && "Signature".equals(attrName)) - { - signature = readUTF8(u + 8, c); - } - else if ("Deprecated".equals(attrName)) - { - access |= Opcodes.ACC_DEPRECATED; - } - else if ("Synthetic".equals(attrName)) - { - access |= Opcodes.ACC_SYNTHETIC - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } - else if (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) - { - anns = u + 8; - } - else if (ANNOTATIONS - && "RuntimeInvisibleAnnotations".equals(attrName)) - { - ianns = u + 8; - } - else - { - Attribute attr = readAttribute(context.attrs, attrName, u + 8, - readInt(u + 4), c, -1, null); - if (attr != null) - { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // visits the field declaration - FieldVisitor fv = classVisitor.visitField(access, name, desc, - signature, value); - if (fv == null) - { - return u; - } - - // visits the field annotations - if (ANNOTATIONS && anns != 0) - { - for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - fv.visitAnnotation(readUTF8(v, c), true)); - } - } - if (ANNOTATIONS && ianns != 0) - { - for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - fv.visitAnnotation(readUTF8(v, c), false)); - } - } - - // visits the field attributes - while (attributes != null) - { - Attribute attr = attributes.next; - attributes.next = null; - fv.visitAttribute(attributes); - attributes = attr; - } - - // visits the end of the field - fv.visitEnd(); - - return u; - } - - /** - * Reads a method and makes the given visitor visit it. - * - * @param classVisitor - * the visitor that must visit the method. - * @param context - * information about the class being parsed. - * @param u - * the start offset of the method in the class file. - * @return the offset of the first byte following the method in the class. - */ - private int readMethod(final ClassVisitor classVisitor, - final Context context, int u) - { - // reads the method declaration - char[] c = context.buffer; - int access = readUnsignedShort(u); - String name = readUTF8(u + 2, c); - String desc = readUTF8(u + 4, c); - u += 6; - - // reads the method attributes - int code = 0; - int exception = 0; - String[] exceptions = null; - String signature = null; - int anns = 0; - int ianns = 0; - int dann = 0; - int mpanns = 0; - int impanns = 0; - int firstAttribute = u; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) - { - String attrName = readUTF8(u + 2, c); - // tests are sorted in decreasing frequency order - // (based on frequencies observed on typical classes) - if ("Code".equals(attrName)) - { - if ((context.flags & SKIP_CODE) == 0) - { - code = u + 8; - } - } - else if ("Exceptions".equals(attrName)) - { - exceptions = new String[readUnsignedShort(u + 8)]; - exception = u + 10; - for (int j = 0; j < exceptions.length; ++j) - { - exceptions[j] = readClass(exception, c); - exception += 2; - } - } - else if (SIGNATURES && "Signature".equals(attrName)) - { - signature = readUTF8(u + 8, c); - } - else if ("Deprecated".equals(attrName)) - { - access |= Opcodes.ACC_DEPRECATED; - } - else if (ANNOTATIONS - && "RuntimeVisibleAnnotations".equals(attrName)) - { - anns = u + 8; - } - else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) - { - dann = u + 8; - } - else if ("Synthetic".equals(attrName)) - { - access |= Opcodes.ACC_SYNTHETIC - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; - } - else if (ANNOTATIONS - && "RuntimeInvisibleAnnotations".equals(attrName)) - { - ianns = u + 8; - } - else if (ANNOTATIONS - && "RuntimeVisibleParameterAnnotations".equals(attrName)) - { - mpanns = u + 8; - } - else if (ANNOTATIONS - && "RuntimeInvisibleParameterAnnotations".equals(attrName)) - { - impanns = u + 8; - } - else - { - Attribute attr = readAttribute(context.attrs, attrName, u + 8, - readInt(u + 4), c, -1, null); - if (attr != null) - { - attr.next = attributes; - attributes = attr; - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // visits the method declaration - MethodVisitor mv = classVisitor.visitMethod(access, name, desc, - signature, exceptions); - if (mv == null) - { - return u; - } - - /* - * if the returned MethodVisitor is in fact a MethodWriter, it means - * there is no method adapter between the reader and the writer. If, in - * addition, the writer's constant pool was copied from this reader - * (mw.cw.cr == this), and the signature and exceptions of the method - * have not been changed, then it is possible to skip all visit events - * and just copy the original code of the method to the writer (the - * access, name and descriptor can have been changed, this is not - * important since they are not copied as is from the reader). - */ - if (WRITER && mv instanceof MethodWriter) - { - MethodWriter mw = (MethodWriter) mv; - if (mw.cw.cr == this && signature == mw.signature) - { - boolean sameExceptions = false; - if (exceptions == null) - { - sameExceptions = mw.exceptionCount == 0; - } - else if (exceptions.length == mw.exceptionCount) - { - sameExceptions = true; - for (int j = exceptions.length - 1; j >= 0; --j) - { - exception -= 2; - if (mw.exceptions[j] != readUnsignedShort(exception)) - { - sameExceptions = false; - break; - } - } - } - if (sameExceptions) - { - /* - * we do not copy directly the code into MethodWriter to - * save a byte array copy operation. The real copy will be - * done in ClassWriter.toByteArray(). - */ - mw.classReaderOffset = firstAttribute; - mw.classReaderLength = u - firstAttribute; - return u; - } - } - } - - // visits the method annotations - if (ANNOTATIONS && dann != 0) - { - AnnotationVisitor dv = mv.visitAnnotationDefault(); - readAnnotationValue(dann, c, null, dv); - if (dv != null) - { - dv.visitEnd(); - } - } - if (ANNOTATIONS && anns != 0) - { - for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - mv.visitAnnotation(readUTF8(v, c), true)); - } - } - if (ANNOTATIONS && ianns != 0) - { - for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) - { - v = readAnnotationValues(v + 2, c, true, - mv.visitAnnotation(readUTF8(v, c), false)); - } - } - if (ANNOTATIONS && mpanns != 0) - { - readParameterAnnotations(mpanns, desc, c, true, mv); - } - if (ANNOTATIONS && impanns != 0) - { - readParameterAnnotations(impanns, desc, c, false, mv); - } - - // visits the method attributes - while (attributes != null) - { - Attribute attr = attributes.next; - attributes.next = null; - mv.visitAttribute(attributes); - attributes = attr; - } - - // visits the method code - if (code != 0) - { - context.access = access; - context.name = name; - context.desc = desc; - mv.visitCode(); - readCode(mv, context, code); - } - - // visits the end of the method - mv.visitEnd(); - - return u; - } - - /** - * Reads the bytecode of a method and makes the given visitor visit it. - * - * @param mv - * the visitor that must visit the method's code. - * @param context - * information about the class being parsed. - * @param u - * the start offset of the code attribute in the class file. - */ - private void readCode(final MethodVisitor mv, final Context context, int u) - { - // reads the header - byte[] b = this.b; - char[] c = context.buffer; - int maxStack = readUnsignedShort(u); - int maxLocals = readUnsignedShort(u + 2); - int codeLength = readInt(u + 4); - u += 8; - - // reads the bytecode to find the labels - int codeStart = u; - int codeEnd = u + codeLength; - Label[] labels = new Label[codeLength + 2]; - readLabel(codeLength + 1, labels); - while (u < codeEnd) - { - int offset = u - codeStart; - int opcode = b[u] & 0xFF; - switch (ClassWriter.TYPE[opcode]) - { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - u += 1; - break; - case ClassWriter.LABEL_INSN: - readLabel(offset + readShort(u + 1), labels); - u += 3; - break; - case ClassWriter.LABELW_INSN: - readLabel(offset + readInt(u + 1), labels); - u += 5; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) - { - u += 6; - } - else - { - u += 4; - } - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - readLabel(offset + readInt(u), labels); - for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) - { - readLabel(offset + readInt(u + 12), labels); - u += 4; - } - u += 12; - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - readLabel(offset + readInt(u), labels); - for (int i = readInt(u + 4); i > 0; --i) - { - readLabel(offset + readInt(u + 12), labels); - u += 8; - } - u += 8; - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - u += 5; - break; - // case MANA_INSN: - default: - u += 4; - break; - } - } - - // reads the try catch entries to find the labels, and also visits them - for (int i = readUnsignedShort(u); i > 0; --i) - { - Label start = readLabel(readUnsignedShort(u + 2), labels); - Label end = readLabel(readUnsignedShort(u + 4), labels); - Label handler = readLabel(readUnsignedShort(u + 6), labels); - String type = readUTF8(items[readUnsignedShort(u + 8)], c); - mv.visitTryCatchBlock(start, end, handler, type); - u += 8; - } - u += 2; - - // reads the code attributes - int varTable = 0; - int varTypeTable = 0; - boolean zip = true; - boolean unzip = (context.flags & EXPAND_FRAMES) != 0; - int stackMap = 0; - int stackMapSize = 0; - int frameCount = 0; - Context frame = null; - Attribute attributes = null; - - for (int i = readUnsignedShort(u); i > 0; --i) - { - String attrName = readUTF8(u + 2, c); - if ("LocalVariableTable".equals(attrName)) - { - if ((context.flags & SKIP_DEBUG) == 0) - { - varTable = u + 8; - for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) - { - int label = readUnsignedShort(v + 10); - if (labels[label] == null) - { - readLabel(label, labels).status |= Label.DEBUG; - } - label += readUnsignedShort(v + 12); - if (labels[label] == null) - { - readLabel(label, labels).status |= Label.DEBUG; - } - v += 10; - } - } - } - else if ("LocalVariableTypeTable".equals(attrName)) - { - varTypeTable = u + 8; - } - else if ("LineNumberTable".equals(attrName)) - { - if ((context.flags & SKIP_DEBUG) == 0) - { - for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) - { - int label = readUnsignedShort(v + 10); - if (labels[label] == null) - { - readLabel(label, labels).status |= Label.DEBUG; - } - labels[label].line = readUnsignedShort(v + 12); - v += 4; - } - } - } - else if (FRAMES && "StackMapTable".equals(attrName)) - { - if ((context.flags & SKIP_FRAMES) == 0) - { - stackMap = u + 10; - stackMapSize = readInt(u + 4); - frameCount = readUnsignedShort(u + 8); - } - /* - * here we do not extract the labels corresponding to the - * attribute content. This would require a full parsing of the - * attribute, which would need to be repeated in the second - * phase (see below). Instead the content of the attribute is - * read one frame at a time (i.e. after a frame has been - * visited, the next frame is read), and the labels it contains - * are also extracted one frame at a time. Thanks to the - * ordering of frames, having only a "one frame lookahead" is - * not a problem, i.e. it is not possible to see an offset - * smaller than the offset of the current insn and for which no - * Label exist. - */ - /* - * This is not true for UNINITIALIZED type offsets. We solve - * this by parsing the stack map table without a full decoding - * (see below). - */ - } - else if (FRAMES && "StackMap".equals(attrName)) - { - if ((context.flags & SKIP_FRAMES) == 0) - { - zip = false; - stackMap = u + 10; - stackMapSize = readInt(u + 4); - frameCount = readUnsignedShort(u + 8); - } - /* - * IMPORTANT! here we assume that the frames are ordered, as in - * the StackMapTable attribute, although this is not guaranteed - * by the attribute format. - */ - } - else - { - for (int j = 0; j < context.attrs.length; ++j) - { - if (context.attrs[j].type.equals(attrName)) - { - Attribute attr = context.attrs[j].read(this, u + 8, - readInt(u + 4), c, codeStart - 8, labels); - if (attr != null) - { - attr.next = attributes; - attributes = attr; - } - } - } - } - u += 6 + readInt(u + 4); - } - u += 2; - - // generates the first (implicit) stack map frame - if (FRAMES && stackMap != 0) - { - /* - * for the first explicit frame the offset is not offset_delta + 1 - * but only offset_delta; setting the implicit frame offset to -1 - * allow the use of the "offset_delta + 1" rule in all cases - */ - frame = context; - frame.offset = -1; - frame.mode = 0; - frame.localCount = 0; - frame.localDiff = 0; - frame.stackCount = 0; - frame.local = new Object[maxLocals]; - frame.stack = new Object[maxStack]; - if (unzip) - { - getImplicitFrame(context); - } - /* - * Finds labels for UNINITIALIZED frame types. Instead of decoding - * each element of the stack map table, we look for 3 consecutive - * bytes that "look like" an UNINITIALIZED type (tag 8, offset - * within code bounds, NEW instruction at this offset). We may find - * false positives (i.e. not real UNINITIALIZED types), but this - * should be rare, and the only consequence will be the creation of - * an unneeded label. This is better than creating a label for each - * NEW instruction, and faster than fully decoding the whole stack - * map table. - */ - for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) - { - if (b[i] == 8) - { // UNINITIALIZED FRAME TYPE - int v = readUnsignedShort(i + 1); - if (v >= 0 && v < codeLength) - { - if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) - { - readLabel(v, labels); - } - } - } - } - } - - // visits the instructions - u = codeStart; - while (u < codeEnd) - { - int offset = u - codeStart; - - // visits the label and line number for this offset, if any - Label l = labels[offset]; - if (l != null) - { - mv.visitLabel(l); - if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) - { - mv.visitLineNumber(l.line, l); - } - } - - // visits the frame for this offset, if any - while (FRAMES && frame != null - && (frame.offset == offset || frame.offset == -1)) - { - // if there is a frame for this offset, makes the visitor visit - // it, and reads the next frame if there is one. - if (frame.offset != -1) - { - if (!zip || unzip) - { - mv.visitFrame(Opcodes.F_NEW, frame.localCount, - frame.local, frame.stackCount, frame.stack); - } - else - { - mv.visitFrame(frame.mode, frame.localDiff, frame.local, - frame.stackCount, frame.stack); - } - } - if (frameCount > 0) - { - stackMap = readFrame(stackMap, zip, unzip, labels, frame); - --frameCount; - } - else - { - frame = null; - } - } - - // visits the instruction at this offset - int opcode = b[u] & 0xFF; - switch (ClassWriter.TYPE[opcode]) - { - case ClassWriter.NOARG_INSN: - mv.visitInsn(opcode); - u += 1; - break; - case ClassWriter.IMPLVAR_INSN: - if (opcode > Opcodes.ISTORE) - { - opcode -= 59; // ISTORE_0 - mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), - opcode & 0x3); - } - else - { - opcode -= 26; // ILOAD_0 - mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); - } - u += 1; - break; - case ClassWriter.LABEL_INSN: - mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); - u += 3; - break; - case ClassWriter.LABELW_INSN: - mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); - u += 5; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) - { - mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); - u += 6; - } - else - { - mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); - u += 4; - } - break; - case ClassWriter.TABL_INSN: - { - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - int label = offset + readInt(u); - int min = readInt(u + 4); - int max = readInt(u + 8); - Label[] table = new Label[max - min + 1]; - u += 12; - for (int i = 0; i < table.length; ++i) - { - table[i] = labels[offset + readInt(u)]; - u += 4; - } - mv.visitTableSwitchInsn(min, max, labels[label], table); - break; - } - case ClassWriter.LOOK_INSN: - { - // skips 0 to 3 padding bytes - u = u + 4 - (offset & 3); - // reads instruction - int label = offset + readInt(u); - int len = readInt(u + 4); - int[] keys = new int[len]; - Label[] values = new Label[len]; - u += 8; - for (int i = 0; i < len; ++i) - { - keys[i] = readInt(u); - values[i] = labels[offset + readInt(u + 4)]; - u += 8; - } - mv.visitLookupSwitchInsn(labels[label], keys, values); - break; - } - case ClassWriter.VAR_INSN: - mv.visitVarInsn(opcode, b[u + 1] & 0xFF); - u += 2; - break; - case ClassWriter.SBYTE_INSN: - mv.visitIntInsn(opcode, b[u + 1]); - u += 2; - break; - case ClassWriter.SHORT_INSN: - mv.visitIntInsn(opcode, readShort(u + 1)); - u += 3; - break; - case ClassWriter.LDC_INSN: - mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); - u += 2; - break; - case ClassWriter.LDCW_INSN: - mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); - u += 3; - break; - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.ITFMETH_INSN: - { - int cpIndex = items[readUnsignedShort(u + 1)]; - String iowner = readClass(cpIndex, c); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - if (opcode < Opcodes.INVOKEVIRTUAL) - { - mv.visitFieldInsn(opcode, iowner, iname, idesc); - } - else - { - mv.visitMethodInsn(opcode, iowner, iname, idesc); - } - if (opcode == Opcodes.INVOKEINTERFACE) - { - u += 5; - } - else - { - u += 3; - } - break; - } - case ClassWriter.INDYMETH_INSN: - { - int cpIndex = items[readUnsignedShort(u + 1)]; - int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; - Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); - int bsmArgCount = readUnsignedShort(bsmIndex + 2); - Object[] bsmArgs = new Object[bsmArgCount]; - bsmIndex += 4; - for (int i = 0; i < bsmArgCount; i++) - { - bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); - bsmIndex += 2; - } - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String iname = readUTF8(cpIndex, c); - String idesc = readUTF8(cpIndex + 2, c); - mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); - u += 5; - break; - } - case ClassWriter.TYPE_INSN: - mv.visitTypeInsn(opcode, readClass(u + 1, c)); - u += 3; - break; - case ClassWriter.IINC_INSN: - mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); - u += 3; - break; - // case MANA_INSN: - default: - mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); - u += 4; - break; - } - } - if (labels[codeLength] != null) - { - mv.visitLabel(labels[codeLength]); - } - - // visits the local variable tables - if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) - { - int[] typeTable = null; - if (varTypeTable != 0) - { - u = varTypeTable + 2; - typeTable = new int[readUnsignedShort(varTypeTable) * 3]; - for (int i = typeTable.length; i > 0;) - { - typeTable[--i] = u + 6; // signature - typeTable[--i] = readUnsignedShort(u + 8); // index - typeTable[--i] = readUnsignedShort(u); // start - u += 10; - } - } - u = varTable + 2; - for (int i = readUnsignedShort(varTable); i > 0; --i) - { - int start = readUnsignedShort(u); - int length = readUnsignedShort(u + 2); - int index = readUnsignedShort(u + 8); - String vsignature = null; - if (typeTable != null) - { - for (int j = 0; j < typeTable.length; j += 3) - { - if (typeTable[j] == start && typeTable[j + 1] == index) - { - vsignature = readUTF8(typeTable[j + 2], c); - break; - } - } - } - mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), - vsignature, labels[start], labels[start + length], - index); - u += 10; - } - } - - // visits the code attributes - while (attributes != null) - { - Attribute attr = attributes.next; - attributes.next = null; - mv.visitAttribute(attributes); - attributes = attr; - } - - // visits the max stack and max locals values - mv.visitMaxs(maxStack, maxLocals); - } - - /** - * Reads parameter annotations and makes the given visitor visit them. - * - * @param v - * start offset in {@link #b b} of the annotations to be read. - * @param desc - * the method descriptor. - * @param buf - * buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or {@link #readConst - * readConst}. - * @param visible - * true if the annotations to be read are visible at - * runtime. - * @param mv - * the visitor that must visit the annotations. - */ - private void readParameterAnnotations(int v, final String desc, - final char[] buf, final boolean visible, final MethodVisitor mv) - { - int i; - int n = b[v++] & 0xFF; - // workaround for a bug in javac (javac compiler generates a parameter - // annotation array whose size is equal to the number of parameters in - // the Java source file, while it should generate an array whose size is - // equal to the number of parameters in the method descriptor - which - // includes the synthetic parameters added by the compiler). This work- - // around supposes that the synthetic parameters are the first ones. - int synthetics = Type.getArgumentTypes(desc).length - n; - AnnotationVisitor av; - for (i = 0; i < synthetics; ++i) - { - // virtual annotation to detect synthetic parameters in MethodWriter - av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); - if (av != null) - { - av.visitEnd(); - } - } - for (; i < n + synthetics; ++i) - { - int j = readUnsignedShort(v); - v += 2; - for (; j > 0; --j) - { - av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible); - v = readAnnotationValues(v + 2, buf, true, av); - } - } - } - - /** - * Reads the values of an annotation and makes the given visitor visit them. - * - * @param v - * the start offset in {@link #b b} of the values to be read - * (including the unsigned short that gives the number of - * values). - * @param buf - * buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or {@link #readConst - * readConst}. - * @param named - * if the annotation values are named or not. - * @param av - * the visitor that must visit the values. - * @return the end offset of the annotation values. - */ - private int readAnnotationValues(int v, final char[] buf, - final boolean named, final AnnotationVisitor av) - { - int i = readUnsignedShort(v); - v += 2; - if (named) - { - for (; i > 0; --i) - { - v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); - } - } - else - { - for (; i > 0; --i) - { - v = readAnnotationValue(v, buf, null, av); - } - } - if (av != null) - { - av.visitEnd(); - } - return v; - } - - /** - * Reads a value of an annotation and makes the given visitor visit it. - * - * @param v - * the start offset in {@link #b b} of the value to be read - * (not including the value name constant pool index). - * @param buf - * buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or {@link #readConst - * readConst}. - * @param name - * the name of the value to be read. - * @param av - * the visitor that must visit the value. - * @return the end offset of the annotation value. - */ - private int readAnnotationValue(int v, final char[] buf, final String name, - final AnnotationVisitor av) - { - int i; - if (av == null) - { - switch (b[v] & 0xFF) - { - case 'e': // enum_const_value - return v + 5; - case '@': // annotation_value - return readAnnotationValues(v + 3, buf, true, null); - case '[': // array_value - return readAnnotationValues(v + 1, buf, false, null); - default: - return v + 3; - } - } - switch (b[v++] & 0xFF) - { - case 'I': // pointer to CONSTANT_Integer - case 'J': // pointer to CONSTANT_Long - case 'F': // pointer to CONSTANT_Float - case 'D': // pointer to CONSTANT_Double - av.visit(name, readConst(readUnsignedShort(v), buf)); - v += 2; - break; - case 'B': // pointer to CONSTANT_Byte - av.visit(name, - new Byte((byte) readInt(items[readUnsignedShort(v)]))); - v += 2; - break; - case 'Z': // pointer to CONSTANT_Boolean - av.visit(name, - readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE - : Boolean.TRUE); - v += 2; - break; - case 'S': // pointer to CONSTANT_Short - av.visit(name, new Short( - (short) readInt(items[readUnsignedShort(v)]))); - v += 2; - break; - case 'C': // pointer to CONSTANT_Char - av.visit(name, new Character( - (char) readInt(items[readUnsignedShort(v)]))); - v += 2; - break; - case 's': // pointer to CONSTANT_Utf8 - av.visit(name, readUTF8(v, buf)); - v += 2; - break; - case 'e': // enum_const_value - av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); - v += 4; - break; - case 'c': // class_info - av.visit(name, Type.getType(readUTF8(v, buf))); - v += 2; - break; - case '@': // annotation_value - v = readAnnotationValues(v + 2, buf, true, - av.visitAnnotation(name, readUTF8(v, buf))); - break; - case '[': // array_value - int size = readUnsignedShort(v); - v += 2; - if (size == 0) - { - return readAnnotationValues(v - 2, buf, false, - av.visitArray(name)); - } - switch (this.b[v++] & 0xFF) - { - case 'B': - byte[] bv = new byte[size]; - for (i = 0; i < size; i++) - { - bv[i] = (byte) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, bv); - --v; - break; - case 'Z': - boolean[] zv = new boolean[size]; - for (i = 0; i < size; i++) - { - zv[i] = readInt(items[readUnsignedShort(v)]) != 0; - v += 3; - } - av.visit(name, zv); - --v; - break; - case 'S': - short[] sv = new short[size]; - for (i = 0; i < size; i++) - { - sv[i] = (short) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, sv); - --v; - break; - case 'C': - char[] cv = new char[size]; - for (i = 0; i < size; i++) - { - cv[i] = (char) readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, cv); - --v; - break; - case 'I': - int[] iv = new int[size]; - for (i = 0; i < size; i++) - { - iv[i] = readInt(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, iv); - --v; - break; - case 'J': - long[] lv = new long[size]; - for (i = 0; i < size; i++) - { - lv[i] = readLong(items[readUnsignedShort(v)]); - v += 3; - } - av.visit(name, lv); - --v; - break; - case 'F': - float[] fv = new float[size]; - for (i = 0; i < size; i++) - { - fv[i] = Float - .intBitsToFloat(readInt(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, fv); - --v; - break; - case 'D': - double[] dv = new double[size]; - for (i = 0; i < size; i++) - { - dv[i] = Double - .longBitsToDouble(readLong(items[readUnsignedShort(v)])); - v += 3; - } - av.visit(name, dv); - --v; - break; - default: - v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); - } - } - return v; - } - - /** - * Computes the implicit frame of the method currently being parsed (as - * defined in the given {@link Context}) and stores it in the given context. - * - * @param frame - * information about the class being parsed. - */ - private void getImplicitFrame(final Context frame) - { - String desc = frame.desc; - Object[] locals = frame.local; - int local = 0; - if ((frame.access & Opcodes.ACC_STATIC) == 0) - { - if ("".equals(frame.name)) - { - locals[local++] = Opcodes.UNINITIALIZED_THIS; - } - else - { - locals[local++] = readClass(header + 2, frame.buffer); - } - } - int i = 1; - loop: while (true) - { - int j = i; - switch (desc.charAt(i++)) - { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - locals[local++] = Opcodes.INTEGER; - break; - case 'F': - locals[local++] = Opcodes.FLOAT; - break; - case 'J': - locals[local++] = Opcodes.LONG; - break; - case 'D': - locals[local++] = Opcodes.DOUBLE; - break; - case '[': - while (desc.charAt(i) == '[') - { - ++i; - } - if (desc.charAt(i) == 'L') - { - ++i; - while (desc.charAt(i) != ';') - { - ++i; - } - } - locals[local++] = desc.substring(j, ++i); - break; - case 'L': - while (desc.charAt(i) != ';') - { - ++i; - } - locals[local++] = desc.substring(j + 1, i++); - break; - default: - break loop; - } - } - frame.localCount = local; - } - - /** - * Reads a stack map frame and stores the result in the given - * {@link Context} object. - * - * @param stackMap - * the start offset of a stack map frame in the class file. - * @param zip - * if the stack map frame at stackMap is compressed or not. - * @param unzip - * if the stack map frame must be uncompressed. - * @param labels - * the labels of the method currently being parsed, indexed by - * their offset. A new label for the parsed stack map frame is - * stored in this array if it does not already exist. - * @param frame - * where the parsed stack map frame must be stored. - * @return the offset of the first byte following the parsed frame. - */ - private int readFrame(int stackMap, boolean zip, boolean unzip, - Label[] labels, Context frame) - { - char[] c = frame.buffer; - int tag; - int delta; - if (zip) - { - tag = b[stackMap++] & 0xFF; - } - else - { - tag = MethodWriter.FULL_FRAME; - frame.offset = -1; - } - frame.localDiff = 0; - if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) - { - delta = tag; - frame.mode = Opcodes.F_SAME; - frame.stackCount = 0; - } - else if (tag < MethodWriter.RESERVED) - { - delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; - stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); - frame.mode = Opcodes.F_SAME1; - frame.stackCount = 1; - } - else - { - delta = readUnsignedShort(stackMap); - stackMap += 2; - if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - { - stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); - frame.mode = Opcodes.F_SAME1; - frame.stackCount = 1; - } - else if (tag >= MethodWriter.CHOP_FRAME - && tag < MethodWriter.SAME_FRAME_EXTENDED) - { - frame.mode = Opcodes.F_CHOP; - frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; - frame.localCount -= frame.localDiff; - frame.stackCount = 0; - } - else if (tag == MethodWriter.SAME_FRAME_EXTENDED) - { - frame.mode = Opcodes.F_SAME; - frame.stackCount = 0; - } - else if (tag < MethodWriter.FULL_FRAME) - { - int local = unzip ? frame.localCount : 0; - for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) - { - stackMap = readFrameType(frame.local, local++, stackMap, c, - labels); - } - frame.mode = Opcodes.F_APPEND; - frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; - frame.localCount += frame.localDiff; - frame.stackCount = 0; - } - else - { // if (tag == FULL_FRAME) { - frame.mode = Opcodes.F_FULL; - int n = readUnsignedShort(stackMap); - stackMap += 2; - frame.localDiff = n; - frame.localCount = n; - for (int local = 0; n > 0; n--) - { - stackMap = readFrameType(frame.local, local++, stackMap, c, - labels); - } - n = readUnsignedShort(stackMap); - stackMap += 2; - frame.stackCount = n; - for (int stack = 0; n > 0; n--) - { - stackMap = readFrameType(frame.stack, stack++, stackMap, c, - labels); - } - } - } - frame.offset += delta + 1; - readLabel(frame.offset, labels); - return stackMap; - } - - /** - * Reads a stack map frame type and stores it at the given index in the - * given array. - * - * @param frame - * the array where the parsed type must be stored. - * @param index - * the index in 'frame' where the parsed type must be stored. - * @param v - * the start offset of the stack map frame type to read. - * @param buf - * a buffer to read strings. - * @param labels - * the labels of the method currently being parsed, indexed by - * their offset. If the parsed type is an Uninitialized type, a - * new label for the corresponding NEW instruction is stored in - * this array if it does not already exist. - * @return the offset of the first byte after the parsed type. - */ - private int readFrameType(final Object[] frame, final int index, int v, - final char[] buf, final Label[] labels) - { - int type = b[v++] & 0xFF; - switch (type) - { - case 0: - frame[index] = Opcodes.TOP; - break; - case 1: - frame[index] = Opcodes.INTEGER; - break; - case 2: - frame[index] = Opcodes.FLOAT; - break; - case 3: - frame[index] = Opcodes.DOUBLE; - break; - case 4: - frame[index] = Opcodes.LONG; - break; - case 5: - frame[index] = Opcodes.NULL; - break; - case 6: - frame[index] = Opcodes.UNINITIALIZED_THIS; - break; - case 7: // Object - frame[index] = readClass(v, buf); - v += 2; - break; - default: // Uninitialized - frame[index] = readLabel(readUnsignedShort(v), labels); - v += 2; - } - return v; - } - - /** - * Returns the label corresponding to the given offset. The default - * implementation of this method creates a label for the given offset if it - * has not been already created. - * - * @param offset - * a bytecode offset in a method. - * @param labels - * the already created labels, indexed by their offset. If a - * label already exists for offset this method must not create a - * new one. Otherwise it must store the new label in this array. - * @return a non null Label, which must be equal to labels[offset]. - */ - protected Label readLabel(int offset, Label[] labels) - { - if (labels[offset] == null) - { - labels[offset] = new Label(); - } - return labels[offset]; - } - - /** - * Returns the start index of the attribute_info structure of this class. - * - * @return the start index of the attribute_info structure of this class. - */ - private int getAttributes() - { - // skips the header - int u = header + 8 + readUnsignedShort(header + 6) * 2; - // skips fields and methods - for (int i = readUnsignedShort(u); i > 0; --i) - { - for (int j = readUnsignedShort(u + 8); j > 0; --j) - { - u += 6 + readInt(u + 12); - } - u += 8; - } - u += 2; - for (int i = readUnsignedShort(u); i > 0; --i) - { - for (int j = readUnsignedShort(u + 8); j > 0; --j) - { - u += 6 + readInt(u + 12); - } - u += 8; - } - // the attribute_info structure starts just after the methods - return u + 2; - } - - /** - * Reads an attribute in {@link #b b}. - * - * @param attrs - * prototypes of the attributes that must be parsed during the - * visit of the class. Any attribute whose type is not equal to - * the type of one the prototypes is ignored (i.e. an empty - * {@link Attribute} instance is returned). - * @param type - * the type of the attribute. - * @param off - * index of the first byte of the attribute's content in - * {@link #b b}. The 6 attribute header bytes, containing the - * type and the length of the attribute, are not taken into - * account here (they have already been read). - * @param len - * the length of the attribute's content. - * @param buf - * buffer to be used to call {@link #readUTF8 readUTF8}, - * {@link #readClass(int,char[]) readClass} or {@link #readConst - * readConst}. - * @param codeOff - * index of the first byte of code's attribute content in - * {@link #b 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 null if the - * attribute to be read is not a code attribute. - * @return the attribute that has been read, or null to skip this - * attribute. - */ - private Attribute readAttribute(final Attribute[] attrs, final String type, - final int off, final int len, final char[] buf, final int codeOff, - final Label[] labels) - { - for (int i = 0; i < attrs.length; ++i) - { - if (attrs[i].type.equals(type)) - { - return attrs[i].read(this, off, len, buf, codeOff, labels); - } - } - return new Attribute(type).read(this, off, len, null, -1, null); - } - - // ------------------------------------------------------------------------ - // Utility methods: low level parsing - // ------------------------------------------------------------------------ - - /** - * Returns the number of constant pool items in {@link #b b}. - * - * @return the number of constant pool items in {@link #b b}. - */ - public int getItemCount() - { - return items.length; - } - - /** - * Returns the start index of the constant pool item in {@link #b b}, plus - * one. This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. - * - * @param item - * the index a constant pool item. - * @return the start index of the constant pool item in {@link #b b}, plus - * one. - */ - public int getItem(final int item) - { - return items[item]; - } - - /** - * Returns the maximum length of the strings contained in the constant pool - * of the class. - * - * @return the maximum length of the strings contained in the constant pool - * of the class. - */ - public int getMaxStringLength() - { - return maxStringLength; - } - - /** - * Reads a byte value in {@link #b b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @param index - * the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readByte(final int index) - { - return b[index] & 0xFF; - } - - /** - * Reads an unsigned short value in {@link #b b}. This method is intended - * for {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @param index - * the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readUnsignedShort(final int index) - { - byte[] b = this.b; - return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); - } - - /** - * Reads a signed short value in {@link #b b}. This method is intended - * for {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @param index - * the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public short readShort(final int index) - { - byte[] b = this.b; - return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); - } - - /** - * Reads a signed int value in {@link #b b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @param index - * the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public int readInt(final int index) - { - byte[] b = this.b; - return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) - | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); - } - - /** - * Reads a signed long value in {@link #b b}. This method is intended for - * {@link Attribute} sub classes, and is normally not needed by class - * generators or adapters. - * - * @param index - * the start index of the value to be read in {@link #b b}. - * @return the read value. - */ - public long readLong(final int index) - { - long l1 = readInt(index); - long l0 = readInt(index + 4) & 0xFFFFFFFFL; - return (l1 << 32) | l0; - } - - /** - * Reads an UTF8 string constant pool item in {@link #b b}. This method - * is intended for {@link Attribute} sub classes, and is normally not needed - * by class generators or adapters. - * - * @param index - * the start index of an unsigned short value in {@link #b b}, - * whose value is the index of an UTF8 constant pool item. - * @param buf - * buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. - * @return the String corresponding to the specified UTF8 item. - */ - public String readUTF8(int index, final char[] buf) - { - int item = readUnsignedShort(index); - if (index == 0 || item == 0 || item > strings.length) - { - return null; - } - String s = strings[item]; - if (s != null) - { - return s; - } - index = items[item]; - return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); - } - - /** - * Reads UTF8 string in {@link #b b}. - * - * @param index - * start offset of the UTF8 string to be read. - * @param utfLen - * length of the UTF8 string to be read. - * @param buf - * buffer to be used to read the string. This buffer must be - * sufficiently large. It is not automatically resized. - * @return the String corresponding to the specified UTF8 string. - */ - private String readUTF(int index, final int utfLen, final char[] buf) - { - int endIndex = index + utfLen; - byte[] b = this.b; - int strLen = 0; - int c; - int st = 0; - char cc = 0; - while (index < endIndex) - { - c = b[index++]; - switch (st) - { - case 0: - c = c & 0xFF; - if (c < 0x80) - { // 0xxxxxxx - buf[strLen++] = (char) c; - } - else if (c < 0xE0 && c > 0xBF) - { // 110x xxxx 10xx xxxx - cc = (char) (c & 0x1F); - st = 1; - } - else - { // 1110 xxxx 10xx xxxx 10xx xxxx - cc = (char) (c & 0x0F); - st = 2; - } - break; - - case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char - buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); - st = 0; - break; - - case 2: // byte 2 of 3-byte char - cc = (char) ((cc << 6) | (c & 0x3F)); - st = 1; - break; - } - } - return new String(buf, 0, strLen); - } - - /** - * Reads a class constant pool item in {@link #b b}. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by - * class generators or adapters. - * - * @param index - * the start index of an unsigned short value in {@link #b b}, - * whose value is the index of a class constant pool item. - * @param buf - * buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. - * @return the String corresponding to the specified class item. - */ - public String readClass(final int index, final char[] buf) - { - // computes the start index of the CONSTANT_Class item in b - // and reads the CONSTANT_Utf8 item designated by - // the first two bytes of this CONSTANT_Class item - return readUTF8(items[readUnsignedShort(index)], buf); - } - - /** - * Reads a numeric or string constant pool item in {@link #b b}. This - * method is intended for {@link Attribute} sub classes, and is normally not - * needed by class generators or adapters. - * - * @param item - * the index of a constant pool item. - * @param buf - * buffer to be used to read the item. This buffer must be - * sufficiently large. It is not automatically resized. - * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, - * {@link String}, {@link Type} or {@link Handle} corresponding to - * the given constant pool item. - */ - public Object readConst(final int item, final char[] buf) - { - int index = items[item]; - switch (b[index - 1]) - { - case ClassWriter.INT: - return new Integer(readInt(index)); - case ClassWriter.FLOAT: - return new Float(Float.intBitsToFloat(readInt(index))); - case ClassWriter.LONG: - return new Long(readLong(index)); - case ClassWriter.DOUBLE: - return new Double(Double.longBitsToDouble(readLong(index))); - case ClassWriter.CLASS: - return Type.getObjectType(readUTF8(index, buf)); - case ClassWriter.STR: - return readUTF8(index, buf); - case ClassWriter.MTYPE: - return Type.getMethodType(readUTF8(index, buf)); - default: // case ClassWriter.HANDLE_BASE + [1..9]: - int tag = readByte(index); - int[] items = this.items; - int cpIndex = items[readUnsignedShort(index + 1)]; - String owner = readClass(cpIndex, buf); - cpIndex = items[readUnsignedShort(cpIndex + 2)]; - String name = readUTF8(cpIndex, buf); - String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); - } - } +public class ClassReader { + + /** + * True to enable signatures support. + */ + static final boolean SIGNATURES = true; + + /** + * True to enable annotations support. + */ + static final boolean ANNOTATIONS = true; + + /** + * True to enable stack map frames support. + */ + static final boolean FRAMES = true; + + /** + * True to enable bytecode writing support. + */ + static final boolean WRITER = true; + + /** + * True to enable JSR_W and GOTO_W support. + */ + static final boolean RESIZE = true; + + /** + * Flag to skip method code. If this class is set CODE attribute won't be visited. + * This can be used, for example, to retrieve annotations for methods and method parameters. + */ + public static final int SKIP_CODE = 1; + + /** + * Flag to skip the debug information in the class. If this flag is set the debug information of + * the class is not visited, i.e. the {@link MethodVisitor#visitLocalVariable + * visitLocalVariable} and {@link MethodVisitor#visitLineNumber visitLineNumber} methods will + * not be called. + */ + public static final int SKIP_DEBUG = 2; + + /** + * Flag to skip the stack map frames in the class. If this flag is set the stack map frames of + * the class is not visited, i.e. the {@link MethodVisitor#visitFrame visitFrame} method will + * not be called. This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is + * used: it avoids visiting frames that will be ignored and recomputed from scratch in the class + * writer. + */ + public static final int SKIP_FRAMES = 4; + + /** + * Flag to expand the stack map frames. By default stack map frames are visited in their + * original format (i.e. "expanded" for classes whose version is less than V1_6, and + * "compressed" for the other classes). If this flag is set, stack map frames are always visited + * in expanded format (this option adds a decompression/recompression step in ClassReader and + * ClassWriter which degrades performances quite a lot). + */ + public static final int EXPAND_FRAMES = 8; + + /** + * The class to be parsed. The content of this array must not be modified. This field is + * intended for {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + */ + public final byte[] b; + + /** + * The start index of each constant pool item in {@link #b b}, plus one. The one byte offset + * skips the constant pool item tag that indicates its type. + */ + private final int[] items; + + /** + * The String objects corresponding to the CONSTANT_Utf8 items. This cache avoids multiple + * parsing of a given CONSTANT_Utf8 constant pool item, which GREATLY improves performances (by + * a factor 2 to 3). This caching strategy could be extended to all constant pool items, but its + * benefit would not be so great for these items (because they are much less expensive to parse + * than CONSTANT_Utf8 items). + */ + private final String[] strings; + + /** + * Maximum length of the strings contained in the constant pool of the class. + */ + private final int maxStringLength; + + /** + * Start index of the class header information (access, name...) in {@link #b b}. + */ + public final int header; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + */ + public ClassReader(final byte[] b) { + this(b, 0, b.length); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param b the bytecode of the class to be read. + * @param off the start offset of the class data. + * @param len the length of the class data. + */ + public ClassReader(final byte[] b, final int off, final int len) { + this.b = b; + // checks the class version + if (readShort(off + 6) > Opcodes.V1_8) { + throw new IllegalArgumentException(); + } + // parses the constant pool + items = new int[readUnsignedShort(off + 8)]; + int n = items.length; + strings = new String[n]; + int max = 0; + int index = off + 10; + for (int i = 1; i < n; ++i) { + items[i] = index + 1; + int size; + switch (b[index]) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + case ClassWriter.INT: + case ClassWriter.FLOAT: + case ClassWriter.NAME_TYPE: + case ClassWriter.INDY: + size = 5; + break; + case ClassWriter.LONG: + case ClassWriter.DOUBLE: + size = 9; + ++i; + break; + case ClassWriter.UTF8: + size = 3 + readUnsignedShort(index + 1); + if (size > max) { + max = size; + } + break; + case ClassWriter.HANDLE: + size = 4; + break; + // case ClassWriter.CLASS: + // case ClassWriter.STR: + // case ClassWriter.MTYPE + default: + size = 3; + break; + } + index += size; + } + maxStringLength = max; + // the class header information starts just after the constant pool + header = index; + } + + /** + * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated + * and Synthetic flags when bytecode is before 1.5 and those flags are represented by + * attributes. + * + * @return the class access flags + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public int getAccess() { + return readUnsignedShort(header); + } + + /** + * Returns the internal name of the class (see {@link Type#getInternalName() getInternalName}). + * + * @return the internal class name + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getClassName() { + return readClass(header + 2, new char[maxStringLength]); + } + + /** + * Returns the internal of name of the super class (see {@link Type#getInternalName() + * getInternalName}). For interfaces, the super class is {@link Object}. + * + * @return the internal name of super class, or null for {@link Object} class. + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String getSuperName() { + return readClass(header + 4, new char[maxStringLength]); + } + + /** + * Returns the internal names of the class's interfaces (see {@link Type#getInternalName() + * getInternalName}). + * + * @return the array of internal names for all implemented interfaces or null. + * + * @see ClassVisitor#visit(int, int, String, String, String, String[]) + */ + public String[] getInterfaces() { + int index = header + 6; + int n = readUnsignedShort(index); + String[] interfaces = new String[n]; + if (n > 0) { + char[] buf = new char[maxStringLength]; + for (int i = 0; i < n; ++i) { + index += 2; + interfaces[i] = readClass(index, buf); + } + } + return interfaces; + } + + /** + * Copies the constant pool data into the given {@link ClassWriter}. Should be called before the + * {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter the {@link ClassWriter} to copy constant pool into. + */ + void copyPool(final ClassWriter classWriter) { + char[] buf = new char[maxStringLength]; + int ll = items.length; + Item[] items2 = new Item[ll]; + for (int i = 1; i < ll; i++) { + int index = items[i]; + int tag = b[index - 1]; + Item item = new Item(i); + int nameType; + switch (tag) { + case ClassWriter.FIELD: + case ClassWriter.METH: + case ClassWriter.IMETH: + nameType = items[readUnsignedShort(index + 2)]; + item.set(tag, readClass(index, buf), readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + case ClassWriter.INT: + item.set(readInt(index)); + break; + case ClassWriter.FLOAT: + item.set(Float.intBitsToFloat(readInt(index))); + break; + case ClassWriter.NAME_TYPE: + item.set(tag, readUTF8(index, buf), readUTF8(index + 2, buf), null); + break; + case ClassWriter.LONG: + item.set(readLong(index)); + ++i; + break; + case ClassWriter.DOUBLE: + item.set(Double.longBitsToDouble(readLong(index))); + ++i; + break; + case ClassWriter.UTF8: { + String s = strings[i]; + if (s == null) { + index = items[i]; + s = strings[i] = readUTF(index + 2, readUnsignedShort(index), buf); + } + item.set(tag, s, null, null); + break; + } + case ClassWriter.HANDLE: { + int fieldOrMethodRef = items[readUnsignedShort(index + 1)]; + nameType = items[readUnsignedShort(fieldOrMethodRef + 2)]; + item.set(ClassWriter.HANDLE_BASE + readByte(index), + readClass(fieldOrMethodRef, buf), readUTF8(nameType, buf), + readUTF8(nameType + 2, buf)); + break; + } + case ClassWriter.INDY: + if (classWriter.bootstrapMethods == null) { + copyBootstrapMethods(classWriter, items2, buf); + } + nameType = items[readUnsignedShort(index + 2)]; + item.set(readUTF8(nameType, buf), readUTF8(nameType + 2, buf), + readUnsignedShort(index)); + break; + // case ClassWriter.STR: + // case ClassWriter.CLASS: + // case ClassWriter.MTYPE + default: + item.set(tag, readUTF8(index, buf), null, null); + break; + } + + int index2 = item.hashCode % items2.length; + item.next = items2[index2]; + items2[index2] = item; + } + + int off = items[1] - 1; + classWriter.pool.putByteArray(b, off, header - off); + classWriter.items = items2; + classWriter.threshold = (int) (0.75d * ll); + classWriter.index = ll; + } + + /** + * Copies the bootstrap method data into the given {@link ClassWriter}. Should be called before + * the {@link #accept(ClassVisitor,int)} method. + * + * @param classWriter the {@link ClassWriter} to copy bootstrap methods into. + */ + private void copyBootstrapMethods(final ClassWriter classWriter, final Item[] items, + final char[] c) { + // finds the "BootstrapMethods" attribute + int u = getAttributes(); + boolean found = false; + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("BootstrapMethods".equals(attrName)) { + found = true; + break; + } + u += 6 + readInt(u + 4); + } + if (!found) { + return; + } + // copies the bootstrap methods in the class writer + int boostrapMethodCount = readUnsignedShort(u + 8); + for (int j = 0, v = u + 10; j < boostrapMethodCount; j++) { + int position = v - u - 10; + int hashCode = readConst(readUnsignedShort(v), c).hashCode(); + for (int k = readUnsignedShort(v + 2); k > 0; --k) { + hashCode ^= readConst(readUnsignedShort(v + 4), c).hashCode(); + v += 2; + } + v += 4; + Item item = new Item(j); + item.set(position, hashCode & 0x7FFFFFFF); + int index = item.hashCode % items.length; + item.next = items[index]; + items[index] = item; + } + int attrSize = readInt(u + 4); + ByteVector bootstrapMethods = new ByteVector(attrSize + 62); + bootstrapMethods.putByteArray(b, u + 10, attrSize - 2); + classWriter.bootstrapMethodsCount = boostrapMethodCount; + classWriter.bootstrapMethods = bootstrapMethods; + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param is an input stream from which to read the class. + * @throws IOException if a problem occurs during reading. + */ + public ClassReader(final InputStream is) throws IOException { + this(readClass(is, false)); + } + + /** + * Constructs a new {@link ClassReader} object. + * + * @param name the binary qualified name of the class to be read. + * @throws IOException if an exception occurs during reading. + */ + public ClassReader(final String name) throws IOException { + this(readClass(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') + ".class"), + true)); + } + + /** + * Reads the bytecode of a class. + * + * @param is an input stream from which to read the class. + * @param close true to close the input stream after reading. + * @return the bytecode read from the given input stream. + * @throws IOException if a problem occurs during reading. + */ + private static byte[] readClass(final InputStream is, boolean close) throws IOException { + if (is == null) { + throw new IOException("Class not found"); + } + try { + byte[] b = new byte[is.available()]; + int len = 0; + while (true) { + int n = is.read(b, len, b.length - len); + if (n == -1) { + if (len < b.length) { + byte[] c = new byte[len]; + System.arraycopy(b, 0, c, 0, len); + b = c; + } + return b; + } + len += n; + if (len == b.length) { + int last = is.read(); + if (last < 0) { + return b; + } + byte[] c = new byte[b.length + 1000]; + System.arraycopy(b, 0, c, 0, len); + c[len++] = (byte) last; + b = c; + } + } + } finally { + if (close) { + is.close(); + } + } + } + + // ------------------------------------------------------------------------ + // Public methods + // ------------------------------------------------------------------------ + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader} . This class is the + * one specified in the constructor (see {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param flags option flags that can be used to modify the default behavior of this class. See + * {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, + * {@link #SKIP_CODE}. + */ + public void accept(final ClassVisitor classVisitor, final int flags) { + accept(classVisitor, new Attribute[0], flags); + } + + /** + * Makes the given visitor visit the Java class of this {@link ClassReader}. This class is the + * one specified in the constructor (see {@link #ClassReader(byte[]) ClassReader}). + * + * @param classVisitor the visitor that must visit this class. + * @param attrs prototypes of the attributes that must be parsed during the visit of the class. + * Any attribute whose type is not equal to the type of one the prototypes will not be + * parsed: its byte array value will be passed unchanged to the ClassWriter. This may + * corrupt it if this value contains references to the constant pool, or has syntactic or + * semantic links with a class element that has been transformed by a class adapter + * between the reader and the writer. + * @param flags option flags that can be used to modify the default behavior of this class. See + * {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES} , {@link #SKIP_FRAMES}, + * {@link #SKIP_CODE}. + */ + public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) { + int u = header; // current offset in the class file + char[] c = new char[maxStringLength]; // buffer used to read strings + + Context context = new Context(); + context.attrs = attrs; + context.flags = flags; + context.buffer = c; + + // reads the class declaration + int access = readUnsignedShort(u); + String name = readClass(u + 2, c); + String superClass = readClass(u + 4, c); + String[] interfaces = new String[readUnsignedShort(u + 6)]; + u += 8; + for (int i = 0; i < interfaces.length; ++i) { + interfaces[i] = readClass(u, c); + u += 2; + } + + // reads the class attributes + String signature = null; + String sourceFile = null; + String sourceDebug = null; + String enclosingOwner = null; + String enclosingName = null; + String enclosingDesc = null; + int anns = 0; + int ianns = 0; + int innerClasses = 0; + Attribute attributes = null; + + u = getAttributes(); + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("SourceFile".equals(attrName)) { + sourceFile = readUTF8(u + 8, c); + } else if ("InnerClasses".equals(attrName)) { + innerClasses = u + 8; + } else if ("EnclosingMethod".equals(attrName)) { + enclosingOwner = readClass(u + 8, c); + int item = readUnsignedShort(u + 10); + if (item != 0) { + enclosingName = readUTF8(items[item], c); + enclosingDesc = readUTF8(items[item] + 2, c); + } + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if ("SourceDebugExtension".equals(attrName)) { + int len = readInt(u + 4); + sourceDebug = readUTF(u + 8, len, new char[len]); + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else if ("BootstrapMethods".equals(attrName)) { + int[] bootstrapMethods = new int[readUnsignedShort(u + 8)]; + for (int j = 0, v = u + 10; j < bootstrapMethods.length; j++) { + bootstrapMethods[j] = v; + v += 2 + readUnsignedShort(v + 2) << 1; + } + context.bootstrapMethods = bootstrapMethods; + } else { + Attribute attr = readAttribute(attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + + // visits the class declaration + classVisitor.visit(readInt(items[1] - 7), access, name, signature, superClass, interfaces); + + // visits the source and debug info + if ((flags & SKIP_DEBUG) == 0 && (sourceFile != null || sourceDebug != null)) { + classVisitor.visitSource(sourceFile, sourceDebug); + } + + // visits the outer class + if (enclosingOwner != null) { + classVisitor.visitOuterClass(enclosingOwner, enclosingName, enclosingDesc); + } + + // visits the class annotations + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + classVisitor.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, + classVisitor.visitAnnotation(readUTF8(v, c), false)); + } + } + + // visits the attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + classVisitor.visitAttribute(attributes); + attributes = attr; + } + + // visits the inner classes + if (innerClasses != 0) { + int v = innerClasses + 2; + for (int i = readUnsignedShort(innerClasses); i > 0; --i) { + classVisitor.visitInnerClass(readClass(v, c), readClass(v + 2, c), + readUTF8(v + 4, c), readUnsignedShort(v + 6)); + v += 8; + } + } + + // visits the fields and methods + u = header + 10 + 2 * interfaces.length; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readField(classVisitor, context, u); + } + u += 2; + for (int i = readUnsignedShort(u - 2); i > 0; --i) { + u = readMethod(classVisitor, context, u); + } + + // visits the end of the class + classVisitor.visitEnd(); + } + + /** + * Reads a field and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the field. + * @param context information about the class being parsed. + * @param u the start offset of the field in the class file. + * @return the offset of the first byte following the field in the class. + */ + private int readField(final ClassVisitor classVisitor, final Context context, int u) { + // reads the field declaration + char[] c = context.buffer; + int access = readUnsignedShort(u); + String name = readUTF8(u + 2, c); + String desc = readUTF8(u + 4, c); + u += 6; + + // reads the field attributes + String signature = null; + int anns = 0; + int ianns = 0; + Object value = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("ConstantValue".equals(attrName)) { + int item = readUnsignedShort(u + 8); + value = item == 0 ? null : readConst(item, c); + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else { + Attribute attr = + readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // visits the field declaration + FieldVisitor fv = classVisitor.visitField(access, name, desc, signature, value); + if (fv == null) { + return u; + } + + // visits the field annotations + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, fv.visitAnnotation(readUTF8(v, c), false)); + } + } + + // visits the field attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + fv.visitAttribute(attributes); + attributes = attr; + } + + // visits the end of the field + fv.visitEnd(); + + return u; + } + + /** + * Reads a method and makes the given visitor visit it. + * + * @param classVisitor the visitor that must visit the method. + * @param context information about the class being parsed. + * @param u the start offset of the method in the class file. + * @return the offset of the first byte following the method in the class. + */ + private int readMethod(final ClassVisitor classVisitor, final Context context, int u) { + // reads the method declaration + char[] c = context.buffer; + int access = readUnsignedShort(u); + String name = readUTF8(u + 2, c); + String desc = readUTF8(u + 4, c); + u += 6; + + // reads the method attributes + int code = 0; + int exception = 0; + String[] exceptions = null; + String signature = null; + int anns = 0; + int ianns = 0; + int dann = 0; + int mpanns = 0; + int impanns = 0; + int firstAttribute = u; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + // tests are sorted in decreasing frequency order + // (based on frequencies observed on typical classes) + if ("Code".equals(attrName)) { + if ((context.flags & SKIP_CODE) == 0) { + code = u + 8; + } + } else if ("Exceptions".equals(attrName)) { + exceptions = new String[readUnsignedShort(u + 8)]; + exception = u + 10; + for (int j = 0; j < exceptions.length; ++j) { + exceptions[j] = readClass(exception, c); + exception += 2; + } + } else if (SIGNATURES && "Signature".equals(attrName)) { + signature = readUTF8(u + 8, c); + } else if ("Deprecated".equals(attrName)) { + access |= Opcodes.ACC_DEPRECATED; + } else if (ANNOTATIONS && "RuntimeVisibleAnnotations".equals(attrName)) { + anns = u + 8; + } else if (ANNOTATIONS && "AnnotationDefault".equals(attrName)) { + dann = u + 8; + } else if ("Synthetic".equals(attrName)) { + access |= Opcodes.ACC_SYNTHETIC | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE; + } else if (ANNOTATIONS && "RuntimeInvisibleAnnotations".equals(attrName)) { + ianns = u + 8; + } else if (ANNOTATIONS && "RuntimeVisibleParameterAnnotations".equals(attrName)) { + mpanns = u + 8; + } else if (ANNOTATIONS && "RuntimeInvisibleParameterAnnotations".equals(attrName)) { + impanns = u + 8; + } else { + Attribute attr = + readAttribute(context.attrs, attrName, u + 8, readInt(u + 4), c, -1, null); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // visits the method declaration + MethodVisitor mv = classVisitor.visitMethod(access, name, desc, signature, exceptions); + if (mv == null) { + return u; + } + + /* + * if the returned MethodVisitor is in fact a MethodWriter, it means there is no method + * adapter between the reader and the writer. If, in addition, the writer's constant pool + * was copied from this reader (mw.cw.cr == this), and the signature and exceptions of the + * method have not been changed, then it is possible to skip all visit events and just copy + * the original code of the method to the writer (the access, name and descriptor can have + * been changed, this is not important since they are not copied as is from the reader). + */ + if (WRITER && mv instanceof MethodWriter) { + MethodWriter mw = (MethodWriter) mv; + if (mw.cw.cr == this && signature == mw.signature) { + boolean sameExceptions = false; + if (exceptions == null) { + sameExceptions = mw.exceptionCount == 0; + } else if (exceptions.length == mw.exceptionCount) { + sameExceptions = true; + for (int j = exceptions.length - 1; j >= 0; --j) { + exception -= 2; + if (mw.exceptions[j] != readUnsignedShort(exception)) { + sameExceptions = false; + break; + } + } + } + if (sameExceptions) { + /* + * we do not copy directly the code into MethodWriter to save a byte array copy + * operation. The real copy will be done in ClassWriter.toByteArray(). + */ + mw.classReaderOffset = firstAttribute; + mw.classReaderLength = u - firstAttribute; + return u; + } + } + } + + // visits the method annotations + if (ANNOTATIONS && dann != 0) { + AnnotationVisitor dv = mv.visitAnnotationDefault(); + readAnnotationValue(dann, c, null, dv); + if (dv != null) { + dv.visitEnd(); + } + } + if (ANNOTATIONS && anns != 0) { + for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), true)); + } + } + if (ANNOTATIONS && ianns != 0) { + for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) { + v = readAnnotationValues(v + 2, c, true, mv.visitAnnotation(readUTF8(v, c), false)); + } + } + if (ANNOTATIONS && mpanns != 0) { + readParameterAnnotations(mpanns, desc, c, true, mv); + } + if (ANNOTATIONS && impanns != 0) { + readParameterAnnotations(impanns, desc, c, false, mv); + } + + // visits the method attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the method code + if (code != 0) { + context.access = access; + context.name = name; + context.desc = desc; + mv.visitCode(); + readCode(mv, context, code); + } + + // visits the end of the method + mv.visitEnd(); + + return u; + } + + /** + * Reads the bytecode of a method and makes the given visitor visit it. + * + * @param mv the visitor that must visit the method's code. + * @param context information about the class being parsed. + * @param u the start offset of the code attribute in the class file. + */ + private void readCode(final MethodVisitor mv, final Context context, int u) { + // reads the header + byte[] b = this.b; + char[] c = context.buffer; + int maxStack = readUnsignedShort(u); + int maxLocals = readUnsignedShort(u + 2); + int codeLength = readInt(u + 4); + u += 8; + + // reads the bytecode to find the labels + int codeStart = u; + int codeEnd = u + codeLength; + Label[] labels = new Label[codeLength + 2]; + readLabel(codeLength + 1, labels); + while (u < codeEnd) { + int offset = u - codeStart; + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + readLabel(offset + readShort(u + 1), labels); + u += 3; + break; + case ClassWriter.LABELW_INSN: + readLabel(offset + readInt(u + 1), labels); + u += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; + } + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + readLabel(offset + readInt(u), labels); + for (int i = readInt(u + 8) - readInt(u + 4) + 1; i > 0; --i) { + readLabel(offset + readInt(u + 12), labels); + u += 4; + } + u += 12; + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + readLabel(offset + readInt(u), labels); + for (int i = readInt(u + 4); i > 0; --i) { + readLabel(offset + readInt(u + 12), labels); + u += 8; + } + u += 8; + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + u += 5; + break; + // case MANA_INSN: + default: + u += 4; + break; + } + } + + // reads the try catch entries to find the labels, and also visits them + for (int i = readUnsignedShort(u); i > 0; --i) { + Label start = readLabel(readUnsignedShort(u + 2), labels); + Label end = readLabel(readUnsignedShort(u + 4), labels); + Label handler = readLabel(readUnsignedShort(u + 6), labels); + String type = readUTF8(items[readUnsignedShort(u + 8)], c); + mv.visitTryCatchBlock(start, end, handler, type); + u += 8; + } + u += 2; + + // reads the code attributes + int varTable = 0; + int varTypeTable = 0; + boolean zip = true; + boolean unzip = (context.flags & EXPAND_FRAMES) != 0; + int stackMap = 0; + int stackMapSize = 0; + int frameCount = 0; + Context frame = null; + Attribute attributes = null; + + for (int i = readUnsignedShort(u); i > 0; --i) { + String attrName = readUTF8(u + 2, c); + if ("LocalVariableTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + varTable = u + 8; + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + label += readUnsignedShort(v + 12); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + v += 10; + } + } + } else if ("LocalVariableTypeTable".equals(attrName)) { + varTypeTable = u + 8; + } else if ("LineNumberTable".equals(attrName)) { + if ((context.flags & SKIP_DEBUG) == 0) { + for (int j = readUnsignedShort(u + 8), v = u; j > 0; --j) { + int label = readUnsignedShort(v + 10); + if (labels[label] == null) { + readLabel(label, labels).status |= Label.DEBUG; + } + labels[label].line = readUnsignedShort(v + 12); + v += 4; + } + } + } else if (FRAMES && "StackMapTable".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * here we do not extract the labels corresponding to the attribute content. This + * would require a full parsing of the attribute, which would need to be repeated in + * the second phase (see below). Instead the content of the attribute is read one + * frame at a time (i.e. after a frame has been visited, the next frame is read), + * and the labels it contains are also extracted one frame at a time. Thanks to the + * ordering of frames, having only a "one frame lookahead" is not a problem, i.e. it + * is not possible to see an offset smaller than the offset of the current insn and + * for which no Label exist. + */ + /* + * This is not true for UNINITIALIZED type offsets. We solve this by parsing the + * stack map table without a full decoding (see below). + */ + } else if (FRAMES && "StackMap".equals(attrName)) { + if ((context.flags & SKIP_FRAMES) == 0) { + zip = false; + stackMap = u + 10; + stackMapSize = readInt(u + 4); + frameCount = readUnsignedShort(u + 8); + } + /* + * IMPORTANT! here we assume that the frames are ordered, as in the StackMapTable + * attribute, although this is not guaranteed by the attribute format. + */ + } else { + for (int j = 0; j < context.attrs.length; ++j) { + if (context.attrs[j].type.equals(attrName)) { + Attribute attr = context.attrs[j].read(this, u + 8, readInt(u + 4), c, + codeStart - 8, labels); + if (attr != null) { + attr.next = attributes; + attributes = attr; + } + } + } + } + u += 6 + readInt(u + 4); + } + u += 2; + + // generates the first (implicit) stack map frame + if (FRAMES && stackMap != 0) { + /* + * for the first explicit frame the offset is not offset_delta + 1 but only + * offset_delta; setting the implicit frame offset to -1 allow the use of the + * "offset_delta + 1" rule in all cases + */ + frame = context; + frame.offset = -1; + frame.mode = 0; + frame.localCount = 0; + frame.localDiff = 0; + frame.stackCount = 0; + frame.local = new Object[maxLocals]; + frame.stack = new Object[maxStack]; + if (unzip) { + getImplicitFrame(context); + } + /* + * Finds labels for UNINITIALIZED frame types. Instead of decoding each element of the + * stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED + * type (tag 8, offset within code bounds, NEW instruction at this offset). We may find + * false positives (i.e. not real UNINITIALIZED types), but this should be rare, and the + * only consequence will be the creation of an unneeded label. This is better than + * creating a label for each NEW instruction, and faster than fully decoding the whole + * stack map table. + */ + for (int i = stackMap; i < stackMap + stackMapSize - 2; ++i) { + if (b[i] == 8) { // UNINITIALIZED FRAME TYPE + int v = readUnsignedShort(i + 1); + if (v >= 0 && v < codeLength) { + if ((b[codeStart + v] & 0xFF) == Opcodes.NEW) { + readLabel(v, labels); + } + } + } + } + } + + // visits the instructions + u = codeStart; + while (u < codeEnd) { + int offset = u - codeStart; + + // visits the label and line number for this offset, if any + Label l = labels[offset]; + if (l != null) { + mv.visitLabel(l); + if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { + mv.visitLineNumber(l.line, l); + } + } + + // visits the frame for this offset, if any + while (FRAMES && frame != null && (frame.offset == offset || frame.offset == -1)) { + // if there is a frame for this offset, makes the visitor visit + // it, and reads the next frame if there is one. + if (frame.offset != -1) { + if (!zip || unzip) { + mv.visitFrame(Opcodes.F_NEW, frame.localCount, frame.local, + frame.stackCount, frame.stack); + } else { + mv.visitFrame(frame.mode, frame.localDiff, frame.local, frame.stackCount, + frame.stack); + } + } + if (frameCount > 0) { + stackMap = readFrame(stackMap, zip, unzip, labels, frame); + --frameCount; + } else { + frame = null; + } + } + + // visits the instruction at this offset + int opcode = b[u] & 0xFF; + switch (ClassWriter.TYPE[opcode]) { + case ClassWriter.NOARG_INSN: + mv.visitInsn(opcode); + u += 1; + break; + case ClassWriter.IMPLVAR_INSN: + if (opcode > Opcodes.ISTORE) { + opcode -= 59; // ISTORE_0 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), opcode & 0x3); + } else { + opcode -= 26; // ILOAD_0 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), opcode & 0x3); + } + u += 1; + break; + case ClassWriter.LABEL_INSN: + mv.visitJumpInsn(opcode, labels[offset + readShort(u + 1)]); + u += 3; + break; + case ClassWriter.LABELW_INSN: + mv.visitJumpInsn(opcode - 33, labels[offset + readInt(u + 1)]); + u += 5; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + mv.visitIincInsn(readUnsignedShort(u + 2), readShort(u + 4)); + u += 6; + } else { + mv.visitVarInsn(opcode, readUnsignedShort(u + 2)); + u += 4; + } + break; + case ClassWriter.TABL_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int min = readInt(u + 4); + int max = readInt(u + 8); + Label[] table = new Label[max - min + 1]; + u += 12; + for (int i = 0; i < table.length; ++i) { + table[i] = labels[offset + readInt(u)]; + u += 4; + } + mv.visitTableSwitchInsn(min, max, labels[label], table); + break; + } + case ClassWriter.LOOK_INSN: { + // skips 0 to 3 padding bytes + u = u + 4 - (offset & 3); + // reads instruction + int label = offset + readInt(u); + int len = readInt(u + 4); + int[] keys = new int[len]; + Label[] values = new Label[len]; + u += 8; + for (int i = 0; i < len; ++i) { + keys[i] = readInt(u); + values[i] = labels[offset + readInt(u + 4)]; + u += 8; + } + mv.visitLookupSwitchInsn(labels[label], keys, values); + break; + } + case ClassWriter.VAR_INSN: + mv.visitVarInsn(opcode, b[u + 1] & 0xFF); + u += 2; + break; + case ClassWriter.SBYTE_INSN: + mv.visitIntInsn(opcode, b[u + 1]); + u += 2; + break; + case ClassWriter.SHORT_INSN: + mv.visitIntInsn(opcode, readShort(u + 1)); + u += 3; + break; + case ClassWriter.LDC_INSN: + mv.visitLdcInsn(readConst(b[u + 1] & 0xFF, c)); + u += 2; + break; + case ClassWriter.LDCW_INSN: + mv.visitLdcInsn(readConst(readUnsignedShort(u + 1), c)); + u += 3; + break; + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.ITFMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + String iowner = readClass(cpIndex, c); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + if (opcode < Opcodes.INVOKEVIRTUAL) { + mv.visitFieldInsn(opcode, iowner, iname, idesc); + } else { + mv.visitMethodInsn(opcode, iowner, iname, idesc); + } + if (opcode == Opcodes.INVOKEINTERFACE) { + u += 5; + } else { + u += 3; + } + break; + } + case ClassWriter.INDYMETH_INSN: { + int cpIndex = items[readUnsignedShort(u + 1)]; + int bsmIndex = context.bootstrapMethods[readUnsignedShort(cpIndex)]; + Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), c); + int bsmArgCount = readUnsignedShort(bsmIndex + 2); + Object[] bsmArgs = new Object[bsmArgCount]; + bsmIndex += 4; + for (int i = 0; i < bsmArgCount; i++) { + bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), c); + bsmIndex += 2; + } + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String iname = readUTF8(cpIndex, c); + String idesc = readUTF8(cpIndex + 2, c); + mv.visitInvokeDynamicInsn(iname, idesc, bsm, bsmArgs); + u += 5; + break; + } + case ClassWriter.TYPE_INSN: + mv.visitTypeInsn(opcode, readClass(u + 1, c)); + u += 3; + break; + case ClassWriter.IINC_INSN: + mv.visitIincInsn(b[u + 1] & 0xFF, b[u + 2]); + u += 3; + break; + // case MANA_INSN: + default: + mv.visitMultiANewArrayInsn(readClass(u + 1, c), b[u + 3] & 0xFF); + u += 4; + break; + } + } + if (labels[codeLength] != null) { + mv.visitLabel(labels[codeLength]); + } + + // visits the local variable tables + if ((context.flags & SKIP_DEBUG) == 0 && varTable != 0) { + int[] typeTable = null; + if (varTypeTable != 0) { + u = varTypeTable + 2; + typeTable = new int[readUnsignedShort(varTypeTable) * 3]; + for (int i = typeTable.length; i > 0;) { + typeTable[--i] = u + 6; // signature + typeTable[--i] = readUnsignedShort(u + 8); // index + typeTable[--i] = readUnsignedShort(u); // start + u += 10; + } + } + u = varTable + 2; + for (int i = readUnsignedShort(varTable); i > 0; --i) { + int start = readUnsignedShort(u); + int length = readUnsignedShort(u + 2); + int index = readUnsignedShort(u + 8); + String vsignature = null; + if (typeTable != null) { + for (int j = 0; j < typeTable.length; j += 3) { + if (typeTable[j] == start && typeTable[j + 1] == index) { + vsignature = readUTF8(typeTable[j + 2], c); + break; + } + } + } + mv.visitLocalVariable(readUTF8(u + 4, c), readUTF8(u + 6, c), vsignature, + labels[start], labels[start + length], index); + u += 10; + } + } + + // visits the code attributes + while (attributes != null) { + Attribute attr = attributes.next; + attributes.next = null; + mv.visitAttribute(attributes); + attributes = attr; + } + + // visits the max stack and max locals values + mv.visitMaxs(maxStack, maxLocals); + } + + /** + * Reads parameter annotations and makes the given visitor visit them. + * + * @param v start offset in {@link #b b} of the annotations to be read. + * @param desc the method descriptor. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst readConst}. + * @param visible true if the annotations to be read are visible at runtime. + * @param mv the visitor that must visit the annotations. + */ + private void readParameterAnnotations(int v, final String desc, final char[] buf, + final boolean visible, final MethodVisitor mv) { + int i; + int n = b[v++] & 0xFF; + // workaround for a bug in javac (javac compiler generates a parameter + // annotation array whose size is equal to the number of parameters in + // the Java source file, while it should generate an array whose size is + // equal to the number of parameters in the method descriptor - which + // includes the synthetic parameters added by the compiler). This work- + // around supposes that the synthetic parameters are the first ones. + int synthetics = Type.getArgumentTypes(desc).length - n; + AnnotationVisitor av; + for (i = 0; i < synthetics; ++i) { + // virtual annotation to detect synthetic parameters in MethodWriter + av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", false); + if (av != null) { + av.visitEnd(); + } + } + for (; i < n + synthetics; ++i) { + int j = readUnsignedShort(v); + v += 2; + for (; j > 0; --j) { + av = mv.visitParameterAnnotation(i, readUTF8(v, buf), visible); + v = readAnnotationValues(v + 2, buf, true, av); + } + } + } + + /** + * Reads the values of an annotation and makes the given visitor visit them. + * + * @param v the start offset in {@link #b b} of the values to be read (including the unsigned + * short that gives the number of values). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst readConst}. + * @param named if the annotation values are named or not. + * @param av the visitor that must visit the values. + * @return the end offset of the annotation values. + */ + private int readAnnotationValues(int v, final char[] buf, final boolean named, + final AnnotationVisitor av) { + int i = readUnsignedShort(v); + v += 2; + if (named) { + for (; i > 0; --i) { + v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); + } + } else { + for (; i > 0; --i) { + v = readAnnotationValue(v, buf, null, av); + } + } + if (av != null) { + av.visitEnd(); + } + return v; + } + + /** + * Reads a value of an annotation and makes the given visitor visit it. + * + * @param v the start offset in {@link #b b} of the value to be read (not including the value + * name constant pool index). + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst readConst}. + * @param name the name of the value to be read. + * @param av the visitor that must visit the value. + * @return the end offset of the annotation value. + */ + private int readAnnotationValue(int v, final char[] buf, final String name, + final AnnotationVisitor av) { + int i; + if (av == null) { + switch (b[v] & 0xFF) { + case 'e': // enum_const_value + return v + 5; + case '@': // annotation_value + return readAnnotationValues(v + 3, buf, true, null); + case '[': // array_value + return readAnnotationValues(v + 1, buf, false, null); + default: + return v + 3; + } + } + switch (b[v++] & 0xFF) { + case 'I': // pointer to CONSTANT_Integer + case 'J': // pointer to CONSTANT_Long + case 'F': // pointer to CONSTANT_Float + case 'D': // pointer to CONSTANT_Double + av.visit(name, readConst(readUnsignedShort(v), buf)); + v += 2; + break; + case 'B': // pointer to CONSTANT_Byte + av.visit(name, new Byte((byte) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'Z': // pointer to CONSTANT_Boolean + av.visit(name, + readInt(items[readUnsignedShort(v)]) == 0 ? Boolean.FALSE : Boolean.TRUE); + v += 2; + break; + case 'S': // pointer to CONSTANT_Short + av.visit(name, new Short((short) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 'C': // pointer to CONSTANT_Char + av.visit(name, new Character((char) readInt(items[readUnsignedShort(v)]))); + v += 2; + break; + case 's': // pointer to CONSTANT_Utf8 + av.visit(name, readUTF8(v, buf)); + v += 2; + break; + case 'e': // enum_const_value + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); + v += 4; + break; + case 'c': // class_info + av.visit(name, Type.getType(readUTF8(v, buf))); + v += 2; + break; + case '@': // annotation_value + v = readAnnotationValues(v + 2, buf, true, + av.visitAnnotation(name, readUTF8(v, buf))); + break; + case '[': // array_value + int size = readUnsignedShort(v); + v += 2; + if (size == 0) { + return readAnnotationValues(v - 2, buf, false, av.visitArray(name)); + } + switch (this.b[v++] & 0xFF) { + case 'B': + byte[] bv = new byte[size]; + for (i = 0; i < size; i++) { + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, bv); + --v; + break; + case 'Z': + boolean[] zv = new boolean[size]; + for (i = 0; i < size; i++) { + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; + v += 3; + } + av.visit(name, zv); + --v; + break; + case 'S': + short[] sv = new short[size]; + for (i = 0; i < size; i++) { + sv[i] = (short) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, sv); + --v; + break; + case 'C': + char[] cv = new char[size]; + for (i = 0; i < size; i++) { + cv[i] = (char) readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, cv); + --v; + break; + case 'I': + int[] iv = new int[size]; + for (i = 0; i < size; i++) { + iv[i] = readInt(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, iv); + --v; + break; + case 'J': + long[] lv = new long[size]; + for (i = 0; i < size; i++) { + lv[i] = readLong(items[readUnsignedShort(v)]); + v += 3; + } + av.visit(name, lv); + --v; + break; + case 'F': + float[] fv = new float[size]; + for (i = 0; i < size; i++) { + fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, fv); + --v; + break; + case 'D': + double[] dv = new double[size]; + for (i = 0; i < size; i++) { + dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); + v += 3; + } + av.visit(name, dv); + --v; + break; + default: + v = readAnnotationValues(v - 3, buf, false, av.visitArray(name)); + } + } + return v; + } + + /** + * Computes the implicit frame of the method currently being parsed (as defined in the given + * {@link Context}) and stores it in the given context. + * + * @param frame information about the class being parsed. + */ + private void getImplicitFrame(final Context frame) { + String desc = frame.desc; + Object[] locals = frame.local; + int local = 0; + if ((frame.access & Opcodes.ACC_STATIC) == 0) { + if ("".equals(frame.name)) { + locals[local++] = Opcodes.UNINITIALIZED_THIS; + } else { + locals[local++] = readClass(header + 2, frame.buffer); + } + } + int i = 1; + loop: while (true) { + int j = i; + switch (desc.charAt(i++)) { + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + locals[local++] = Opcodes.INTEGER; + break; + case 'F': + locals[local++] = Opcodes.FLOAT; + break; + case 'J': + locals[local++] = Opcodes.LONG; + break; + case 'D': + locals[local++] = Opcodes.DOUBLE; + break; + case '[': + while (desc.charAt(i) == '[') { + ++i; + } + if (desc.charAt(i) == 'L') { + ++i; + while (desc.charAt(i) != ';') { + ++i; + } + } + locals[local++] = desc.substring(j, ++i); + break; + case 'L': + while (desc.charAt(i) != ';') { + ++i; + } + locals[local++] = desc.substring(j + 1, i++); + break; + default: + break loop; + } + } + frame.localCount = local; + } + + /** + * Reads a stack map frame and stores the result in the given {@link Context} object. + * + * @param stackMap the start offset of a stack map frame in the class file. + * @param zip if the stack map frame at stackMap is compressed or not. + * @param unzip if the stack map frame must be uncompressed. + * @param labels the labels of the method currently being parsed, indexed by their offset. A new + * label for the parsed stack map frame is stored in this array if it does not already + * exist. + * @param frame where the parsed stack map frame must be stored. + * @return the offset of the first byte following the parsed frame. + */ + private int readFrame(int stackMap, boolean zip, boolean unzip, Label[] labels, Context frame) { + char[] c = frame.buffer; + int tag; + int delta; + if (zip) { + tag = b[stackMap++] & 0xFF; + } else { + tag = MethodWriter.FULL_FRAME; + frame.offset = -1; + } + frame.localDiff = 0; + if (tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) { + delta = tag; + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.RESERVED) { + delta = tag - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else { + delta = readUnsignedShort(stackMap); + stackMap += 2; + if (tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) { + stackMap = readFrameType(frame.stack, 0, stackMap, c, labels); + frame.mode = Opcodes.F_SAME1; + frame.stackCount = 1; + } else if (tag >= MethodWriter.CHOP_FRAME && tag < MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_CHOP; + frame.localDiff = MethodWriter.SAME_FRAME_EXTENDED - tag; + frame.localCount -= frame.localDiff; + frame.stackCount = 0; + } else if (tag == MethodWriter.SAME_FRAME_EXTENDED) { + frame.mode = Opcodes.F_SAME; + frame.stackCount = 0; + } else if (tag < MethodWriter.FULL_FRAME) { + int local = unzip ? frame.localCount : 0; + for (int i = tag - MethodWriter.SAME_FRAME_EXTENDED; i > 0; i--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, labels); + } + frame.mode = Opcodes.F_APPEND; + frame.localDiff = tag - MethodWriter.SAME_FRAME_EXTENDED; + frame.localCount += frame.localDiff; + frame.stackCount = 0; + } else { // if (tag == FULL_FRAME) { + frame.mode = Opcodes.F_FULL; + int n = readUnsignedShort(stackMap); + stackMap += 2; + frame.localDiff = n; + frame.localCount = n; + for (int local = 0; n > 0; n--) { + stackMap = readFrameType(frame.local, local++, stackMap, c, labels); + } + n = readUnsignedShort(stackMap); + stackMap += 2; + frame.stackCount = n; + for (int stack = 0; n > 0; n--) { + stackMap = readFrameType(frame.stack, stack++, stackMap, c, labels); + } + } + } + frame.offset += delta + 1; + readLabel(frame.offset, labels); + return stackMap; + } + + /** + * Reads a stack map frame type and stores it at the given index in the given array. + * + * @param frame the array where the parsed type must be stored. + * @param index the index in 'frame' where the parsed type must be stored. + * @param v the start offset of the stack map frame type to read. + * @param buf a buffer to read strings. + * @param labels the labels of the method currently being parsed, indexed by their offset. If + * the parsed type is an Uninitialized type, a new label for the corresponding NEW + * instruction is stored in this array if it does not already exist. + * @return the offset of the first byte after the parsed type. + */ + private int readFrameType(final Object[] frame, final int index, int v, final char[] buf, + final Label[] labels) { + int type = b[v++] & 0xFF; + switch (type) { + case 0: + frame[index] = Opcodes.TOP; + break; + case 1: + frame[index] = Opcodes.INTEGER; + break; + case 2: + frame[index] = Opcodes.FLOAT; + break; + case 3: + frame[index] = Opcodes.DOUBLE; + break; + case 4: + frame[index] = Opcodes.LONG; + break; + case 5: + frame[index] = Opcodes.NULL; + break; + case 6: + frame[index] = Opcodes.UNINITIALIZED_THIS; + break; + case 7: // Object + frame[index] = readClass(v, buf); + v += 2; + break; + default: // Uninitialized + frame[index] = readLabel(readUnsignedShort(v), labels); + v += 2; + } + return v; + } + + /** + * Returns the label corresponding to the given offset. The default implementation of this + * method creates a label for the given offset if it has not been already created. + * + * @param offset a bytecode offset in a method. + * @param labels the already created labels, indexed by their offset. If a label already exists + * for offset this method must not create a new one. Otherwise it must store the new + * label in this array. + * @return a non null Label, which must be equal to labels[offset]. + */ + protected Label readLabel(int offset, Label[] labels) { + if (labels[offset] == null) { + labels[offset] = new Label(); + } + return labels[offset]; + } + + /** + * Returns the start index of the attribute_info structure of this class. + * + * @return the start index of the attribute_info structure of this class. + */ + private int getAttributes() { + // skips the header + int u = header + 8 + readUnsignedShort(header + 6) * 2; + // skips fields and methods + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + u += 2; + for (int i = readUnsignedShort(u); i > 0; --i) { + for (int j = readUnsignedShort(u + 8); j > 0; --j) { + u += 6 + readInt(u + 12); + } + u += 8; + } + // the attribute_info structure starts just after the methods + return u + 2; + } + + /** + * Reads an attribute in {@link #b b}. + * + * @param attrs prototypes of the attributes that must be parsed during the visit of the class. + * Any attribute whose type is not equal to the type of one the prototypes is ignored + * (i.e. an empty {@link Attribute} instance is returned). + * @param type the type of the attribute. + * @param off index of the first byte of the attribute's content in {@link #b b}. The 6 + * attribute header bytes, containing the type and the length of the attribute, are not + * taken into account here (they have already been read). + * @param len the length of the attribute's content. + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, + * {@link #readClass(int,char[]) readClass} or {@link #readConst readConst}. + * @param codeOff index of the first byte of code's attribute content in {@link #b 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 null if the attribute to be read + * is not a code attribute. + * @return the attribute that has been read, or null to skip this attribute. + */ + private Attribute readAttribute(final Attribute[] attrs, final String type, final int off, + final int len, final char[] buf, final int codeOff, final Label[] labels) { + for (int i = 0; i < attrs.length; ++i) { + if (attrs[i].type.equals(type)) { + return attrs[i].read(this, off, len, buf, codeOff, labels); + } + } + return new Attribute(type).read(this, off, len, null, -1, null); + } + + // ------------------------------------------------------------------------ + // Utility methods: low level parsing + // ------------------------------------------------------------------------ + + /** + * Returns the number of constant pool items in {@link #b b}. + * + * @return the number of constant pool items in {@link #b b}. + */ + public int getItemCount() { + return items.length; + } + + /** + * Returns the start index of the constant pool item in {@link #b b}, plus one. This method + * is intended for {@link Attribute} sub classes, and is normally not needed by class generators + * or adapters. + * + * @param item the index a constant pool item. + * @return the start index of the constant pool item in {@link #b b}, plus one. + */ + public int getItem(final int item) { + return items[item]; + } + + /** + * Returns the maximum length of the strings contained in the constant pool of the class. + * + * @return the maximum length of the strings contained in the constant pool of the class. + */ + public int getMaxStringLength() { + return maxStringLength; + } + + /** + * Reads a byte value in {@link #b b}. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readByte(final int index) { + return b[index] & 0xFF; + } + + /** + * Reads an unsigned short value in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readUnsignedShort(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); + } + + /** + * Reads a signed short value in {@link #b b}. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public short readShort(final int index) { + byte[] b = this.b; + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); + } + + /** + * Reads a signed int value in {@link #b b}. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public int readInt(final int index) { + byte[] b = this.b; + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); + } + + /** + * Reads a signed long value in {@link #b b}. This method is intended for {@link Attribute} + * sub classes, and is normally not needed by class generators or adapters. + * + * @param index the start index of the value to be read in {@link #b b}. + * @return the read value. + */ + public long readLong(final int index) { + long l1 = readInt(index); + long l0 = readInt(index + 4) & 0xFFFFFFFFL; + return (l1 << 32) | l0; + } + + /** + * Reads an UTF8 string constant pool item in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, whose value is the + * index of an UTF8 constant pool item. + * @param buf buffer to be used to read the item. This buffer must be sufficiently large. It is + * not automatically resized. + * @return the String corresponding to the specified UTF8 item. + */ + public String readUTF8(int index, final char[] buf) { + int item = readUnsignedShort(index); + if (index == 0 || item == 0 || item > strings.length) { + return null; + } + String s = strings[item]; + if (s != null) { + return s; + } + index = items[item]; + return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); + } + + /** + * Reads UTF8 string in {@link #b b}. + * + * @param index start offset of the UTF8 string to be read. + * @param utfLen length of the UTF8 string to be read. + * @param buf buffer to be used to read the string. This buffer must be sufficiently large. It + * is not automatically resized. + * @return the String corresponding to the specified UTF8 string. + */ + private String readUTF(int index, final int utfLen, final char[] buf) { + int endIndex = index + utfLen; + byte[] b = this.b; + int strLen = 0; + int c; + int st = 0; + char cc = 0; + while (index < endIndex) { + c = b[index++]; + switch (st) { + case 0: + c = c & 0xFF; + if (c < 0x80) { // 0xxxxxxx + buf[strLen++] = (char) c; + } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx + cc = (char) (c & 0x1F); + st = 1; + } else { // 1110 xxxx 10xx xxxx 10xx xxxx + cc = (char) (c & 0x0F); + st = 2; + } + break; + + case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char + buf[strLen++] = (char) ((cc << 6) | (c & 0x3F)); + st = 0; + break; + + case 2: // byte 2 of 3-byte char + cc = (char) ((cc << 6) | (c & 0x3F)); + st = 1; + break; + } + } + return new String(buf, 0, strLen); + } + + /** + * Reads a class constant pool item in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param index the start index of an unsigned short value in {@link #b b}, whose value is the + * index of a class constant pool item. + * @param buf buffer to be used to read the item. This buffer must be sufficiently large. It is + * not automatically resized. + * @return the String corresponding to the specified class item. + */ + public String readClass(final int index, final char[] buf) { + // computes the start index of the CONSTANT_Class item in b + // and reads the CONSTANT_Utf8 item designated by + // the first two bytes of this CONSTANT_Class item + return readUTF8(items[readUnsignedShort(index)], buf); + } + + /** + * Reads a numeric or string constant pool item in {@link #b b}. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. + * + * @param item the index of a constant pool item. + * @param buf buffer to be used to read the item. This buffer must be sufficiently large. It is + * not automatically resized. + * @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, + * {@link Type} or {@link Handle} corresponding to the given constant pool item. + */ + public Object readConst(final int item, final char[] buf) { + int index = items[item]; + switch (b[index - 1]) { + case ClassWriter.INT: + return new Integer(readInt(index)); + case ClassWriter.FLOAT: + return new Float(Float.intBitsToFloat(readInt(index))); + case ClassWriter.LONG: + return new Long(readLong(index)); + case ClassWriter.DOUBLE: + return new Double(Double.longBitsToDouble(readLong(index))); + case ClassWriter.CLASS: + return Type.getObjectType(readUTF8(index, buf)); + case ClassWriter.STR: + return readUTF8(index, buf); + case ClassWriter.MTYPE: + return Type.getMethodType(readUTF8(index, buf)); + default: // case ClassWriter.HANDLE_BASE + [1..9]: + int tag = readByte(index); + int[] items = this.items; + int cpIndex = items[readUnsignedShort(index + 1)]; + String owner = readClass(cpIndex, buf); + cpIndex = items[readUnsignedShort(cpIndex + 2)]; + String name = readUTF8(cpIndex, buf); + String desc = readUTF8(cpIndex + 2, buf); + return new Handle(tag, owner, name, desc); + } + } } diff --git a/src/main/asm/org/objectweb/asm/ClassVisitor.java b/src/main/asm/org/objectweb/asm/ClassVisitor.java index cf3366c..1f33212 100644 --- a/src/main/asm/org/objectweb/asm/ClassVisitor.java +++ b/src/main/asm/org/objectweb/asm/ClassVisitor.java @@ -1,38 +1,29 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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: visit [ visitSource ] [ - * visitOuterClass ] ( visitAnnotation | + * A visitor to visit a Java class. The methods of this class must be called in the following order: + * visit [ visitSource ] [ visitOuterClass ] ( visitAnnotation | * visitAttribute )* ( visitInnerClass | visitField | * visitMethod )* visitEnd. * @@ -41,23 +32,21 @@ package org.objectweb.asm; public abstract class ClassVisitor { /** - * The ASM API version implemented by this visitor. The value of this field - * must be one of {@link Opcodes#ASM4}. + * 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. + * 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}. + * @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); @@ -66,12 +55,9 @@ public abstract class ClassVisitor { /** * 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. + * @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) { @@ -84,30 +70,21 @@ public abstract class ClassVisitor { /** * 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 null 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 - * null, but only for the {@link Object} class. - * @param interfaces - * the internal names of the class's interfaces (see - * {@link Type#getInternalName() getInternalName}). May be - * null. + * @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 null 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 + * null, but only for the {@link Object} class. + * @param interfaces the internal names of the class's interfaces (see + * {@link Type#getInternalName() getInternalName}). May be null. */ - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { + 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); } @@ -116,13 +93,10 @@ public abstract class ClassVisitor { /** * Visits the source of the class. * - * @param source - * the name of the source file from which the class was compiled. - * May be null. - * @param debug - * additional debug information to compute the correspondance - * between source and compiled elements of the class. May be - * null. + * @param source the name of the source file from which the class was compiled. May be + * null. + * @param debug additional debug information to compute the correspondance between source and + * compiled elements of the class. May be null. */ public void visitSource(String source, String debug) { if (cv != null) { @@ -131,19 +105,14 @@ public abstract class ClassVisitor { } /** - * Visits the enclosing class of the class. This method must be called only - * if the class has an enclosing class. + * 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 - * null 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 - * null if the class is not enclosed in a method of its - * 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 null 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 null 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) { @@ -154,12 +123,10 @@ public abstract class ClassVisitor { /** * Visits an annotation of the class. * - * @param desc - * the class descriptor of the annotation class. - * @param visible - * true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if - * this visitor is not interested in visiting this annotation. + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if this visitor is not + * interested in visiting this annotation. */ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (cv != null) { @@ -171,8 +138,7 @@ public abstract class ClassVisitor { /** * Visits a non standard attribute of the class. * - * @param attr - * an attribute. + * @param attr an attribute. */ public void visitAttribute(Attribute attr) { if (cv != null) { @@ -181,25 +147,20 @@ public abstract class ClassVisitor { } /** - * Visits information about an inner class. This inner class is not - * necessarily a member of the class being visited. + * 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 null for not member classes. - * @param innerName - * the (simple) name of the inner class inside its enclosing - * class. May be null for anonymous inner classes. - * @param access - * the access flags of the inner class as originally declared in - * the enclosing class. + * @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 null for not member + * classes. + * @param innerName the (simple) name of the inner class inside its enclosing class. May be + * null 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) { + public void visitInnerClass(String name, String outerName, String innerName, int access) { if (cv != null) { cv.visitInnerClass(name, outerName, innerName, access); } @@ -208,32 +169,23 @@ public abstract class ClassVisitor { /** * 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 null if the field's - * type does not use generic types. - * @param value - * the field's initial value. This parameter, which may be - * null 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 int, - * float, long or String fields - * respectively). This parameter is only used for static - * fields. 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 - * null if this class visitor is not interested in visiting - * these annotations and attributes. + * @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 null if the field's type does not use + * generic types. + * @param value the field's initial value. This parameter, which may be null 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 int, float, + * long or String fields respectively). This parameter is only used + * for static fields. 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 null 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) { + public FieldVisitor visitField(int access, String name, String desc, String signature, + Object value) { if (cv != null) { return cv.visitField(access, name, desc, signature, value); } @@ -241,32 +193,23 @@ public abstract class ClassVisitor { } /** - * Visits a method of the class. This method must return a new - * {@link MethodVisitor} instance (or null) each time it is called, - * i.e., it should not return a previously returned visitor. + * Visits a method of the class. This method must return a new {@link MethodVisitor} + * instance (or null) 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 null 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 - * null. - * @return an object to visit the byte code of the method, or null - * if this class visitor is not interested in visiting the code of - * this method. + * @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 null 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 null. + * @return an object to visit the byte code of the method, or null 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) { + public MethodVisitor visitMethod(int access, String name, String desc, String signature, + String[] exceptions) { if (cv != null) { return cv.visitMethod(access, name, desc, signature, exceptions); } @@ -274,9 +217,8 @@ public abstract class ClassVisitor { } /** - * 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. + * 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) { diff --git a/src/main/asm/org/objectweb/asm/ClassWriter.java b/src/main/asm/org/objectweb/asm/ClassWriter.java index 4dfd03e..ca15bb4 100644 --- a/src/main/asm/org/objectweb/asm/ClassWriter.java +++ b/src/main/asm/org/objectweb/asm/ClassWriter.java @@ -1,81 +1,68 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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 {@link ClassVisitor} that generates classes in bytecode form. More - * precisely this visitor generates a byte array conforming to the Java class - * file format. It can be used alone, to generate a Java class "from scratch", - * or with one or more {@link ClassReader ClassReader} and adapter class visitor - * to generate a modified class from one or more existing Java classes. + * A {@link ClassVisitor} that generates classes in bytecode form. More precisely this visitor + * generates a byte array conforming to the Java class file format. It can be used alone, to + * generate a Java class "from scratch", or with one or more {@link ClassReader ClassReader} and + * adapter class visitor to generate a modified class from one or more existing Java classes. * * @author Eric Bruneton */ public class ClassWriter extends ClassVisitor { /** - * Flag to automatically compute the maximum stack size and the maximum - * number of local variables of methods. If this flag is set, then the - * arguments of the {@link MethodVisitor#visitMaxs visitMaxs} method of the - * {@link MethodVisitor} returned by the {@link #visitMethod visitMethod} - * method will be ignored, and computed automatically from the signature and - * the bytecode of each method. + * Flag to automatically compute the maximum stack size and the maximum number of local + * variables of methods. If this flag is set, then the arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method of the {@link MethodVisitor} returned by the + * {@link #visitMethod visitMethod} method will be ignored, and computed automatically from the + * signature and the bytecode of each method. * * @see #ClassWriter(int) */ public static final int COMPUTE_MAXS = 1; /** - * Flag to automatically compute the stack map frames of methods from - * scratch. If this flag is set, then the calls to the - * {@link MethodVisitor#visitFrame} method are ignored, and the stack map - * frames are recomputed from the methods bytecode. The arguments of the - * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and - * recomputed from the bytecode. In other words, computeFrames implies - * computeMaxs. + * Flag to automatically compute the stack map frames of methods from scratch. If this flag is + * set, then the calls to the {@link MethodVisitor#visitFrame} method are ignored, and the stack + * map frames are recomputed from the methods bytecode. The arguments of the + * {@link MethodVisitor#visitMaxs visitMaxs} method are also ignored and recomputed from the + * bytecode. In other words, computeFrames implies computeMaxs. * * @see #ClassWriter(int) */ public static final int COMPUTE_FRAMES = 2; /** - * Pseudo access flag to distinguish between the synthetic attribute and the - * synthetic access flag. + * Pseudo access flag to distinguish between the synthetic attribute and the synthetic access + * flag. */ static final int ACC_SYNTHETIC_ATTRIBUTE = 0x40000; /** * Factor to convert from ACC_SYNTHETIC_ATTRIBUTE to Opcode.ACC_SYNTHETIC. */ - static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE - / Opcodes.ACC_SYNTHETIC; + static final int TO_ACC_SYNTHETIC = ACC_SYNTHETIC_ATTRIBUTE / Opcodes.ACC_SYNTHETIC; /** * The type of instructions without any argument. @@ -243,37 +230,35 @@ public class ClassWriter extends ClassVisitor { static final int INDY = 18; /** - * The base value for all CONSTANT_MethodHandle constant pool items. - * Internally, ASM store the 9 variations of CONSTANT_MethodHandle into 9 - * different items. + * The base value for all CONSTANT_MethodHandle constant pool items. Internally, ASM store the 9 + * variations of CONSTANT_MethodHandle into 9 different items. */ static final int HANDLE_BASE = 20; /** - * Normal type Item 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. + * Normal type Item 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. */ static final int TYPE_NORMAL = 30; /** - * Uninitialized type Item 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. + * Uninitialized type Item 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. */ static final int TYPE_UNINIT = 31; /** - * Merged type Item 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. + * Merged type Item 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. */ static final int TYPE_MERGED = 32; /** - * The type of BootstrapMethods items. These items are stored in a special - * class attribute named BootstrapMethods and not in the constant pool. + * The type of BootstrapMethods items. These items are stored in a special class attribute named + * BootstrapMethods and not in the constant pool. */ static final int BSM = 33; @@ -328,15 +313,13 @@ public class ClassWriter extends ClassVisitor { final Item key4; /** - * A type table used to temporarily store internal names that will not - * necessarily be stored in the constant pool. This type table is used by - * the control flow and data flow analysis algorithm used to compute stack - * map frames from scratch. This array associates to each index i - * the Item whose index is i. All Item objects stored in this array - * are also stored in the {@link #items} hash table. These two arrays allow - * to retrieve an Item from its index or, conversely, to get the index of an - * Item from its value. Each Item stores an internal name in its - * {@link Item#strVal1} field. + * A type table used to temporarily store internal names that will not necessarily be stored in + * the constant pool. This type table is used by the control flow and data flow analysis + * algorithm used to compute stack map frames from scratch. This array associates to each index + * i the Item whose index is i. All Item objects stored in this array are also + * stored in the {@link #items} hash table. These two arrays allow to retrieve an Item from its + * index or, conversely, to get the index of an Item from its value. Each Item stores an + * internal name in its {@link Item#strVal1} field. */ Item[] typeTable; @@ -366,8 +349,7 @@ public class ClassWriter extends ClassVisitor { private int signature; /** - * The constant pool item that contains the internal name of the super class - * of this class. + * The constant pool item that contains the internal name of the super class of this class. */ private int superName; @@ -377,15 +359,15 @@ public class ClassWriter extends ClassVisitor { private int interfaceCount; /** - * The interfaces implemented or extended by this class or interface. More - * precisely, this array contains the indexes of the constant pool items - * that contain the internal names of these interfaces. + * The interfaces implemented or extended by this class or interface. More precisely, this array + * contains the indexes of the constant pool items that contain the internal names of these + * interfaces. */ private int[] interfaces; /** - * The index of the constant pool item that contains the name of the source - * file from which this class was compiled. + * The index of the constant pool item that contains the name of the source file from which this + * class was compiled. */ private int sourceFile; @@ -395,14 +377,13 @@ public class ClassWriter extends ClassVisitor { private ByteVector sourceDebug; /** - * The constant pool item that contains the name of the enclosing class of - * this class. + * The constant pool item that contains the name of the enclosing class of this class. */ private int enclosingMethodOwner; /** - * The constant pool item that contains the name and descriptor of the - * enclosing method of this class. + * The constant pool item that contains the name and descriptor of the enclosing method of this + * class. */ private int enclosingMethod; @@ -442,40 +423,36 @@ public class ClassWriter extends ClassVisitor { ByteVector bootstrapMethods; /** - * The fields of this class. These fields are stored in a linked list of - * {@link FieldWriter} objects, linked to each other by their - * {@link FieldWriter#fv} field. This field stores the first element of this - * list. + * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} + * objects, linked to each other by their {@link FieldWriter#fv} field. This field stores the + * first element of this list. */ FieldWriter firstField; /** - * The fields of this class. These fields are stored in a linked list of - * {@link FieldWriter} objects, linked to each other by their - * {@link FieldWriter#fv} field. This field stores the last element of this - * list. + * The fields of this class. These fields are stored in a linked list of {@link FieldWriter} + * objects, linked to each other by their {@link FieldWriter#fv} field. This field stores the + * last element of this list. */ FieldWriter lastField; /** - * The methods of this class. These methods are stored in a linked list of - * {@link MethodWriter} objects, linked to each other by their - * {@link MethodWriter#mv} field. This field stores the first element of - * this list. + * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} + * objects, linked to each other by their {@link MethodWriter#mv} field. This field stores the + * first element of this list. */ MethodWriter firstMethod; /** - * The methods of this class. These methods are stored in a linked list of - * {@link MethodWriter} objects, linked to each other by their - * {@link MethodWriter#mv} field. This field stores the last element of this - * list. + * The methods of this class. These methods are stored in a linked list of {@link MethodWriter} + * objects, linked to each other by their {@link MethodWriter#mv} field. This field stores the + * last element of this list. */ MethodWriter lastMethod; /** - * true if the maximum stack size and number of local variables - * must be automatically computed. + * true if the maximum stack size and number of local variables must be automatically + * computed. */ private boolean computeMaxs; @@ -486,11 +463,10 @@ public class ClassWriter extends ClassVisitor { /** * true if the stack map tables of this class are invalid. The - * {@link MethodWriter#resizeInstructions} method cannot transform existing - * stack map tables, and so produces potentially invalid classes when it is - * executed. In this case the class is reread and rewritten with the - * {@link #COMPUTE_FRAMES} option (the resizeInstructions method can resize - * stack map tables when this option is used). + * {@link MethodWriter#resizeInstructions} method cannot transform existing stack map tables, + * and so produces potentially invalid classes when it is executed. In this case the class is + * reread and rewritten with the {@link #COMPUTE_FRAMES} option (the resizeInstructions method + * can resize stack map tables when this option is used). */ boolean invalidFrames; @@ -589,10 +565,8 @@ public class ClassWriter extends ClassVisitor { /** * Constructs a new {@link ClassWriter} object. * - * @param flags - * option flags that can be used to modify the default behavior - * of this class. See {@link #COMPUTE_MAXS}, - * {@link #COMPUTE_FRAMES}. + * @param flags option flags that can be used to modify the default behavior of this class. See + * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. */ public ClassWriter(final int flags) { super(Opcodes.ASM4); @@ -609,36 +583,27 @@ public class ClassWriter extends ClassVisitor { } /** - * Constructs a new {@link ClassWriter} object and enables optimizations for - * "mostly add" bytecode transformations. These optimizations are the - * following: + * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" + * bytecode transformations. These optimizations are the following: * *
    - *
  • The constant pool from the original class is copied as is in the new - * class, which saves time. New constant pool entries will be added at the - * end if necessary, but unused constant pool entries won't be - * removed.
  • - *
  • Methods that are not transformed are copied as is in the new class, - * directly from the original class bytecode (i.e. without emitting visit - * events for all the method instructions), which saves a lot of - * time. Untransformed methods are detected by the fact that the - * {@link ClassReader} receives {@link MethodVisitor} objects that come from - * a {@link ClassWriter} (and not from any other {@link ClassVisitor} - * instance).
  • + *
  • The constant pool from the original class is copied as is in the new class, which saves + * time. New constant pool entries will be added at the end if necessary, but unused constant + * pool entries won't be removed.
  • + *
  • Methods that are not transformed are copied as is in the new class, directly from the + * original class bytecode (i.e. without emitting visit events for all the method instructions), + * which saves a lot of time. Untransformed methods are detected by the fact that the + * {@link ClassReader} receives {@link MethodVisitor} objects that come from a + * {@link ClassWriter} (and not from any other {@link ClassVisitor} instance).
  • *
* - * @param classReader - * the {@link ClassReader} used to read the original class. It - * will be used to copy the entire constant pool from the - * original class and also to copy other fragments of original - * bytecode where applicable. - * @param flags - * option flags that can be used to modify the default behavior - * of this class. These option flags do not affect methods - * that are copied as is in the new class. This means that the - * maximum stack size nor the stack frames will be computed for - * these methods. See {@link #COMPUTE_MAXS}, - * {@link #COMPUTE_FRAMES}. + * @param classReader the {@link ClassReader} used to read the original class. It will be used + * to copy the entire constant pool from the original class and also to copy other + * fragments of original bytecode where applicable. + * @param flags option flags that can be used to modify the default behavior of this class. + * These option flags do not affect methods that are copied as is in the new class. + * This means that the maximum stack size nor the stack frames will be computed for these + * methods. See {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { this(flags); @@ -651,9 +616,8 @@ public class ClassWriter extends ClassVisitor { // ------------------------------------------------------------------------ @Override - public final void visit(final int version, final int access, - final String name, final String signature, final String superName, - final String[] interfaces) { + public final 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 = newClass(name); @@ -682,8 +646,7 @@ public class ClassWriter extends ClassVisitor { } @Override - public final void visitOuterClass(final String owner, final String name, - final String desc) { + public final void visitOuterClass(final String owner, final String name, final String desc) { enclosingMethodOwner = newClass(owner); if (name != null && desc != null) { enclosingMethod = newNameType(name, desc); @@ -691,8 +654,7 @@ public class ClassWriter extends ClassVisitor { } @Override - public final AnnotationVisitor visitAnnotation(final String desc, - final boolean visible) { + public final AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -717,8 +679,8 @@ public class ClassWriter extends ClassVisitor { } @Override - public final void visitInnerClass(final String name, - final String outerName, final String innerName, final int access) { + public final void visitInnerClass(final String name, final String outerName, + final String innerName, final int access) { if (innerClasses == null) { innerClasses = new ByteVector(); } @@ -730,21 +692,20 @@ public class ClassWriter extends ClassVisitor { } @Override - public final FieldVisitor visitField(final int access, final String name, - final String desc, final String signature, final Object value) { + public final FieldVisitor visitField(final int access, final String name, final String desc, + final String signature, final Object value) { return new FieldWriter(this, access, name, desc, signature, value); } @Override - public final MethodVisitor visitMethod(final int access, final String name, - final String desc, final String signature, final String[] exceptions) { - return new MethodWriter(this, access, name, desc, signature, - exceptions, computeMaxs, computeFrames); + public final MethodVisitor visitMethod(final int access, final String name, final String desc, + final String signature, final String[] exceptions) { + return new MethodWriter(this, access, name, desc, signature, exceptions, computeMaxs, + computeFrames); } @Override - public final void visitEnd() { - } + public final void visitEnd() {} // ------------------------------------------------------------------------ // Other public methods @@ -809,8 +770,7 @@ public class ClassWriter extends ClassVisitor { newUTF8("Deprecated"); } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((version & 0xFFFF) < Opcodes.V1_5 - || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { ++attributeCount; size += 6; newUTF8("Synthetic"); @@ -863,8 +823,7 @@ public class ClassWriter extends ClassVisitor { out.putShort(attributeCount); if (bootstrapMethods != null) { out.putShort(newUTF8("BootstrapMethods")); - out.putInt(bootstrapMethods.length + 2).putShort( - bootstrapMethodsCount); + out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount); out.putByteArray(bootstrapMethods.data, 0, bootstrapMethods.length); } if (ClassReader.SIGNATURES && signature != 0) { @@ -886,8 +845,7 @@ public class ClassWriter extends ClassVisitor { out.putShort(newUTF8("Deprecated")).putInt(0); } if ((access & Opcodes.ACC_SYNTHETIC) != 0) { - if ((version & 0xFFFF) < Opcodes.V1_5 - || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { + if ((version & 0xFFFF) < Opcodes.V1_5 || (access & ACC_SYNTHETIC_ATTRIBUTE) != 0) { out.putShort(newUTF8("Synthetic")).putInt(0); } } @@ -933,14 +891,12 @@ public class ClassWriter extends ClassVisitor { // ------------------------------------------------------------------------ /** - * Adds a number or string constant to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. + * Adds a number or string constant to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. * - * @param cst - * the value of the constant to be added to the constant pool. - * This parameter must be an {@link Integer}, a {@link Float}, a - * {@link Long}, a {@link Double}, a {@link String} or a - * {@link Type}. + * @param cst the value of the constant to be added to the constant pool. This parameter must be + * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a + * {@link String} or a {@link Type}. * @return a new or already existing constant item with the given value. */ Item newConstItem(final Object cst) { @@ -989,30 +945,27 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a number or string constant to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a number or string constant to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param cst - * the value of the constant to be added to the constant pool. - * This parameter must be an {@link Integer}, a {@link Float}, a - * {@link Long}, a {@link Double} or a {@link String}. - * @return the index of a new or already existing constant item with the - * given value. + * @param cst the value of the constant to be added to the constant pool. This parameter must be + * an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a + * {@link String}. + * @return the index of a new or already existing constant item with the given value. */ public int newConst(final Object cst) { return newConstItem(cst).index; } /** - * Adds an UTF8 string to the constant pool of the class being build. Does - * nothing if the constant pool already contains a similar item. This - * method is intended for {@link Attribute} sub classes, and is normally not - * needed by class generators or adapters. + * Adds an UTF8 string to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param value - * the String value. + * @param value the String value. * @return the index of a new or already existing UTF8 item. */ public int newUTF8(final String value) { @@ -1027,13 +980,12 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a class reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a class reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param value - * the internal name of the class. + * @param value the internal name of the class. * @return a new or already existing class reference item. */ Item newClassItem(final String value) { @@ -1048,13 +1000,12 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a class reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a class reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param value - * the internal name of the class. + * @param value the internal name of the class. * @return the index of a new or already existing class reference item. */ public int newClass(final String value) { @@ -1062,13 +1013,12 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a method type reference to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a method type reference to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param methodDesc - * method descriptor of the method type. + * @param methodDesc method descriptor of the method type. * @return a new or already existing method type reference item. */ Item newMethodTypeItem(final String methodDesc) { @@ -1083,54 +1033,41 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a method type reference to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a method type reference to the constant pool of the class being build. Does nothing if + * the constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param methodDesc - * method descriptor of the method type. - * @return the index of a new or already existing method type reference - * item. + * @param methodDesc method descriptor of the method type. + * @return the index of a new or already existing method type reference item. */ public int newMethodType(final String methodDesc) { return newMethodTypeItem(methodDesc).index; } /** - * Adds a handle to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by - * class generators or adapters. + * Adds a handle to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. * - * @param tag - * the kind of 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 field or method owner class. - * @param name - * the name of the field or method. - * @param desc - * the descriptor of the field or method. + * @param tag the kind of 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 field or method owner class. + * @param name the name of the field or method. + * @param desc the descriptor of the field or method. * @return a new or an already existing method type reference item. */ - Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + Item newHandleItem(final int tag, final String owner, final String name, final String desc) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { if (tag <= Opcodes.H_PUTSTATIC) { put112(HANDLE, tag, newField(owner, name, desc)); } else { - put112(HANDLE, - tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + put112(HANDLE, tag, newMethod(owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE)); } result = new Item(index++, key4); put(result); @@ -1139,52 +1076,39 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a handle to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. This method is - * intended for {@link Attribute} sub classes, and is normally not needed by - * class generators or adapters. + * Adds a handle to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. This method is intended for {@link Attribute} sub + * classes, and is normally not needed by class generators or adapters. * - * @param tag - * the kind of 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 field or method owner class. - * @param name - * the name of the field or method. - * @param desc - * the descriptor of the field or method. - * @return the index of a new or already existing method type reference - * item. + * @param tag the kind of 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 field or method owner class. + * @param name the name of the field or method. + * @param desc the descriptor of the field or method. + * @return the index of a new or already existing method type reference item. */ - public int newHandle(final int tag, final String owner, final String name, - final String desc) { + public int newHandle(final int tag, final String owner, final String name, final String desc) { return newHandleItem(tag, owner, name, desc).index; } /** - * Adds an invokedynamic reference to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param name - * name of the invoked method. - * @param desc - * descriptor of the invoke method. - * @param bsm - * the bootstrap method. - * @param bsmArgs - * the bootstrap method constant arguments. + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. * * @return a new or an already existing invokedynamic type reference item. */ - Item newInvokeDynamicItem(final String name, final String desc, - final Handle bsm, final Object... bsmArgs) { + Item newInvokeDynamicItem(final String name, final String desc, final Handle bsm, + final Object... bsmArgs) { // cache for performance ByteVector bootstrapMethods = this.bootstrapMethods; if (bootstrapMethods == null) { @@ -1194,8 +1118,7 @@ public class ClassWriter extends ClassVisitor { int position = bootstrapMethods.length; // record current position int hashCode = bsm.hashCode(); - bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, bsm.desc)); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); @@ -1251,38 +1174,30 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds an invokedynamic reference to the constant pool of the class being - * build. Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds an invokedynamic reference to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param name - * name of the invoked method. - * @param desc - * descriptor of the invoke method. - * @param bsm - * the bootstrap method. - * @param bsmArgs - * the bootstrap method constant arguments. + * @param name name of the invoked method. + * @param desc descriptor of the invoke method. + * @param bsm the bootstrap method. + * @param bsmArgs the bootstrap method constant arguments. * - * @return the index of a new or already existing invokedynamic reference - * item. + * @return the index of a new or already existing invokedynamic reference item. */ - public int newInvokeDynamic(final String name, final String desc, - final Handle bsm, final Object... bsmArgs) { + public int newInvokeDynamic(final String name, final String desc, final Handle bsm, + final Object... bsmArgs) { return newInvokeDynamicItem(name, desc, bsm, bsmArgs).index; } /** - * Adds a field reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. + * Adds a field reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. * - * @param owner - * the internal name of the field's owner class. - * @param name - * the field's name. - * @param desc - * the field's descriptor. + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. * @return a new or already existing field reference item. */ Item newFieldItem(final String owner, final String name, final String desc) { @@ -1297,17 +1212,14 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a field reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a field reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param owner - * the internal name of the field's owner class. - * @param name - * the field's name. - * @param desc - * the field's descriptor. + * @param owner the internal name of the field's owner class. + * @param name the field's name. + * @param desc the field's descriptor. * @return the index of a new or already existing field reference item. */ public int newField(final String owner, final String name, final String desc) { @@ -1315,21 +1227,17 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a method reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. + * Adds a method reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. * - * @param owner - * the internal name of the method's owner class. - * @param name - * the method's name. - * @param desc - * the method's descriptor. - * @param itf - * true if owner is an interface. + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf true if owner is an interface. * @return a new or already existing method reference item. */ - Item newMethodItem(final String owner, final String name, - final String desc, final boolean itf) { + Item newMethodItem(final String owner, final String name, final String desc, + final boolean itf) { int type = itf ? IMETH : METH; key3.set(type, owner, name, desc); Item result = get(key3); @@ -1342,32 +1250,27 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a method reference to the constant pool of the class being build. - * Does nothing if the constant pool already contains a similar item. - * This method is intended for {@link Attribute} sub classes, and is - * normally not needed by class generators or adapters. + * Adds a method reference to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param owner - * the internal name of the method's owner class. - * @param name - * the method's name. - * @param desc - * the method's descriptor. - * @param itf - * true if owner is an interface. + * @param owner the internal name of the method's owner class. + * @param name the method's name. + * @param desc the method's descriptor. + * @param itf true if owner is an interface. * @return the index of a new or already existing method reference item. */ - public int newMethod(final String owner, final String name, - final String desc, final boolean itf) { + public int newMethod(final String owner, final String name, final String desc, + final boolean itf) { return newMethodItem(owner, name, desc, itf).index; } /** - * Adds an integer to the constant pool of the class being build. Does - * nothing if the constant pool already contains a similar item. + * Adds an integer to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. * - * @param value - * the int value. + * @param value the int value. * @return a new or already existing int item. */ Item newInteger(final int value) { @@ -1382,11 +1285,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a float to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. + * Adds a float to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. * - * @param value - * the float value. + * @param value the float value. * @return a new or already existing float item. */ Item newFloat(final float value) { @@ -1401,11 +1303,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a long to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. + * Adds a long to the constant pool of the class being build. Does nothing if the constant pool + * already contains a similar item. * - * @param value - * the long value. + * @param value the long value. * @return a new or already existing long item. */ Item newLong(final long value) { @@ -1421,11 +1322,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a double to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. + * Adds a double to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. * - * @param value - * the double value. + * @param value the double value. * @return a new or already existing double item. */ Item newDouble(final double value) { @@ -1441,11 +1341,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a string to the constant pool of the class being build. Does nothing - * if the constant pool already contains a similar item. + * Adds a string to the constant pool of the class being build. Does nothing if the constant + * pool already contains a similar item. * - * @param value - * the String value. + * @param value the String value. * @return a new or already existing string item. */ private Item newString(final String value) { @@ -1460,15 +1359,13 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a name and type to the constant pool of the class being build. Does - * nothing if the constant pool already contains a similar item. This - * method is intended for {@link Attribute} sub classes, and is normally not - * needed by class generators or adapters. + * Adds a name and type to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. This method is intended for + * {@link Attribute} sub classes, and is normally not needed by class generators or + * adapters. * - * @param name - * a name. - * @param desc - * a type descriptor. + * @param name a name. + * @param desc a type descriptor. * @return the index of a new or already existing name and type item. */ public int newNameType(final String name, final String desc) { @@ -1476,13 +1373,11 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds a name and type to the constant pool of the class being build. Does - * nothing if the constant pool already contains a similar item. + * Adds a name and type to the constant pool of the class being build. Does nothing if the + * constant pool already contains a similar item. * - * @param name - * a name. - * @param desc - * a type descriptor. + * @param name a name. + * @param desc a type descriptor. * @return a new or already existing name and type item. */ Item newNameTypeItem(final String name, final String desc) { @@ -1497,11 +1392,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds the given internal name to {@link #typeTable} and returns its index. - * Does nothing if the type table already contains this internal name. + * Adds the given internal name to {@link #typeTable} and returns its index. Does nothing if the + * type table already contains this internal name. * - * @param type - * the internal name to be added to the type table. + * @param type the internal name to be added to the type table. * @return the index of this internal name in the type table. */ int addType(final String type) { @@ -1514,15 +1408,12 @@ public class ClassWriter extends ClassVisitor { } /** - * Adds the given "uninitialized" type to {@link #typeTable} and returns its - * index. This method is used for UNINITIALIZED types, made of an internal - * name and a bytecode offset. + * Adds the given "uninitialized" type to {@link #typeTable} and returns its index. This method + * is used for UNINITIALIZED types, made of an internal name and a bytecode offset. * - * @param type - * the internal name to be added to the type table. - * @param offset - * the bytecode offset of the NEW instruction that created this - * UNINITIALIZED type value. + * @param type the internal name to be added to the type table. + * @param offset the bytecode offset of the NEW instruction that created this UNINITIALIZED type + * value. * @return the index of this internal name in the type table. */ int addUninitializedType(final String type, final int offset) { @@ -1540,10 +1431,8 @@ public class ClassWriter extends ClassVisitor { /** * Adds the given Item to {@link #typeTable}. * - * @param item - * the value to be added to the type table. - * @return the added Item, which a new Item instance with the same value as - * the given Item. + * @param item the value to be added to the type table. + * @return the added Item, which a new Item instance with the same value as the given Item. */ private Item addType(final Item item) { ++typeCount; @@ -1562,15 +1451,12 @@ public class ClassWriter extends ClassVisitor { } /** - * Returns the index of the common super type of the two given types. This - * method calls {@link #getCommonSuperClass} and caches the result in the - * {@link #items} hash table to speedup future calls with the same - * parameters. + * Returns the index of the common super type of the two given types. This method calls + * {@link #getCommonSuperClass} and caches the result in the {@link #items} hash table to + * speedup future calls with the same parameters. * - * @param type1 - * index of an internal name in {@link #typeTable}. - * @param type2 - * index of an internal name in {@link #typeTable}. + * @param type1 index of an internal name in {@link #typeTable}. + * @param type2 index of an internal name in {@link #typeTable}. * @return the index of the common super type of the two given types. */ int getMergedType(final int type1, final int type2) { @@ -1589,20 +1475,16 @@ public class ClassWriter extends ClassVisitor { } /** - * Returns the common super type of the two given types. The default - * implementation of this method loads the two given classes and uses - * the java.lang.Class methods to find the common super class. It can be - * overridden to compute this common super type in other ways, in particular - * without actually loading any class, or to take into account the class - * that is currently being generated by this ClassWriter, which can of - * course not be loaded since it is under construction. + * Returns the common super type of the two given types. The default implementation of this + * method loads the two given classes and uses the java.lang.Class methods to find the + * common super class. It can be overridden to compute this common super type in other ways, in + * particular without actually loading any class, or to take into account the class that is + * currently being generated by this ClassWriter, which can of course not be loaded since it is + * under construction. * - * @param type1 - * the internal name of a class. - * @param type2 - * the internal name of another class. - * @return the internal name of the common super class of the two given - * classes. + * @param type1 the internal name of a class. + * @param type2 the internal name of another class. + * @return the internal name of the common super class of the two given classes. */ protected String getCommonSuperClass(final String type1, final String type2) { Class c, d; @@ -1630,13 +1512,11 @@ public class ClassWriter extends ClassVisitor { } /** - * Returns the constant pool's hash table item which is equal to the given - * item. + * Returns the constant pool's hash table item which is equal to the given item. * - * @param key - * a constant pool item. - * @return the constant pool's hash table item which is equal to the given - * item, or null if there is no such item. + * @param key a constant pool item. + * @return the constant pool's hash table item which is equal to the given item, or + * null if there is no such item. */ private Item get(final Item key) { Item i = items[key.hashCode % items.length]; @@ -1647,11 +1527,10 @@ public class ClassWriter extends ClassVisitor { } /** - * Puts the given item in the constant pool's hash table. The hash table - * must not already contains this item. + * Puts the given item in the constant pool's hash table. The hash table must not already + * contains this item. * - * @param i - * the item to be added to the constant pool's hash table. + * @param i the item to be added to the constant pool's hash table. */ private void put(final Item i) { if (index + typeCount > threshold) { @@ -1679,12 +1558,9 @@ public class ClassWriter extends ClassVisitor { /** * Puts one byte and two shorts into the constant pool. * - * @param b - * a byte. - * @param s1 - * a short. - * @param s2 - * another short. + * @param b a byte. + * @param s1 a short. + * @param s2 another short. */ private void put122(final int b, final int s1, final int s2) { pool.put12(b, s1).putShort(s2); @@ -1693,12 +1569,9 @@ public class ClassWriter extends ClassVisitor { /** * Puts two bytes and one short into the constant pool. * - * @param b1 - * a byte. - * @param b2 - * another byte. - * @param s - * a short. + * @param b1 a byte. + * @param b2 another byte. + * @param s a short. */ private void put112(final int b1, final int b2, final int s) { pool.put11(b1, b2).putShort(s); diff --git a/src/main/asm/org/objectweb/asm/Context.java b/src/main/asm/org/objectweb/asm/Context.java index 34691b6..b5b41b2 100644 --- a/src/main/asm/org/objectweb/asm/Context.java +++ b/src/main/asm/org/objectweb/asm/Context.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -88,8 +80,8 @@ class Context { int localCount; /** - * The number locals in the latest stack map frame that has been parsed, - * minus the number of locals in the previous frame. + * The number locals in the latest stack map frame that has been parsed, minus the number of + * locals in the previous frame. */ int localDiff; @@ -107,4 +99,4 @@ class Context { * The stack values of the latest stack map frame that has been parsed. */ Object[] stack; -} \ No newline at end of file +} diff --git a/src/main/asm/org/objectweb/asm/Edge.java b/src/main/asm/org/objectweb/asm/Edge.java index 4e87cba..e57a1ce 100644 --- a/src/main/asm/org/objectweb/asm/Edge.java +++ b/src/main/asm/org/objectweb/asm/Edge.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -42,23 +34,20 @@ class 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. + * 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). + * 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; @@ -68,8 +57,8 @@ class Edge { Label successor; /** - * The next edge in the list of successors of the originating basic block. - * See {@link Label#successors successors}. + * The next edge in the list of successors of the originating basic block. See + * {@link Label#successors successors}. */ Edge next; } diff --git a/src/main/asm/org/objectweb/asm/FieldVisitor.java b/src/main/asm/org/objectweb/asm/FieldVisitor.java index ad6db26..4fd4ad5 100644 --- a/src/main/asm/org/objectweb/asm/FieldVisitor.java +++ b/src/main/asm/org/objectweb/asm/FieldVisitor.java @@ -1,61 +1,50 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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: ( visitAnnotation | visitAttribute )* - * visitEnd. + * A visitor to visit a Java field. The methods of this class must be called in the following order: + * ( visitAnnotation | visitAttribute )* visitEnd. * * @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}. + * 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. + * 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}. + * @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); @@ -64,12 +53,9 @@ public abstract class FieldVisitor { /** * 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. + * @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) { @@ -82,12 +68,10 @@ public abstract class FieldVisitor { /** * Visits an annotation of the field. * - * @param desc - * the class descriptor of the annotation class. - * @param visible - * true if the annotation is visible at runtime. - * @return a visitor to visit the annotation values, or null if - * this visitor is not interested in visiting this annotation. + * @param desc the class descriptor of the annotation class. + * @param visible true if the annotation is visible at runtime. + * @return a visitor to visit the annotation values, or null if this visitor is not + * interested in visiting this annotation. */ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (fv != null) { @@ -99,8 +83,7 @@ public abstract class FieldVisitor { /** * Visits a non standard attribute of the field. * - * @param attr - * an attribute. + * @param attr an attribute. */ public void visitAttribute(Attribute attr) { if (fv != null) { @@ -109,9 +92,8 @@ public abstract class FieldVisitor { } /** - * 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. + * 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) { diff --git a/src/main/asm/org/objectweb/asm/FieldWriter.java b/src/main/asm/org/objectweb/asm/FieldWriter.java index 5cbd9c7..75c17db 100644 --- a/src/main/asm/org/objectweb/asm/FieldWriter.java +++ b/src/main/asm/org/objectweb/asm/FieldWriter.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -47,26 +39,22 @@ final class FieldWriter extends FieldVisitor { private final int access; /** - * The index of the constant pool item that contains the name of this - * method. + * 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. + * 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. + * 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. + * The index of the constant pool item that contains the constant value of this field. */ private int value; @@ -92,21 +80,15 @@ final class FieldWriter extends FieldVisitor { /** * 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 null. - * @param value - * the field's constant value. May be null. + * @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 null. + * @param value the field's constant value. May be null. */ - FieldWriter(final ClassWriter cw, final int access, final String name, - final String desc, final String signature, final Object value) { + 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; @@ -131,8 +113,7 @@ final class FieldWriter extends FieldVisitor { // ------------------------------------------------------------------------ @Override - public AnnotationVisitor visitAnnotation(final String desc, - final boolean visible) { + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -157,8 +138,7 @@ final class FieldWriter extends FieldVisitor { } @Override - public void visitEnd() { - } + public void visitEnd() {} // ------------------------------------------------------------------------ // Utility methods @@ -207,8 +187,7 @@ final class FieldWriter extends FieldVisitor { /** * Puts the content of this field into the given byte vector. * - * @param out - * where the content of this field must be put. + * @param out where the content of this field must be put. */ void put(final ByteVector out) { final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; diff --git a/src/main/asm/org/objectweb/asm/Frame.java b/src/main/asm/org/objectweb/asm/Frame.java index 10e15bc..07e7644 100644 --- a/src/main/asm/org/objectweb/asm/Frame.java +++ b/src/main/asm/org/objectweb/asm/Frame.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -37,61 +29,51 @@ package org.objectweb.asm; final class Frame { /* - * Frames are computed in a two steps process: during the visit of each - * instruction, the state of the frame at the end of current basic block is - * updated by simulating the action of the instruction on the previous state - * of this so called "output frame". In visitMaxs, a fix point algorithm is - * used to compute the "input frame" of each basic block, i.e. the stack map - * frame at the beginning of the basic block, starting from the input frame - * of the first basic block (which is computed from the method descriptor), - * and by using the previously computed output frames to compute the input - * state of the other blocks. + * Frames are computed in a two steps process: during the visit of each instruction, the state + * of the frame at the end of current basic block is updated by simulating the action of the + * instruction on the previous state of this so called "output frame". In visitMaxs, a fix point + * algorithm is used to compute the "input frame" of each basic block, i.e. the stack map frame + * at the beginning of the basic block, starting from the input frame of the first basic block + * (which is computed from the method descriptor), and by using the previously computed output + * frames to compute the input state of the other blocks. * - * All output and input frames are stored as arrays of integers. Reference - * and array types are represented by an index into a type table (which is - * not the same as the constant pool of the class, in order to avoid adding - * unnecessary constants in the pool - not all computed frames will end up - * being stored in the stack map table). This allows very fast type - * comparisons. + * All output and input frames are stored as arrays of integers. Reference and array types are + * represented by an index into a type table (which is not the same as the constant pool of the + * class, in order to avoid adding unnecessary constants in the pool - not all computed frames + * will end up being stored in the stack map table). This allows very fast type comparisons. * - * Output stack map frames are computed relatively to the input frame of the - * basic block, which is not yet known when output frames are computed. It - * is therefore necessary to be able to represent abstract types such as - * "the type at position x in the input frame locals" or "the type at - * position x from the top of the input frame stack" or even "the type at - * position x in the input frame, with y more (or less) array dimensions". - * This explains the rather complicated type format used in output frames. + * Output stack map frames are computed relatively to the input frame of the basic block, which + * is not yet known when output frames are computed. It is therefore necessary to be able to + * represent abstract types such as "the type at position x in the input frame locals" or "the + * type at position x from the top of the input frame stack" or even "the type at position x in + * the input frame, with y more (or less) array dimensions". This explains the rather + * complicated type format used in output frames. * - * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a - * signed number of array dimensions (from -8 to 7). KIND is either BASE, - * LOCAL or STACK. BASE is used for types that are not relative to the input - * frame. LOCAL is used for types that are relative to the input local - * variable types. STACK is used for types that are relative to the input - * stack types. VALUE depends on KIND. For LOCAL types, it is an index in - * the input local variable types. For STACK types, it is a position - * relatively to the top of input frame stack. For BASE types, it is either - * one of the constants defined in FrameVisitor, or for OBJECT and + * This format is the following: DIM KIND VALUE (4, 4 and 24 bits). DIM is a signed number of + * array dimensions (from -8 to 7). KIND is either BASE, LOCAL or STACK. BASE is used for types + * that are not relative to the input frame. LOCAL is used for types that are relative to the + * input local variable types. STACK is used for types that are relative to the input stack + * types. VALUE depends on KIND. For LOCAL types, it is an index in the input local variable + * types. For STACK types, it is a position relatively to the top of input frame stack. For BASE + * types, it is either one of the constants defined in FrameVisitor, or for OBJECT and * UNINITIALIZED types, a tag and an index in the type table. * - * Output frames can contain types of any kind and with a positive or - * negative dimension (and even unassigned types, represented by 0 - which - * does not correspond to any valid type value). Input frames can only - * contain BASE types of positive or null dimension. In all cases the type - * table contains only internal type names (array type descriptors are - * forbidden - dimensions must be represented through the DIM field). + * Output frames can contain types of any kind and with a positive or negative dimension (and + * even unassigned types, represented by 0 - which does not correspond to any valid type value). + * Input frames can only contain BASE types of positive or null dimension. In all cases the type + * table contains only internal type names (array type descriptors are forbidden - dimensions + * must be represented through the DIM field). * - * The LONG and DOUBLE types are always represented by using two slots (LONG - * + TOP or DOUBLE + TOP), for local variable types as well as in the - * operand stack. This is necessary to be able to simulate DUPx_y - * instructions, whose effect would be dependent on the actual type values - * if types were always represented by a single slot in the stack (and this - * is not possible, since actual type values are not always known - cf LOCAL - * and STACK type kinds). + * The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + + * TOP), for local variable types as well as in the operand stack. This is necessary to be able + * to simulate DUPx_y instructions, whose effect would be dependent on the actual type values if + * types were always represented by a single slot in the stack (and this is not possible, since + * actual type values are not always known - cf LOCAL and STACK type kinds). */ /** - * Mask to get the dimension of a frame type. This dimension is a signed - * integer between -8 and 7. + * Mask to get the dimension of a frame type. This dimension is a signed integer between -8 and + * 7. */ static final int DIM = 0xF0000000; @@ -115,11 +97,10 @@ final class Frame { static final int KIND = 0xF000000; /** - * Flag used for LOCAL and STACK types. Indicates that if this type happens - * to be a long or double type (during the computations of input frames), - * then it must be set to TOP because the second word of this value has been - * reused to store other data in the basic block. Hence the first word no - * longer stores a valid long or double value. + * Flag used for LOCAL and STACK types. Indicates that if this type happens to be a long or + * double type (during the computations of input frames), then it must be set to TOP because the + * second word of this value has been reused to store other data in the basic block. Hence the + * first word no longer stores a valid long or double value. */ static final int TOP_IF_LONG_OR_DOUBLE = 0x800000; @@ -144,28 +125,27 @@ final class Frame { static final int BASE = 0x1000000; /** - * Base kind of the base reference types. The BASE_VALUE of such types is an - * index into the type table. + * Base kind of the base reference types. The BASE_VALUE of such types is an index into the type + * table. */ static final int OBJECT = BASE | 0x700000; /** - * Base kind of the uninitialized base types. The BASE_VALUE of such types - * in an index into the type table (the Item at that index contains both an - * instruction offset and an internal class name). + * Base kind of the uninitialized base types. The BASE_VALUE of such types in an index into the + * type table (the Item at that index contains both an instruction offset and an internal class + * name). */ static final int UNINITIALIZED = BASE | 0x800000; /** - * Kind of the types that are relative to the local variable types of an - * input stack map frame. The value of such types is a local variable index. + * Kind of the types that are relative to the local variable types of an input stack map frame. + * The value of such types is a local variable index. */ private static final int LOCAL = 0x2000000; /** - * Kind of the the types that are relative to the stack of an input stack - * map frame. The value of such types is a position relatively to the top of - * this stack. + * Kind of the the types that are relative to the stack of an input stack map frame. The value + * of such types is a position relatively to the top of this stack. */ private static final int STACK = 0x3000000; @@ -225,9 +205,9 @@ final class Frame { static final int UNINITIALIZED_THIS = BASE | 6; /** - * The stack size variation corresponding to each JVM instruction. This - * stack variation is equal to the size of the values produced by an - * instruction, minus the size of the values consumed by this instruction. + * The stack size variation corresponding to each JVM instruction. This stack variation is equal + * to the size of the values produced by an instruction, minus the size of the values consumed + * by this instruction. */ static final int[] SIZE; @@ -461,8 +441,7 @@ final class Frame { } /** - * The label (i.e. basic block) to which these input and output stack map - * frames correspond. + * The label (i.e. basic block) to which these input and output stack map frames correspond. */ Label owner; @@ -487,14 +466,14 @@ final class Frame { private int[] outputStack; /** - * Relative size of the output stack. The exact semantics of this field - * depends on the algorithm that is used. + * Relative size of the output 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 size of - * the output stack relatively to the top of the input stack. + * When only the maximum stack size is computed, this field is the size of the output stack + * relatively to the top of the input stack. * - * When the stack map frames are completely computed, this field is the - * actual number of types in {@link #outputStack}. + * When the stack map frames are completely computed, this field is the actual number of types + * in {@link #outputStack}. */ private int outputStackTop; @@ -506,25 +485,22 @@ final class Frame { private int initializationCount; /** - * The types that are initialized in the basic block. A constructor - * invocation on an UNINITIALIZED or UNINITIALIZED_THIS type must replace - * every occurence of this type in the local variables and in the - * operand stack. This cannot be done during the first phase of the - * algorithm since, during this phase, the local variables and the operand - * stack are not completely computed. It is therefore necessary to store the - * types on which constructors are invoked in the basic block, in order to - * do this replacement during the second phase of the algorithm, where the - * frames are fully computed. Note that this array can contain types that - * are relative to input locals or to the input stack (see below for the - * description of the algorithm). + * The types that are initialized in the basic block. A constructor invocation on an + * UNINITIALIZED or UNINITIALIZED_THIS type must replace every occurence of this type in + * the local variables and in the operand stack. This cannot be done during the first phase of + * the algorithm since, during this phase, the local variables and the operand stack are not + * completely computed. It is therefore necessary to store the types on which constructors are + * invoked in the basic block, in order to do this replacement during the second phase of the + * algorithm, where the frames are fully computed. Note that this array can contain types that + * are relative to input locals or to the input stack (see below for the description of the + * algorithm). */ private int[] initializations; /** * Returns the output frame local variable type at the given index. * - * @param local - * the index of the local that must be returned. + * @param local the index of the local that must be returned. * @return the output frame local variable type at the given index. */ private int get(final int local) { @@ -546,10 +522,8 @@ final class Frame { /** * Sets the output frame local variable type at the given index. * - * @param local - * the index of the local that must be set. - * @param type - * the value of the local that must be set. + * @param local the index of the local that must be set. + * @param type the value of the local that must be set. */ private void set(final int local, final int type) { // creates and/or resizes the output local variables array if necessary @@ -569,8 +543,7 @@ final class Frame { /** * Pushes a new type onto the output frame stack. * - * @param type - * the type that must be pushed. + * @param type the type that must be pushed. */ private void push(final int type) { // creates and/or resizes the output stack array if necessary @@ -595,12 +568,9 @@ final class Frame { /** * Pushes a new type onto the output frame stack. * - * @param cw - * the ClassWriter to which this label belongs. - * @param desc - * the descriptor of the type to be pushed. Can also be a method - * descriptor (in this case this method pushes its return type - * onto the output frame stack). + * @param cw the ClassWriter to which this label belongs. + * @param desc the descriptor of the type to be pushed. Can also be a method descriptor (in this + * case this method pushes its return type onto the output frame stack). */ private void push(final ClassWriter cw, final String desc) { int type = type(cw, desc); @@ -615,74 +585,72 @@ final class Frame { /** * Returns the int encoding of the given type. * - * @param cw - * the ClassWriter to which this label belongs. - * @param desc - * a type descriptor. + * @param cw the ClassWriter to which this label belongs. + * @param desc a type descriptor. * @return the int encoding of the given type. */ private static int type(final ClassWriter cw, final String desc) { String t; int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0; switch (desc.charAt(index)) { - case 'V': - return 0; - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - return INTEGER; - case 'F': - return FLOAT; - case 'J': - return LONG; - case 'D': - return DOUBLE; - case 'L': - // stores the internal name, not the descriptor! - t = desc.substring(index + 1, desc.length() - 1); - return OBJECT | cw.addType(t); - // case '[': - default: - // extracts the dimensions and the element type - int data; - int dims = index + 1; - while (desc.charAt(dims) == '[') { - ++dims; - } - switch (desc.charAt(dims)) { + case 'V': + return 0; case 'Z': - data = BOOLEAN; - break; case 'C': - data = CHAR; - break; case 'B': - data = BYTE; - break; case 'S': - data = SHORT; - break; case 'I': - data = INTEGER; - break; + return INTEGER; case 'F': - data = FLOAT; - break; + return FLOAT; case 'J': - data = LONG; - break; + return LONG; case 'D': - data = DOUBLE; - break; - // case 'L': + return DOUBLE; + case 'L': + // stores the internal name, not the descriptor! + t = desc.substring(index + 1, desc.length() - 1); + return OBJECT | cw.addType(t); + // case '[': default: - // stores the internal name, not the descriptor - t = desc.substring(dims + 1, desc.length() - 1); - data = OBJECT | cw.addType(t); - } - return (dims - index) << 28 | data; + // extracts the dimensions and the element type + int data; + int dims = index + 1; + while (desc.charAt(dims) == '[') { + ++dims; + } + switch (desc.charAt(dims)) { + case 'Z': + data = BOOLEAN; + break; + case 'C': + data = CHAR; + break; + case 'B': + data = BYTE; + break; + case 'S': + data = SHORT; + break; + case 'I': + data = INTEGER; + break; + case 'F': + data = FLOAT; + break; + case 'J': + data = LONG; + break; + case 'D': + data = DOUBLE; + break; + // case 'L': + default: + // stores the internal name, not the descriptor + t = desc.substring(dims + 1, desc.length() - 1); + data = OBJECT | cw.addType(t); + } + return (dims - index) << 28 | data; } } @@ -703,8 +671,7 @@ final class Frame { /** * Pops the given number of types from the output frame stack. * - * @param elements - * the number of types that must be popped. + * @param elements the number of types that must be popped. */ private void pop(final int elements) { if (outputStackTop >= elements) { @@ -721,10 +688,8 @@ final class Frame { /** * Pops a type from the output frame stack. * - * @param desc - * the descriptor of the type to be popped. Can also be a method - * descriptor (in this case this method pops the types - * corresponding to the method arguments). + * @param desc the descriptor of the type to be popped. Can also be a method descriptor (in this + * case this method pops the types corresponding to the method arguments). */ private void pop(final String desc) { char c = desc.charAt(0); @@ -738,11 +703,9 @@ final class Frame { } /** - * Adds a new type to the list of types on which a constructor is invoked in - * the basic block. + * Adds a new type to the list of types on which a constructor is invoked in the basic block. * - * @param var - * a type on a which a constructor is invoked. + * @param var a type on a which a constructor is invoked. */ private void init(final int var) { // creates and/or resizes the initializations array if necessary @@ -760,15 +723,13 @@ final class Frame { } /** - * Replaces the given type with the appropriate type if it is one of the - * types on which a constructor is invoked in the basic block. + * Replaces the given type with the appropriate type if it is one of the types on which a + * constructor is invoked in the basic block. * - * @param cw - * the ClassWriter to which this label belongs. - * @param t - * a type - * @return t or, if t is one of the types on which a constructor is invoked - * in the basic block, the type corresponding to this constructor. + * @param cw the ClassWriter to which this label belongs. + * @param t a type + * @return t or, if t is one of the types on which a constructor is invoked in the basic block, + * the type corresponding to this constructor. */ private int init(final ClassWriter cw, final int t) { int s; @@ -797,20 +758,15 @@ final class Frame { } /** - * Initializes the input frame of the first basic block from the method - * descriptor. + * Initializes the input frame of the first basic block from the method descriptor. * - * @param cw - * the ClassWriter to which this label belongs. - * @param access - * the access flags of the method to which this label belongs. - * @param args - * the formal parameter types of this method. - * @param maxLocals - * the maximum number of local variables of this method. + * @param cw the ClassWriter to which this label belongs. + * @param access the access flags of the method to which this label belongs. + * @param args the formal parameter types of this method. + * @param maxLocals the maximum number of local variables of this method. */ - void initInputFrame(final ClassWriter cw, final int access, - final Type[] args, final int maxLocals) { + void initInputFrame(final ClassWriter cw, final int access, final Type[] args, + final int maxLocals) { inputLocals = new int[maxLocals]; inputStack = new int[0]; int i = 0; @@ -836,452 +792,442 @@ final class Frame { /** * Simulates the action of the given instruction on the output stack frame. * - * @param opcode - * the opcode of the instruction. - * @param arg - * the operand of the instruction, if any. - * @param cw - * the class writer to which this label belongs. - * @param item - * the operand of the instructions, if any. + * @param opcode the opcode of the instruction. + * @param arg the operand of the instruction, if any. + * @param cw the class writer to which this label belongs. + * @param item the operand of the instructions, if any. */ - void execute(final int opcode, final int arg, final ClassWriter cw, - final Item item) { + void execute(final int opcode, final int arg, final ClassWriter cw, final Item item) { int 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(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: - case Opcodes.ILOAD: - push(INTEGER); - break; - case Opcodes.LCONST_0: - case Opcodes.LCONST_1: - case Opcodes.LLOAD: - push(LONG); - push(TOP); - break; - case Opcodes.FCONST_0: - case Opcodes.FCONST_1: - case Opcodes.FCONST_2: - case Opcodes.FLOAD: - push(FLOAT); - break; - case Opcodes.DCONST_0: - case Opcodes.DCONST_1: - case Opcodes.DLOAD: - push(DOUBLE); - push(TOP); - break; - case Opcodes.LDC: - switch (item.type) { - case ClassWriter.INT: + 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(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: + case Opcodes.ILOAD: push(INTEGER); break; - case ClassWriter.LONG: + case Opcodes.LCONST_0: + case Opcodes.LCONST_1: + case Opcodes.LLOAD: push(LONG); push(TOP); break; - case ClassWriter.FLOAT: + case Opcodes.FCONST_0: + case Opcodes.FCONST_1: + case Opcodes.FCONST_2: + case Opcodes.FLOAD: push(FLOAT); break; - case ClassWriter.DOUBLE: + case Opcodes.DCONST_0: + case Opcodes.DCONST_1: + case Opcodes.DLOAD: push(DOUBLE); push(TOP); break; - case ClassWriter.CLASS: - push(OBJECT | cw.addType("java/lang/Class")); - break; - case ClassWriter.STR: - push(OBJECT | cw.addType("java/lang/String")); - break; - case ClassWriter.MTYPE: - push(OBJECT | cw.addType("java/lang/invoke/MethodType")); - break; - // case ClassWriter.HANDLE_BASE + [1..9]: - default: - push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); - } - break; - case Opcodes.ALOAD: - push(get(arg)); - break; - case Opcodes.IALOAD: - case Opcodes.BALOAD: - case Opcodes.CALOAD: - case Opcodes.SALOAD: - pop(2); - push(INTEGER); - break; - case Opcodes.LALOAD: - case Opcodes.D2L: - pop(2); - push(LONG); - push(TOP); - break; - case Opcodes.FALOAD: - pop(2); - push(FLOAT); - break; - case Opcodes.DALOAD: - case Opcodes.L2D: - pop(2); - push(DOUBLE); - push(TOP); - break; - case Opcodes.AALOAD: - pop(1); - t1 = pop(); - push(ELEMENT_OF + t1); - break; - case Opcodes.ISTORE: - case Opcodes.FSTORE: - case Opcodes.ASTORE: - t1 = pop(); - set(arg, t1); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + case Opcodes.LDC: + switch (item.type) { + case ClassWriter.INT: + push(INTEGER); + break; + case ClassWriter.LONG: + push(LONG); + push(TOP); + break; + case ClassWriter.FLOAT: + push(FLOAT); + break; + case ClassWriter.DOUBLE: + push(DOUBLE); + push(TOP); + break; + case ClassWriter.CLASS: + push(OBJECT | cw.addType("java/lang/Class")); + break; + case ClassWriter.STR: + push(OBJECT | cw.addType("java/lang/String")); + break; + case ClassWriter.MTYPE: + push(OBJECT | cw.addType("java/lang/invoke/MethodType")); + break; + // case ClassWriter.HANDLE_BASE + [1..9]: + default: + push(OBJECT | cw.addType("java/lang/invoke/MethodHandle")); } - } - break; - case Opcodes.LSTORE: - case Opcodes.DSTORE: - pop(1); - t1 = pop(); - set(arg, t1); - set(arg + 1, TOP); - if (arg > 0) { - t2 = get(arg - 1); - // if t2 is of kind STACK or LOCAL we cannot know its size! - if (t2 == LONG || t2 == DOUBLE) { - set(arg - 1, TOP); - } else if ((t2 & KIND) != BASE) { - set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); - } - } - 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(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(LONG); - push(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(FLOAT); - break; - case Opcodes.DADD: - case Opcodes.DSUB: - case Opcodes.DMUL: - case Opcodes.DDIV: - case Opcodes.DREM: - pop(4); - push(DOUBLE); - push(TOP); - break; - case Opcodes.LSHL: - case Opcodes.LSHR: - case Opcodes.LUSHR: - pop(3); - push(LONG); - push(TOP); - break; - case Opcodes.IINC: - set(arg, INTEGER); - break; - case Opcodes.I2L: - case Opcodes.F2L: - pop(1); - push(LONG); - push(TOP); - break; - case Opcodes.I2F: - pop(1); - push(FLOAT); - break; - case Opcodes.I2D: - case Opcodes.F2D: - pop(1); - push(DOUBLE); - push(TOP); - break; - case Opcodes.F2I: - case Opcodes.ARRAYLENGTH: - case Opcodes.INSTANCEOF: - pop(1); - push(INTEGER); - break; - case Opcodes.LCMP: - case Opcodes.DCMPL: - case Opcodes.DCMPG: - pop(4); - push(INTEGER); - break; - case Opcodes.JSR: - case Opcodes.RET: - throw new RuntimeException( - "JSR/RET are not supported with computeFrames option"); - case Opcodes.GETSTATIC: - push(cw, item.strVal3); - break; - case Opcodes.PUTSTATIC: - pop(item.strVal3); - break; - case Opcodes.GETFIELD: - pop(1); - push(cw, item.strVal3); - break; - case Opcodes.PUTFIELD: - pop(item.strVal3); - pop(); - break; - case Opcodes.INVOKEVIRTUAL: - case Opcodes.INVOKESPECIAL: - case Opcodes.INVOKESTATIC: - case Opcodes.INVOKEINTERFACE: - pop(item.strVal3); - if (opcode != Opcodes.INVOKESTATIC) { + break; + case Opcodes.ALOAD: + push(get(arg)); + break; + case Opcodes.IALOAD: + case Opcodes.BALOAD: + case Opcodes.CALOAD: + case Opcodes.SALOAD: + pop(2); + push(INTEGER); + break; + case Opcodes.LALOAD: + case Opcodes.D2L: + pop(2); + push(LONG); + push(TOP); + break; + case Opcodes.FALOAD: + pop(2); + push(FLOAT); + break; + case Opcodes.DALOAD: + case Opcodes.L2D: + pop(2); + push(DOUBLE); + push(TOP); + break; + case Opcodes.AALOAD: + pop(1); t1 = pop(); - if (opcode == Opcodes.INVOKESPECIAL - && item.strVal2.charAt(0) == '<') { - init(t1); + push(ELEMENT_OF + t1); + break; + case Opcodes.ISTORE: + case Opcodes.FSTORE: + case Opcodes.ASTORE: + t1 = pop(); + set(arg, t1); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } } - } - push(cw, item.strVal3); - break; - case Opcodes.INVOKEDYNAMIC: - pop(item.strVal2); - push(cw, item.strVal2); - break; - case Opcodes.NEW: - push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); - break; - case Opcodes.NEWARRAY: - pop(); - switch (arg) { - case Opcodes.T_BOOLEAN: - push(ARRAY_OF | BOOLEAN); break; - case Opcodes.T_CHAR: - push(ARRAY_OF | CHAR); + case Opcodes.LSTORE: + case Opcodes.DSTORE: + pop(1); + t1 = pop(); + set(arg, t1); + set(arg + 1, TOP); + if (arg > 0) { + t2 = get(arg - 1); + // if t2 is of kind STACK or LOCAL we cannot know its size! + if (t2 == LONG || t2 == DOUBLE) { + set(arg - 1, TOP); + } else if ((t2 & KIND) != BASE) { + set(arg - 1, t2 | TOP_IF_LONG_OR_DOUBLE); + } + } break; - case Opcodes.T_BYTE: - push(ARRAY_OF | BYTE); + case Opcodes.IASTORE: + case Opcodes.BASTORE: + case Opcodes.CASTORE: + case Opcodes.SASTORE: + case Opcodes.FASTORE: + case Opcodes.AASTORE: + pop(3); break; - case Opcodes.T_SHORT: - push(ARRAY_OF | SHORT); + case Opcodes.LASTORE: + case Opcodes.DASTORE: + pop(4); break; - case Opcodes.T_INT: - push(ARRAY_OF | INTEGER); + 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.T_FLOAT: - push(ARRAY_OF | FLOAT); + 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.T_DOUBLE: - push(ARRAY_OF | DOUBLE); + case Opcodes.DUP: + t1 = pop(); + push(t1); + push(t1); break; - // case Opcodes.T_LONG: + 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(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(LONG); + push(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(FLOAT); + break; + case Opcodes.DADD: + case Opcodes.DSUB: + case Opcodes.DMUL: + case Opcodes.DDIV: + case Opcodes.DREM: + pop(4); + push(DOUBLE); + push(TOP); + break; + case Opcodes.LSHL: + case Opcodes.LSHR: + case Opcodes.LUSHR: + pop(3); + push(LONG); + push(TOP); + break; + case Opcodes.IINC: + set(arg, INTEGER); + break; + case Opcodes.I2L: + case Opcodes.F2L: + pop(1); + push(LONG); + push(TOP); + break; + case Opcodes.I2F: + pop(1); + push(FLOAT); + break; + case Opcodes.I2D: + case Opcodes.F2D: + pop(1); + push(DOUBLE); + push(TOP); + break; + case Opcodes.F2I: + case Opcodes.ARRAYLENGTH: + case Opcodes.INSTANCEOF: + pop(1); + push(INTEGER); + break; + case Opcodes.LCMP: + case Opcodes.DCMPL: + case Opcodes.DCMPG: + pop(4); + push(INTEGER); + break; + case Opcodes.JSR: + case Opcodes.RET: + throw new RuntimeException("JSR/RET are not supported with computeFrames option"); + case Opcodes.GETSTATIC: + push(cw, item.strVal3); + break; + case Opcodes.PUTSTATIC: + pop(item.strVal3); + break; + case Opcodes.GETFIELD: + pop(1); + push(cw, item.strVal3); + break; + case Opcodes.PUTFIELD: + pop(item.strVal3); + pop(); + break; + case Opcodes.INVOKEVIRTUAL: + case Opcodes.INVOKESPECIAL: + case Opcodes.INVOKESTATIC: + case Opcodes.INVOKEINTERFACE: + pop(item.strVal3); + if (opcode != Opcodes.INVOKESTATIC) { + t1 = pop(); + if (opcode == Opcodes.INVOKESPECIAL && item.strVal2.charAt(0) == '<') { + init(t1); + } + } + push(cw, item.strVal3); + break; + case Opcodes.INVOKEDYNAMIC: + pop(item.strVal2); + push(cw, item.strVal2); + break; + case Opcodes.NEW: + push(UNINITIALIZED | cw.addUninitializedType(item.strVal1, arg)); + break; + case Opcodes.NEWARRAY: + pop(); + switch (arg) { + case Opcodes.T_BOOLEAN: + push(ARRAY_OF | BOOLEAN); + break; + case Opcodes.T_CHAR: + push(ARRAY_OF | CHAR); + break; + case Opcodes.T_BYTE: + push(ARRAY_OF | BYTE); + break; + case Opcodes.T_SHORT: + push(ARRAY_OF | SHORT); + break; + case Opcodes.T_INT: + push(ARRAY_OF | INTEGER); + break; + case Opcodes.T_FLOAT: + push(ARRAY_OF | FLOAT); + break; + case Opcodes.T_DOUBLE: + push(ARRAY_OF | DOUBLE); + break; + // case Opcodes.T_LONG: + default: + push(ARRAY_OF | LONG); + break; + } + break; + case Opcodes.ANEWARRAY: + String s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, '[' + s); + } else { + push(ARRAY_OF | OBJECT | cw.addType(s)); + } + break; + case Opcodes.CHECKCAST: + s = item.strVal1; + pop(); + if (s.charAt(0) == '[') { + push(cw, s); + } else { + push(OBJECT | cw.addType(s)); + } + break; + // case Opcodes.MULTIANEWARRAY: default: - push(ARRAY_OF | LONG); + pop(arg); + push(cw, item.strVal1); break; - } - break; - case Opcodes.ANEWARRAY: - String s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, '[' + s); - } else { - push(ARRAY_OF | OBJECT | cw.addType(s)); - } - break; - case Opcodes.CHECKCAST: - s = item.strVal1; - pop(); - if (s.charAt(0) == '[') { - push(cw, s); - } else { - push(OBJECT | cw.addType(s)); - } - break; - // case Opcodes.MULTIANEWARRAY: - default: - pop(arg); - push(cw, item.strVal1); - break; } } /** - * Merges the input frame of the given basic block with the input and output - * frames of this basic block. Returns true if the input frame of - * the given label has been changed by this operation. + * Merges the input frame of the given basic block with the input and output frames of this + * basic block. Returns true if the input frame of the given label has been changed by + * this operation. * - * @param cw - * the ClassWriter to which this label belongs. - * @param frame - * the basic block whose input frame must be updated. - * @param edge - * the kind of the {@link Edge} between this label and 'label'. - * See {@link Edge#info}. - * @return true if the input frame of the given label has been - * changed by this operation. + * @param cw the ClassWriter to which this label belongs. + * @param frame the basic block whose input frame must be updated. + * @param edge the kind of the {@link Edge} between this label and 'label'. See + * {@link Edge#info}. + * @return true if the input frame of the given label has been changed by this + * operation. */ boolean merge(final ClassWriter cw, final Frame frame, final int edge) { boolean changed = false; @@ -1310,8 +1256,7 @@ final class Frame { } else { t = dim + inputStack[nStack - (s & VALUE)]; } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 - && (t == LONG || t == DOUBLE)) { + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { t = TOP; } } @@ -1363,8 +1308,7 @@ final class Frame { } else { t = dim + inputStack[nStack - (s & VALUE)]; } - if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 - && (t == LONG || t == DOUBLE)) { + if ((s & TOP_IF_LONG_OR_DOUBLE) != 0 && (t == LONG || t == DOUBLE)) { t = TOP; } } @@ -1377,23 +1321,16 @@ final class Frame { } /** - * Merges the type at the given index in the given type array with the given - * type. Returns true if the type array has been modified by this - * operation. + * Merges the type at the given index in the given type array with the given type. Returns + * true if the type array has been modified by this operation. * - * @param cw - * the ClassWriter to which this label belongs. - * @param t - * the type with which the type array element must be merged. - * @param types - * an array of types. - * @param index - * the index of the type that must be merged in 'types'. - * @return true if the type array has been modified by this - * operation. + * @param cw the ClassWriter to which this label belongs. + * @param t the type with which the type array element must be merged. + * @param types an array of types. + * @param index the index of the type that must be merged in 'types'. + * @return true if the type array has been modified by this operation. */ - private static boolean merge(final ClassWriter cw, int t, - final int[] types, final int index) { + private static boolean merge(final ClassWriter cw, int t, final int[] types, final int index) { int u = types[index]; if (u == t) { // if the types are equal, merge(u,t)=u, so there is no change @@ -1421,8 +1358,7 @@ final class Frame { // if t is also a reference type, and if u and t have the // same dimension merge(u,t) = dim(t) | common parent of the // element types of u and t - v = (t & DIM) | OBJECT - | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); + v = (t & DIM) | OBJECT | cw.getMergedType(t & BASE_VALUE, u & BASE_VALUE); } else { // if u and t are array types, but not with the same element // type, merge(u,t)=java/lang/Object diff --git a/src/main/asm/org/objectweb/asm/Handle.java b/src/main/asm/org/objectweb/asm/Handle.java index a627911..9cca494 100644 --- a/src/main/asm/org/objectweb/asm/Handle.java +++ b/src/main/asm/org/objectweb/asm/Handle.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -39,9 +31,8 @@ package org.objectweb.asm; 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}, + * 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}. @@ -49,8 +40,7 @@ public final class Handle { final int tag; /** - * The internal name of the class that owns the field or method designated - * by this handle. + * The internal name of the class that owns the field or method designated by this handle. */ final String owner; @@ -67,23 +57,15 @@ public final class Handle { /** * 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. + * @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; @@ -95,23 +77,21 @@ public final class Handle { /** * 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}. + * @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. + * 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. + * @return the internal name of the class that owns the field or method designated by this + * handle. */ public String getOwner() { return owner; @@ -144,8 +124,7 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) - && desc.equals(h.desc); + return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) && desc.equals(h.desc); } @Override @@ -154,8 +133,7 @@ public final class Handle { } /** - * Returns the textual representation of this handle. The textual - * representation is: + * Returns the textual representation of this handle. The textual representation is: * *
      * owner '.' name desc ' ' '(' tag ')'
diff --git a/src/main/asm/org/objectweb/asm/Handler.java b/src/main/asm/org/objectweb/asm/Handler.java
index b24591d..ef818c8 100644
--- a/src/main/asm/org/objectweb/asm/Handler.java
+++ b/src/main/asm/org/objectweb/asm/Handler.java
@@ -1,31 +1,23 @@
 /***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * 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.
+ * 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;
 
@@ -52,14 +44,14 @@ class Handler {
     Label handler;
 
     /**
-     * Internal name of the type of exceptions handled by this handler, or
-     * null to catch any exceptions.
+     * Internal name of the type of exceptions handled by this handler, or null 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.
+     * Constant pool index of the internal name of the type of exceptions handled by this handler,
+     * or 0 to catch any exceptions.
      */
     int type;
 
@@ -69,15 +61,11 @@ class Handler {
     Handler next;
 
     /**
-     * Removes the range between start and end from the given exception
-     * handlers.
+     * 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.
+     * @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) {
diff --git a/src/main/asm/org/objectweb/asm/Item.java b/src/main/asm/org/objectweb/asm/Item.java
index c25b7b7..b60f424 100644
--- a/src/main/asm/org/objectweb/asm/Item.java
+++ b/src/main/asm/org/objectweb/asm/Item.java
@@ -1,37 +1,29 @@
 /***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * 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.
+ * 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.
+ * A constant pool item. Constant pool items can be created with the 'newXXX' methods in the
+ * {@link ClassWriter} class.
  * 
  * @author Eric Bruneton
  */
@@ -43,25 +35,21 @@ final class Item {
     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}.
+     * 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.
+     * 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#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;
@@ -77,20 +65,17 @@ final class Item {
     long longVal;
 
     /**
-     * First part of the value of this item, for items that do not hold a
-     * primitive value.
+     * 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.
+     * 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.
+     * Third part of the value of this item, for items that do not hold a primitive value.
      */
     String strVal3;
 
@@ -100,23 +85,20 @@ final class Item {
     int hashCode;
 
     /**
-     * Link to another constant pool item, used for collision lists in the
-     * constant pool's hash table.
+     * 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() {
-    }
+    Item() {}
 
     /**
-     * Constructs an uninitialized {@link Item} for constant pool element at
-     * given position.
+     * Constructs an uninitialized {@link Item} for constant pool element at given position.
      * 
-     * @param index
-     *            index of the item to be constructed.
+     * @param index index of the item to be constructed.
      */
     Item(final int index) {
         this.index = index;
@@ -125,10 +107,8 @@ final class Item {
     /**
      * 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.
+     * @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;
@@ -144,8 +124,7 @@ final class Item {
     /**
      * Sets this item to an integer item.
      * 
-     * @param intVal
-     *            the value of this item.
+     * @param intVal the value of this item.
      */
     void set(final int intVal) {
         this.type = ClassWriter.INT;
@@ -156,8 +135,7 @@ final class Item {
     /**
      * Sets this item to a long item.
      * 
-     * @param longVal
-     *            the value of this item.
+     * @param longVal the value of this item.
      */
     void set(final long longVal) {
         this.type = ClassWriter.LONG;
@@ -168,8 +146,7 @@ final class Item {
     /**
      * Sets this item to a float item.
      * 
-     * @param floatVal
-     *            the value of this item.
+     * @param floatVal the value of this item.
      */
     void set(final float floatVal) {
         this.type = ClassWriter.FLOAT;
@@ -180,8 +157,7 @@ final class Item {
     /**
      * Sets this item to a double item.
      * 
-     * @param doubleVal
-     *            the value of this item.
+     * @param doubleVal the value of this item.
      */
     void set(final double doubleVal) {
         this.type = ClassWriter.DOUBLE;
@@ -192,72 +168,60 @@ final class Item {
     /**
      * 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.
+     * @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) {
+    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());
+            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.
+     * @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());
+        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.
+     * @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;
@@ -266,45 +230,42 @@ final class Item {
     }
 
     /**
-     * Indicates if the given item is equal to this one. This method assumes
-     * that the two items have the same {@link #type}.
+     * Indicates if the given item is equal to this one. This method assumes that the two items
+     * have the same {@link #type}.
      * 
-     * @param i
-     *            the item to be compared to this one. Both items must have the
-     *            same {@link #type}.
-     * @return true if the given item if equal to this one,
-     *         false otherwise.
+     * @param i the item to be compared to this one. Both items must have the same {@link #type}.
+     * @return true if the given item if equal to this one, false 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);
+            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);
         }
     }
 
diff --git a/src/main/asm/org/objectweb/asm/Label.java b/src/main/asm/org/objectweb/asm/Label.java
index 1c4de30..d993c3f 100644
--- a/src/main/asm/org/objectweb/asm/Label.java
+++ b/src/main/asm/org/objectweb/asm/Label.java
@@ -1,50 +1,40 @@
 /***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * 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.
+ * 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 instruction 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.).
+ * 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 instruction 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).
+     * 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;
 
@@ -59,14 +49,14 @@ public class Label {
     static final int RESIZED = 4;
 
     /**
-     * Indicates if this basic block has been pushed in the basic block stack.
-     * See {@link MethodWriter#visitMaxs visitMaxs}.
+     * 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.
+     * Indicates if this label is the target of a jump instruction, or the start of an exception
+     * handler.
      */
     static final int TARGET = 16;
 
@@ -96,21 +86,20 @@ public class Label {
     static final int SUBROUTINE = 512;
 
     /**
-     * Indicates if this subroutine basic block has been visited by a
-     * visitSubroutine(null, ...) call.
+     * 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.
+     * 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
+     * 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;
@@ -146,100 +135,89 @@ public class Label {
     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.
+     * 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.
+     * 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", relatively to the frame
-     * state at the beginning of the basic block, which is called the "input
-     * frame", and which is unknown 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 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", relatively to the frame state at the
+     * beginning of the basic block, which is called the "input frame", and which is unknown
+     * 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.
+     * 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.
+     * 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 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.
+     * 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.
+     * 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.
+     * 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).
+     * 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.
+     * 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.
+     * 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
      */
@@ -252,49 +230,39 @@ public class Label {
     /**
      * Constructs a new label.
      */
-    public 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. This method is intended for
-     * {@link Attribute} sub classes, and is normally not needed by class
-     * generators or adapters.
+     * Returns the offset corresponding to this label. This offset is computed from the start of the
+     * method's bytecode. This method is intended for {@link Attribute} sub classes, and is
+     * normally not needed by class generators or adapters.
      * 
      * @return the offset corresponding to this label.
-     * @throws IllegalStateException
-     *             if this label is not resolved yet.
+     * @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");
+            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.
+     * 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
-     *            true if the reference must be stored in 4 bytes, or
-     *            false if it must be stored with 2 bytes.
-     * @throws IllegalArgumentException
-     *             if this label has not been created by the given code writer.
+     * @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 true if the reference must be stored in 4 bytes, or false
+     *        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) {
@@ -316,27 +284,22 @@ public class Label {
     }
 
     /**
-     * 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.
+     * 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.
+     * @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) {
+    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);
+            System.arraycopy(srcAndRefPositions, 0, a, 0, srcAndRefPositions.length);
             srcAndRefPositions = a;
         }
         srcAndRefPositions[referenceCount++] = sourcePosition;
@@ -344,30 +307,23 @@ public class Label {
     }
 
     /**
-     * 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.
+     * 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 true 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.
+     * @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 true 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 resolve(final MethodWriter owner, final int position, final byte[] data) {
         boolean needUpdate = false;
         this.status |= RESOLVED;
         this.position = position;
@@ -380,13 +336,11 @@ public class Label {
                 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).
+                     * 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) {
@@ -412,10 +366,9 @@ public class Label {
     }
 
     /**
-     * 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.
+     * 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.
      */
@@ -430,8 +383,7 @@ public class Label {
     /**
      * Returns true is this basic block belongs to the given subroutine.
      * 
-     * @param id
-     *            a subroutine id.
+     * @param id a subroutine id.
      * @return true is this basic block belongs to the given subroutine.
      */
     boolean inSubroutine(final long id) {
@@ -442,13 +394,10 @@ public class Label {
     }
 
     /**
-     * Returns true if this basic block and the given one belong to a common
-     * subroutine.
+     * 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.
+     * @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) {
@@ -465,10 +414,8 @@ public class Label {
     /**
      * 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.
+     * @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) {
@@ -479,19 +426,14 @@ public class Label {
     }
 
     /**
-     * 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.
+     * 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.
+     * @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
diff --git a/src/main/asm/org/objectweb/asm/MethodVisitor.java b/src/main/asm/org/objectweb/asm/MethodVisitor.java
index bd26721..98abeb1 100644
--- a/src/main/asm/org/objectweb/asm/MethodVisitor.java
+++ b/src/main/asm/org/objectweb/asm/MethodVisitor.java
@@ -1,71 +1,58 @@
 /***
- * ASM: a very small and fast Java bytecode manipulation framework
- * Copyright (c) 2000-2011 INRIA, France Telecom
- * All rights reserved.
+ * 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.
+ * 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.
+ * 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: [ visitAnnotationDefault ] (
- * visitAnnotation | visitParameterAnnotation |
- * visitAttribute )* [ visitCode ( visitFrame |
- * visitXInsn | visitLabel |
- * visitTryCatchBlock | visitLocalVariable |
- * visitLineNumber )* visitMaxs ] visitEnd. In
- * addition, the visitXInsn and visitLabel methods
- * must be called in the sequential order of the bytecode instructions of the
- * visited code, visitTryCatchBlock must be called before the
- * labels passed as arguments have been visited, and the
- * visitLocalVariable and visitLineNumber methods must be
- * called after the labels passed as arguments have been visited.
+ * A visitor to visit a Java method. The methods of this class must be called in the following
+ * order: [ visitAnnotationDefault ] ( visitAnnotation |
+ * visitParameterAnnotation | visitAttribute )* [ visitCode (
+ * visitFrame | visitXInsn | visitLabel |
+ * visitTryCatchBlock | visitLocalVariable | visitLineNumber )*
+ * visitMaxs ] visitEnd. In addition, the visitXInsn and
+ * visitLabel methods must be called in the sequential order of the bytecode instructions
+ * of the visited code, visitTryCatchBlock must be called before the labels passed
+ * as arguments have been visited, and the visitLocalVariable and visitLineNumber
+ * methods must be called after 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}.
+     * 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.
+     * 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}.
+     * @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);
@@ -74,12 +61,9 @@ public abstract class MethodVisitor {
     /**
      * 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.
+     * @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) {
@@ -96,12 +80,11 @@ public abstract class MethodVisitor {
     /**
      * 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 null 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.
+     * @return a visitor to the visit the actual default value of this annotation interface method,
+     *         or null 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) {
@@ -113,12 +96,10 @@ public abstract class MethodVisitor {
     /**
      * Visits an annotation of this method.
      * 
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            true if the annotation is visible at runtime.
-     * @return a visitor to visit the annotation values, or null if
-     *         this visitor is not interested in visiting this annotation.
+     * @param desc the class descriptor of the annotation class.
+     * @param visible true if the annotation is visible at runtime.
+     * @return a visitor to visit the annotation values, or null if this visitor is not
+     *         interested in visiting this annotation.
      */
     public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
         if (mv != null) {
@@ -130,17 +111,13 @@ public abstract class MethodVisitor {
     /**
      * Visits an annotation of a parameter this method.
      * 
-     * @param parameter
-     *            the parameter index.
-     * @param desc
-     *            the class descriptor of the annotation class.
-     * @param visible
-     *            true if the annotation is visible at runtime.
-     * @return a visitor to visit the annotation values, or null if
-     *         this visitor is not interested in visiting this annotation.
+     * @param parameter the parameter index.
+     * @param desc the class descriptor of the annotation class.
+     * @param visible true if the annotation is visible at runtime.
+     * @return a visitor to visit the annotation values, or null if this visitor is not
+     *         interested in visiting this annotation.
      */
-    public AnnotationVisitor visitParameterAnnotation(int parameter,
-            String desc, boolean visible) {
+    public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
         if (mv != null) {
             return mv.visitParameterAnnotation(parameter, desc, visible);
         }
@@ -150,8 +127,7 @@ public abstract class MethodVisitor {
     /**
      * Visits a non standard attribute of this method.
      * 
-     * @param attr
-     *            an attribute.
+     * @param attr an attribute.
      */
     public void visitAttribute(Attribute attr) {
         if (mv != null) {
@@ -169,80 +145,63 @@ public abstract class MethodVisitor {
     }
 
     /**
-     * Visits the current state of the local variables and operand stack
-     * elements. This method must(*) be called just before any
-     * instruction i 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 just
-     * before i is executed.
+ * Visits the current state of the local variables and operand stack elements. This method + * must(*) be called just before any instruction i 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 just before i is executed.
*
- * (*) this is mandatory only for classes whose version is greater than or - * equal to {@link Opcodes#V1_6 V1_6}.
+ * (*) this is mandatory only for classes whose version is greater than or equal to + * {@link Opcodes#V1_6 V1_6}.
*
- * 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): + * 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): *
    *
  • In expanded form, all frames must have the F_NEW type.
  • - *
  • In compressed form, frames are basically "deltas" from the state of - * the previous frame: + *
  • In compressed form, frames are basically "deltas" from the state of the previous frame: *
      - *
    • {@link Opcodes#F_SAME} representing frame with exactly the same - * locals as the previous frame and with the empty stack.
    • - *
    • {@link Opcodes#F_SAME1} representing frame with exactly the same - * locals as the previous frame and with single value on the stack ( - * nStack is 1 and stack[0] contains value for the - * type of the stack item).
    • - *
    • {@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 (nLocal is 1, 2 or 3 and - * local elements contains values representing added types).
    • - *
    • {@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 (nLocals is 1, 2 or 3).
    • + *
    • {@link Opcodes#F_SAME} representing frame with exactly the same locals as the previous + * frame and with the empty stack.
    • + *
    • {@link Opcodes#F_SAME1} representing frame with exactly the same locals as the previous + * frame and with single value on the stack ( nStack is 1 and stack[0] + * contains value for the type of the stack item).
    • + *
    • {@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 (nLocal + * is 1, 2 or 3 and local elements contains values representing added types).
    • + *
    • {@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 + * (nLocals is 1, 2 or 3).
    • *
    • {@link Opcodes#F_FULL} representing complete frame data.
    • *
    - *

- * 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). + * + *
+ * 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). + * @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) { + public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { if (mv != null) { mv.visitFrame(type, nLocal, local, nStack, stack); } @@ -255,22 +214,17 @@ public abstract class MethodVisitor { /** * 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. + * @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) { @@ -281,20 +235,17 @@ public abstract class MethodVisitor { /** * 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.
- * When opcode is BIPUSH, operand value should be between - * Byte.MIN_VALUE and Byte.MAX_VALUE.
- * When opcode is SIPUSH, operand value should be between - * Short.MIN_VALUE and Short.MAX_VALUE.
- * 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}. + * @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.
+ * When opcode is BIPUSH, operand value should be between Byte.MIN_VALUE and + * Byte.MAX_VALUE.
+ * When opcode is SIPUSH, operand value should be between Short.MIN_VALUE and + * Short.MAX_VALUE.
+ * 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) { @@ -303,16 +254,14 @@ public abstract class MethodVisitor { } /** - * Visits a local variable instruction. A local variable instruction is an - * instruction that loads or stores the value of a local variable. + * 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. + * @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) { @@ -321,16 +270,13 @@ public abstract class MethodVisitor { } /** - * Visits a type instruction. A type instruction is an instruction that - * takes the internal name of a class as parameter. + * 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}). + * @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) { @@ -339,45 +285,33 @@ public abstract class MethodVisitor { } /** - * Visits a field instruction. A field instruction is an instruction that - * loads or stores the value of a field of an object. + * 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}). + * @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) { + 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. + * 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}). + * @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) { + public void visitMethodInsn(int opcode, String owner, String name, String desc) { if (mv != null) { mv.visitMethodInsn(opcode, owner, name, desc); } @@ -386,39 +320,29 @@ public abstract class MethodVisitor { /** * 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. + * @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) { + 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. + * 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. + * @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) { @@ -427,11 +351,9 @@ public abstract class MethodVisitor { } /** - * Visits a label. A label designates the instruction that will be visited - * just after it. + * Visits a label. A label designates the instruction that will be visited just after it. * - * @param label - * a {@link Label Label} object. + * @param label a {@link Label Label} object. */ public void visitLabel(Label label) { if (mv != null) { @@ -444,10 +366,9 @@ public abstract class MethodVisitor { // ------------------------------------------------------------------------- /** - * 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: + * 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: * *
      * if (cst instanceof Integer) {
@@ -478,14 +399,11 @@ public abstract class MethodVisitor {
      * }
      * 
* - * @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 .class 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. + * @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 .class 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) { @@ -496,10 +414,8 @@ public abstract class MethodVisitor { /** * Visits an IINC instruction. * - * @param var - * index of the local variable to be incremented. - * @param increment - * amount to increment the local variable by. + * @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) { @@ -510,18 +426,13 @@ public abstract class MethodVisitor { /** * 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. labels[i] is the - * beginning of the handler block for the min + i key. + * @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. labels[i] is the beginning of the + * handler block for the min + i key. */ - public void visitTableSwitchInsn(int min, int max, Label dflt, - Label... labels) { + public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) { if (mv != null) { mv.visitTableSwitchInsn(min, max, dflt, labels); } @@ -530,13 +441,10 @@ public abstract class MethodVisitor { /** * 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. labels[i] is the - * beginning of the handler block for the keys[i] key. + * @param dflt beginning of the default handler block. + * @param keys the values of the keys. + * @param labels beginnings of the handler blocks. labels[i] is the beginning of the + * handler block for the keys[i] key. */ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { if (mv != null) { @@ -547,10 +455,8 @@ public abstract class MethodVisitor { /** * Visits a MULTIANEWARRAY instruction. * - * @param desc - * an array type descriptor (see {@link Type Type}). - * @param dims - * number of dimensions of the array to allocate. + * @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) { @@ -565,22 +471,15 @@ public abstract class MethodVisitor { /** * 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 null 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). + * @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 null + * 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) { + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { if (mv != null) { mv.visitTryCatchBlock(start, end, handler, type); } @@ -589,28 +488,20 @@ public abstract class MethodVisitor { /** * 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 - * null 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). + * @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 null 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) { + 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); } @@ -619,14 +510,11 @@ public abstract class MethodVisitor { /** * 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 start has not already been visited by this - * visitor (by the {@link #visitLabel visitLabel} method). + * @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 start has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public void visitLineNumber(int line, Label start) { if (mv != null) { @@ -635,13 +523,10 @@ public abstract class MethodVisitor { } /** - * Visits the maximum stack size and the maximum number of local variables - * of the method. + * 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. + * @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) { @@ -650,9 +535,8 @@ public abstract class MethodVisitor { } /** - * 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. + * 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) { diff --git a/src/main/asm/org/objectweb/asm/MethodWriter.java b/src/main/asm/org/objectweb/asm/MethodWriter.java index ff03f19..9e23b72 100644 --- a/src/main/asm/org/objectweb/asm/MethodWriter.java +++ b/src/main/asm/org/objectweb/asm/MethodWriter.java @@ -1,38 +1,30 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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 {@link MethodVisitor} that generates methods in bytecode form. Each visit - * method of this class appends the bytecode corresponding to the visited - * instruction to a byte vector, in the order these methods are called. + * A {@link MethodVisitor} that generates methods in bytecode form. Each visit method of this class + * appends the bytecode corresponding to the visited instruction to a byte vector, in the order + * these methods are called. * * @author Eric Bruneton * @author Eugene Kuleshov @@ -43,16 +35,16 @@ class MethodWriter extends MethodVisitor { * Pseudo access flag used to denote constructors. */ static final int ACC_CONSTRUCTOR = 0x80000; - + /** - * Frame has exactly the same locals as the previous stack map frame and - * number of stack items is zero. + * Frame has exactly the same locals as the previous stack map frame and number of stack items + * is zero. */ static final int SAME_FRAME = 0; // to 63 (0-3f) /** - * Frame has exactly the same locals as the previous stack map frame and - * number of stack items is 1 + * Frame has exactly the same locals as the previous stack map frame and number of stack items + * is 1 */ static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f) @@ -62,28 +54,26 @@ class MethodWriter extends MethodVisitor { static final int RESERVED = 128; /** - * Frame has exactly the same locals as the previous stack map frame and - * number of stack items is 1. Offset is bigger then 63; + * Frame has exactly the same locals as the previous stack map frame and number of stack items + * is 1. Offset is bigger then 63; */ static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7 /** - * Frame where current locals are the same as the locals in the previous - * frame, except that the k last locals are absent. The value of k is given - * by the formula 251-frame_type. + * Frame where current locals are the same as the locals in the previous frame, except that the + * k last locals are absent. The value of k is given by the formula 251-frame_type. */ static final int CHOP_FRAME = 248; // to 250 (f8-fA) /** - * Frame has exactly the same locals as the previous stack map frame and - * number of stack items is zero. Offset is bigger then 63; + * Frame has exactly the same locals as the previous stack map frame and number of stack items + * is zero. Offset is bigger then 63; */ static final int SAME_FRAME_EXTENDED = 251; // fb /** - * Frame where current locals are the same as the locals in the previous - * frame, except that k additional locals are defined. The value of k is - * given by the formula frame_type-251. + * Frame where current locals are the same as the locals in the previous frame, except that k + * additional locals are defined. The value of k is given by the formula frame_type-251. */ static final int APPEND_FRAME = 252; // to 254 // fc-fe @@ -93,17 +83,16 @@ class MethodWriter extends MethodVisitor { static final int FULL_FRAME = 255; // ff /** - * Indicates that the stack map frames must be recomputed from scratch. In - * this case the maximum stack size and number of local variables is also - * recomputed from scratch. + * Indicates that the stack map frames must be recomputed from scratch. In this case the maximum + * stack size and number of local variables is also recomputed from scratch. * * @see #compute */ private static final int FRAMES = 0; /** - * Indicates that the maximum stack size and number of local variables must - * be automatically computed. + * Indicates that the maximum stack size and number of local variables must be automatically + * computed. * * @see #compute */ @@ -127,14 +116,12 @@ class MethodWriter extends MethodVisitor { private int access; /** - * The index of the constant pool item that contains the name of this - * method. + * 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 - * method. + * The index of the constant pool item that contains the descriptor of this method. */ private final int desc; @@ -149,18 +136,16 @@ class MethodWriter extends MethodVisitor { String signature; /** - * If not zero, indicates that the code of this method must be copied from - * the ClassReader associated to this writer in cw.cr. More - * precisely, this field gives the index of the first byte to copied from - * cw.cr.b. + * If not zero, indicates that the code of this method must be copied from the ClassReader + * associated to this writer in cw.cr. More precisely, this field gives the index + * of the first byte to copied from cw.cr.b. */ int classReaderOffset; /** - * If not zero, indicates that the code of this method must be copied from - * the ClassReader associated to this writer in cw.cr. More - * precisely, this field gives the number of bytes to copied from - * cw.cr.b. + * If not zero, indicates that the code of this method must be copied from the ClassReader + * associated to this writer in cw.cr. More precisely, this field gives the number + * of bytes to copied from cw.cr.b. */ int classReaderLength; @@ -170,9 +155,9 @@ class MethodWriter extends MethodVisitor { int exceptionCount; /** - * The exceptions that can be thrown by this method. More precisely, this - * array contains the indexes of the constant pool items that contain the - * internal names of these exception classes. + * The exceptions that can be thrown by this method. More precisely, this array contains the + * indexes of the constant pool items that contain the internal names of these exception + * classes. */ int[] exceptions; @@ -192,14 +177,12 @@ class MethodWriter extends MethodVisitor { private AnnotationWriter ianns; /** - * The runtime visible parameter annotations of this method. May be - * null. + * The runtime visible parameter annotations of this method. May be null. */ private AnnotationWriter[] panns; /** - * The runtime invisible parameter annotations of this method. May be - * null. + * The runtime invisible parameter annotations of this method. May be null. */ private AnnotationWriter[] ipanns; @@ -244,8 +227,7 @@ class MethodWriter extends MethodVisitor { private ByteVector stackMap; /** - * The offset of the last frame that was written in the StackMapTable - * attribute. + * The offset of the last frame that was written in the StackMapTable attribute. */ private int previousFrameOffset; @@ -257,13 +239,12 @@ class MethodWriter extends MethodVisitor { private int[] previousFrame; /** - * The current stack map frame. The first element contains the offset of the - * instruction to which the frame corresponds, the second element is the - * number of locals and the third one is the number of stack elements. The - * local variables start at index 3 and are followed by the operand stack - * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = - * nStack, frame[3] = nLocal. All types are encoded as integers, with the - * same format as the one used in {@link Label}, but limited to BASE types. + * The current stack map frame. The first element contains the offset of the instruction to + * which the frame corresponds, the second element is the number of locals and the third one is + * the number of stack elements. The local variables start at index 3 and are followed by the + * operand stack values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] = nStack, + * frame[3] = nLocal. All types are encoded as integers, with the same format as the one used in + * {@link Label}, but limited to BASE types. */ private int[] frame; @@ -330,13 +311,11 @@ class MethodWriter extends MethodVisitor { // ------------------------------------------------------------------------ /* - * Fields for the control flow graph analysis algorithm (used to compute the - * maximum stack size). 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. + * Fields for the control flow graph analysis algorithm (used to compute the maximum stack + * size). 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. */ /** @@ -349,11 +328,9 @@ class MethodWriter extends MethodVisitor { private final int compute; /** - * A list of labels. This list is the list of basic blocks in the method, - * i.e. a list of Label objects linked to each other by their - * {@link Label#successor} field, in the order they are visited by - * {@link MethodVisitor#visitLabel}, and starting with the first basic - * block. + * A list of labels. This list is the list of basic blocks in the method, i.e. a list of Label + * objects linked to each other by their {@link Label#successor} field, in the order they are + * visited by {@link MethodVisitor#visitLabel}, and starting with the first basic block. */ private Label labels; @@ -368,20 +345,18 @@ class MethodWriter extends MethodVisitor { private Label currentBlock; /** - * The (relative) stack size after the last visited instruction. This size - * is relative to the beginning of the current basic block, i.e., the true - * stack size after the last visited instruction is equal to the - * {@link Label#inputStackTop beginStackSize} of the current basic block - * plus stackSize. + * The (relative) stack size after the last visited instruction. This size is relative to the + * beginning of the current basic block, i.e., the true stack size after the last visited + * instruction is equal to the {@link Label#inputStackTop beginStackSize} of the current basic + * block plus stackSize. */ private int stackSize; /** - * The (relative) maximum stack size after the last visited instruction. - * This size is relative to the beginning of the current basic block, i.e., - * the true maximum stack size after the last visited instruction is equal - * to the {@link Label#inputStackTop beginStackSize} of the current basic - * block plus stackSize. + * The (relative) maximum stack size after the last visited instruction. This size is relative + * to the beginning of the current basic block, i.e., the true maximum stack size after the last + * visited instruction is equal to the {@link Label#inputStackTop beginStackSize} of the current + * basic block plus stackSize. */ private int maxStackSize; @@ -392,29 +367,18 @@ class MethodWriter extends MethodVisitor { /** * Constructs a new {@link MethodWriter}. * - * @param cw - * the class writer in which the method must be added. - * @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}). - * @param signature - * the method's signature. May be null. - * @param exceptions - * the internal names of the method's exceptions. May be - * null. - * @param computeMaxs - * true if the maximum stack size and number of local - * variables must be automatically computed. - * @param computeFrames - * true if the stack map tables must be recomputed from - * scratch. + * @param cw the class writer in which the method must be added. + * @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}). + * @param signature the method's signature. May be null. + * @param exceptions the internal names of the method's exceptions. May be null. + * @param computeMaxs true if the maximum stack size and number of local variables must + * be automatically computed. + * @param computeFrames true if the stack map tables must be recomputed from scratch. */ - MethodWriter(final ClassWriter cw, final int access, final String name, - final String desc, final String signature, - final String[] exceptions, final boolean computeMaxs, + MethodWriter(final ClassWriter cw, final int access, final String name, final String desc, + final String signature, final String[] exceptions, final boolean computeMaxs, final boolean computeFrames) { super(Opcodes.ASM4); if (cw.firstMethod == null) { @@ -471,8 +435,7 @@ class MethodWriter extends MethodVisitor { } @Override - public AnnotationVisitor visitAnnotation(final String desc, - final boolean visible) { + public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -491,8 +454,8 @@ class MethodWriter extends MethodVisitor { } @Override - public AnnotationVisitor visitParameterAnnotation(final int parameter, - final String desc, final boolean visible) { + public AnnotationVisitor visitParameterAnnotation(final int parameter, final String desc, + final boolean visible) { if (!ClassReader.ANNOTATIONS) { return null; } @@ -534,12 +497,11 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitCode() { - } + public void visitCode() {} @Override - public void visitFrame(final int type, final int nLocal, - final Object[] local, final int nStack, final Object[] stack) { + public void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, + final Object[] stack) { if (!ClassReader.FRAMES || compute == FRAMES) { return; } @@ -552,26 +514,22 @@ class MethodWriter extends MethodVisitor { int frameIndex = startFrame(code.length, nLocal, nStack); for (int i = 0; i < nLocal; ++i) { if (local[i] instanceof String) { - frame[frameIndex++] = Frame.OBJECT - | cw.addType((String) local[i]); + frame[frameIndex++] = Frame.OBJECT | cw.addType((String) local[i]); } else if (local[i] instanceof Integer) { frame[frameIndex++] = ((Integer) local[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED - | cw.addUninitializedType("", - ((Label) local[i]).position); + | cw.addUninitializedType("", ((Label) local[i]).position); } } for (int i = 0; i < nStack; ++i) { if (stack[i] instanceof String) { - frame[frameIndex++] = Frame.OBJECT - | cw.addType((String) stack[i]); + frame[frameIndex++] = Frame.OBJECT | cw.addType((String) stack[i]); } else if (stack[i] instanceof Integer) { frame[frameIndex++] = ((Integer) stack[i]).intValue(); } else { frame[frameIndex++] = Frame.UNINITIALIZED - | cw.addUninitializedType("", - ((Label) stack[i]).position); + | cw.addUninitializedType("", ((Label) stack[i]).position); } } endFrame(); @@ -592,44 +550,43 @@ class MethodWriter extends MethodVisitor { } switch (type) { - case Opcodes.F_FULL: - currentLocals = nLocal; - stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - stackMap.putShort(nStack); - for (int i = 0; i < nStack; ++i) { - writeFrameType(stack[i]); - } - break; - case Opcodes.F_APPEND: - currentLocals += nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); - for (int i = 0; i < nLocal; ++i) { - writeFrameType(local[i]); - } - break; - case Opcodes.F_CHOP: - currentLocals -= nLocal; - stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); - break; - case Opcodes.F_SAME: - if (delta < 64) { - stackMap.putByte(delta); - } else { - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - } - break; - case Opcodes.F_SAME1: - if (delta < 64) { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - } else { - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) - .putShort(delta); - } - writeFrameType(stack[0]); - break; + case Opcodes.F_FULL: + currentLocals = nLocal; + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(nLocal); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + stackMap.putShort(nStack); + for (int i = 0; i < nStack; ++i) { + writeFrameType(stack[i]); + } + break; + case Opcodes.F_APPEND: + currentLocals += nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED + nLocal).putShort(delta); + for (int i = 0; i < nLocal; ++i) { + writeFrameType(local[i]); + } + break; + case Opcodes.F_CHOP: + currentLocals -= nLocal; + stackMap.putByte(SAME_FRAME_EXTENDED - nLocal).putShort(delta); + break; + case Opcodes.F_SAME: + if (delta < 64) { + stackMap.putByte(delta); + } else { + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + } + break; + case Opcodes.F_SAME1: + if (delta < 64) { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + } else { + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(delta); + } + writeFrameType(stack[0]); + break; } previousFrameOffset = code.length; @@ -716,8 +673,8 @@ class MethodWriter extends MethodVisitor { if (compute != NOTHING) { // updates max locals int n; - if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD - || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE) { + if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD || opcode == Opcodes.LSTORE + || opcode == Opcodes.DSTORE) { n = var + 2; } else { n = var + 1; @@ -769,8 +726,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitFieldInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitFieldInsn(final int opcode, final String owner, final String name, + final String desc) { Item i = cw.newFieldItem(owner, name, desc); // Label currentBlock = this.currentBlock; if (currentBlock != null) { @@ -781,19 +738,19 @@ class MethodWriter extends MethodVisitor { // computes the stack size variation char c = desc.charAt(0); switch (opcode) { - case Opcodes.GETSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); - break; - case Opcodes.PUTSTATIC: - size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); - break; - case Opcodes.GETFIELD: - size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); - break; - // case Constants.PUTFIELD: - default: - size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); - break; + case Opcodes.GETSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? 2 : 1); + break; + case Opcodes.PUTSTATIC: + size = stackSize + (c == 'D' || c == 'J' ? -2 : -1); + break; + case Opcodes.GETFIELD: + size = stackSize + (c == 'D' || c == 'J' ? 1 : 0); + break; + // case Constants.PUTFIELD: + default: + size = stackSize + (c == 'D' || c == 'J' ? -3 : -2); + break; } // updates current and max stack sizes if (size > maxStackSize) { @@ -807,8 +764,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + public void visitMethodInsn(final int opcode, final String owner, final String name, + final String desc) { boolean itf = opcode == Opcodes.INVOKEINTERFACE; Item i = cw.newMethodItem(owner, name, desc, itf); int argSize = i.intVal; @@ -818,12 +775,10 @@ class MethodWriter extends MethodVisitor { currentBlock.frame.execute(opcode, 0, cw, i); } else { /* - * computes the stack size variation. In order not to recompute - * several times this variation for the same Item, we use the - * intVal field of this item to store this variation, once it - * has been computed. More precisely this intVal field stores - * the sizes of the arguments and of the return value - * corresponding to desc. + * computes the stack size variation. In order not to recompute several times this + * variation for the same Item, we use the intVal field of this item to store this + * variation, once it has been computed. More precisely this intVal field stores the + * sizes of the arguments and of the return value corresponding to desc. */ if (argSize == 0) { // the above sizes have not been computed yet, @@ -859,8 +814,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitInvokeDynamicInsn(final String name, final String desc, - final Handle bsm, final Object... bsmArgs) { + public void visitInvokeDynamicInsn(final String name, final String desc, final Handle bsm, + final Object... bsmArgs) { Item i = cw.newInvokeDynamicItem(name, desc, bsm, bsmArgs); int argSize = i.intVal; // Label currentBlock = this.currentBlock; @@ -869,12 +824,10 @@ class MethodWriter extends MethodVisitor { currentBlock.frame.execute(Opcodes.INVOKEDYNAMIC, 0, cw, i); } else { /* - * computes the stack size variation. In order not to recompute - * several times this variation for the same Item, we use the - * intVal field of this item to store this variation, once it - * has been computed. More precisely this intVal field stores - * the sizes of the arguments and of the return value - * corresponding to desc. + * computes the stack size variation. In order not to recompute several times this + * variation for the same Item, we use the intVal field of this item to store this + * variation, once it has been computed. More precisely this intVal field stores the + * sizes of the arguments and of the return value corresponding to desc. */ if (argSize == 0) { // the above sizes have not been computed yet, @@ -924,10 +877,9 @@ class MethodWriter extends MethodVisitor { // creates a Label for the next basic block nextInsn = new Label(); /* - * note that, by construction in this method, a JSR block - * has at least two successors in the control flow graph: - * the first one leads the next instruction after the JSR, - * while the second one leads to the JSR target. + * note that, by construction in this method, a JSR block has at least two + * successors in the control flow graph: the first one leads the next + * instruction after the JSR, while the second one leads to the JSR target. */ } else { // updates current stack size (max stack size unchanged @@ -942,10 +894,9 @@ class MethodWriter extends MethodVisitor { if ((label.status & Label.RESOLVED) != 0 && label.position - code.length < Short.MIN_VALUE) { /* - * case of a backward jump with an offset < -32768. In this case we - * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx - * with IFNOTxxx GOTO_W , where IFNOTxxx is the - * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where + * case of a backward jump with an offset < -32768. In this case we automatically + * replace GOTO with GOTO_W, JSR with JSR_W and IFxxx with IFNOTxxx GOTO_W , + * where IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where * designates the instruction just after the GOTO_W. */ if (opcode == Opcodes.GOTO) { @@ -958,18 +909,16 @@ class MethodWriter extends MethodVisitor { if (nextInsn != null) { nextInsn.status |= Label.TARGET; } - code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 - : opcode ^ 1); + code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); code.putShort(8); // jump offset code.putByte(200); // GOTO_W } label.put(this, code, code.length - 1, true); } else { /* - * case of a backward jump with an offset >= -32768, or of a forward - * jump with, of course, an unknown offset. In these cases we store - * the offset in 2 bytes (which will be increased in - * resizeInstructions, if needed). + * case of a backward jump with an offset >= -32768, or of a forward jump with, of + * course, an unknown offset. In these cases we store the offset in 2 bytes (which will + * be increased in resizeInstructions, if needed). */ code.putByte(opcode); label.put(this, code, code.length - 1, false); @@ -1092,16 +1041,15 @@ class MethodWriter extends MethodVisitor { } // adds the instruction to the bytecode of the method if ((var > 255) || (increment > 127) || (increment < -128)) { - code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var) - .putShort(increment); + code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var).putShort(increment); } else { code.putByte(Opcodes.IINC).put11(var, increment); } } @Override - public void visitTableSwitchInsn(final int min, final int max, - final Label dflt, final Label... labels) { + public void visitTableSwitchInsn(final int min, final int max, final Label dflt, + final Label... labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.TABLESWITCH); @@ -1116,8 +1064,7 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitLookupSwitchInsn(final Label dflt, final int[] keys, - final Label[] labels) { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { // adds the instruction to the bytecode of the method int source = code.length; code.putByte(Opcodes.LOOKUPSWITCH); @@ -1176,8 +1123,8 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitTryCatchBlock(final Label start, final Label end, - final Label handler, final String type) { + public void visitTryCatchBlock(final Label start, final Label end, final Label handler, + final String type) { ++handlerCount; Handler h = new Handler(); h.start = start; @@ -1194,27 +1141,22 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitLocalVariable(final String name, final String desc, - final String signature, final Label start, final Label end, - final int index) { + public void visitLocalVariable(final String name, final String desc, final String signature, + final Label start, final Label end, final int index) { if (signature != null) { if (localVarType == null) { localVarType = new ByteVector(); } ++localVarTypeCount; - localVarType.putShort(start.position) - .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)) - .putShort(index); + localVarType.putShort(start.position).putShort(end.position - start.position) + .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(signature)).putShort(index); } if (localVar == null) { localVar = new ByteVector(); } ++localVarCount; - localVar.putShort(start.position) - .putShort(end.position - start.position) - .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)) - .putShort(index); + localVar.putShort(start.position).putShort(end.position - start.position) + .putShort(cw.newUTF8(name)).putShort(cw.newUTF8(desc)).putShort(index); if (compute != NOTHING) { // updates max locals char c = desc.charAt(0); @@ -1245,8 +1187,7 @@ class MethodWriter extends MethodVisitor { Label h = handler.handler.getFirst(); Label e = handler.end.getFirst(); // computes the kind of the edges to 'h' - String t = handler.desc == null ? "java/lang/Throwable" - : handler.desc; + String t = handler.desc == null ? "java/lang/Throwable" : handler.desc; int kind = Frame.OBJECT | cw.addType(t); // h is an exception handler h.status |= Label.TARGET; @@ -1272,10 +1213,9 @@ class MethodWriter extends MethodVisitor { visitFrame(f); /* - * fix point algorithm: mark the first basic block as 'changed' - * (i.e. put it in the 'changed' list) and, while there are changed - * basic blocks, choose one, mark it as unchanged, and update its - * successors (which can be changed in the process). + * fix point algorithm: mark the first basic block as 'changed' (i.e. put it in the + * 'changed' list) and, while there are changed basic blocks, choose one, mark it as + * unchanged, and update its successors (which can be changed in the process). */ int max = 0; Label changed = labels; @@ -1333,8 +1273,7 @@ class MethodWriter extends MethodVisitor { code.data[end] = (byte) Opcodes.ATHROW; // emits a frame for this unreachable block int frameIndex = startFrame(start, 0, 1); - frame[frameIndex] = Frame.OBJECT - | cw.addType("java/lang/Throwable"); + frame[frameIndex] = Frame.OBJECT | cw.addType("java/lang/Throwable"); endFrame(); // removes the start-end range from the exception // handlers @@ -1385,8 +1324,8 @@ class MethodWriter extends MethodVisitor { if (subroutines > 0) { // completes the control flow graph with the RET successors /* - * first step: finds the subroutines. This step determines, for - * each basic block, to which subroutine(s) it belongs. + * first step: finds the subroutines. This step determines, for each basic block, to + * which subroutine(s) it belongs. */ // finds the basic blocks that belong to the "main" subroutine int id = 0; @@ -1401,8 +1340,8 @@ class MethodWriter extends MethodVisitor { if ((subroutine.status & Label.VISITED) == 0) { // ...assigns it a new id and finds its basic blocks id += 1; - subroutine.visitSubroutine(null, (id / 32L) << 32 - | (1L << (id % 32)), subroutines); + subroutine.visitSubroutine(null, (id / 32L) << 32 | (1L << (id % 32)), + subroutines); } } l = l.successor; @@ -1425,14 +1364,12 @@ class MethodWriter extends MethodVisitor { } /* - * control flow analysis algorithm: while the block stack is not - * empty, pop a block from this stack, update the max stack size, - * compute the true (non relative) begin stack size of the - * successors of this block, and push these successors onto the - * stack (unless they have already been pushed onto the stack). - * Note: by hypothesis, the {@link Label#inputStackTop} of the - * blocks in the block stack are the true (non relative) beginning - * stack sizes of these blocks. + * control flow analysis algorithm: while the block stack is not empty, pop a block from + * this stack, update the max stack size, compute the true (non relative) begin stack + * size of the successors of this block, and push these successors onto the stack + * (unless they have already been pushed onto the stack). Note: by hypothesis, the + * {@link Label#inputStackTop} of the blocks in the block stack are the true (non + * relative) beginning stack sizes of these blocks. */ int max = 0; Label stack = labels; @@ -1458,8 +1395,7 @@ class MethodWriter extends MethodVisitor { // if this successor has not already been pushed... if ((l.status & Label.PUSHED) == 0) { // computes its true beginning stack size... - l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start - + b.info; + l.inputStackTop = b.info == Edge.EXCEPTION ? 1 : start + b.info; // ...and pushes it onto the stack l.status |= Label.PUSHED; l.next = stack; @@ -1476,8 +1412,7 @@ class MethodWriter extends MethodVisitor { } @Override - public void visitEnd() { - } + public void visitEnd() {} // ------------------------------------------------------------------------ // Utility methods: control flow analysis algorithm @@ -1486,10 +1421,8 @@ class MethodWriter extends MethodVisitor { /** * Adds a successor to the {@link #currentBlock currentBlock} block. * - * @param info - * information about the control flow edge to be added. - * @param successor - * the successor block to be added to the current block. + * @param info information about the control flow edge to be added. + * @param successor the successor block to be added to the current block. */ private void addSuccessor(final int info, final Label successor) { // creates and initializes an Edge object... @@ -1502,8 +1435,8 @@ class MethodWriter extends MethodVisitor { } /** - * Ends the current basic block. This method must be used in the case where - * the current basic block does not have any successor. + * Ends the current basic block. This method must be used in the case where the current basic + * block does not have any successor. */ private void noSuccessor() { if (compute == FRAMES) { @@ -1526,8 +1459,7 @@ class MethodWriter extends MethodVisitor { /** * Visits a frame that has been computed from scratch. * - * @param f - * the frame that must be visited. + * @param f the frame that must be visited. */ private void visitFrame(final Frame f) { int i, t; @@ -1595,44 +1527,43 @@ class MethodWriter extends MethodVisitor { loop: while (true) { int j = i; switch (descriptor.charAt(i++)) { - case 'Z': - case 'C': - case 'B': - case 'S': - case 'I': - frame[frameIndex++] = 1; // Opcodes.INTEGER; - break; - case 'F': - frame[frameIndex++] = 2; // Opcodes.FLOAT; - break; - case 'J': - frame[frameIndex++] = 4; // Opcodes.LONG; - break; - case 'D': - frame[frameIndex++] = 3; // Opcodes.DOUBLE; - break; - case '[': - while (descriptor.charAt(i) == '[') { - ++i; - } - if (descriptor.charAt(i) == 'L') { - ++i; + case 'Z': + case 'C': + case 'B': + case 'S': + case 'I': + frame[frameIndex++] = 1; // Opcodes.INTEGER; + break; + case 'F': + frame[frameIndex++] = 2; // Opcodes.FLOAT; + break; + case 'J': + frame[frameIndex++] = 4; // Opcodes.LONG; + break; + case 'D': + frame[frameIndex++] = 3; // Opcodes.DOUBLE; + break; + case '[': + while (descriptor.charAt(i) == '[') { + ++i; + } + if (descriptor.charAt(i) == 'L') { + ++i; + while (descriptor.charAt(i) != ';') { + ++i; + } + } + frame[frameIndex++] = Frame.OBJECT | cw.addType(descriptor.substring(j, ++i)); + break; + case 'L': while (descriptor.charAt(i) != ';') { ++i; } - } - frame[frameIndex++] = Frame.OBJECT - | cw.addType(descriptor.substring(j, ++i)); - break; - case 'L': - while (descriptor.charAt(i) != ';') { - ++i; - } - frame[frameIndex++] = Frame.OBJECT - | cw.addType(descriptor.substring(j + 1, i++)); - break; - default: - break loop; + frame[frameIndex++] = + Frame.OBJECT | cw.addType(descriptor.substring(j + 1, i++)); + break; + default: + break loop; } } frame[1] = frameIndex - 3; @@ -1642,12 +1573,9 @@ class MethodWriter extends MethodVisitor { /** * Starts the visit of a stack map frame. * - * @param offset - * the offset of the instruction to which the frame corresponds. - * @param nLocal - * the number of local variables in the frame. - * @param nStack - * the number of stack elements in the frame. + * @param offset the offset of the instruction to which the frame corresponds. + * @param nLocal the number of local variables in the frame. + * @param nStack the number of stack elements in the frame. * @return the index of the next element to be written in this frame. */ private int startFrame(final int offset, final int nLocal, final int nStack) { @@ -1662,8 +1590,8 @@ class MethodWriter extends MethodVisitor { } /** - * Checks if the visit of the current frame {@link #frame} is finished, and - * if yes, write it in the StackMapTable attribute. + * Checks if the visit of the current frame {@link #frame} is finished, and if yes, write it in + * the StackMapTable attribute. */ private void endFrame() { if (previousFrame != null) { // do not write the first frame @@ -1678,8 +1606,7 @@ class MethodWriter extends MethodVisitor { } /** - * Compress and writes the current frame {@link #frame} in the StackMapTable - * attribute. + * Compress and writes the current frame {@link #frame} in the StackMapTable attribute. */ private void writeFrame() { int clocalsSize = frame[1]; @@ -1703,20 +1630,20 @@ class MethodWriter extends MethodVisitor { if (cstackSize == 0) { k = clocalsSize - localsSize; switch (k) { - case -3: - case -2: - case -1: - type = CHOP_FRAME; - localsSize = clocalsSize; - break; - case 0: - type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; - break; - case 1: - case 2: - case 3: - type = APPEND_FRAME; - break; + case -3: + case -2: + case -1: + type = CHOP_FRAME; + localsSize = clocalsSize; + break; + case 0: + type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED; + break; + case 1: + case 2: + case 3: + type = APPEND_FRAME; + break; } } else if (clocalsSize == localsSize && cstackSize == 1) { type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME @@ -1734,47 +1661,44 @@ class MethodWriter extends MethodVisitor { } } switch (type) { - case SAME_FRAME: - stackMap.putByte(delta); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: - stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort( - delta); - writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); - break; - case SAME_FRAME_EXTENDED: - stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); - break; - case CHOP_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - break; - case APPEND_FRAME: - stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); - writeFrameTypes(3 + localsSize, 3 + clocalsSize); - break; - // case FULL_FRAME: - default: - stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); - writeFrameTypes(3, 3 + clocalsSize); - stackMap.putShort(cstackSize); - writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); + case SAME_FRAME: + stackMap.putByte(delta); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED: + stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED).putShort(delta); + writeFrameTypes(3 + clocalsSize, 4 + clocalsSize); + break; + case SAME_FRAME_EXTENDED: + stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta); + break; + case CHOP_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + break; + case APPEND_FRAME: + stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta); + writeFrameTypes(3 + localsSize, 3 + clocalsSize); + break; + // case FULL_FRAME: + default: + stackMap.putByte(FULL_FRAME).putShort(delta).putShort(clocalsSize); + writeFrameTypes(3, 3 + clocalsSize); + stackMap.putShort(cstackSize); + writeFrameTypes(3 + clocalsSize, 3 + clocalsSize + cstackSize); } } /** - * Writes some types of the current frame {@link #frame} into the - * StackMapTableAttribute. This method converts types from the format used - * in {@link Label} to the format used in StackMapTable attributes. In - * particular, it converts type table indexes to constant pool indexes. + * Writes some types of the current frame {@link #frame} into the StackMapTableAttribute. This + * method converts types from the format used in {@link Label} to the format used in + * StackMapTable attributes. In particular, it converts type table indexes to constant pool + * indexes. * - * @param start - * index of the first type in {@link #frame} to write. - * @param end - * index of last type in {@link #frame} to write (exclusive). + * @param start index of the first type in {@link #frame} to write. + * @param end index of last type in {@link #frame} to write (exclusive). */ private void writeFrameTypes(final int start, final int end) { for (int i = start; i < end; ++i) { @@ -1783,15 +1707,14 @@ class MethodWriter extends MethodVisitor { if (d == 0) { int v = t & Frame.BASE_VALUE; switch (t & Frame.BASE_KIND) { - case Frame.OBJECT: - stackMap.putByte(7).putShort( - cw.newClass(cw.typeTable[v].strVal1)); - break; - case Frame.UNINITIALIZED: - stackMap.putByte(8).putShort(cw.typeTable[v].intVal); - break; - default: - stackMap.putByte(v); + case Frame.OBJECT: + stackMap.putByte(7).putShort(cw.newClass(cw.typeTable[v].strVal1)); + break; + case Frame.UNINITIALIZED: + stackMap.putByte(8).putShort(cw.typeTable[v].intVal); + break; + default: + stackMap.putByte(v); } } else { StringBuffer buf = new StringBuffer(); @@ -1805,29 +1728,29 @@ class MethodWriter extends MethodVisitor { buf.append(';'); } else { switch (t & 0xF) { - case 1: - buf.append('I'); - break; - case 2: - buf.append('F'); - break; - case 3: - buf.append('D'); - break; - case 9: - buf.append('Z'); - break; - case 10: - buf.append('B'); - break; - case 11: - buf.append('C'); - break; - case 12: - buf.append('S'); - break; - default: - buf.append('J'); + case 1: + buf.append('I'); + break; + case 2: + buf.append('F'); + break; + case 3: + buf.append('D'); + break; + case 9: + buf.append('Z'); + break; + case 10: + buf.append('B'); + break; + case 11: + buf.append('C'); + break; + case 12: + buf.append('S'); + break; + default: + buf.append('J'); } } stackMap.putByte(7).putShort(cw.newClass(buf.toString())); @@ -1891,8 +1814,7 @@ class MethodWriter extends MethodVisitor { size += 8 + stackMap.length; } if (cattrs != null) { - size += cattrs.getSize(cw, code.data, code.length, maxStack, - maxLocals); + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } } if (exceptionCount > 0) { @@ -1950,14 +1872,11 @@ class MethodWriter extends MethodVisitor { /** * Puts the bytecode of this method in the given byte vector. * - * @param out - * the byte vector into which the bytecode of this method must be - * copied. + * @param out the byte vector into which the bytecode of this method must be copied. */ final void put(final ByteVector out) { final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; - int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED - | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE + int mask = ACC_CONSTRUCTOR | Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE | ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); out.putShort(access & ~mask).putShort(name).putShort(desc); if (classReaderOffset != 0) { @@ -2017,8 +1936,7 @@ class MethodWriter extends MethodVisitor { size += 8 + stackMap.length; } if (cattrs != null) { - size += cattrs.getSize(cw, code.data, code.length, maxStack, - maxLocals); + size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals); } out.putShort(cw.newUTF8("Code")).putInt(size); out.putShort(maxStack).putShort(maxLocals); @@ -2075,8 +1993,7 @@ class MethodWriter extends MethodVisitor { } } if (exceptionCount > 0) { - out.putShort(cw.newUTF8("Exceptions")).putInt( - 2 * exceptionCount + 2); + out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2); out.putShort(exceptionCount); for (int i = 0; i < exceptionCount; ++i) { out.putShort(exceptions[i]); @@ -2092,8 +2009,7 @@ class MethodWriter extends MethodVisitor { out.putShort(cw.newUTF8("Deprecated")).putInt(0); } if (ClassReader.SIGNATURES && signature != null) { - out.putShort(cw.newUTF8("Signature")).putInt(2) - .putShort(cw.newUTF8(signature)); + out.putShort(cw.newUTF8("Signature")).putInt(2).putShort(cw.newUTF8(signature)); } if (ClassReader.ANNOTATIONS && annd != null) { out.putShort(cw.newUTF8("AnnotationDefault")); @@ -2126,50 +2042,44 @@ class MethodWriter extends MethodVisitor { // ------------------------------------------------------------------------ /** - * Resizes and replaces the temporary instructions inserted by - * {@link Label#resolve} for wide forward jumps, while keeping jump offsets - * and instruction addresses consistent. This may require to resize other - * existing instructions, or even to introduce new instructions: for - * example, increasing the size of an instruction by 2 at the middle of a - * method can increases the offset of an IFEQ instruction from 32766 to - * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W - * 32765. This, in turn, may require to increase the size of another jump - * instruction, and so on... All these operations are handled automatically - * by this method. + * Resizes and replaces the temporary instructions inserted by {@link Label#resolve} for wide + * forward jumps, while keeping jump offsets and instruction addresses consistent. This may + * require to resize other existing instructions, or even to introduce new instructions: for + * example, increasing the size of an instruction by 2 at the middle of a method can increases + * the offset of an IFEQ instruction from 32766 to 32768, in which case IFEQ 32766 must be + * replaced with IFNEQ 8 GOTO_W 32765. This, in turn, may require to increase the size of + * another jump instruction, and so on... All these operations are handled automatically by this + * method. *

- * This method must be called after all the method that is being built - * has been visited. In particular, the {@link Label Label} objects used - * to construct the method are no longer valid after this method has been - * called. + * This method must be called after all the method that is being built has been visited. + * In particular, the {@link Label Label} objects used to construct the method are no longer + * valid after this method has been called. */ private void resizeInstructions() { byte[] b = code.data; // bytecode of the method int u, v, label; // indexes in b int i, j; // loop indexes /* - * 1st step: As explained above, resizing an instruction may require to - * resize another one, which may require to resize yet another one, and - * so on. The first step of the algorithm consists in finding all the - * instructions that need to be resized, without modifying the code. - * This is done by the following "fix point" algorithm: + * 1st step: As explained above, resizing an instruction may require to resize another one, + * which may require to resize yet another one, and so on. The first step of the algorithm + * consists in finding all the instructions that need to be resized, without modifying the + * code. This is done by the following "fix point" algorithm: * - * Parse the code to find the jump instructions whose offset will need - * more than 2 bytes to be stored (the future offset is computed from - * the current offset and from the number of bytes that will be inserted - * or removed between the source and target instructions). For each such - * instruction, adds an entry in (a copy of) the indexes and sizes - * arrays (if this has not already been done in a previous iteration!). + * Parse the code to find the jump instructions whose offset will need more than 2 bytes to + * be stored (the future offset is computed from the current offset and from the number of + * bytes that will be inserted or removed between the source and target instructions). For + * each such instruction, adds an entry in (a copy of) the indexes and sizes arrays (if this + * has not already been done in a previous iteration!). * - * If at least one entry has been added during the previous step, go - * back to the beginning, otherwise stop. + * If at least one entry has been added during the previous step, go back to the beginning, + * otherwise stop. * - * In fact the real algorithm is complicated by the fact that the size - * of TABLESWITCH and LOOKUPSWITCH instructions depends on their - * position in the bytecode (because of padding). In order to ensure the - * convergence of the algorithm, the number of bytes to be added or - * removed from these instructions is over estimated during the previous - * loop, and computed exactly only after the loop is finished (this - * requires another pass to parse the bytecode of the method). + * In fact the real algorithm is complicated by the fact that the size of TABLESWITCH and + * LOOKUPSWITCH instructions depends on their position in the bytecode (because of padding). + * In order to ensure the convergence of the algorithm, the number of bytes to be added or + * removed from these instructions is over estimated during the previous loop, and computed + * exactly only after the loop is finished (this requires another pass to parse the bytecode + * of the method). */ int[] allIndexes = new int[0]; // copy of indexes int[] allSizes = new int[0]; // copy of sizes @@ -2190,118 +2100,116 @@ class MethodWriter extends MethodVisitor { int insert = 0; // bytes to be added after this instruction switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - u += 1; - break; - case ClassWriter.LABEL_INSN: - if (opcode > 201) { - // converts temporary opcodes 202 to 217, 218 and - // 219 to IFEQ ... JSR (inclusive), IFNULL and - // IFNONNULL - opcode = opcode < 218 ? opcode - 49 : opcode - 20; - label = u + readUnsignedShort(b, u + 1); - } else { - label = u + readShort(b, u + 1); - } - newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (newOffset < Short.MIN_VALUE - || newOffset > Short.MAX_VALUE) { - if (!resize[u]) { - if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { - // two additional bytes will be required to - // replace this GOTO or JSR instruction with - // a GOTO_W or a JSR_W - insert = 2; - } else { - // five additional bytes will be required to - // replace this IFxxx instruction with - // IFNOTxxx GOTO_W , where IFNOTxxx - // is the "opposite" opcode of IFxxx (i.e., - // IFNE for IFEQ) and where designates - // the instruction just after the GOTO_W. - insert = 5; + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // converts temporary opcodes 202 to 217, 218 and + // 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) { + if (!resize[u]) { + if (opcode == Opcodes.GOTO || opcode == Opcodes.JSR) { + // two additional bytes will be required to + // replace this GOTO or JSR instruction with + // a GOTO_W or a JSR_W + insert = 2; + } else { + // five additional bytes will be required to + // replace this IFxxx instruction with + // IFNOTxxx GOTO_W , where IFNOTxxx + // is the "opposite" opcode of IFxxx (i.e., + // IFNE for IFEQ) and where designates + // the instruction just after the GOTO_W. + insert = 5; + } + resize[u] = true; } + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + u += 5; + break; + case ClassWriter.TABL_INSN: + if (state == 1) { + // true number of bytes to be added (or removed) + // from this instruction = (future number of padding + // bytes - current number of padding byte) - + // previously over estimated variation = + // = ((3 - newOffset%4) - (3 - u%4)) - u%4 + // = (-newOffset%4 + u%4) - u%4 + // = -(newOffset & 3) + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // over estimation of the number of bytes to be + // added to this instruction = 3 - current number + // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 + insert = u & 3; resize[u] = true; } - } - u += 3; - break; - case ClassWriter.LABELW_INSN: - u += 5; - break; - case ClassWriter.TABL_INSN: - if (state == 1) { - // true number of bytes to be added (or removed) - // from this instruction = (future number of padding - // bytes - current number of padding byte) - - // previously over estimated variation = - // = ((3 - newOffset%4) - (3 - u%4)) - u%4 - // = (-newOffset%4 + u%4) - u%4 - // = -(newOffset & 3) - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // over estimation of the number of bytes to be - // added to this instruction = 3 - current number - // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3 - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; - break; - case ClassWriter.LOOK_INSN: - if (state == 1) { - // like TABL_INSN - newOffset = getNewOffset(allIndexes, allSizes, 0, u); - insert = -(newOffset & 3); - } else if (!resize[u]) { - // like TABL_INSN - insert = u & 3; - resize[u] = true; - } - // skips instruction - u = u + 4 - (u & 3); - u += 8 * readInt(b, u + 4) + 8; - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - u += 6; - } else { + // skips instruction + u = u + 4 - (u & 3); + u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12; + break; + case ClassWriter.LOOK_INSN: + if (state == 1) { + // like TABL_INSN + newOffset = getNewOffset(allIndexes, allSizes, 0, u); + insert = -(newOffset & 3); + } else if (!resize[u]) { + // like TABL_INSN + insert = u & 3; + resize[u] = true; + } + // skips instruction + u = u + 4 - (u & 3); + u += 8 * readInt(b, u + 4) + 8; + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + u += 6; + } else { + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + u += 5; + break; + // case ClassWriter.MANA_INSN: + default: u += 4; - } - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - u += 5; - break; - // case ClassWriter.MANA_INSN: - default: - u += 4; - break; + break; } if (insert != 0) { // adds a new (u, insert) entry in the allIndexes and // allSizes arrays int[] newIndexes = new int[allIndexes.length + 1]; int[] newSizes = new int[allSizes.length + 1]; - System.arraycopy(allIndexes, 0, newIndexes, 0, - allIndexes.length); + System.arraycopy(allIndexes, 0, newIndexes, 0, allIndexes.length); System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length); newIndexes[allIndexes.length] = u; newSizes[allSizes.length] = insert; @@ -2327,135 +2235,134 @@ class MethodWriter extends MethodVisitor { while (u < code.length) { int opcode = b[u] & 0xFF; switch (ClassWriter.TYPE[opcode]) { - case ClassWriter.NOARG_INSN: - case ClassWriter.IMPLVAR_INSN: - newCode.putByte(opcode); - u += 1; - break; - case ClassWriter.LABEL_INSN: - if (opcode > 201) { - // changes temporary opcodes 202 to 217 (inclusive), 218 - // and 219 to IFEQ ... JSR (inclusive), IFNULL and - // IFNONNULL - opcode = opcode < 218 ? opcode - 49 : opcode - 20; - label = u + readUnsignedShort(b, u + 1); - } else { - label = u + readShort(b, u + 1); - } - newOffset = getNewOffset(allIndexes, allSizes, u, label); - if (resize[u]) { - // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx - // with IFNOTxxx GOTO_W , where IFNOTxxx is - // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) - // and where designates the instruction just after - // the GOTO_W. - if (opcode == Opcodes.GOTO) { - newCode.putByte(200); // GOTO_W - } else if (opcode == Opcodes.JSR) { - newCode.putByte(201); // JSR_W - } else { - newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 - : opcode ^ 1); - newCode.putShort(8); // jump offset - newCode.putByte(200); // GOTO_W - // newOffset now computed from start of GOTO_W - newOffset -= 3; - } - newCode.putInt(newOffset); - } else { + case ClassWriter.NOARG_INSN: + case ClassWriter.IMPLVAR_INSN: newCode.putByte(opcode); - newCode.putShort(newOffset); - } - u += 3; - break; - case ClassWriter.LABELW_INSN: - label = u + readInt(b, u + 1); - newOffset = getNewOffset(allIndexes, allSizes, u, label); - newCode.putByte(opcode); - newCode.putInt(newOffset); - u += 5; - break; - case ClassWriter.TABL_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.TABLESWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - j = readInt(b, u) - j + 1; - u += 4; - newCode.putInt(readInt(b, u - 4)); - for (; j > 0; --j) { + u += 1; + break; + case ClassWriter.LABEL_INSN: + if (opcode > 201) { + // changes temporary opcodes 202 to 217 (inclusive), 218 + // and 219 to IFEQ ... JSR (inclusive), IFNULL and + // IFNONNULL + opcode = opcode < 218 ? opcode - 49 : opcode - 20; + label = u + readUnsignedShort(b, u + 1); + } else { + label = u + readShort(b, u + 1); + } + newOffset = getNewOffset(allIndexes, allSizes, u, label); + if (resize[u]) { + // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx + // with IFNOTxxx GOTO_W , where IFNOTxxx is + // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) + // and where designates the instruction just after + // the GOTO_W. + if (opcode == Opcodes.GOTO) { + newCode.putByte(200); // GOTO_W + } else if (opcode == Opcodes.JSR) { + newCode.putByte(201); // JSR_W + } else { + newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1); + newCode.putShort(8); // jump offset + newCode.putByte(200); // GOTO_W + // newOffset now computed from start of GOTO_W + newOffset -= 3; + } + newCode.putInt(newOffset); + } else { + newCode.putByte(opcode); + newCode.putShort(newOffset); + } + u += 3; + break; + case ClassWriter.LABELW_INSN: + label = u + readInt(b, u + 1); + newOffset = getNewOffset(allIndexes, allSizes, u, label); + newCode.putByte(opcode); + newCode.putInt(newOffset); + u += 5; + break; + case ClassWriter.TABL_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.TABLESWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); - } - break; - case ClassWriter.LOOK_INSN: - // skips 0 to 3 padding bytes - v = u; - u = u + 4 - (v & 3); - // reads and copies instruction - newCode.putByte(Opcodes.LOOKUPSWITCH); - newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); - label = v + readInt(b, u); - u += 4; - newOffset = getNewOffset(allIndexes, allSizes, v, label); - newCode.putInt(newOffset); - j = readInt(b, u); - u += 4; - newCode.putInt(j); - for (; j > 0; --j) { - newCode.putInt(readInt(b, u)); + j = readInt(b, u); u += 4; + newCode.putInt(j); + j = readInt(b, u) - j + 1; + u += 4; + newCode.putInt(readInt(b, u - 4)); + for (; j > 0; --j) { + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.LOOK_INSN: + // skips 0 to 3 padding bytes + v = u; + u = u + 4 - (v & 3); + // reads and copies instruction + newCode.putByte(Opcodes.LOOKUPSWITCH); + newCode.putByteArray(null, 0, (4 - newCode.length % 4) % 4); label = v + readInt(b, u); u += 4; newOffset = getNewOffset(allIndexes, allSizes, v, label); newCode.putInt(newOffset); - } - break; - case ClassWriter.WIDE_INSN: - opcode = b[u + 1] & 0xFF; - if (opcode == Opcodes.IINC) { - newCode.putByteArray(b, u, 6); - u += 6; - } else { + j = readInt(b, u); + u += 4; + newCode.putInt(j); + for (; j > 0; --j) { + newCode.putInt(readInt(b, u)); + u += 4; + label = v + readInt(b, u); + u += 4; + newOffset = getNewOffset(allIndexes, allSizes, v, label); + newCode.putInt(newOffset); + } + break; + case ClassWriter.WIDE_INSN: + opcode = b[u + 1] & 0xFF; + if (opcode == Opcodes.IINC) { + newCode.putByteArray(b, u, 6); + u += 6; + } else { + newCode.putByteArray(b, u, 4); + u += 4; + } + break; + case ClassWriter.VAR_INSN: + case ClassWriter.SBYTE_INSN: + case ClassWriter.LDC_INSN: + newCode.putByteArray(b, u, 2); + u += 2; + break; + case ClassWriter.SHORT_INSN: + case ClassWriter.LDCW_INSN: + case ClassWriter.FIELDORMETH_INSN: + case ClassWriter.TYPE_INSN: + case ClassWriter.IINC_INSN: + newCode.putByteArray(b, u, 3); + u += 3; + break; + case ClassWriter.ITFMETH_INSN: + case ClassWriter.INDYMETH_INSN: + newCode.putByteArray(b, u, 5); + u += 5; + break; + // case MANA_INSN: + default: newCode.putByteArray(b, u, 4); u += 4; - } - break; - case ClassWriter.VAR_INSN: - case ClassWriter.SBYTE_INSN: - case ClassWriter.LDC_INSN: - newCode.putByteArray(b, u, 2); - u += 2; - break; - case ClassWriter.SHORT_INSN: - case ClassWriter.LDCW_INSN: - case ClassWriter.FIELDORMETH_INSN: - case ClassWriter.TYPE_INSN: - case ClassWriter.IINC_INSN: - newCode.putByteArray(b, u, 3); - u += 3; - break; - case ClassWriter.ITFMETH_INSN: - case ClassWriter.INDYMETH_INSN: - newCode.putByteArray(b, u, 5); - u += 5; - break; - // case MANA_INSN: - default: - newCode.putByteArray(b, u, 4); - u += 4; - break; + break; } } @@ -2474,8 +2381,8 @@ class MethodWriter extends MethodVisitor { Label l = labels; while (l != null) { /* - * here we need the original label position. getNewOffset - * must therefore never have been called for this label. + * here we need the original label position. getNewOffset must therefore never + * have been called for this label. */ u = l.position - 3; if ((l.status & Label.STORE) != 0 || (u >= 0 && resize[u])) { @@ -2487,18 +2394,15 @@ class MethodWriter extends MethodVisitor { } } else { /* - * Resizing an existing stack map frame table is really hard. - * Not only the table must be parsed to update the offets, but - * new frames may be needed for jump instructions that were - * inserted by this method. And updating the offsets or - * inserting frames can change the format of the following - * frames, in case of packed frames. In practice the whole table - * must be recomputed. For this the frames are marked as - * potentially invalid. This will cause the whole class to be - * reread and rewritten with the COMPUTE_FRAMES option (see the - * ClassWriter.toByteArray method). This is not very efficient - * but is much easier and requires much less code than any other - * method I can think of. + * Resizing an existing stack map frame table is really hard. Not only the table + * must be parsed to update the offets, but new frames may be needed for jump + * instructions that were inserted by this method. And updating the offsets or + * inserting frames can change the format of the following frames, in case of packed + * frames. In practice the whole table must be recomputed. For this the frames are + * marked as potentially invalid. This will cause the whole class to be reread and + * rewritten with the COMPUTE_FRAMES option (see the ClassWriter.toByteArray + * method). This is not very efficient but is much easier and requires much less + * code than any other method I can think of. */ cw.invalidFrames = true; } @@ -2523,8 +2427,7 @@ class MethodWriter extends MethodVisitor { newOffset = getNewOffset(allIndexes, allSizes, 0, label); writeShort(b, u, newOffset); label += readUnsignedShort(b, u + 2); - newOffset = getNewOffset(allIndexes, allSizes, 0, label) - - newOffset; + newOffset = getNewOffset(allIndexes, allSizes, 0, label) - newOffset; writeShort(b, u + 2, newOffset); u += 10; } @@ -2534,11 +2437,7 @@ class MethodWriter extends MethodVisitor { b = lineNumber.data; u = 0; while (u < lineNumber.length) { - writeShort( - b, - u, - getNewOffset(allIndexes, allSizes, 0, - readUnsignedShort(b, u))); + writeShort(b, u, getNewOffset(allIndexes, allSizes, 0, readUnsignedShort(b, u))); u += 4; } } @@ -2561,10 +2460,8 @@ class MethodWriter extends MethodVisitor { /** * Reads an unsigned short value in the given byte array. * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. + * @param b a byte array. + * @param index the start index of the value to be read. * @return the read value. */ static int readUnsignedShort(final byte[] b, final int index) { @@ -2574,10 +2471,8 @@ class MethodWriter extends MethodVisitor { /** * Reads a signed short value in the given byte array. * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. + * @param b a byte array. + * @param index the start index of the value to be read. * @return the read value. */ static short readShort(final byte[] b, final int index) { @@ -2587,10 +2482,8 @@ class MethodWriter extends MethodVisitor { /** * Reads a signed int value in the given byte array. * - * @param b - * a byte array. - * @param index - * the start index of the value to be read. + * @param b a byte array. + * @param index the start index of the value to be read. * @return the read value. */ static int readInt(final byte[] b, final int index) { @@ -2601,12 +2494,9 @@ class MethodWriter extends MethodVisitor { /** * Writes a short value in the given byte array. * - * @param b - * a byte array. - * @param index - * where the first byte of the short value must be written. - * @param s - * the value to be written in the given byte array. + * @param b a byte array. + * @param index where the first byte of the short value must be written. + * @param s the value to be written in the given byte array. */ static void writeShort(final byte[] b, final int index, final int s) { b[index] = (byte) (s >>> 8); @@ -2616,32 +2506,24 @@ class MethodWriter extends MethodVisitor { /** * Computes the future value of a bytecode offset. *

- * Note: it is possible to have several entries for the same instruction in - * the indexes and sizes: two entries (index=a,size=b) and - * (index=a,size=b') are equivalent to a single entry (index=a,size=b+b'). + * Note: it is possible to have several entries for the same instruction in the indexes + * and sizes: two entries (index=a,size=b) and (index=a,size=b') are equivalent to a + * single entry (index=a,size=b+b'). * - * @param indexes - * current positions of the instructions to be resized. Each - * instruction must be designated by the index of its last - * byte, plus one (or, in other words, by the index of the - * first byte of the next instruction). - * @param sizes - * the number of bytes to be added to the above - * instructions. More precisely, for each i < len, - * sizes[i] bytes will be added at the end of the - * instruction designated by indexes[i] or, if - * sizes[i] is negative, the last | - * sizes[i]| bytes of the instruction will be removed - * (the instruction size must not become negative or - * null). - * @param begin - * index of the first byte of the source instruction. - * @param end - * index of the first byte of the target instruction. + * @param indexes current positions of the instructions to be resized. Each instruction must be + * designated by the index of its last byte, plus one (or, in other words, by the + * index of the first byte of the next instruction). + * @param sizes the number of bytes to be added to the above instructions. More + * precisely, for each i < len, sizes[i] bytes will be added at the end + * of the instruction designated by indexes[i] or, if sizes[i] is + * negative, the last | sizes[i]| bytes of the instruction will be + * removed (the instruction size must not become negative or null). + * @param begin index of the first byte of the source instruction. + * @param end index of the first byte of the target instruction. * @return the future value of the given bytecode offset. */ - static int getNewOffset(final int[] indexes, final int[] sizes, - final int begin, final int end) { + static int getNewOffset(final int[] indexes, final int[] sizes, final int begin, + final int end) { int offset = end - begin; for (int i = 0; i < indexes.length; ++i) { if (begin < indexes[i] && indexes[i] <= end) { @@ -2658,25 +2540,17 @@ class MethodWriter extends MethodVisitor { /** * Updates the offset of the given label. * - * @param indexes - * current positions of the instructions to be resized. Each - * instruction must be designated by the index of its last - * byte, plus one (or, in other words, by the index of the - * first byte of the next instruction). - * @param sizes - * the number of bytes to be added to the above - * instructions. More precisely, for each i < len, - * sizes[i] bytes will be added at the end of the - * instruction designated by indexes[i] or, if - * sizes[i] is negative, the last | - * sizes[i]| bytes of the instruction will be removed - * (the instruction size must not become negative or - * null). - * @param label - * the label whose offset must be updated. + * @param indexes current positions of the instructions to be resized. Each instruction must be + * designated by the index of its last byte, plus one (or, in other words, by the + * index of the first byte of the next instruction). + * @param sizes the number of bytes to be added to the above instructions. More + * precisely, for each i < len, sizes[i] bytes will be added at the end + * of the instruction designated by indexes[i] or, if sizes[i] is + * negative, the last | sizes[i]| bytes of the instruction will be + * removed (the instruction size must not become negative or null). + * @param label the label whose offset must be updated. */ - static void getNewOffset(final int[] indexes, final int[] sizes, - final Label label) { + static void getNewOffset(final int[] indexes, final int[] sizes, final Label label) { if ((label.status & Label.RESIZED) == 0) { label.position = getNewOffset(indexes, sizes, 0, label.position); label.status |= Label.RESIZED; diff --git a/src/main/asm/org/objectweb/asm/Opcodes.java b/src/main/asm/org/objectweb/asm/Opcodes.java index f9b6af1..dd7adf0 100644 --- a/src/main/asm/org/objectweb/asm/Opcodes.java +++ b/src/main/asm/org/objectweb/asm/Opcodes.java @@ -1,42 +1,32 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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. + * 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 @@ -120,28 +110,26 @@ public interface Opcodes { 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. + * 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. + * 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. + * 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. + * 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; diff --git a/src/main/asm/org/objectweb/asm/Type.java b/src/main/asm/org/objectweb/asm/Type.java index be69a2c..11e08b9 100644 --- a/src/main/asm/org/objectweb/asm/Type.java +++ b/src/main/asm/org/objectweb/asm/Type.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -33,8 +25,8 @@ 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. + * 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 @@ -104,56 +96,56 @@ public class Type { /** * The void type. */ - public static final Type VOID_TYPE = new Type(VOID, null, ('V' << 24) - | (5 << 16) | (0 << 8) | 0, 1); + public static final Type VOID_TYPE = + new Type(VOID, null, ('V' << 24) | (5 << 16) | (0 << 8) | 0, 1); /** * The boolean type. */ - public static final Type BOOLEAN_TYPE = new Type(BOOLEAN, null, ('Z' << 24) - | (0 << 16) | (5 << 8) | 1, 1); + public static final Type BOOLEAN_TYPE = + new Type(BOOLEAN, null, ('Z' << 24) | (0 << 16) | (5 << 8) | 1, 1); /** * The char type. */ - public static final Type CHAR_TYPE = new Type(CHAR, null, ('C' << 24) - | (0 << 16) | (6 << 8) | 1, 1); + public static final Type CHAR_TYPE = + new Type(CHAR, null, ('C' << 24) | (0 << 16) | (6 << 8) | 1, 1); /** * The byte type. */ - public static final Type BYTE_TYPE = new Type(BYTE, null, ('B' << 24) - | (0 << 16) | (5 << 8) | 1, 1); + public static final Type BYTE_TYPE = + new Type(BYTE, null, ('B' << 24) | (0 << 16) | (5 << 8) | 1, 1); /** * The short type. */ - public static final Type SHORT_TYPE = new Type(SHORT, null, ('S' << 24) - | (0 << 16) | (7 << 8) | 1, 1); + public static final Type SHORT_TYPE = + new Type(SHORT, null, ('S' << 24) | (0 << 16) | (7 << 8) | 1, 1); /** * The int type. */ - public static final Type INT_TYPE = new Type(INT, null, ('I' << 24) - | (0 << 16) | (0 << 8) | 1, 1); + public static final Type INT_TYPE = + new Type(INT, null, ('I' << 24) | (0 << 16) | (0 << 8) | 1, 1); /** * The float type. */ - public static final Type FLOAT_TYPE = new Type(FLOAT, null, ('F' << 24) - | (2 << 16) | (2 << 8) | 1, 1); + public static final Type FLOAT_TYPE = + new Type(FLOAT, null, ('F' << 24) | (2 << 16) | (2 << 8) | 1, 1); /** * The long type. */ - public static final Type LONG_TYPE = new Type(LONG, null, ('J' << 24) - | (1 << 16) | (1 << 8) | 2, 1); + public static final Type LONG_TYPE = + new Type(LONG, null, ('J' << 24) | (1 << 16) | (1 << 8) | 2, 1); /** * The double type. */ - public static final Type DOUBLE_TYPE = new Type(DOUBLE, null, ('D' << 24) - | (3 << 16) | (3 << 8) | 2, 1); + public static final Type DOUBLE_TYPE = + new Type(DOUBLE, null, ('D' << 24) | (3 << 16) | (3 << 8) | 2, 1); // ------------------------------------------------------------------------ // Fields @@ -165,16 +157,16 @@ public class Type { private final int sort; /** - * A buffer containing the internal name of this Java type. This field is - * only used for reference types. + * 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). + * 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; @@ -190,14 +182,10 @@ public class Type { /** * 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. + * @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; @@ -209,8 +197,7 @@ public class Type { /** * Returns the Java type corresponding to the given type descriptor. * - * @param typeDescriptor - * a field or method 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) { @@ -220,8 +207,7 @@ public class Type { /** * Returns the Java type corresponding to the given internal name. * - * @param internalName - * an internal name. + * @param internalName an internal name. * @return the Java type corresponding to the given internal name. */ public static Type getObjectType(final String internalName) { @@ -230,11 +216,10 @@ public class Type { } /** - * Returns the Java type corresponding to the given method descriptor. - * Equivalent to Type.getType(methodDescriptor). + * Returns the Java type corresponding to the given method descriptor. Equivalent to + * Type.getType(methodDescriptor). * - * @param methodDescriptor - * a method descriptor. + * @param methodDescriptor a method descriptor. * @return the Java type corresponding to the given method descriptor. */ public static Type getMethodType(final String methodDescriptor) { @@ -242,26 +227,20 @@ public class Type { } /** - * Returns the Java method type corresponding to the given argument and - * return types. + * 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. + * @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) { + 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. + * @param c a class. * @return the Java type corresponding to the given class. */ public static Type getType(final Class c) { @@ -282,7 +261,7 @@ public class Type { return DOUBLE_TYPE; } else if (c == Float.TYPE) { return FLOAT_TYPE; - } else /* if (c == Long.TYPE) */{ + } else /* if (c == Long.TYPE) */ { return LONG_TYPE; } } else { @@ -293,8 +272,7 @@ public class Type { /** * Returns the Java method type corresponding to the given constructor. * - * @param c - * a {@link Constructor Constructor} object. + * @param c a {@link Constructor Constructor} object. * @return the Java method type corresponding to the given constructor. */ public static Type getType(final Constructor c) { @@ -304,8 +282,7 @@ public class Type { /** * Returns the Java method type corresponding to the given method. * - * @param m - * a {@link Method Method} object. + * @param m a {@link Method Method} object. * @return the Java method type corresponding to the given method. */ public static Type getType(final Method m) { @@ -313,13 +290,10 @@ public class Type { } /** - * Returns the Java types corresponding to the argument types of the given - * method descriptor. + * 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. + * @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(); @@ -349,13 +323,10 @@ public class Type { } /** - * Returns the Java types corresponding to the argument types of the given - * method. + * 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. + * @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(); @@ -367,13 +338,10 @@ public class Type { } /** - * Returns the Java type corresponding to the return type of the given - * method descriptor. + * 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. + * @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(); @@ -381,13 +349,10 @@ public class Type { } /** - * Returns the Java type corresponding to the return type of the given - * method. + * 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. + * @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()); @@ -396,13 +361,11 @@ public class Type { /** * 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 = - * (argSize << 2) | retSize (argSize is therefore equal to - * i >> 2, and retSize to i & 0x03). + * @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 = + * (argSize << 2) | retSize (argSize is therefore equal to i >> 2, and + * retSize to i & 0x03). */ public static int getArgumentsAndReturnSizes(final String desc) { int n = 1; @@ -411,8 +374,7 @@ public class Type { char car = desc.charAt(c++); if (car == ')') { car = desc.charAt(c); - return n << 2 - | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); + return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1)); } else if (car == 'L') { while (desc.charAt(c++) != ';') { } @@ -433,58 +395,55 @@ public class Type { } /** - * Returns the Java type corresponding to the given type descriptor. For - * method descriptors, buf is supposed to contain nothing more than the - * descriptor itself. + * 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. + * @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; + 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(ARRAY, buf, off, len + 1); - case 'L': - len = 1; - while (buf[off + len] != ';') { - ++len; - } - return new Type(OBJECT, buf, off + 1, len - 1); + return new Type(OBJECT, buf, off + 1, len - 1); // case '(': - default: - return new Type(METHOD, buf, off, buf.length - off); + default: + return new Type(METHOD, buf, off, buf.length - off); } } @@ -495,19 +454,18 @@ public class Type { /** * 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}. + * @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. + * 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. */ @@ -520,8 +478,8 @@ public class Type { } /** - * Returns the type of the elements of this array type. This method should - * only be used for an array type. + * 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. */ @@ -530,49 +488,48 @@ public class Type { } /** - * Returns the binary name of the class corresponding to this type. This - * method must not be used on method types. + * 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; + 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. + * 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. */ @@ -581,8 +538,8 @@ public class Type { } /** - * Returns the argument types of methods of this type. This method should - * only be used for method types. + * 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. */ @@ -591,8 +548,8 @@ public class Type { } /** - * Returns the return type of methods of this type. This method should only - * be used for method types. + * 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. */ @@ -601,14 +558,13 @@ public class Type { } /** - * 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. + * 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 = (argSize << 2) | retSize - * (argSize is therefore equal to i >> 2, and retSize to - * i & 0x03). + * @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 = + * (argSize << 2) | retSize (argSize is therefore equal to i >> 2, and + * retSize to i & 0x03). */ public int getArgumentsAndReturnSizes() { return getArgumentsAndReturnSizes(getDescriptor()); @@ -630,18 +586,13 @@ public class Type { } /** - * Returns the descriptor corresponding to the given argument and return - * types. + * 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. + * @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) { + public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { StringBuffer buf = new StringBuffer(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { @@ -653,11 +604,9 @@ public class Type { } /** - * Appends the descriptor corresponding to this Java type to the given - * string buffer. + * 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. + * @param buf the string buffer to which the descriptor must be appended. */ private void getDescriptor(final StringBuffer buf) { if (this.buf == null) { @@ -679,12 +628,10 @@ public class Type { // ------------------------------------------------------------------------ /** - * 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 '/'. + * 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. + * @param c an object or array class. * @return the internal name of the given class. */ public static String getInternalName(final Class c) { @@ -694,8 +641,7 @@ public class Type { /** * Returns the descriptor corresponding to the given Java type. * - * @param c - * an object class, a primitive class or an array class. + * @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) { @@ -707,8 +653,7 @@ public class Type { /** * Returns the descriptor corresponding to the given constructor. * - * @param c - * a {@link Constructor Constructor} object. + * @param c a {@link Constructor Constructor} object. * @return the descriptor of the given constructor. */ public static String getConstructorDescriptor(final Constructor c) { @@ -724,8 +669,7 @@ public class Type { /** * Returns the descriptor corresponding to the given method. * - * @param m - * a {@link Method Method} object. + * @param m a {@link Method Method} object. * @return the descriptor of the given method. */ public static String getMethodDescriptor(final Method m) { @@ -743,10 +687,8 @@ public class Type { /** * 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. + * @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; @@ -769,7 +711,7 @@ public class Type { car = 'D'; } else if (d == Float.TYPE) { car = 'F'; - } else /* if (d == Long.TYPE) */{ + } else /* if (d == Long.TYPE) */ { car = 'J'; } buf.append(car); @@ -796,11 +738,10 @@ public class Type { // ------------------------------------------------------------------------ /** - * Returns the size of values of this type. This method must not be used for - * method types. + * 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 long and - * double, 0 for void and 1 otherwise. + * @return the size of values of this type, i.e., 2 for long and double, 0 for + * void and 1 otherwise. */ public int getSize() { // the size is in byte 0 of 'off' for primitive types (buf == null) @@ -808,16 +749,15 @@ public class Type { } /** - * Returns a JVM instruction opcode adapted to this Java type. This method - * must not be used for method types. + * 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 float and - * opcode is IRETURN, this method returns FRETURN. + * @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 float and opcode is IRETURN, this method + * returns FRETURN. */ public int getOpcode(final int opcode) { if (opcode == Opcodes.IALOAD || opcode == Opcodes.IASTORE) { @@ -838,8 +778,7 @@ public class Type { /** * Tests if the given object is equal to this type. * - * @param o - * the object to be compared to this type. + * @param o the object to be compared to this type. * @return true if the given object is equal to this type. */ @Override diff --git a/src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java b/src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java index c693215..c9c4c25 100644 --- a/src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java +++ b/src/main/asm/org/objectweb/asm/commons/AdviceAdapter.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -41,17 +33,17 @@ 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. + * A {@link org.objectweb.asm.MethodVisitor} to insert before, after and around advices in methods + * and constructors. *

* The behavior for constructors is like this: *

    * - *
  1. as long as the INVOKESPECIAL for the object initialization has not been - * reached, every bytecode instruction is dispatched in the ctor code visitor
  2. + *
  3. as long as the INVOKESPECIAL for the object initialization has not been reached, every + * bytecode instruction is dispatched in the ctor code visitor
  4. * - *
  5. when this one is reached, it is only added in the ctor code visitor and a - * JP invoke is added
  6. + *
  7. when this one is reached, it is only added in the ctor code visitor and a JP invoke is + * added
  8. * *
  9. after that, only the other code visitor receives the instructions
  10. * @@ -81,20 +73,15 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes /** * 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}). + * @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) { + 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; @@ -130,178 +117,178 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes 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; + 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; + case RETURN: + case IRETURN: + case FRETURN: + case ARETURN: + case LRETURN: + case DRETURN: + case ATHROW: + onMethodExit(opcode); + break; } } mv.visitInsn(opcode); @@ -312,64 +299,64 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes 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; + 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) { + 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) { + case GETSTATIC: pushValue(OTHER); - } - break; - case PUTSTATIC: - popValue(); - if (longOrDouble) { + if (longOrDouble) { + pushValue(OTHER); + } + break; + case PUTSTATIC: popValue(); - } - break; - case PUTFIELD: - popValue(); - if (longOrDouble) { + if (longOrDouble) { + popValue(); + } + break; + case PUTFIELD: popValue(); - popValue(); - } - break; - // case GETFIELD: - default: - if (longOrDouble) { - pushValue(OTHER); - } + if (longOrDouble) { + popValue(); + popValue(); + } + break; + // case GETFIELD: + default: + if (longOrDouble) { + pushValue(OTHER); + } } } } @@ -414,8 +401,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } @Override - public void visitMethodInsn(final int opcode, final String owner, - final String name, final String desc) { + 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); @@ -426,22 +413,22 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } } 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; + // 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); @@ -455,8 +442,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } @Override - public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, - Object... bsmArgs) { + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs); if (constructor) { Type[] types = Type.getArgumentTypes(desc); @@ -482,38 +468,37 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes 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; + 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) { + public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) { mv.visitLookupSwitchInsn(dflt, keys, labels); if (constructor) { popValue(); @@ -522,8 +507,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } @Override - public void visitTableSwitchInsn(final int min, final int max, - final Label dflt, final Label... labels) { + public void visitTableSwitchInsn(final int min, final int max, final Label dflt, + final Label... labels) { mv.visitTableSwitchInsn(min, max, dflt, labels); if (constructor) { popValue(); @@ -532,8 +517,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, - String type) { + public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { super.visitTryCatchBlock(start, end, handler, type); if (constructor && !branches.containsKey(handler)) { List stackFrame = new ArrayList(); @@ -569,20 +553,18 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } /** - * Called at the beginning of the method or after super class class call in - * the constructor.
    + * Called at the beginning of the method or after super class class call in the constructor. + *
    *
    * - * Custom code can use or change all the local variables, but should not - * change state of the stack. + * Custom code can use or change all the local variables, but should not change state of the + * stack. */ - protected void onMethodEnter() { - } + 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: + * 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: * *
          *   public void onMethodExit(int opcode) {
    @@ -610,16 +592,13 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
          * 
    *
    * - * Custom code can use or change all the local variables, but should not - * change state of the stack. + * Custom code can use or change all the local variables, but should not change state of the + * stack. * - * @param opcode - * one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN - * or ATHROW + * @param opcode one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN or ATHROW * */ - protected void onMethodExit(int opcode) { - } + protected void onMethodExit(int opcode) {} // TODO onException, onMethodCall } diff --git a/src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java b/src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java index 156af0c..a2d2f29 100644 --- a/src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java +++ b/src/main/asm/org/objectweb/asm/commons/AnalyzerAdapter.java @@ -1,31 +1,23 @@ /*** - * ASM: a very small and fast Java bytecode manipulation framework - * Copyright (c) 2000-2011 INRIA, France Telecom - * All rights reserved. + * 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. + * 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. + * 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; @@ -42,65 +34,55 @@ 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 - * visitX 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 before each instruction - * by reading the value of these fields in its visitX 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. + * {@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 visitX + * 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 before each instruction + * by reading the value of these fields in its visitX 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 { /** - * List 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 null for unreachable - * instructions. + * List 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 null for + * unreachable instructions. */ public List locals; /** - * List 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 null for unreachable - * instructions. + * List 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 null for + * unreachable instructions. */ public List stack; /** - * The labels that designate the next instruction to be visited. May be - * null. + * The labels that designate the next instruction to be visited. May be null. */ private List