1 cananian 1.1.2.1 // FieldSyncOracle.java, created Sun Jan 14 00:56:29 2001 by cananian
  2 cananian 1.1.2.2 // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Analysis.Quads;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.Analysis.CallGraph;
  7 cananian 1.1.2.1 import harpoon.Analysis.ClassHierarchy;
  8 cananian 1.1.2.1 import harpoon.Analysis.CallGraph;
  9 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
 10 cananian 1.1.2.1 import harpoon.ClassFile.HCode;
 11 cananian 1.1.2.1 import harpoon.ClassFile.HCodeFactory;
 12 cananian 1.1.2.1 import harpoon.ClassFile.HField;
 13 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
 14 cananian 1.1.2.1 import harpoon.IR.Quads.GET;
 15 cananian 1.1.2.1 import harpoon.IR.Quads.MONITORENTER;
 16 cananian 1.1.2.1 import harpoon.IR.Quads.MONITOREXIT;
 17 cananian 1.1.2.1 import harpoon.IR.Quads.Quad;
 18 cananian 1.1.2.1 import harpoon.IR.Quads.SET;
 19 cananian 1.3     import net.cscott.jutil.WorkSet;
 20 cananian 1.3     import net.cscott.jutil.AggregateSetFactory;
 21 cananian 1.3     import net.cscott.jutil.BitSetFactory;
 22 cananian 1.3     import net.cscott.jutil.GenericInvertibleMultiMap;
 23 cananian 1.3     import net.cscott.jutil.GenericMultiMap;
 24 cananian 1.3     import net.cscott.jutil.InvertibleMultiMap;
 25 cananian 1.3     import net.cscott.jutil.MultiMap;
 26 cananian 1.3     import net.cscott.jutil.SetFactory;
 27 cananian 1.1.2.1 
 28 cananian 1.1.2.1 import java.util.Arrays;
 29 cananian 1.1.2.1 import java.util.Collection;
 30 cananian 1.1.2.5 import java.util.Collections;
 31 cananian 1.1.2.1 import java.util.HashSet;
 32 cananian 1.1.2.1 import java.util.Iterator;
 33 cananian 1.1.2.1 import java.util.Set;
 34 cananian 1.1.2.1 /**
 35 cananian 1.1.2.1  * A <code>FieldSyncOracle</code> tells which fields a given method could
 36 cananian 1.1.2.1  * possibly access (either directly, or via a method call), and whether
 37 cananian 1.1.2.1  * the given method will ever acquire/release a lock (either directly, or
 38 cananian 1.1.2.1  * via a method call).  This analysis is useful for determining which
 39 cananian 1.1.2.4  * memory optimizations are safe across a given method call (and
 40 cananian 1.1.2.4  * other things).
 41 cananian 1.1.2.1  * 
 42 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 43 cananian 1.4      * @version $Id: FieldSyncOracle.java,v 1.4 2004/02/08 03:20:10 cananian Exp $
 44 cananian 1.1.2.1  */
 45 cananian 1.1.2.4 public class FieldSyncOracle {
 46 cananian 1.1.2.1     final MultiMap fieldsRead, fieldsWritten;
 47 cananian 1.1.2.1     final Set syncMethods = new HashSet();
 48 cananian 1.1.2.1     /** Returns <code>true</code> if <code>HMethod</code>
 49 cananian 1.1.2.1         <code>hm</code> will ever acquire/release a lock (either
 50 cananian 1.1.2.1         directly, or via a method call). */
 51 cananian 1.1.2.1     public boolean isSync(HMethod hm) {
 52 cananian 1.1.2.1         return syncMethods.contains(hm);
 53 cananian 1.1.2.1     }
 54 cananian 1.1.2.1     /** Returns <code>true</code> if <code>HMethod</code>
 55 cananian 1.1.2.1         <code>hm</code> will ever read <code>HField</code>
 56 cananian 1.1.2.1         <code>hf</code>, either directly or via a method call. */
 57 cananian 1.1.2.1     public boolean isRead(HMethod hm, HField hf) {
 58 cananian 1.1.2.1         return fieldsRead.contains(hm, hf);
 59 cananian 1.1.2.1     }
 60 cananian 1.1.2.5     /** Returns a <code>Set</code> of <code>HField</code>s read,
 61 cananian 1.1.2.5      *  either directly or indirectly, by <code>HMethod</code> hm. */
 62 cananian 1.1.2.5     public Set fieldsRead(HMethod hm) {
 63 cananian 1.1.2.5         return Collections.unmodifiableSet((Set) fieldsRead.getValues(hm));
 64 cananian 1.1.2.5     }
 65 cananian 1.1.2.1     /** Returns <code>true</code> if <code>HMethod</code>
 66 cananian 1.1.2.5         <code>hm</code> will ever write <code>HField</code>
 67 cananian 1.1.2.1         <code>hf</code>, either directly or via a method call. */
 68 cananian 1.1.2.1     public boolean isWritten(HMethod hm, HField hf) {
 69 cananian 1.1.2.1         return fieldsWritten.contains(hm, hf);
 70 cananian 1.1.2.5     }
 71 cananian 1.1.2.5     /** Returns a <code>Set</code> of <code>HField</code>s written,
 72 cananian 1.1.2.5      *  either directly or indirectly, by <code>HMethod</code> hm. */
 73 cananian 1.1.2.5     public Set fieldsWritten(HMethod hm) {
 74 cananian 1.1.2.5         return Collections.unmodifiableSet((Set) fieldsWritten.getValues(hm));
 75 cananian 1.1.2.1     }
 76 cananian 1.1.2.1     /** Creates a <code>FieldSyncOracle</code>. */
 77 cananian 1.1.2.1     public FieldSyncOracle(HCodeFactory hcf, ClassHierarchy ch, CallGraph cg) {
 78 cananian 1.1.2.1         Set s = new HashSet();
 79 cananian 1.1.2.1         /* compute field universe */
 80 cananian 1.4             for (Object hcO : ch.classes()) {
 81 cananian 1.4                 HClass hc = (HClass) hcO;
 82 cananian 1.1.2.1             s.addAll(Arrays.asList(hc.getDeclaredFields()));
 83 cananian 1.1.2.1         }
 84 cananian 1.1.2.1         /* initialize maps. */
 85 cananian 1.1.2.1         SetFactory sf =new BitSetFactory(s);
 86 cananian 1.1.2.1         this.fieldsRead = new GenericMultiMap(sf);
 87 cananian 1.1.2.1         this.fieldsWritten = new GenericMultiMap(sf);
 88 cananian 1.1.2.1 
 89 cananian 1.1.2.1         /* analyze all callable methods */
 90 cananian 1.1.2.1         for (Iterator it=ch.callableMethods().iterator(); it.hasNext(); )
 91 cananian 1.1.2.1             analyze((HMethod)it.next(), hcf);
 92 cananian 1.1.2.1         /* compute transitive closure */
 93 cananian 1.1.2.1         transClose(ch, callGraphMap(ch, cg));
 94 cananian 1.1.2.1         /* done! */
 95 cananian 1.1.2.3         int sum=0, n=0;
 96 cananian 1.1.2.3         for (Iterator it=fieldsRead.keySet().iterator(); it.hasNext(); n++)
 97 cananian 1.1.2.3             sum+=fieldsRead.getValues(it.next()).size();
 98 cananian 1.1.2.3         System.out.println("FIELDS read: (avg) "+((float)sum/n)+
 99 cananian 1.1.2.3                            " of "+s.size());
100 cananian 1.1.2.3         sum=0; n=0;
101 cananian 1.1.2.3         for (Iterator it=fieldsWritten.keySet().iterator(); it.hasNext(); n++)
102 cananian 1.1.2.3             sum+=fieldsWritten.getValues(it.next()).size();
103 cananian 1.1.2.3         System.out.println("FIELDS written: (avg) "+((float)sum/n)+
104 cananian 1.1.2.3                            " of "+s.size());
105 cananian 1.1.2.3         System.out.println("SYNC methods: "+syncMethods.size()+
106 cananian 1.1.2.3                            " of "+ch.callableMethods().size());
107 cananian 1.1.2.1     }
108 cananian 1.1.2.1 
109 cananian 1.1.2.1     //----------------------------------------------------------------
110 cananian 1.1.2.1     //  method analysis
111 cananian 1.1.2.1     void analyze(HMethod hm, HCodeFactory hcf) {
112 cananian 1.1.2.1         HCode hc = hcf.convert(hm);
113 cananian 1.1.2.1         if (hc==null) return; // abstract.
114 cananian 1.1.2.1         for (Iterator it=hc.getElementsI(); it.hasNext(); ) {
115 cananian 1.1.2.1             Quad q = (Quad) it.next();
116 cananian 1.1.2.1             /* analyze q */
117 cananian 1.1.2.1             if (q instanceof MONITORENTER || q instanceof MONITOREXIT)
118 cananian 1.1.2.1                 syncMethods.add(hm);
119 cananian 1.1.2.1             if (q instanceof GET)
120 cananian 1.1.2.1                 fieldsRead.add(hm, ((GET)q).field());
121 cananian 1.1.2.1             if (q instanceof SET)
122 cananian 1.1.2.1                 fieldsWritten.add(hm, ((SET)q).field());
123 cananian 1.1.2.1         }
124 cananian 1.1.2.1     }
125 cananian 1.1.2.1     // make invertible multimap out of the callgraph
126 cananian 1.1.2.1     InvertibleMultiMap callGraphMap(ClassHierarchy ch, CallGraph cg) {
127 cananian 1.1.2.1         InvertibleMultiMap imm =
128 cananian 1.1.2.1             new GenericInvertibleMultiMap(new AggregateSetFactory());
129 cananian 1.4             for (Object hmO : ch.callableMethods()) {
130 cananian 1.4                 HMethod hm = (HMethod) hmO;
131 cananian 1.1.2.1             imm.addAll(hm, Arrays.asList(cg.calls(hm)));
132 cananian 1.1.2.1         }
133 cananian 1.1.2.1         return imm;
134 cananian 1.1.2.1     }
135 cananian 1.1.2.1 
136 cananian 1.1.2.1     //----------------------------------------------------------------
137 cananian 1.1.2.1     // compute transitive closure.
138 cananian 1.1.2.1     void transClose(ClassHierarchy ch, InvertibleMultiMap calls) {
139 cananian 1.1.2.1         // create an invertable multimap from the call graph.
140 cananian 1.1.2.1         WorkSet w = new WorkSet(ch.callableMethods());
141 cananian 1.1.2.1         while (!w.isEmpty()) {
142 cananian 1.1.2.1             HMethod hm = (HMethod) w.pop();
143 cananian 1.1.2.1             boolean changed = false;
144 cananian 1.4                 for (Object calleeO : calls.getValues(hm)) {
145 cananian 1.4                     HMethod callee = (HMethod) calleeO;
146 cananian 1.1.2.1                 // add all fields read/written by callee to this.
147 cananian 1.1.2.1                 if (fieldsRead.addAll(hm, fieldsRead.getValues(callee)))
148 cananian 1.1.2.1                     changed = true;
149 cananian 1.1.2.1                 if (fieldsWritten.addAll(hm, fieldsWritten.getValues(callee)))
150 cananian 1.1.2.1                     changed = true;
151 cananian 1.1.2.1                 // close on syncMethods.
152 cananian 1.1.2.1                 if (syncMethods.contains(callee))
153 cananian 1.1.2.1                     if (syncMethods.add(hm))
154 cananian 1.1.2.1                         changed = true;
155 cananian 1.1.2.1             }
156 cananian 1.1.2.1             // if hm's data was modified, add all callers to the worklist.
157 cananian 1.1.2.1             if (changed)
158 cananian 1.1.2.1                 w.addAll(calls.invert().getValues(hm));
159 cananian 1.1.2.1         }
160 cananian 1.1.2.1         // done.
161 cananian 1.1.2.1     }
162 cananian 1.2     }