1
2
3
4
5
6
7 package joeq.Compiler.Analysis.IPA;
8
9 import java.util.Collection;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.LinkedList;
14 import java.util.Map;
15 import java.util.Set;
16 import java.io.DataOutputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.io.PrintStream;
20 import java.math.BigInteger;
21 import joeq.Class.jq_Class;
22 import joeq.Class.jq_Field;
23 import joeq.Class.jq_Initializer;
24 import joeq.Class.jq_InstanceMethod;
25 import joeq.Class.jq_Method;
26 import joeq.Class.jq_Reference;
27 import joeq.Class.jq_Type;
28 import joeq.Compiler.Analysis.FlowInsensitive.MethodSummary;
29 import joeq.Compiler.Analysis.FlowInsensitive.MethodSummary.Node;
30 import joeq.Compiler.Analysis.IPSSA.IPSSABuilder;
31 import joeq.Compiler.Analysis.IPSSA.IPSSABuilder.Application;
32 import jwutil.util.Assert;
33 import net.sf.javabdd.BDD;
34 import net.sf.javabdd.TypedBDDFactory;
35 import net.sf.javabdd.TypedBDDFactory.TypedBDD;
36
37 /***
38 * Finds and outputs information about polymorphic:
39 * - fields
40 * - method parameters
41 *
42 * The result is output in XML.
43 * */
44 public class CollectionFinder extends Application {
45 static final String OBJECT_SIGNATURE = "Ljava.lang.Object;";
46
47 public static String xmlEscape(String s) {
48 s = s.replaceAll("<", "<");
49 s = s.replaceAll("<", ">");
50
51 return s;
52 }
53 private final static String _outFile = "polyclasses.xml";
54 private PA _r = null;
55 private static final boolean TRACE = false;
56
57 public CollectionFinder() {
58 this(null,null,null);
59 }
60 public CollectionFinder(IPSSABuilder builder, String name, String[] args) {
61 super(builder, name, args);
62 }
63
64 private Collection buildList(BDD e) {
65 Collection c = new LinkedList();
66 for (Iterator i = e.iterator(_r.T2set); i.hasNext(); ) {
67 BDD b = (BDD) i.next();
68 BDD d = b.relprod(_r.aT, _r.T2set);
69 b.free();
70
71
72 c.add(d.toString());
73 }
74
75 return c;
76 }
77
78 public BDD calculateCommonSupertype(BDD types) {
79 if (types.isZero()) return _r.bdd.zero();
80 BDD bestTypes = _r.T1.domain();
81
82
83
84 for (Iterator i = types.iterator(_r.T2set); i.hasNext(); ) {
85 BDD b = (BDD) i.next();
86 BDD c = b.relprod(_r.aT, _r.T2set);
87 b.free();
88 bestTypes.andWith(c);
89 }
90
91
92 for (Iterator i = bestTypes.iterator(_r.T1set); i.hasNext(); ) {
93 BDD b = (BDD) i.next();
94 BDD c = b.relprod(_r.aT, _r.T1set);
95 b.free();
96
97
98
99
100
101
102
103
104
105
106
107 c.replaceWith(_r.T2toT1);
108 c.andWith(bestTypes.id());
109
110 if (c.satCount(_r.T1set) == 1.0) {
111 return c;
112 }
113 }
114 System.out.println("No subtype matches! "+bestTypes.toStringWithDomains(_r.TS));
115 return _r.bdd.zero();
116 }
117
118 public BDD calculateConcreteTypes(BDD types, boolean removeNull) {
119 TypedBDD tb = (TypedBDD)types;
120 BDD t = tb.getDomainSet().contains(_r.H1c) ?
121 types.relprod(_r.hT, _r.H1set.union(_r.H1cset)) :
122 types.relprod(_r.hT, _r.H1set);
123
124
125 if(removeNull && !t.and(_r.T2.ithVar(0)).isZero()) {
126
127
128
129 t.restrictWith(_r.T2.ithVar(0));
130 }
131
132
133
134 return t;
135 }
136
137 public jq_Reference getType(TypedBDD types) {
138 BigInteger[] indeces = _r.T2.getVarIndices(types);
139 Assert._assert(indeces.length == 1, "There are " + indeces.length + " indeces in " + types.toStringWithDomains());
140 BigInteger index = indeces[0];
141 jq_Reference type = (jq_Reference)_r.Tmap.get(index.intValue());
142
143
144 return type;
145 }
146
147 protected void parseParams(String[] args) {}
148
149 private void printFields(PrintStream out, Collection c, String name) {
150 out.println("<fieldset name = \"" + name + "\">");
151 for(Iterator iter = c.iterator(); iter.hasNext();) {
152 jq_Field f = (jq_Field)iter.next();
153
154 out.println("\t<field name=\"" + f + "\" type=\"" + f.getType() + "\">");
155 out.println("\t</field>");
156 }
157 out.println("</fieldset>");
158 }
159
160 private void printFieldsWithPointeeTypes(PrintStream out, Collection c, Map map, String name) {
161 out.println("<fieldset name = \"" + name + "\">");
162 for(Iterator iter = c.iterator(); iter.hasNext();) {
163 jq_Field f = (jq_Field)iter.next();
164
165 out.println("\t<field name=\"" + f + "\" type=\"" + f.getType() + "\">");
166 if(map != null && map.containsKey(f)) {
167 String s = (String)map.get(f);
168
169
170 out.println(s);
171 }
172
173 out.println("\t</field>");
174 }
175 out.println("</fieldset>");
176 }
177
178 private void printNodesWithPointeeTypes(PrintStream out, Map methodMap, Map map, String name) {
179 for(Iterator methodIter = methodMap.keySet().iterator(); methodIter.hasNext();) {
180 jq_Class clazz = (jq_Class)methodIter.next();
181 out.println("<paramset name = \"" + xmlEscape(clazz.toString()) + "\">");
182 Collection c = (Collection)methodMap.get(clazz);
183 for(Iterator iter = c.iterator(); iter.hasNext();) {
184 MethodSummary.ParamNode n = (MethodSummary.ParamNode)iter.next();
185 out.println(
186 "\t<param method=\"" + xmlEscape(n.getDefiningMethod().toString()) +
187
188 " \" number=\"" + n.getIndex() + "\">");
189 if(map != null && map.containsKey(n)) {
190 String s = (String)map.get(n);
191
192
193 out.println(s);
194 }
195
196 out.println("\t</param>");
197 }
198 out.println("</paramset>");
199 }
200 }
201
202 void printPolyFieldInfo(PrintStream out) throws IOException {
203 _r = _builder.getPAResults().getPAResults();
204
205 BDD fh2 = _r.hP.exist(_r.H1set);
206
207 Collection singleTypeFields = new LinkedList();
208 Collection singleObjectFields = new LinkedList();
209 Collection unusedFields = new LinkedList();
210 Collection refinedTypeFields = new LinkedList();
211 Collection nullFields = new LinkedList();
212
213 Map refinedData = new HashMap();
214 Set polyClasses = new HashSet();
215
216 for (int i = 0; i < _r.Fmap.size(); ++i) {
217 jq_Field f = (jq_Field) _r.Fmap.get(i);
218 BDD b = _r.F.ithVar(i);
219 BDD c = fh2.restrict(b);
220 if (c.isZero()) {
221 unusedFields.add(f);
222 if(TRACE) System.err.println("Unused field " + f);
223 continue;
224 }
225 c.replaceWith(_r.H2toH1);
226 if (c.satCount(_r.H1set) == 1.0) {
227 singleObjectFields.add(f);
228 if(TRACE) System.err.println("Single object field " + f);
229 }
230 BDD d = c.relprod(_r.hT, _r.H1set);
231
232 if (d.satCount(_r.T2set) == 1.0) {
233 singleTypeFields.add(f);
234 if(TRACE) System.err.println("Single type field " + f);
235 } else {
236 if (f != null && !f.isStatic()) {
237 if(TRACE) System.err.println("Poly class " + f.getDeclaringClass());
238 polyClasses.add(f.getDeclaringClass());
239 }
240 }
241
242
243
244 BDD e = calculateConcreteTypes(c, true);
245 if(f == null) continue;
246 if(e.isOne()) {
247
248 nullFields.add(f);
249 }else
250 if(e.satCount(_r.T2set) > 1){
251 refinedTypeFields.add(f);
252
253 refinedData.put(f, typesetToString(e));
254
255
256 }
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280 d.free();
281 e.free();
282 c.free();
283 b.free();
284 }
285
286
287 printFieldsWithPointeeTypes(out, refinedTypeFields, refinedData, "multitype (polymorphic) fields");
288
289 printFields(out, nullFields, "null fields");
290
291 if(TRACE) {
292 System.out.println("Refined-type fields: "+refinedTypeFields+" / "+_r.Fmap.size()+" = "+(double)refinedTypeFields.size()/_r.Fmap.size());
293 System.out.println("Single-type fields: "+singleTypeFields+" / "+_r.Fmap.size()+" = "+(double)singleTypeFields.size()/_r.Fmap.size());
294 System.out.println("Single-object fields: "+singleObjectFields+" / "+_r.Fmap.size()+" = "+(double)singleObjectFields.size()/_r.Fmap.size());
295 System.out.println("Unused fields: "+unusedFields+" / "+_r.Fmap.size()+" = "+(double)unusedFields.size()/_r.Fmap.size());
296 System.out.println("Poly classes: "+polyClasses.size());
297 }
298 }
299
300 void printPolyParamInfo(PrintStream out) throws IOException {
301 _r = _builder.getPAResults().getPAResults();
302
303 Map polyMethods = new HashMap();
304 Map polyParamsData = new HashMap();
305
306 for(int i = 0; i < _r.Vmap.size(); ++i) {
307 Node node = (Node)_r.Vmap.get(i);
308 if(node instanceof MethodSummary.ParamNode) {
309 BDD param = _r.V1.ithVar(i);
310 MethodSummary.ParamNode pnode = (MethodSummary.ParamNode)node;
311
312 BDD h = param.relprod(_r.vP, _r.V1set);
313 BDD e = calculateConcreteTypes(h, true);
314 jq_Method method = node.getDefiningMethod();
315 if(method instanceof jq_Initializer) {
316
317 continue;
318 }
319
320 if(pnode.getIndex() == 0 && method instanceof jq_InstanceMethod &&
321 !((jq_InstanceMethod)method).isStatic())
322 {
323
324 continue;
325 }
326 if( !((TypedBDD)e).getDomainSet().isEmpty() && e.satCount(_r.T2set) > 1 ){
327
328
329
330
331 jq_Class clazz = method.getDeclaringClass();
332 Collection c = (Collection)polyMethods.get(clazz);
333 if(c == null) {
334 c = new LinkedList();
335 polyMethods.put(clazz, c);
336 }
337 c.add(node);
338 polyParamsData.put(node, typesetToString(e));
339
340
341 }
342 param.free();
343 h.free();
344 }
345 }
346
347 printNodesWithPointeeTypes(out, polyMethods, polyParamsData, "polymorphic parameters");
348 }
349
350 public void run() {
351 try {
352 PrintStream out = new PrintStream(new DataOutputStream(new FileOutputStream(_outFile)));
353 out.println("<?xml version=\"1.0\"?>");
354 out.println("<root>");
355
356 printPolyFieldInfo(out);
357
358 printPolyParamInfo(out);
359 out.println("</root>");
360 out.close();
361 } catch (IOException e) {
362 e.printStackTrace();
363 }
364 }
365
366 private String typesetToString(BDD e) {
367 TypedBDDFactory.TypedBDD te = (TypedBDD)e;
368
369 if(te.getDomainSet().isEmpty()){
370 return "";
371 }
372 Assert._assert(te.getDomainSet().contains(_r.T2));
373
374 StringBuffer result =
375 new StringBuffer("\t\t<typeset size=\"" + (int)e.satCount(_r.T2set) + "\"> \n");
376 for(Iterator iter2 = e.iterator(_r.T2set); iter2.hasNext();) {
377 BDD tt = (BDD)iter2.next();
378 jq_Type type = getType((TypedBDD)tt);
379 Assert._assert(type != null);
380 boolean isAbstract = type instanceof jq_Class && ((jq_Class)type).isAbstract();
381 boolean isInterface = type instanceof jq_Class && ((jq_Class)type).isInterface();
382
383 result.append(
384 "\t\t\t<type " +
385 "abstract=\"" + (isAbstract ?"yes":"no") + "\" " +
386 "interface=\"" + (isInterface?"yes":"no") +
387 "\">" +
388 "<![CDATA[" + type.toString() + "]]>"
389 + "</type> \n");
390 }
391
392 result.append("\t\t</typeset>\n");
393
394 return result.toString();
395 }
396 }
397