1 package joeq.Compiler.Analysis.FlowInsensitive;
2
3 import java.io.FileReader;
4 import java.io.IOException;
5 import java.io.LineNumberReader;
6 import java.util.Collection;
7 import java.util.Iterator;
8 import java.util.LinkedList;
9 import java.util.StringTokenizer;
10 import joeq.Class.PrimordialClassLoader;
11 import joeq.Class.jq_Class;
12 import joeq.Class.jq_Method;
13 import joeq.Class.jq_Type;
14 import joeq.Compiler.Analysis.IPA.PA;
15 import joeq.Compiler.Analysis.IPA.ProgramLocation;
16 import joeq.Compiler.Analysis.IPA.ProgramLocation.QuadProgramLocation;
17 import joeq.Compiler.Quad.CodeCache;
18 import joeq.Main.HostedVM;
19 import joeq.UTF.Utf8;
20 import jwutil.util.Assert;
21
22 /***
23 * @author V.Benjamin Livshits
24 * @version $Id: ReflectionInformationProvider.java 2465 2006-06-07 23:03:17Z joewhaley $
25 *
26 * This class declares methods for resolving reflective calls.
27 */
28 public abstract class ReflectionInformationProvider {
29 public class NewInstanceTargets {
30 private jq_Method declaredIn;
31 private Collection targets = new LinkedList();
32
33 /***
34 * @param declaredIn
35 */
36 public NewInstanceTargets(String declaredIn) {
37 this.declaredIn = getMethod(declaredIn);
38 if(PA.TRACE_REFLECTION){
39 if(this.declaredIn == null) {
40 System.out.println("No method for " + declaredIn + " in NewInstanceTargets. "
41 + " The classpath is [" + PrimordialClassLoader.loader.classpathToString() + "]");
42 } else {
43 System.out.println("Created a NewInstanceTarget object for " + this.declaredIn.toString());
44 }
45 }
46 }
47
48 public boolean isValid(){
49 return getDeclaredIn() != null && targets.size() > 0;
50 }
51
52 private jq_Method getMethod(String fullMethodName) {
53 int index = fullMethodName.lastIndexOf('.');
54 Assert._assert(index != -1);
55
56 String className = fullMethodName.substring(0, index);
57 String methodName = fullMethodName.substring(index+1, fullMethodName.length());
58
59 String classdesc = "L" + className.replace('.', '/') + ";";
60 jq_Class clazz = (jq_Class)PrimordialClassLoader.loader.getOrCreateBSType(classdesc);
61
62
63 try {
64 clazz.prepare();
65 } catch (NoClassDefFoundError e){
66
67 if(PA.TRACE_REFLECTION) System.err.println("Failed to load class " + className);
68 return null;
69 }
70 jq_Method method = clazz.getDeclaredMethod(methodName);
71 Assert._assert(method != null);
72
73 if(PA.TRACE_REFLECTION) System.out.println("Retrieved method " + method);
74
75 return method;
76 }
77
78 private jq_Class getClass(String className) {
79 jq_Class clazz = (jq_Class) jq_Type.parseType(className);
80 try {
81 clazz.prepare();
82 } catch (NoClassDefFoundError e){
83 return null;
84 }
85 Assert._assert(clazz != null);
86
87 return clazz;
88 }
89
90 public void addTarget(String target) {
91 jq_Class clazz = getClass(target);
92 if(clazz != null){
93 addTarget(clazz);
94 }
95 }
96
97 public void addTarget(jq_Class clazz) {
98 jq_Method constructor = clazz.getInitializer(Utf8.get("()V"));
99 targets.add(constructor);
100 }
101
102 public String toString(){
103 return declaredIn + " -> " + targets.toString();
104 }
105
106 public jq_Method getDeclaredIn() {
107 return this.declaredIn;
108 }
109
110 public Collection getTargets() {
111 return this.targets;
112 }
113
114 public void addSubclasses(String className) {
115 jq_Class clazz = getClass(className);
116
117 for(Iterator iter = PrimordialClassLoader.loader.listPackages(); iter.hasNext();){
118
119 String packageName = (String) iter.next();
120
121 for(Iterator classIter = PrimordialClassLoader.loader.listPackage(packageName, true); classIter.hasNext();){
122 String className2 = (String) classIter.next();
123 className2 = className2.substring(0, className2.length()-6);
124
125 jq_Class c = (jq_Class) jq_Type.parseType(className2);
126 try {
127 if(c.isSubtypeOf(clazz)){
128 c.prepare();
129 System.out.println(
130 "Initialized a subclass of " + className +
131 ", class: " + c);
132 }
133 } catch(Throwable e){
134 continue;
135 }
136
137
138 }
139
140 }
141 }
142 }
143
144 /***
145 * Reflective methods to be used in isReflective(...)
146 */
147 private static String[][] methodSpecs = {
148 {"java.lang.Class", "forName"},
149 {"java.lang.Object", "newInstance"},
150 {"java.lang.reflection.Constructor", "newInstance"},
151 };
152
153 /***
154 * Checks if method is reflective.
155 *
156 * @param method
157 */
158 public static boolean isReflective(jq_Method method){
159 for(int i = 0; i < methodSpecs.length; i++){
160 String[] methodSpec = methodSpecs[i];
161 String className = methodSpec[0];
162 String methodName = methodSpec[1];
163
164 if(!className.equals(method.getDeclaringClass().getName())) continue;
165 if(!methodName.toString().equals(method.getName())) continue;
166
167 return true;
168 }
169
170 return false;
171 }
172
173 /***
174 * Checks if mc corresponds to a newInstance call.
175 */
176 public static boolean isNewInstance(ProgramLocation.QuadProgramLocation mc){
177 jq_Method target = mc.getTargetMethod();
178 return isNewInstance(target);
179 }
180
181 /***
182 * Checks if target is a newInstance method.
183 */
184 public static boolean isNewInstance(jq_Method target) {
185 String className = target.getDeclaringClass().getName();
186 String methodName = target.getName().toString();
187
188 if(!className.equals("java.lang.Class")) return false;
189 if(!methodName.equals("newInstance")) return false;
190
191 return true;
192 }
193
194 public static boolean isForName(jq_Method target) {
195 String className = target.getDeclaringClass().getName();
196 String methodName = target.getName().toString();
197
198 if(!className.equals("java.lang.Class")) return false;
199 if(!methodName.equals("forName")) return false;
200
201 return true;
202 }
203
204 /***
205 * Resolves constructors being pointed to by a newInstance() call mc.
206 * */
207 public abstract Collection
208
209 /***
210 * Resolves constructors being pointed to by a newInstance() calls within
211 * method n.
212 *
213 * Notice that information may be imprecise because we only have one piece of
214 * data per method.
215 * */
216 public abstract Collection
217
218 /***
219 * This implementation of ReflectionInformationProvider
220 * reads answers from a file.
221 * */
222 public static class CribSheetReflectionInformationProvider extends ReflectionInformationProvider {
223 private static final String DEFAULT_CRIB_FILE = "reflection.spec";
224
225 public CribSheetReflectionInformationProvider(String cribSheetFileName){
226 try {
227 readSpec(cribSheetFileName);
228 } catch (IOException e) {
229
230 System.err.println("Error reading " + cribSheetFileName + e.getMessage());
231 }
232 }
233
234 public CribSheetReflectionInformationProvider() {
235 this(DEFAULT_CRIB_FILE);
236 }
237
238 public static void main(String[] args) {
239 HostedVM.initialize();
240 CodeCache.AlwaysMap = true;
241
242 CribSheetReflectionInformationProvider provider =
243 new CribSheetReflectionInformationProvider(args[0]);
244 }
245
246 /***
247 * @param cribSheetFileName
248 * @throws IOException
249 */
250 private void readSpec_old(String cribSheetFileName) throws IOException {
251 FileReader fileIn = new FileReader(cribSheetFileName);
252 LineNumberReader in = new LineNumberReader(fileIn);
253 String line = in.readLine();
254 do {
255 if(!line.startsWith("#") && line.trim().length() > 0){
256 NewInstanceTargets spec = parseSpecLine(line);
257 if(spec.isValid()){
258 if(PA.TRACE_REFLECTION){
259 System.out.println("Adding a reflection spec for " + spec.getDeclaredIn());
260 }
261 specs.add(spec);
262 }
263 }
264 line = in.readLine();
265 } while (line != null);
266 in.close();
267
268 if(PA.TRACE_REFLECTION) {
269 System.out.println(
270 "There are " + specs.size() +
271 " specifications read from " + cribSheetFileName);
272 }
273 }
274
275 private void readSpec(String cribSheetFileName) throws IOException {
276 FileReader fileIn = new FileReader(cribSheetFileName);
277 LineNumberReader in = new LineNumberReader(fileIn);
278 String line = in.readLine();
279 NewInstanceTargets spec = null;
280 do {
281 if(!line.startsWith("#") && line.trim().length() > 0){
282 if(!Character.isWhitespace(line.charAt(0))){
283 int indexBracket = line.indexOf('(');
284 Assert._assert(indexBracket != -1, "No brackets in " + line);
285 String declaredIn = line.substring(0, indexBracket);
286
287 if(spec != null){
288 if(PA.TRACE_REFLECTION && spec.isValid()){
289 System.out.println("Read " + spec);
290 }
291 if(spec.isValid()){
292 if(PA.TRACE_REFLECTION){
293 System.out.println(
294 "Adding a reflection spec for " + spec.getDeclaredIn());
295 }
296 specs.add(spec);
297 }
298 }
299 spec = new NewInstanceTargets(declaredIn);
300 }else{
301 line = line.trim();
302 spec.addTarget(line);
303 }
304 }
305 line = in.readLine();
306 } while (line != null);
307 in.close();
308
309 if(PA.TRACE_REFLECTION) {
310 System.out.println(
311 "There are " + specs.size() +
312 " specifications read from " + cribSheetFileName);
313 }
314 }
315
316 Collection
317 private static final Object SUBCLASSES_MARKER = "<";
318 private static final Object ELLIPSES = "...";
319
320 /***
321 * Parses one line like this:
322 org.roller.presentation.RollerContext.getAuthenticator org.roller.presentation.DefaultAuthenticator ...
323 */
324 private NewInstanceTargets parseSpecLine(String line) {
325 StringTokenizer tok = new StringTokenizer(line);
326 String declaredIn = tok.nextToken();
327 NewInstanceTargets targets = new NewInstanceTargets(declaredIn);
328 while(tok.hasMoreTokens()){
329 String token = tok.nextToken();
330 if(!token.equals(ELLIPSES)){
331 if(!token.equals(SUBCLASSES_MARKER)){
332 targets.addTarget(token);
333 }else{
334 targets.addSubclasses(tok.nextToken());
335 }
336 }else{
337 if(PA.TRACE_REFLECTION){
338 System.err.println("Specification for " + declaredIn + " is incomplete.");
339 }
340 }
341 }
342 if(PA.TRACE_REFLECTION && targets.isValid()){
343 System.out.println("Read " + targets);
344 }
345
346 return targets;
347 }
348
349
350
351
352 public Collection getNewInstanceTargets(QuadProgramLocation mc) {
353
354 return null;
355 }
356
357 public Collection
358 if(PA.TRACE_REFLECTION) System.out.println("There are " + specs.size() + " specs to check against.");
359 for(Iterator iter = specs.iterator(); iter.hasNext();){
360 NewInstanceTargets spec = (NewInstanceTargets) iter.next();
361 if(PA.TRACE_REFLECTION) System.out.println("\tChecking against " + spec.getDeclaredIn());
362
363 if(spec.getDeclaredIn() == n){
364 return spec.getTargets();
365 }
366 }
367 if(PA.TRACE_REFLECTION){
368 System.out.println("No information for method " + n);
369 }
370 return null;
371 }
372 }
373 }