KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > vna > ValueNumberAnalysis


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba.vna;
21
22 import java.util.BitSet JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.IdentityHashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26
27 import org.apache.bcel.classfile.Method;
28 import org.apache.bcel.generic.InstructionHandle;
29 import org.apache.bcel.generic.MethodGen;
30
31 import edu.umd.cs.findbugs.SystemProperties;
32 import edu.umd.cs.findbugs.ba.BasicBlock;
33 import edu.umd.cs.findbugs.ba.CFGBuilderException;
34 import edu.umd.cs.findbugs.ba.ClassContext;
35 import edu.umd.cs.findbugs.ba.Dataflow;
36 import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
37 import edu.umd.cs.findbugs.ba.DataflowTestDriver;
38 import edu.umd.cs.findbugs.ba.DepthFirstSearch;
39 import edu.umd.cs.findbugs.ba.Edge;
40 import edu.umd.cs.findbugs.ba.Frame;
41 import edu.umd.cs.findbugs.ba.FrameDataflowAnalysis;
42 import edu.umd.cs.findbugs.ba.Location;
43 import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback;
44
45 /**
46  * A dataflow analysis to track the production and flow of values in the Java
47  * stack frame. See the {@link ValueNumber ValueNumber} class for an explanation
48  * of what the value numbers mean, and when they can be compared.
49  *
50  * <p>This class is still experimental.
51  *
52  * @author David Hovemeyer
53  * @see ValueNumber
54  * @see edu.umd.cs.findbugs.ba.DominatorsAnalysis
55  */

