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 edu.umd.cs.findbugs.annotations.Nullable;
023:
024: /**
025: * A convenient base class for dataflow analysis classes which
026: * use Frames as values.
027: *
028: * @author David Hovemeyer
029: * @see Frame
030: * @see DataflowAnalysis
031: */
032: public abstract class FrameDataflowAnalysis<ValueType, FrameType extends Frame<ValueType>>
033: extends ForwardDataflowAnalysis<FrameType> {
034: public FrameDataflowAnalysis(DepthFirstSearch dfs) {
035: super (dfs);
036: }
037:
038: public void copy(FrameType source, FrameType dest) {
039: dest.copyFrom(source);
040: }
041:
042: public void makeFactTop(FrameType fact) {
043: fact.setTop();
044: }
045:
046: public boolean isTop(FrameType fact) {
047: return fact.isTop();
048: }
049:
050: public boolean same(FrameType fact1, FrameType fact2) {
051: return fact1.sameAs(fact2);
052: }
053:
054: @Override
055: public boolean isFactValid(FrameType fact) {
056: return fact.isValid();
057: }
058:
059: @Override
060: public int getLastUpdateTimestamp(FrameType fact) {
061: return fact.getLastUpdateTimestamp();
062: }
063:
064: @Override
065: public void setLastUpdateTimestamp(FrameType fact, int lastTimestamp) {
066: fact.setLastUpdateTimestamp(lastTimestamp);
067: }
068:
069: /**
070: * Create a modifiable copy of a frame.
071: * This is useful for meetInto(), if the frame needs to be
072: * modified in a path-sensitive fashion.
073: * A typical usage pattern is:
074: * <p/>
075: * <pre>
076: * FrameType copy = null;
077: * if (someCondition()) {
078: * copy = modifyFrame(fact, copy);
079: * // modify copy
080: * }
081: * if (someOtherCondition()) {
082: * copy = modifyFrame(fact, copy);
083: * // modify copy
084: * }
085: * if (copy != null)
086: * fact = copy;
087: * <p/>
088: * mergeInto(fact, result);
089: * </pre>
090: * <p/>
091: * The advantage of using modifyFrame() is that new code can be added
092: * before or after other places where the frame is modified, and the
093: * code will remain correct.
094: *
095: * @param orig the original frame
096: * @param copy the modifiable copy (returned by a previous call to modifyFrame()),
097: * or null if this is the first time modifyFrame() is being called
098: * @return a modifiable copy of fact
099: */
100: final protected FrameType modifyFrame(FrameType orig, @Nullable
101: FrameType copy) {
102: if (copy == null) {
103: copy = createFact();
104: copy.copyFrom(orig);
105: }
106: return copy;
107: }
108:
109: /**
110: * Merge one frame into another.
111: *
112: * @param other the frame to merge with the result
113: * @param result the result frame, which is modified to be the
114: * merge of the two frames
115: */
116: protected void mergeInto(FrameType other, FrameType result)
117: throws DataflowAnalysisException {
118: // Handle if result Frame or the other Frame is the special "TOP" value.
119: if (result.isTop()) {
120: // Result is the identity element, so copy the other Frame
121: result.copyFrom(other);
122: return;
123: } else if (other.isTop()) {
124: // Other Frame is the identity element, so result stays the same
125: return;
126: }
127:
128: // Handle if result Frame or the other Frame is the special "BOTTOM" value.
129: if (result.isBottom()) {
130: // Result is the bottom element, so it stays that way
131: return;
132: } else if (other.isBottom()) {
133: // Other Frame is the bottom element, so result becomes the bottom element too
134: result.setBottom();
135: return;
136: }
137:
138: // If the number of slots in the Frames differs,
139: // then the result is the special "BOTTOM" value.
140: if (result.getNumSlots() != other.getNumSlots()) {
141: result.setBottom();
142: return;
143: }
144:
145: // Usual case: ordinary Frames consisting of the same number of values.
146: // Merge each value in the two slot lists element-wise.
147: for (int i = 0; i < result.getNumSlots(); ++i) {
148: mergeValues(other, result, i);
149: }
150: }
151:
152: /**
153: * Merge the values contained in a given slot of two Frames.
154: *
155: * @param otherFrame a Frame
156: * @param resultFrame a Frame which will contain the resulting merged value
157: * @param slot a slot in both frames
158: * @throws DataflowAnalysisException
159: */
160: protected abstract void mergeValues(FrameType otherFrame,
161: FrameType resultFrame, int slot)
162: throws DataflowAnalysisException;
163: }
164:
165: // vim:ts=4
|