View Javadoc

1   package joeq.Compiler.Analysis.IPA;
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 SubtypeHelper {
20      protected PA 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 SubtypeHelper(PA 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 SubtypeHelper {
40          static final String kind = KNOWN;
41          public KnownClassesSubtypeHelper(PA 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);          // T2
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 SubtypeHelper {    
70          private Map/*<jq_Class, Collection<jq_Class>>*/ type2subtypeCache = new HashMap();
71          static final String kind = ONLINE;
72  
73          public OnlineSubtypeHelper(PA 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                  //System.out.println("\t" + iter.next());
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                         //le.printStackTrace(System.err);
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 SubtypeHelper {
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(PA 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                     // add the class itself to the list of subclasses
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         /* (non-Javadoc)
159          * @see joeq.Compiler.Analysis.IPA.SubtypeHelper#getSubtypes(joeq.Class.jq_Class)
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();         // lazily initialize the subclasses
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     //                    if(TRACE){
186     //                        System.out.println("Preparing class " + subtypeClass + " by name " + canonicalName);
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 SubtypeHelper newSubtypeHelper(PA 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 }