56 public class ValueNumberAnalysis extends FrameDataflowAnalysis<ValueNumber, ValueNumberFrame> {
57
58     public static final boolean DEBUG = SystemProperties.getBoolean("vna.debug");
59
60     private MethodGen methodGen;
61     private ValueNumberFactory factory;
62     private ValueNumberFrameModelingVisitor visitor;
63     private ValueNumber[] entryLocalValueList;
64     private IdentityHashMap JavaDoc<BasicBlock, ValueNumber> exceptionHandlerValueNumberMap;
65     private ValueNumber thisValue;
66     private HashMap JavaDoc<Location, ValueNumberFrame> factAtLocationMap;
67     private HashMap JavaDoc<Location, ValueNumberFrame> factAfterLocationMap;
68     private MergeTree mergeTree;
69
70     public ValueNumberAnalysis(MethodGen methodGen, DepthFirstSearch dfs,
71                                LoadedFieldSet loadedFieldSet,
72                                RepositoryLookupFailureCallback lookupFailureCallback) {
73
74         super(dfs);
75         this.methodGen = methodGen;
76         this.factory = new ValueNumberFactory();
77         ValueNumberCache cache = new ValueNumberCache();
78         this.visitor = new ValueNumberFrameModelingVisitor(methodGen, factory, cache,
79                 loadedFieldSet,
80                 lookupFailureCallback);
81
82         int numLocals = methodGen.getMaxLocals();
83         this.entryLocalValueList = new ValueNumber[numLocals];
84         for (int i = 0; i < numLocals; ++i)
85             this.entryLocalValueList[i] = factory.createFreshValue();
86
87         this.exceptionHandlerValueNumberMap = new IdentityHashMap JavaDoc<BasicBlock, ValueNumber>();
88
89         // For non-static methods, keep track of which value represents the
90
// "this" reference
91
if (!methodGen.isStatic())
92             this.thisValue = entryLocalValueList[0];
93
94         this.factAtLocationMap = new HashMap JavaDoc<Location, ValueNumberFrame>();
95         this.factAfterLocationMap = new HashMap JavaDoc<Location, ValueNumberFrame>();
96         if (DEBUG) System.out.println("VNA Analysis " + methodGen.getClassName() + "." + methodGen.getName() + " : " + methodGen.getSignature());
97         
98     }
99     public ValueNumber getClassObjectValue(String JavaDoc className) {
100         return visitor.getClassObjectValue(className);
101     }
102     public void setMergeTree(MergeTree mergeTree) {
103         this.mergeTree = mergeTree;
104     }
105     
106     public MergeTree getMergeTree() {
107         return mergeTree;
108     }
109
110     public ValueNumberFactory getFactory() {
111         return factory;
112     }
113
114     public int getNumValuesAllocated() {
115         return factory.getNumValuesAllocated();
116     }
117
118     public boolean isThisValue(ValueNumber value) {
119         return thisValue != null && thisValue.getNumber() == value.getNumber();
120     }
121
122     public ValueNumber getThisValue() {
123         return thisValue;
124     }
125
126     public ValueNumber getEntryValue(int local) {
127         return entryLocalValueList[local];
128     }
129
130     public ValueNumberFrame createFact() {
131         return new ValueNumberFrame(methodGen.getMaxLocals());
132     }
133
134     public void initEntryFact(ValueNumberFrame result) {
135         // Change the frame from TOP to something valid.
136
result.setValid();
137
138         // At entry to the method, each local has (as far as we know) a unique value.
139
int numSlots = result.getNumSlots();
140         for (int i = 0; i < numSlots; ++i)
141             result.setValue(i, entryLocalValueList[i]);
142     }
143
144     @Override JavaDoc
145     public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, ValueNumberFrame fact)
146             throws DataflowAnalysisException {
147
148         Location location = new Location(handle, basicBlock);
149
150         ValueNumberFrame atLocation = getFactAtLocation(location);
151         copy(fact, atLocation);
152
153         visitor.setFrameAndLocation(fact, new Location(handle, basicBlock));
154         visitor.setHandle(handle);
155         visitor.analyzeInstruction(handle.getInstruction());
156
157         ValueNumberFrame afterLocation = getFactAfterLocation(location);
158         copy(fact, afterLocation);
159     }
160
161     public void meetInto(ValueNumberFrame fact, Edge edge, ValueNumberFrame result) throws DataflowAnalysisException {
162         if (edge.getTarget().isExceptionHandler() && fact.isValid()) {
163             // Special case: when merging predecessor facts for entry to
164
// an exception handler, we clear the stack and push a
165
// single entry for the exception object. That way, the locals
166
// can still be merged.
167

168             // Get the value number for the exception
169
BasicBlock handlerBlock = edge.getTarget();
170             ValueNumber exceptionValueNumber = getExceptionValueNumber(handlerBlock);
171
172             // Set up the stack frame
173
ValueNumberFrame tmpFact = createFact();
174             tmpFact.copyFrom(fact);
175             tmpFact.clearStack();
176             tmpFact.pushValue(exceptionValueNumber);
177             fact = tmpFact;
178         }
179
180         mergeInto(fact, result);
181     }
182
183     @Override JavaDoc
184     protected void mergeInto(ValueNumberFrame frame, ValueNumberFrame result) throws DataflowAnalysisException {
185         result.mergeAvailableLoadSets(frame, factory, mergeTree);
186         super.mergeInto(frame, result);
187     }
188     
189     @Override JavaDoc
190     protected void mergeValues(ValueNumberFrame otherFrame, ValueNumberFrame resultFrame, int slot) throws DataflowAnalysisException {
191         ValueNumber value =
192             mergeValues(resultFrame, slot, resultFrame.getValue(slot), otherFrame.getValue(slot));
193         resultFrame.setValue(slot, value);
194     }
195
196     private ValueNumber mergeValues(ValueNumberFrame frame, int slot, ValueNumber mine, ValueNumber other)
197             throws DataflowAnalysisException {
198
199         // Merging slot values:
200
// - Merging identical values results in no change
201
// - If the values are different, and the value in the result
202
// frame is not the result of a previous result, a fresh value
203
// is allocated.
204
// - If the value in the result frame is the result of a
205
// previous merge, IT STAYS THE SAME.
206
//
207
// The "one merge" rule means that merged values are essentially like
208
// phi nodes. They combine some number of other values.
209

210         // I believe (but haven't proved) that this technique is a dumb way
211
// of computing SSA.
212

213         if (mine != frame.getValue(slot)) throw new IllegalStateException JavaDoc();
214
215         if (mine.equals(other))
216             return mine;
217
218         ValueNumber mergedValue = frame.getMergedValue(slot);
219         if (mergedValue == null) {
220             mergedValue = factory.createFreshValue();
221             mergedValue.setFlags(mine.getFlags() | other.getFlags() | ValueNumber.PHI_NODE);
222             frame.setMergedValue(slot, mergedValue);
223             
224         }
225
226         if (mergeTree != null) {
227             mergeTree.mapInputToOutput(mine, mergedValue);
228             mergeTree.mapInputToOutput(other, mergedValue);
229         }
230
231         return mergedValue;
232     }
233
234     @Override JavaDoc
235     public ValueNumberFrame getFactAtLocation(Location location) {
236         ValueNumberFrame fact = factAtLocationMap.get(location);
237         if (fact == null) {
238             fact = createFact();
239             makeFactTop(fact);
240             factAtLocationMap.put(location, fact);
241         }
242         return fact;
243     }
244
245     @Override JavaDoc
246     public ValueNumberFrame getFactAfterLocation(Location location) {
247         ValueNumberFrame fact = factAfterLocationMap.get(location);
248         if (fact == null) {
249             fact = createFact();
250             makeFactTop(fact);
251             factAfterLocationMap.put(location, fact);
252         }
253         return fact;
254     }
255
256     /**
257      * Get an Iterator over all dataflow facts that we've recorded for
258      * the Locations in the CFG. Note that this does not include
259      * result facts (since there are no Locations corresponding to
260      * the end of basic blocks).
261      */

