KickJava   Java API By Example, From Geeks To Geeks.

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


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.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.Map JavaDoc;
30
31 import edu.umd.cs.findbugs.annotations.CheckForNull;
32 import edu.umd.cs.findbugs.annotations.NonNull;
33 import edu.umd.cs.findbugs.ba.Frame;
34 import edu.umd.cs.findbugs.ba.XField;
35 import edu.umd.cs.findbugs.util.Strings;
36
37 /**
38  * A dataflow value representing a Java stack frame with value number
39  * information.
40  *
41  * @author David Hovemeyer
42  * @see ValueNumber
43  * @see ValueNumberAnalysis
44  */

45 public class ValueNumberFrame extends Frame<ValueNumber> implements ValueNumberAnalysisFeatures {
46
47     private ArrayList JavaDoc<ValueNumber> mergedValueList;
48     private Map JavaDoc<AvailableLoad, ValueNumber[]> availableLoadMap;
49     private Map JavaDoc<AvailableLoad,ValueNumber> mergedLoads ;
50     private Map JavaDoc<ValueNumber, AvailableLoad> previouslyKnownAs;
51     public boolean phiNodeForLoads;
52
53     public ValueNumberFrame(int numLocals) {
54         super(numLocals);
55         if (REDUNDANT_LOAD_ELIMINATION) {
56             setAvailableLoadMap(Collections.EMPTY_MAP);
57             setMergedLoads(Collections.EMPTY_MAP);
58             setPreviouslyKnownAs(Collections.EMPTY_MAP);
59         }
60     }
61
62     public String JavaDoc availableLoadMapAsString() {
63         StringBuffer JavaDoc buf = new StringBuffer JavaDoc("{ ");
64         for(Map.Entry JavaDoc<AvailableLoad, ValueNumber[]> e : getAvailableLoadMap().entrySet()) {
65             buf.append(e.getKey());
66             buf.append("=");
67             for(ValueNumber v : e.getValue())
68                 buf.append(v).append(",");
69             buf.append("; ");
70         }
71         
72         buf.append(" }");
73         return buf.toString();
74     }
75     public @CheckForNull AvailableLoad getLoad(ValueNumber v) {
76         for(Map.Entry JavaDoc<AvailableLoad, ValueNumber[]> e : getAvailableLoadMap().entrySet()) {
77             if (e.getValue() != null)
78                 for(ValueNumber v2 : e.getValue())
79                     if (v.equals(v2)) return e.getKey();
80         }
81         return null;
82     }
83     /**
84      * Look for an available load.
85      *
86      * @param availableLoad the AvailableLoad (reference and field)
87      * @return the value(s) available, or null if no matching entry is found
88      */

89     public ValueNumber[] getAvailableLoad(AvailableLoad availableLoad) {
90         return getAvailableLoadMap().get(availableLoad);
91     }
92
93     /**
94      * Add an available load.
95      *
96      * @param availableLoad the AvailableLoad (reference and field)
97      * @param value the value(s) loaded
98      */

99     public void addAvailableLoad(AvailableLoad availableLoad, @NonNull ValueNumber[] value) {
100         if (value == null) throw new IllegalStateException JavaDoc();
101         getUpdateableAvailableLoadMap().put(availableLoad, value);
102
103         for(ValueNumber v : value) {
104             getUpdateablePreviouslyKnownAs().put(v, availableLoad);
105             if (RLE_DEBUG) {
106                 System.out.println("Adding available load of " + availableLoad + " for " + v + " to " + System.identityHashCode(this));
107             }
108         }
109     }
110
111     /**
112      * Kill all loads of given field.
113      *
114      * @param field the field
115      */

116     public void killLoadsOfField(XField field) {
117         Iterator JavaDoc<AvailableLoad> i = getAvailableLoadMap().keySet().iterator();
118         while (i.hasNext()) {
119             AvailableLoad availableLoad = i.next();
120             if (availableLoad.getField().equals(field)) {
121                 if (RLE_DEBUG)
122                     System.out.println("KILLING Load of " + availableLoad + " in " + this);
123                 i.remove();
124             }
125         }
126     }
127
128     /**
129      * Kill all loads.
130      * This conservatively handles method calls where we
131      * don't really know what fields might be assigned.
132      */

133     public void killAllLoads() {
134         if (REDUNDANT_LOAD_ELIMINATION) {
135             for(Iterator JavaDoc<AvailableLoad> i = getAvailableLoadMap().keySet().iterator(); i.hasNext(); ) {
136                 AvailableLoad availableLoad = i.next();
137                 if (!availableLoad.getField().isFinal()) {
138                     if (RLE_DEBUG)
139                         System.out.println("KILLING load of " + availableLoad + " in " + this);
140                     i.remove();
141                 }
142             }
143         }
144     }
145     /**
146      * Kill all loads.
147      * This conservatively handles method calls where we
148      * don't really know what fields might be assigned.
149      */

150     public void killAllLoadsOf(@CheckForNull ValueNumber v) {
151         if (REDUNDANT_LOAD_ELIMINATION) {
152             for(Iterator JavaDoc<AvailableLoad> i = getAvailableLoadMap().keySet().iterator(); i.hasNext(); ) {
153                 AvailableLoad availableLoad = i.next();
154                 if (!availableLoad.getField().isFinal() && availableLoad.getReference() == v) {
155                     if (RLE_DEBUG) System.out.println("Killing load of " + availableLoad + " in " + this);
156                     i.remove();
157                 }
158             }
159         }
160     }
161
162     void mergeAvailableLoadSets(ValueNumberFrame other, ValueNumberFactory factory, MergeTree mergeTree) {
163         if (REDUNDANT_LOAD_ELIMINATION) {
164             // Merge available load sets.
165
// Only loads that are available in both frames
166
// remain available. All others are discarded.
167
String JavaDoc s = "";
168             if (RLE_DEBUG) {
169                 s = "Merging " + this.availableLoadMapAsString() + " and " + other.availableLoadMapAsString();
170             }
171             boolean changed = false;
172             if (other.isBottom()) {
173                 changed = !this.getAvailableLoadMap().isEmpty();
174                 setAvailableLoadMap(Collections.EMPTY_MAP);
175             }
176             else if (!other.isTop()) {
177                 for(Map.Entry JavaDoc<AvailableLoad,ValueNumber[]> e : getAvailableLoadMap().entrySet()) {
178                     AvailableLoad load = e.getKey();
179                     ValueNumber[] myVN = e.getValue();
180                     ValueNumber[] otherVN = other.getAvailableLoadMap().get(load);
181                     if (false && this.phiNodeForLoads && myVN != null && myVN.length == 1 && myVN[0].hasFlag(ValueNumber.PHI_NODE))
182                         continue;
183                     if (!Arrays.equals(myVN, otherVN)) {
184                         
185                         ValueNumber phi = getMergedLoads().get(load);
186                         if (phi == null) {
187                             phi = factory.createFreshValue();
188                             int flags = ValueNumber.PHI_NODE;
189                             
190                             getUpdateableMergedLoads().put(load, phi);
191                             for(ValueNumber vn : myVN) {
192                                 mergeTree.mapInputToOutput(vn, phi);
193                                 flags |= vn.getFlags();
194                             }
195                             if (otherVN != null) for(ValueNumber vn : otherVN) {
196                                 mergeTree.mapInputToOutput(vn, phi);
197                                 flags |= vn.getFlags();
198                             }
199                             phi.setFlag(flags);
200                             if (RLE_DEBUG)
201                                 System.out.println("Creating phi node " + phi + " for " + load + " from " + Strings.toString(myVN) + " x " + Strings.toString(otherVN) + " in " + System.identityHashCode(this));
202                             changed = true;
203                             e.setValue(new ValueNumber[] { phi });
204                         } else {
205                             if (RLE_DEBUG)
206                                     System.out.println("Reusing phi node : " + phi + " for " + load + " from "+ Strings.toString(myVN) + " x " + Strings.toString(otherVN)+ " in " + System.identityHashCode(this));
207                             if (myVN.length != 0 || !myVN[0].equals(phi))
208                                 e.setValue(new ValueNumber[] { phi });
209                         }
210
211                     }
212                     
213                 }
214             }
215             Map JavaDoc<ValueNumber, AvailableLoad> previouslyKnownAsOther = other.getPreviouslyKnownAs();
216             if (previouslyKnownAsOther.size() != 0)
217                 getUpdateablePreviouslyKnownAs().putAll(previouslyKnownAsOther);
218             if (changed)
219                 this.phiNodeForLoads = true;
220             if (changed && RLE_DEBUG) {
221                 System.out.println(s);
222                 System.out.println(" Result is " + this.availableLoadMapAsString());
223                 System.out.println(" Set phi for " + System.identityHashCode(this));
224             }
225         }
226     }
227
228
229     ValueNumber getMergedValue(int slot) {
230         return mergedValueList.get(slot);
231     }
232
233     void setMergedValue(int slot, ValueNumber value) {
234         mergedValueList.set(slot, value);
235     }
236
237     @Override JavaDoc
238     public void copyFrom(Frame<ValueNumber> other) {
239         // If merged value list hasn't been created yet, create it.
240
if (mergedValueList == null && other.isValid()) {
241             // This is where this frame gets its size.
242
// It will have the same size as long as it remains valid.
243
mergedValueList = new ArrayList JavaDoc<ValueNumber>();
244             int numSlots = other.getNumSlots();
245             for (int i = 0; i < numSlots; ++i)
246                 mergedValueList.add(null);
247         }
248
249         if (REDUNDANT_LOAD_ELIMINATION) {
250             // Copy available load set.
251
Map JavaDoc<AvailableLoad, ValueNumber[]> availableLoadMapOther = ((ValueNumberFrame) other).getAvailableLoadMap();
252             if (availableLoadMapOther.size() == 0)
253                 setAvailableLoadMap(Collections.EMPTY_MAP);
254             else {
255                 getUpdateableAvailableLoadMap().clear();
256                 getUpdateableAvailableLoadMap().putAll(availableLoadMapOther);
257             }
258             Map JavaDoc<ValueNumber, AvailableLoad> previouslyKnownAsOther = ((ValueNumberFrame) other).getPreviouslyKnownAs();
259             if (previouslyKnownAsOther.size() == 0)
260                 setPreviouslyKnownAs(Collections.EMPTY_MAP);
261             else {
262                 getUpdateablePreviouslyKnownAs().clear();
263                 getUpdateablePreviouslyKnownAs().putAll(previouslyKnownAsOther);
264             }
265         
266         }
267
268         super.copyFrom(other);
269     }
270
271     @Override JavaDoc
272     public String JavaDoc toString() {
273         String JavaDoc frameValues = super.toString();
274         if (RLE_DEBUG) {
275             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
276             buf.append(frameValues);
277
278             Iterator JavaDoc<AvailableLoad> i = getAvailableLoadMap().keySet().iterator();
279             boolean first = true;
280             while (i.hasNext()) {
281                 AvailableLoad key = i.next();
282                 ValueNumber[] value = getAvailableLoadMap().get(key);
283                 if (first)
284                     first = false;
285                 else
286                     buf.append(',');
287                 buf.append(key + "=" + valueToString(value));
288             }
289             
290             buf.append(" #");
291             buf.append(System.identityHashCode(this));
292             if (phiNodeForLoads) buf.append(" phi");
293             return buf.toString();
294         } else {
295             return frameValues;
296         }
297     }
298
299     private static String JavaDoc valueToString(ValueNumber[] valueNumberList) {
300         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
301         buf.append('[');
302         boolean first = true;
303         for (ValueNumber aValueNumberList : valueNumberList) {
304             if (first)
305                 first = false;
306             else
307                 buf.append(',');
308             buf.append(aValueNumberList.getNumber());
309         }
310         buf.append(']');
311         return buf.toString();
312     }
313
314     public boolean fuzzyMatch(ValueNumber v1, ValueNumber v2) {
315         return v1.equals(v2) || fromMatchingLoads(v1, v2) || haveMatchingFlags(v1, v2);
316     }
317         
318     public boolean fromMatchingLoads(ValueNumber v1, ValueNumber v2) {
319         AvailableLoad load1 = getLoad(v1);
320         if (load1 == null) load1 = getPreviouslyKnownAs().get(v1);
321         if (load1 == null) return false;
322         AvailableLoad load2 = getLoad(v2);
323         if (load2 == null) load2 = getPreviouslyKnownAs().get(v2);
324         if (load2 == null) return false;
325         return load1.equals(load2);
326     }
327
328     /**
329      * @param v1
330      * @param v2
331      * @return true if v1 and v2 have a flag in common
332      */

333     public boolean haveMatchingFlags(ValueNumber v1, ValueNumber v2) {
334         int flag1 = v1.getFlags();
335         int flag2 = v2.getFlags();
336         return (flag1 & flag2) != 0;
337     }
338     
339     public Collection JavaDoc<ValueNumber> valueNumbersForLoads() {
340         HashSet JavaDoc<ValueNumber> result = new HashSet JavaDoc<ValueNumber>();
341         if (REDUNDANT_LOAD_ELIMINATION)
342         for(Map.Entry JavaDoc<AvailableLoad, ValueNumber[]> e : getAvailableLoadMap().entrySet()) {
343             if (e.getValue() != null)
344                 for(ValueNumber v2 : e.getValue())
345                     result.add(v2);
346         }
347
348         return result;
349     }
350
351     /**
352      * @param availableLoadMap The availableLoadMap to set.
353      */

354     private void setAvailableLoadMap(Map JavaDoc<AvailableLoad, ValueNumber[]> availableLoadMap) {
355         this.availableLoadMap = availableLoadMap;
356     }
357
358     /**
359      * @return Returns the availableLoadMap.
360      */

361     private Map JavaDoc<AvailableLoad, ValueNumber[]> getAvailableLoadMap() {
362         return availableLoadMap;
363     }
364     private Map JavaDoc<AvailableLoad, ValueNumber[]> getUpdateableAvailableLoadMap() {
365         if (!(availableLoadMap instanceof HashMap JavaDoc))
366             availableLoadMap = new HashMap JavaDoc<AvailableLoad, ValueNumber[]>();
367         return availableLoadMap;
368     }
369     /**
370      * @param mergedLoads The mergedLoads to set.
371      */

372     private void setMergedLoads(Map JavaDoc<AvailableLoad,ValueNumber> mergedLoads) {
373         this.mergedLoads = mergedLoads;
374     }
375
376     /**
377      * @return Returns the mergedLoads.
378      */

379     private Map JavaDoc<AvailableLoad,ValueNumber> getMergedLoads() {
380         return mergedLoads;
381     }
382     private Map JavaDoc<AvailableLoad,ValueNumber> getUpdateableMergedLoads() {
383         if (!(mergedLoads instanceof HashMap JavaDoc))
384             mergedLoads = new HashMap JavaDoc<AvailableLoad, ValueNumber>();
385         
386         return mergedLoads;
387     }
388
389     /**
390      * @param previouslyKnownAs The previouslyKnownAs to set.
391      */

392     private void setPreviouslyKnownAs(Map JavaDoc<ValueNumber, AvailableLoad> previouslyKnownAs) {
393         this.previouslyKnownAs = previouslyKnownAs;
394     }
395
396     /**
397      * @return Returns the previouslyKnownAs.
398      */

399     private Map JavaDoc<ValueNumber, AvailableLoad> getPreviouslyKnownAs() {
400         return previouslyKnownAs;
401     }
402     private Map JavaDoc<ValueNumber, AvailableLoad> getUpdateablePreviouslyKnownAs() {
403         if (!(previouslyKnownAs instanceof HashMap JavaDoc))
404             previouslyKnownAs = new HashMap JavaDoc<ValueNumber, AvailableLoad>();
405         
406         
407         return previouslyKnownAs;
408     }
409     
410     
411 }
412
413 // vim:ts=4
414
Popular Tags