1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2014 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.info;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.CodeAttribute;
25import proguard.classfile.instruction.*;
26import proguard.classfile.instruction.visitor.InstructionVisitor;
27import proguard.classfile.util.SimplifiedVisitor;
28
29/**
30 * This class can tell whether an instruction might throw exceptions.
31 *
32 * @author Eric Lafortune
33 */
34public class ExceptionInstructionChecker
35extends      SimplifiedVisitor
36implements   InstructionVisitor
37//             ConstantVisitor,
38//             MemberVisitor
39{
40    // A return value for the visitor methods.
41    private boolean mayThrowExceptions;
42
43
44    /**
45     * Returns whether the specified method may throw exceptions.
46     */
47    public boolean mayThrowExceptions(Clazz         clazz,
48                                      Method        method,
49                                      CodeAttribute codeAttribute)
50    {
51        return mayThrowExceptions(clazz,
52                                  method,
53                                  codeAttribute,
54                                  0,
55                                  codeAttribute.u4codeLength);
56    }
57
58
59    /**
60     * Returns whether the specified block of code may throw exceptions.
61     */
62    public boolean mayThrowExceptions(Clazz         clazz,
63                                      Method        method,
64                                      CodeAttribute codeAttribute,
65                                      int           startOffset,
66                                      int           endOffset)
67    {
68        byte[] code = codeAttribute.code;
69
70        // Go over all instructions.
71        int offset = startOffset;
72        while (offset < endOffset)
73        {
74            // Get the current instruction.
75            Instruction instruction = InstructionFactory.create(code, offset);
76
77            // Check if it may be throwing exceptions.
78            if (mayThrowExceptions(clazz,
79                                   method,
80                                   codeAttribute,
81                                   offset,
82                                   instruction))
83            {
84                return true;
85            }
86
87            // Go to the next instruction.
88            offset += instruction.length(offset);
89        }
90
91        return false;
92    }
93
94
95    /**
96     * Returns whether the specified instruction may throw exceptions.
97     */
98    public boolean mayThrowExceptions(Clazz         clazz,
99                                      Method        method,
100                                      CodeAttribute codeAttribute,
101                                      int           offset)
102    {
103        Instruction instruction = InstructionFactory.create(codeAttribute.code, offset);
104
105        return mayThrowExceptions(clazz,
106                                  method,
107                                  codeAttribute,
108                                  offset,
109                                  instruction);
110    }
111
112
113    /**
114     * Returns whether the given instruction may throw exceptions.
115     */
116    public boolean mayThrowExceptions(Clazz         clazz,
117                                      Method        method,
118                                      CodeAttribute codeAttribute,
119                                      int           offset,
120                                      Instruction   instruction)
121    {
122        return instruction.mayThrowExceptions();
123
124//        mayThrowExceptions = false;
125//
126//        instruction.accept(clazz, method,  codeAttribute, offset, this);
127//
128//        return mayThrowExceptions;
129    }
130
131
132    // Implementations for InstructionVisitor.
133
134    public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
135
136
137    public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
138    {
139        // Check for instructions that may throw exceptions.
140        // Note that monitorexit can not sensibly throw exceptions, except the
141        // broken and deprecated asynchronous ThreadDeath. Removing the
142        // artificial infinite looping exception blocks that recent compilers
143        // add does not strictly follow the JVM specs, but it does have the
144        // additional benefit of avoiding a bug in the JVM in JDK 1.1.
145        switch (simpleInstruction.opcode)
146        {
147            case InstructionConstants.OP_IDIV:
148            case InstructionConstants.OP_LDIV:
149            case InstructionConstants.OP_IREM:
150            case InstructionConstants.OP_LREM:
151            case InstructionConstants.OP_IALOAD:
152            case InstructionConstants.OP_LALOAD:
153            case InstructionConstants.OP_FALOAD:
154            case InstructionConstants.OP_DALOAD:
155            case InstructionConstants.OP_AALOAD:
156            case InstructionConstants.OP_BALOAD:
157            case InstructionConstants.OP_CALOAD:
158            case InstructionConstants.OP_SALOAD:
159            case InstructionConstants.OP_IASTORE:
160            case InstructionConstants.OP_LASTORE:
161            case InstructionConstants.OP_FASTORE:
162            case InstructionConstants.OP_DASTORE:
163            case InstructionConstants.OP_AASTORE:
164            case InstructionConstants.OP_BASTORE:
165            case InstructionConstants.OP_CASTORE:
166            case InstructionConstants.OP_SASTORE:
167            case InstructionConstants.OP_NEWARRAY:
168            case InstructionConstants.OP_ARRAYLENGTH:
169            case InstructionConstants.OP_ATHROW:
170            case InstructionConstants.OP_MONITORENTER:
171                // These instructions may throw exceptions.
172                mayThrowExceptions = true;
173        }
174    }
175
176
177    public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
178    {
179        // Check for instructions that may throw exceptions.
180        switch (constantInstruction.opcode)
181        {
182            case InstructionConstants.OP_GETSTATIC:
183            case InstructionConstants.OP_PUTSTATIC:
184            case InstructionConstants.OP_GETFIELD:
185            case InstructionConstants.OP_PUTFIELD:
186            case InstructionConstants.OP_INVOKEVIRTUAL:
187            case InstructionConstants.OP_INVOKESPECIAL:
188            case InstructionConstants.OP_INVOKESTATIC:
189            case InstructionConstants.OP_INVOKEINTERFACE:
190            case InstructionConstants.OP_INVOKEDYNAMIC:
191            case InstructionConstants.OP_NEW:
192            case InstructionConstants.OP_ANEWARRAY:
193            case InstructionConstants.OP_CHECKCAST:
194            case InstructionConstants.OP_INSTANCEOF:
195            case InstructionConstants.OP_MULTIANEWARRAY:
196                // These instructions may throw exceptions.
197                mayThrowExceptions = true;
198
199//          case InstructionConstants.OP_INVOKEVIRTUAL:
200//          case InstructionConstants.OP_INVOKESPECIAL:
201//          case InstructionConstants.OP_INVOKESTATIC:
202//          case InstructionConstants.OP_INVOKEINTERFACE:
203//            // Check if the invoking the method may throw an exception.
204//            clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this);
205        }
206    }
207
208
209//    // Implementations for ConstantVisitor.
210//
211//    public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant)
212//    {
213//        Member referencedMember = refConstant.referencedMember;
214//
215//        // Do we have a reference to the method?
216//        if (referencedMember == null)
217//        {
218//            // We'll have to assume invoking the unknown method may throw an
219//            // an exception.
220//            mayThrowExceptions = true;
221//        }
222//        else
223//        {
224//            // First check the referenced method itself.
225//            refConstant.referencedMemberAccept(this);
226//
227//            // If the result isn't conclusive, check down the hierarchy.
228//            if (!mayThrowExceptions)
229//            {
230//                Clazz  referencedClass  = refConstant.referencedClass;
231//                Method referencedMethod = (Method)referencedMember;
232//
233//                // Check all other implementations of the method in the class
234//                // hierarchy.
235//                referencedClass.methodImplementationsAccept(referencedMethod,
236//                                                            false,
237//                                                            false,
238//                                                            true,
239//                                                            true,
240//                                                            this);
241//            }
242//        }
243//    }
244//
245//
246//    // Implementations for MemberVisitor.
247//
248//    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
249//    {
250//        mayThrowExceptions = mayThrowExceptions ||
251//                             ExceptionMethodMarker.mayThrowExceptions(programMethod);
252//    }
253//
254//
255//    public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
256//    {
257//        mayThrowExceptions = mayThrowExceptions ||
258//                             !NoExceptionMethodMarker.doesntThrowExceptions(libraryMethod);
259//    }
260}
261