262     public Iterator JavaDoc<ValueNumberFrame> factIterator() {
263         return factAtLocationMap.values().iterator();
264     }
265
266     // These fields are used by the compactValueNumbers() method.
267
private static class ValueCompacter {
268         public final BitSet JavaDoc valuesUsed;
269         public int numValuesUsed;
270         public final int[] discovered;
271
272         public ValueCompacter(int origNumValuesAllocated) {
273             valuesUsed = new BitSet JavaDoc();
274             numValuesUsed = 0;
275
276             // The "discovered" array tells us the mapping of old value numbers
277
// to new (which are based on order of discovery). Negative values
278
// specify value numbers which are not actually used (and thus can
279
// be purged.)
280
discovered = new int[origNumValuesAllocated];
281             for (int i = 0; i < discovered.length; ++i)
282                 discovered[i] = -1;
283         }
284
285         public boolean isUsed(int number) {
286             return valuesUsed.get(number);
287         }
288
289         public void setUsed(int number) {
290             valuesUsed.set(number, true);
291         }
292
293         public int allocateValue() {
294             return numValuesUsed++;
295         }
296     }
297
298     /**
299      * Compact the value numbers assigned.
300      * This should be done only after the dataflow algorithm has executed.
301      * This works by modifying the actual ValueNumber objects assigned.
302      * After this method is called, the getNumValuesAllocated() method
303      * of this object will return a value less than or equal to the value
304      * it would have returned before the call to this method.
305      * <p/>
306      * <p> <em>This method should be called at most once</em>.
307      *
308      * @param dataflow the Dataflow object which executed this analysis
309      * (and has all of the block result values)
310      */

311     public void compactValueNumbers(Dataflow<ValueNumberFrame, ValueNumberAnalysis> dataflow) {
312         ValueCompacter compacter = new ValueCompacter(factory.getNumValuesAllocated());
313
314         // We can get all extant Frames by looking at the values in
315
// the location to value map, and also the block result values.
316
for (Iterator JavaDoc<ValueNumberFrame> i = factIterator(); i.hasNext();) {
317             ValueNumberFrame frame = i.next();
318             markFrameValues(frame, compacter);
319         }
320         for (Iterator JavaDoc<ValueNumberFrame> i = resultFactIterator(); i.hasNext();) {
321             ValueNumberFrame frame = i.next();
322             markFrameValues(frame, compacter);
323         }
324
325         int before = factory.getNumValuesAllocated();
326
327         // Now the factory can modify the ValueNumbers.
328
factory.compact(compacter.discovered, compacter.numValuesUsed);
329
330         int after = factory.getNumValuesAllocated();
331
332         if (DEBUG && after < before && before > 0)
333             System.out.println("Value compaction: " + after + "/" + before + " (" +
334                     ((after * 100) / before) + "%)");
335
336     }
337
338     /**
339      * Mark value numbers in a value number frame for compaction.
340      */

341     private static void markFrameValues(ValueNumberFrame frame, ValueCompacter compacter) {
342         // We don't need to do anything for top and bottom frames.
343
if (!frame.isValid())
344             return;
345
346         for (int j = 0; j < frame.getNumSlots(); ++j) {
347             ValueNumber value = frame.getValue(j);
348             int number = value.getNumber();
349
350             if (!compacter.isUsed(number)) {
351                 compacter.discovered[number] = compacter.allocateValue();
352                 compacter.setUsed(number);
353             }
354         }
355     }
356
357     /**
358      * Test driver.
359      */

360     public static void main(String JavaDoc[] argv) {
361         try {
362             if (argv.length != 1) {
363                 System.out.println("Usage: edu.umd.cs.findbugs.ba.ValueNumberAnalysis <filename>");
364                 System.exit(1);
365             }
366
367             DataflowTestDriver<ValueNumberFrame, ValueNumberAnalysis> driver =
368                     new DataflowTestDriver<ValueNumberFrame, ValueNumberAnalysis>() {
369                         @Override JavaDoc
370                                          public Dataflow<ValueNumberFrame, ValueNumberAnalysis> createDataflow(ClassContext classContext, Method method)
371                                 throws CFGBuilderException, DataflowAnalysisException {
372                             return classContext.getValueNumberDataflow(method);
373                         }
374                     };
375
376             driver.execute(argv[0]);
377
378         } catch (Exception JavaDoc e) {
379             e.printStackTrace();
380         }
381     }
382
383     private ValueNumber getExceptionValueNumber(BasicBlock handlerBlock) {
384         ValueNumber valueNumber = exceptionHandlerValueNumberMap.get(handlerBlock);
385         if (valueNumber == null) {
386             valueNumber = factory.createFreshValue();
387             exceptionHandlerValueNumberMap.put(handlerBlock, valueNumber);
388         }
389         return valueNumber;
390     }
391 }
392
393 // vim:ts=4
394
Popular Tags