001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003,2004 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba;
021:
022: import java.util.IdentityHashMap;
023: import java.util.LinkedList;
024: import java.util.List;
025:
026: import org.apache.bcel.generic.CodeExceptionGen;
027: import org.apache.bcel.generic.InstructionHandle;
028: import org.apache.bcel.generic.MethodGen;
029:
030: /**
031: * This class provides a convenient way of determining the exception handlers
032: * for instructions in a method. Essentially, it's a
033: * a map of InstructionHandles to lists of CodeExceptionGen objects.
034: * This class also maps instructions which are the start of exception handlers
035: * to the CodeExceptionGen object representing the handler.
036: *
037: * @author David Hovemeyer
038: */
039: public class ExceptionHandlerMap {
040: private IdentityHashMap<InstructionHandle, List<CodeExceptionGen>> codeToHandlerMap;
041: private IdentityHashMap<InstructionHandle, CodeExceptionGen> startInstructionToHandlerMap;
042:
043: /**
044: * Constructor.
045: *
046: * @param methodGen the method to build the map for
047: */
048: public ExceptionHandlerMap(MethodGen methodGen) {
049: codeToHandlerMap = new IdentityHashMap<InstructionHandle, List<CodeExceptionGen>>();
050: startInstructionToHandlerMap = new IdentityHashMap<InstructionHandle, CodeExceptionGen>();
051: build(methodGen);
052: }
053:
054: /**
055: * Get the list of exception handlers (CodeExceptionGen objects)
056: * which are specified to handle exceptions for the instruction whose
057: * handle is given. Note that the handlers in the returned list
058: * are <b>in order of priority</b>, as defined in the method's exception handler
059: * table.
060: *
061: * @param handle the handle of the instruction we want the exception handlers for
062: * @return the list of exception handlers, or null if there are no handlers
063: * registered for the instruction
064: */
065: public List<CodeExceptionGen> getHandlerList(
066: InstructionHandle handle) {
067: return codeToHandlerMap.get(handle);
068: }
069:
070: /**
071: * If the given instruction is the start of an exception handler,
072: * get the CodeExceptionGen object representing the handler.
073: *
074: * @param start the instruction
075: * @return the CodeExceptionGen object, or null if the instruction is not the
076: * start of an exception handler
077: */
078: public CodeExceptionGen getHandlerForStartInstruction(
079: InstructionHandle start) {
080: return startInstructionToHandlerMap.get(start);
081: }
082:
083: private void build(MethodGen methodGen) {
084: CodeExceptionGen[] handlerList = methodGen
085: .getExceptionHandlers();
086:
087: // Map handler start instructions to the actual exception handlers
088: for (CodeExceptionGen exceptionHandler : handlerList) {
089: startInstructionToHandlerMap.put(exceptionHandler
090: .getHandlerPC(), exceptionHandler);
091: }
092:
093: // For each instruction, determine which handlers it can reach
094: InstructionHandle handle = methodGen.getInstructionList()
095: .getStart();
096: while (handle != null) {
097: int offset = handle.getPosition();
098:
099: handlerLoop: for (CodeExceptionGen exceptionHandler : handlerList) {
100: int startOfRange = exceptionHandler.getStartPC()
101: .getPosition();
102: int endOfRange = exceptionHandler.getEndPC()
103: .getPosition();
104:
105: if (offset >= startOfRange && offset <= endOfRange) {
106: // This handler is reachable from the instruction
107: addHandler(handle, exceptionHandler);
108:
109: // If this handler handles all exception types
110: // i.e., an ANY handler, or catch(Throwable...),
111: // then no further (lower-priority)
112: // handlers are reachable from the instruction.
113: if (Hierarchy
114: .isUniversalExceptionHandler(exceptionHandler
115: .getCatchType()))
116: break handlerLoop;
117: }
118: }
119:
120: handle = handle.getNext();
121: }
122: }
123:
124: private void addHandler(InstructionHandle handle,
125: CodeExceptionGen exceptionHandler) {
126: List<CodeExceptionGen> handlerList = codeToHandlerMap
127: .get(handle);
128: if (handlerList == null) {
129: handlerList = new LinkedList<CodeExceptionGen>();
130: codeToHandlerMap.put(handle, handlerList);
131: }
132: handlerList.add(exceptionHandler);
133: }
134: }
135:
136: // vim:ts=4
|