1b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/* 2b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ProGuard -- shrinking, optimization, obfuscation, and preverification 3b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * of Java bytecode. 4b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 52270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) 6b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 7b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is free software; you can redistribute it and/or modify it 8b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * under the terms of the GNU General Public License as published by the Free 9b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Software Foundation; either version 2 of the License, or (at your option) 10b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * any later version. 11b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 12b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This program is distributed in the hope that it will be useful, but WITHOUT 13b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * more details. 16b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 17b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * You should have received a copy of the GNU General Public License along 18b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * with this program; if not, write to the Free Software Foundation, Inc., 19b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 21b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopackage proguard.preverify; 22b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 23b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.*; 24b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.*; 25b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.attribute.visitor.*; 26b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.editor.CodeAttributeComposer; 27b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.*; 28b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.instruction.visitor.InstructionVisitor; 29b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.util.SimplifiedVisitor; 30b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.classfile.visitor.*; 31b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimport proguard.optimize.peephole.BranchTargetFinder; 32b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 33b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato/** 34b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * This AttributeVisitor inlines local subroutines (jsr/ret) in the code 35b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * attributes that it visits. 36b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * 37b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * @author Eric Lafortune 38b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 39b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratopublic class CodeSubroutineInliner 40b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoextends SimplifiedVisitor 41b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onoratoimplements AttributeVisitor, 42b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato InstructionVisitor, 43b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ExceptionInfoVisitor 44b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato{ 45b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato //* 46b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private static final boolean DEBUG = false; 47b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /*/ 48b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang private static boolean DEBUG = System.getProperty("csi") != null; 49b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato //*/ 50b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 51b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private final BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); 522270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom private final CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(true, true, true); 53b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 54b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private ExceptionInfoVisitor subroutineExceptionInliner = this; 55b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int clipStart = 0; 56b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private int clipEnd = Integer.MAX_VALUE; 57b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 58b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 59b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for AttributeVisitor. 60b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 61b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 62b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 63b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 64b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 65b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 66b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// DEBUG = 67b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// clazz.getName().equals("abc/Def") && 68b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato// method.getName(clazz).equals("abc"); 69b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang// CodeAttributeComposer.DEBUG = DEBUG; 70b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 71b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // TODO: Remove this when the subroutine inliner has stabilized. 72b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Catch any unexpected exceptions from the actual visiting method. 73b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato try 74b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 75b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Process the code. 76b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato visitCodeAttribute0(clazz, method, codeAttribute); 77b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 78b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato catch (RuntimeException ex) 79b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 80b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println("Unexpected error while inlining subroutines:"); 81b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Class = ["+clazz.getName()+"]"); 82b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Method = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 83b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.err.println(" Exception = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")"); 84b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 85b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 86b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 87b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method.accept(clazz, new ClassPrinter()); 88b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 89b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 90b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato throw ex; 91b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 92b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 93b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 94b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 95b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute) 96b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 97b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); 98b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 99b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Don't bother if there aren't any subroutines anyway. 100b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang if (!branchTargetFinder.containsSubroutines()) 101b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 102b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato return; 103b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 104b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 105b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 106b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 107b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("SubroutineInliner: processing ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 108b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 109b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 110b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append the body of the code. 111b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.reset(); 112b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); 113b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 114b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Copy the non-subroutine instructions. 115b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int offset = 0; 116b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato while (offset < codeAttribute.u4codeLength) 117b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 118b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); 119b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int instructionLength = instruction.length(offset); 120b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 1212270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom // Is this a returning subroutine? 122b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (branchTargetFinder.isSubroutine(offset) && 123b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato branchTargetFinder.isSubroutineReturning(offset)) 124b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 125b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Skip the subroutine. 126b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 127b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 128b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Skipping original subroutine instruction "+instruction.toString(offset)); 129b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 130b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 131b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label at this offset instead. 132b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(offset); 133b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 134b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 135b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 136b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Copy the instruction, inlining any subroutine call recursively. 137b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato instruction.accept(clazz, method, codeAttribute, offset, this); 138b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 139b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 140b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset += instructionLength; 141b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 142b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 143b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Copy the exceptions. Note that exceptions with empty try blocks 144b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // are automatically removed. 145b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute.exceptionsAccept(clazz, 146b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 147b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineExceptionInliner); 148b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 149b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 150b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 151b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Appending label after code at ["+offset+"]"); 152b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 153b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 154b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label just after the code. 155b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); 156b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 157b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // End and update the code attribute. 158b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.endCodeFragment(); 159b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); 160b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 161b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 162b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 163b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato /** 164b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato * Appends the specified subroutine. 165b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato */ 166b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato private void inlineSubroutine(Clazz clazz, 167b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Method method, 168b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato CodeAttribute codeAttribute, 169b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int subroutineInvocationOffset, 170b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int subroutineStart) 171b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 172b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart); 173b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 174b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 175b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 176b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Inlining subroutine ["+subroutineStart+" -> "+subroutineEnd+"] at ["+subroutineInvocationOffset+"]"); 177b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 178b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 179b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Don't go inlining exceptions that are already applicable to this 180b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // subroutine invocation. 181b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato ExceptionInfoVisitor oldSubroutineExceptionInliner = subroutineExceptionInliner; 182b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int oldClipStart = clipStart; 183b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int oldClipEnd = clipEnd; 184b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 185b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineExceptionInliner = 186b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new ExceptionExcludedOffsetFilter(subroutineInvocationOffset, 187b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineExceptionInliner); 188b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato clipStart = subroutineStart; 189b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato clipEnd = subroutineEnd; 190b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 191b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); 192b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 193b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Copy the subroutine instructions, inlining any subroutine calls 194b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // recursively. 195b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute.instructionsAccept(clazz, 196b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 197b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineStart, 198b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineEnd, 199b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato this); 200b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 201b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 202b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 203b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Appending label after inlined subroutine at ["+subroutineEnd+"]"); 204b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 205b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 206b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label just after the code. 207b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(subroutineEnd); 208b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 209b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Inline the subroutine exceptions. 210b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute.exceptionsAccept(clazz, 211b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 212b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineStart, 213b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineEnd, 214b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineExceptionInliner); 215b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 216b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // We can again inline exceptions that are applicable to this 217b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // subroutine invocation. 218b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato subroutineExceptionInliner = oldSubroutineExceptionInliner; 219b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato clipStart = oldClipStart; 220b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato clipEnd = oldClipEnd; 221b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 222b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.endCodeFragment(); 223b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 224b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 225b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 226b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for InstructionVisitor. 227b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 228b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) 229b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 2302270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom if (branchTargetFinder.isSubroutineStart(offset)) 2312270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom { 2322270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom if (DEBUG) 2332270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom { 2342270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom System.out.println(" Replacing first subroutine instruction "+instruction.toString(offset)+" by a label"); 2352270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom } 2362270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom 2372270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom // Append a label at this offset instead of saving the subroutine 2382270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom // return address. 2392270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom codeAttributeComposer.appendLabel(offset); 2402270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom } 2412270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom else 2422270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom { 2432270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom // Append the instruction. 2442270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom codeAttributeComposer.appendInstruction(offset, instruction); 2452270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom } 246b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 247b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 248b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 249b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 250b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 251b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato byte opcode = variableInstruction.opcode; 252b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (opcode == InstructionConstants.OP_RET) 253b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 254b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is the return instruction the last instruction of the subroutine? 255b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (branchTargetFinder.subroutineEnd(offset) == offset + variableInstruction.length(offset)) 256b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 257b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 258b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 259b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Replacing subroutine return at ["+offset+"] by a label"); 260b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 261b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 262b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label at this offset instead of the subroutine return. 263b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(offset); 264b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 265b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 266b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 267b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 268b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 269b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Replacing subroutine return at ["+offset+"] by a simple branch"); 270b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 271b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 272b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Replace the instruction by a branch. 273b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Instruction replacementInstruction = 274b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new BranchInstruction(InstructionConstants.OP_GOTO, 275b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang branchTargetFinder.subroutineEnd(offset) - offset); 276b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 277b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendInstruction(offset, replacementInstruction); 278b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 279b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 280b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else if (branchTargetFinder.isSubroutineStart(offset)) 281b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 282b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 283b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 2842270795fbe0b277bfd49f40950ecaa78583175ccBrian Carlstrom System.out.println(" Replacing first subroutine instruction "+variableInstruction.toString(offset)+" by a label"); 285b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 286b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 287b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label at this offset instead of saving the subroutine 288b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // return address. 289b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(offset); 290b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 291b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 292b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 293b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append the instruction. 294b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendInstruction(offset, variableInstruction); 295b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 296b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 297b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 298b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 299b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 300b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 301b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato byte opcode = branchInstruction.opcode; 302b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (opcode == InstructionConstants.OP_JSR || 303b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato opcode == InstructionConstants.OP_JSR_W) 304b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 305b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int branchOffset = branchInstruction.branchOffset; 306b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int branchTarget = offset + branchOffset; 307b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 308b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is the subroutine ever returning? 309b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (branchTargetFinder.isSubroutineReturning(branchTarget)) 310b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 311b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a label at this offset instead of the subroutine invocation. 312b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendLabel(offset); 313b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 314b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Inline the invoked subroutine. 315b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato inlineSubroutine(clazz, 316b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato method, 317b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttribute, 318b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset, 319b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato branchTarget); 320b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 321b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 322b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 323b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 324b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 325b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println("Replacing subroutine invocation at ["+offset+"] by a simple branch"); 326b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 327b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 328b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Replace the subroutine invocation by a simple branch. 329b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Instruction replacementInstruction = 330b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato new BranchInstruction(InstructionConstants.OP_GOTO, 331b9cc48a43ed984587c939d02fba5316bf5c0df6eYing Wang branchOffset); 332b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 333b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendInstruction(offset, replacementInstruction); 334b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 335b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 336b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 337b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 338b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append the instruction. 339b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendInstruction(offset, branchInstruction); 340b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 341b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 342b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 343b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 344b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Implementations for ExceptionInfoVisitor. 345b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 346b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 347b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 348b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int startPC = Math.max(exceptionInfo.u2startPC, clipStart); 349b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int endPC = Math.min(exceptionInfo.u2endPC, clipEnd); 350b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int handlerPC = exceptionInfo.u2handlerPC; 351b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int catchType = exceptionInfo.u2catchType; 352b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 353b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Exclude any subroutine invocations that jump out of the try block, 354b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // by adding a try block before (and later on, after) each invocation. 355b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato for (int offset = startPC; offset < endPC; offset++) 356b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 357b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (branchTargetFinder.isSubroutineInvocation(offset)) 358b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 359b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); 360b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato int instructionLength = instruction.length(offset); 361b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 362b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Is it a subroutine invocation? 363b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (!exceptionInfo.isApplicable(offset + ((BranchInstruction)instruction).branchOffset)) 364b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 365b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 366b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 367b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Appending extra exception ["+startPC+" -> "+offset+"] -> "+handlerPC); 368b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 369b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 370b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append a try block that ends before the subroutine invocation. 371b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendException(new ExceptionInfo(startPC, 372b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato offset, 373b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato handlerPC, 374b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato catchType)); 375b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 376b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // The next try block will start after the subroutine invocation. 377b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato startPC = offset + instructionLength; 378b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 379b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 380b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 381b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 382b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (DEBUG) 383b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 384b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato if (startPC == exceptionInfo.u2startPC && 385b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato endPC == exceptionInfo.u2endPC) 386b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 387b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Appending exception ["+startPC+" -> "+endPC+"] -> "+handlerPC); 388b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 389b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato else 390b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato { 391b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato System.out.println(" Appending clipped exception ["+exceptionInfo.u2startPC+" -> "+exceptionInfo.u2endPC+"] ~> ["+startPC+" -> "+endPC+"] -> "+handlerPC); 392b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 393b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 394b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato 395b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // Append the exception. Note that exceptions with empty try blocks 396b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato // are automatically ignored. 397b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato codeAttributeComposer.appendException(new ExceptionInfo(startPC, 398b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato endPC, 399b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato handlerPC, 400b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato catchType)); 401b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato } 402b72c5c2e5482cf10117b2b25f642f7616b2326c3Joe Onorato} 403