1 package joeq.Compiler.Analysis.Primitive;
2
3 import java.io.BufferedReader;
4 import java.io.FileReader;
5 import java.io.IOException;
6 import java.util.Collection;
7 import java.util.HashMap;
8 import java.util.HashSet;
9 import java.util.Iterator;
10 import java.util.LinkedList;
11 import java.util.Map;
12 import joeq.Class.PrimordialClassLoader;
13 import joeq.Class.jq_Class;
14 import joeq.Class.jq_Reference;
15 import joeq.Class.jq_Reference.jq_NullType;
16 import jwutil.util.Assert;
17 import net.sf.javabdd.BDD;
18
19 public abstract class PrimitiveSubtypeHelper {
20 protected PrimitivePA pa;
21 protected static boolean TRACE = true;
22 protected static final String OFFLINE = "offline";
23 protected static final String ONLINE = "online";
24 protected static final String KNOWN = "known";
25
26 public PrimitiveSubtypeHelper(PrimitivePA pa){
27 this.pa = pa;
28 }
29
30 static String canonicalizeClassName(String s) {
31 if (s.endsWith(".class")) s = s.substring(0, s.length() - 6);
32 s = s.replace('.', '/');
33 String desc = "L" + s + ";";
34 return desc;
35 }
36
37 public abstract Collection getSubtypes(jq_Class clazz);
38
39 public static class KnownClassesSubtypeHelper extends PrimitiveSubtypeHelper {
40 static final String kind = KNOWN;
41 public KnownClassesSubtypeHelper(PrimitivePA pa) {
42 super(pa);
43
44 if(TRACE) System.out.println("Instantiating a subtype helper of type " + kind);
45 }
46
47 public Collection getSubtypes(jq_Class t) {
48 if(TRACE) System.out.println("Requesting subtypes of class " + t);
49
50 Collection result = new LinkedList();
51 int T1_i = pa.Tmap.get(t);
52 BDD subtypes = pa.aT.relprod(pa.T1.ithVar(T1_i), pa.T1set);
53 for(Iterator typeIter = subtypes.iterator(pa.T2set); typeIter.hasNext();){
54 jq_Reference subtype = (jq_Reference) pa.Tmap.get(((BDD)typeIter.next()).scanVar(pa.T2).intValue());
55 if (subtype == null || subtype == jq_NullType.NULL_TYPE) continue;
56 if(!(subtype instanceof jq_Class)){
57 System.err.println("Skipping a non-class type: " + t);
58 continue;
59 }
60 jq_Class c = (jq_Class) subtype;
61 result.add(c);
62 }
63
64 if(TRACE) System.out.println("Returning " + result.size() + " subtypes.");
65 return result;
66 }
67 }
68
69 public static class OnlineSubtypeHelper extends PrimitiveSubtypeHelper {
70 private Map
71 static final String kind = ONLINE;
72
73 public OnlineSubtypeHelper(PrimitivePA pa) {
74 super(pa);
75
76 if(TRACE) System.out.println("Instantiating a subtype helper of type " + kind);
77 }
78
79 public Collection getSubtypes(jq_Class clazz) {
80 if(TRACE) System.out.println("Requesting subtypes of class " + clazz);
81 Collection result = (Collection) type2subtypeCache.get(clazz);
82 if(result != null) {
83 return result;
84 }
85 result = new LinkedList();
86 for(Iterator iter = PrimordialClassLoader.loader.listPackages(); iter.hasNext();){
87
88 String packageName = (String) iter.next();
89 HashSet loaded = new HashSet();
90 if(TRACE) System.out.println("Processing package " + packageName);
91
92 for(Iterator classIter = PrimordialClassLoader.loader.listPackage(packageName, true); classIter.hasNext();){
93 String className = (String) classIter.next();
94 String canonicalClassName = canonicalizeClassName(className);
95 if (loaded.contains(canonicalClassName))
96 continue;
97 loaded.add(canonicalClassName);
98 try {
99 jq_Class c = (jq_Class) PrimordialClassLoader.loader.getOrCreateBSType(canonicalClassName);
100 c.load();
101 c.prepare();
102 if(c.isSubtypeOf(clazz)){
103 System.out.println("Initialized a subclass of " + clazz + ", class: " + c);
104 result.add(c);
105 }
106 } catch (NoClassDefFoundError x) {
107 if(TRACE) System.err.println("Package " + packageName + ": Class not found (canonical name " + canonicalClassName + ").");
108 } catch (LinkageError le) {
109 if(TRACE) System.err.println("Linkage error occurred while loading class (" + canonicalClassName + "):" + le.getMessage());
110
111 } catch (RuntimeException e){
112 if(TRACE) System.err.println("Security error occured: " + e.getMessage());
113 }
114 }
115 }
116
117 type2subtypeCache.put(clazz, result);
118 if(TRACE) System.out.println("Returning " + result.size() + " subtypes.");
119 return result;
120 }
121 }
122
123 public static class OfflineSubtypeHelper extends PrimitiveSubtypeHelper {
124 static final String subtypeFileName = "reversed_subclasses.txt";
125 Map classes2subclasses = new HashMap();
126 private boolean initialized = false;
127 final static String kind = OFFLINE;
128 public OfflineSubtypeHelper(PrimitivePA pa) {
129 super(pa);
130
131 if(TRACE) System.out.println("Instantiating a subtype helper of type " + kind);
132 }
133
134 void initializeSubclasses() throws IOException {
135 if(initialized) return;
136 BufferedReader r = new BufferedReader(new FileReader(subtypeFileName));
137 String s = null;
138 String className = null;
139 Collection subclassList = null;
140 while ((s = r.readLine()) != null) {
141 if(s.startsWith("CLASS ")){
142 className = s.substring("CLASS ".length(), s.indexOf(" ", "CLASS ".length() + 1));
143 subclassList = new LinkedList();
144
145 subclassList.add(className);
146 classes2subclasses.put(className, subclassList);
147 }else{
148 int index = s.indexOf("SUBCLASS ");
149 if(index != -1){
150 String subclass = s.substring(index + "SUBCLASS ".length(), s.length());
151 subclassList.add(subclass);
152 }
153 }
154 }
155 initialized = true;
156 }
157
158
159
160
161 public Collection getSubtypes(jq_Class clazz) {
162 if(TRACE) System.out.println("Requesting subtypes of class " + clazz);
163 String className = clazz.getName();
164 try {
165 initializeSubclasses();
166 } catch (IOException e) {
167 Assert._assert(false, e.toString());
168 return null;
169 }
170
171 Collection subtypeNames = (Collection) classes2subclasses.get(className);
172 if(subtypeNames == null){
173 System.err.println("No match for class \"" + className + "\" in " + subtypeFileName);
174 return null;
175 }
176 Collection result = new LinkedList();
177 for(Iterator iter = subtypeNames.iterator(); iter.hasNext();){
178 String subtypeName = (String) iter.next();
179 String canonicalName = canonicalizeClassName(subtypeName.trim());
180
181 try {
182 jq_Class subtypeClass = (jq_Class) jq_Class.parseType(canonicalName);
183
184 if(!subtypeClass.isPrepared()){
185
186
187
188 subtypeClass.prepare();
189 }
190 result.add(subtypeClass);
191 } catch (java.lang.NoClassDefFoundError e){
192 if(TRACE) System.err.println("Can't load " + subtypeName + ": " + e);
193 continue;
194 }
195 }
196 Assert._assert(result.size() <= subtypeNames.size());
197
198 if(TRACE) System.out.println("Returning " + result.size() + " subtypes.");
199 return result;
200 }
201 }
202
203 public static PrimitiveSubtypeHelper newSubtypeHelper(PrimitivePA pa, String kind) {
204 if(kind.equals(OFFLINE)) {
205 return new OfflineSubtypeHelper(pa);
206 }
207 if(kind.equals(ONLINE)) {
208 return new OnlineSubtypeHelper(pa);
209 }
210 if(kind.equals(KNOWN)) {
211 return new KnownClassesSubtypeHelper(pa);
212 }
213
214 Assert._assert(false, "Unknown kind: " + kind);
215 return null;
216 }
217 }