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