1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.optimize.peephole;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.visitor.AttributeVisitor;
26import proguard.classfile.editor.CodeAttributeEditor;
27import proguard.classfile.instruction.Instruction;
28import proguard.classfile.instruction.visitor.InstructionVisitor;
29import proguard.classfile.util.SimplifiedVisitor;
30
31/**
32 * This InstructionVisitor deletes blocks of code that can never be reached by
33 * regular calls or branches.
34 *
35 * @author Eric Lafortune
36 */
37public class UnreachableCodeRemover
38extends      SimplifiedVisitor
39implements   AttributeVisitor,
40             InstructionVisitor
41{
42    //*
43    private static final boolean DEBUG = false;
44    /*/
45    private static       boolean DEBUG = true;
46    //*/
47
48    private final InstructionVisitor  extraInstructionVisitor;
49
50    private final ReachableCodeMarker reachableCodeMarker = new ReachableCodeMarker();
51    private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
52
53
54    /**
55     * Creates a new UnreachableCodeRemover.
56     */
57    public UnreachableCodeRemover()
58    {
59        this(null);
60    }
61
62
63    /**
64     * Creates a new UnreachableCodeRemover.
65     * @param extraInstructionVisitor an optional extra visitor for all
66     *                                deleted instructions.
67     */
68    public UnreachableCodeRemover(InstructionVisitor  extraInstructionVisitor)
69    {
70        this.extraInstructionVisitor = extraInstructionVisitor;
71    }
72
73
74    // Implementations for AttributeVisitor.
75
76    public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
77
78
79    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
80    {
81//        DEBUG =
82//            clazz.getName().equals("abc/Def") &&
83//            method.getName(clazz).equals("abc");
84
85        // TODO: Remove this when the code has stabilized.
86        // Catch any unexpected exceptions from the actual visiting method.
87        try
88        {
89            // Process the code.
90            visitCodeAttribute0(clazz, method, codeAttribute);
91        }
92        catch (RuntimeException ex)
93        {
94            System.err.println("Unexpected error while removing unreachable code:");
95            System.err.println("  Class       = ["+clazz.getName()+"]");
96            System.err.println("  Method      = ["+method.getName(clazz)+method.getDescriptor(clazz)+"]");
97            System.err.println("  Exception   = ["+ex.getClass().getName()+"] ("+ex.getMessage()+")");
98
99            throw ex;
100        }
101    }
102
103
104    public void visitCodeAttribute0(Clazz clazz, Method method, CodeAttribute codeAttribute)
105    {
106        if (DEBUG)
107        {
108            System.out.println("UnreachableCodeRemover: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz));
109        }
110
111        reachableCodeMarker.visitCodeAttribute(clazz, method, codeAttribute);
112
113        codeAttributeEditor.reset(codeAttribute.u4codeLength);
114
115        codeAttribute.instructionsAccept(clazz, method, this);
116
117        codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
118    }
119
120
121    // Implementations for InstructionVisitor.
122
123    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
124    {
125        if (DEBUG)
126        {
127            System.out.println("  "+(reachableCodeMarker.isReachable(offset) ? "+" : "-")+" "+instruction.toString(offset));
128        }
129
130        // Is this instruction unreachable?
131        if (!reachableCodeMarker.isReachable(offset))
132        {
133            // Then delete it.
134            codeAttributeEditor.deleteInstruction(offset);
135
136            // Visit the instruction, if required.
137            if (extraInstructionVisitor != null)
138            {
139                instruction.accept(clazz, method, codeAttribute, offset, extraInstructionVisitor);
140            }
141        }
142    }
143}
144