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 org.apache.bcel.generic.AASTORE;
023: import org.apache.bcel.generic.ARETURN;
024: import org.apache.bcel.generic.ArrayInstruction;
025: import org.apache.bcel.generic.CHECKCAST;
026: import org.apache.bcel.generic.ConstantPoolGen;
027: import org.apache.bcel.generic.FieldInstruction;
028: import org.apache.bcel.generic.INVOKEINTERFACE;
029: import org.apache.bcel.generic.INVOKESPECIAL;
030: import org.apache.bcel.generic.INVOKESTATIC;
031: import org.apache.bcel.generic.INVOKEVIRTUAL;
032: import org.apache.bcel.generic.InstructionHandle;
033: import org.apache.bcel.generic.InvokeInstruction;
034: import org.apache.bcel.generic.PUTFIELD;
035: import org.apache.bcel.generic.PUTSTATIC;
036:
037: public abstract class ResourceValueFrameModelingVisitor extends
038: AbstractFrameModelingVisitor<ResourceValue, ResourceValueFrame> {
039: public ResourceValueFrameModelingVisitor(ConstantPoolGen cpg) {
040: super (cpg);
041: }
042:
043: @Override
044: public ResourceValue getDefaultValue() {
045: return ResourceValue.notInstance();
046: }
047:
048: /**
049: * Subclasses must override this to model the effect of the
050: * given instruction on the current frame.
051: */
052: public abstract void transferInstruction(InstructionHandle handle,
053: BasicBlock basicBlock) throws DataflowAnalysisException;
054:
055: // Things to do:
056: // Automatically detect when resource instances escape:
057: // - putfield, putstatic
058: // - parameters to invoke, but subclasses may override
059: // - aastore; (conservative, since the dest array may not itself escape)
060: // - return (areturn)
061:
062: private void handleFieldStore(FieldInstruction ins) {
063: try {
064: // If the resource instance is stored in a field, then it escapes
065: ResourceValueFrame frame = getFrame();
066: ResourceValue topValue = frame.getTopValue();
067: if (topValue.equals(ResourceValue.instance()))
068: frame.setStatus(ResourceValueFrame.ESCAPED);
069: } catch (DataflowAnalysisException e) {
070: throw new InvalidBytecodeException("Stack underflow", e);
071: }
072:
073: handleNormalInstruction(ins);
074: }
075:
076: @Override
077: public void visitPUTFIELD(PUTFIELD putfield) {
078: handleFieldStore(putfield);
079: }
080:
081: private void handleArrayStore(ArrayInstruction ins) {
082: try {
083: // If the resource instance is stored in an array, then we consider
084: // it as having escaped. This is conservative; ideally we would
085: // check whether this array is a field or gets passed out of the
086: // method.
087: ResourceValueFrame frame = getFrame();
088: ResourceValue topValue = frame.getTopValue();
089: if (topValue.equals(ResourceValue.instance())) {
090: frame.setStatus(ResourceValueFrame.ESCAPED);
091: }
092: } catch (DataflowAnalysisException e) {
093: throw new InvalidBytecodeException("Stack underflow", e);
094: }
095: handleNormalInstruction(ins);
096: }
097:
098: @Override
099: public void visitAASTORE(AASTORE arr) {
100: handleArrayStore(arr);
101: }
102:
103: @Override
104: public void visitPUTSTATIC(PUTSTATIC putstatic) {
105: handleFieldStore(putstatic);
106: }
107:
108: /**
109: * Override this to check for methods that it is legal to
110: * pass the instance to without the instance escaping.
111: * By default, we consider all methods to be possible escape routes.
112: *
113: * @param inv the InvokeInstruction to which the resource instance
114: * is passed as an argument
115: * @param instanceArgNum the first argument the instance is passed in
116: */
117: protected boolean instanceEscapes(InvokeInstruction inv,
118: int instanceArgNum) {
119: return true;
120: }
121:
122: private void handleInvoke(InvokeInstruction inv) {
123: ResourceValueFrame frame = getFrame();
124: int numSlots = frame.getNumSlots();
125: int numConsumed = getNumWordsConsumed(inv);
126:
127: // See if the resource instance is passed as an argument
128: int instanceArgNum = -1;
129: for (int i = numSlots - numConsumed, argCount = 0; i < numSlots; ++i, ++argCount) {
130: ResourceValue value = frame.getValue(i);
131: if (value.equals(ResourceValue.instance())) {
132: instanceArgNum = argCount;
133: break;
134: }
135: }
136:
137: if (instanceArgNum >= 0 && instanceEscapes(inv, instanceArgNum))
138: frame.setStatus(ResourceValueFrame.ESCAPED);
139:
140: handleNormalInstruction(inv);
141: }
142:
143: @Override
144: public void visitCHECKCAST(CHECKCAST obj) {
145: try {
146: ResourceValueFrame frame = getFrame();
147: ResourceValue topValue;
148:
149: topValue = frame.getTopValue();
150:
151: if (topValue.equals(ResourceValue.instance()))
152: frame.setStatus(ResourceValueFrame.ESCAPED);
153: } catch (DataflowAnalysisException e) {
154: AnalysisContext.logError("Analysis error", e);
155: }
156: }
157:
158: @Override
159: public void visitINVOKEVIRTUAL(INVOKEVIRTUAL inv) {
160: handleInvoke(inv);
161: }
162:
163: @Override
164: public void visitINVOKEINTERFACE(INVOKEINTERFACE inv) {
165: handleInvoke(inv);
166: }
167:
168: @Override
169: public void visitINVOKESPECIAL(INVOKESPECIAL inv) {
170: handleInvoke(inv);
171: }
172:
173: @Override
174: public void visitINVOKESTATIC(INVOKESTATIC inv) {
175: handleInvoke(inv);
176: }
177:
178: @Override
179: public void visitARETURN(ARETURN ins) {
180: try {
181: ResourceValueFrame frame = getFrame();
182: ResourceValue topValue = frame.getTopValue();
183: if (topValue.equals(ResourceValue.instance()))
184: frame.setStatus(ResourceValueFrame.ESCAPED);
185: } catch (DataflowAnalysisException e) {
186: throw new InvalidBytecodeException("Stack underflow", e);
187: }
188:
189: handleNormalInstruction(ins);
190: }
191:
192: }
193:
194: // vim:ts=4
|