KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gov > nasa > jpf > tools > GenPeerDispatcher


1 //
2
// Copyright (C) 2005 United States Government as represented by the
3
// Administrator of the National Aeronautics and Space Administration
4
// (NASA). All Rights Reserved.
5
//
6
// This software is distributed under the NASA Open Source Agreement
7
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
8
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
9
// directory tree for the complete NOSA document.
10
//
11
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
12
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
13
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
14
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
15
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
16
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
17
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
18
//
19
package gov.nasa.jpf.tools;
20
21 import gov.nasa.jpf.jvm.Types;
22
23 import java.io.PrintWriter JavaDoc;
24
25 import java.lang.reflect.*;
26
27
28 /**
29  * tool to create NativePeerDispatchers, i.e. classes that do the NativePeer
30  * method lookup with explicit hahcode values instead of reflection.
31  * Given a NativePeer, this class computes the hashcodes and creates a
32  * dispatcher class that mostly consists of one big dispatcher method directly
33  * calling the native methods
34  * Since reflection call efficiency got significantly improved since Java 1.4,
35  * dispatcher classes are not really required anymore.
36  */

37 public class GenPeerDispatcher {
38   static final String JavaDoc SYS_PKG = "gov.nasa.jpf.jvm";
39   static final String JavaDoc INDENT = " ";
40   static final String JavaDoc EXECUTE = "Instruction executeMethod (ThreadInfo ti, MethodInfo mi)";
41   static final String JavaDoc IS_COND_DETERMINISTIC = "boolean isMethodCondDeterministic (ThreadInfo ti, MethodInfo mi)";
42   static final String JavaDoc IS_COND_EXECUTABLE = "boolean isMethodCondExecutable (ThreadInfo ti, MethodInfo mi)";
43   static final String JavaDoc EXEC_COND = "$isExecutable_";
44   static final String JavaDoc DETERM_COND = "$isDeterministic_";
45   static final int MJI_MODS = Modifier.PUBLIC | Modifier.STATIC;
46   static String JavaDoc clsName;
47   static PrintWriter JavaDoc pw;
48   static Method[] tmethods; // target class method cache (for reverse lookup)
49

50   public static void main (String JavaDoc[] args) {
51     if ((args.length == 0) || !readOptions(args)) {
52       showUsage();
53
54       return;
55     }
56
57     pw = new PrintWriter JavaDoc(System.out, true);
58
59     Class JavaDoc cls = getClass(clsName);
60
61     if (cls != null) {
62       printNativePeerDispatcher(cls);
63     }
64   }
65
66   static Class JavaDoc getClass (String JavaDoc cname) {
67     Class JavaDoc clazz = null;
68
69     try {
70       clazz = Class.forName(cname);
71     } catch (ClassNotFoundException JavaDoc cnfx) {
72       System.err.println("target class not found: " + cname);
73     } catch (Throwable JavaDoc x) {
74       x.printStackTrace();
75     }
76
77     return clazz;
78   }
79
80   static boolean isMJIDetermCondCandidate (Method m) {
81     if ((m.getModifiers() & MJI_MODS) == MJI_MODS) {
82       String JavaDoc name = m.getName();
83
84       return name.startsWith(DETERM_COND);
85     }
86
87     return false;
88   }
89
90   static boolean isMJIExecCondCandidate (Method m) {
91     if ((m.getModifiers() & MJI_MODS) == MJI_MODS) {
92       String JavaDoc name = m.getName();
93
94       return name.startsWith(EXEC_COND);
95     }
96
97     return false;
98   }
99
100   static boolean isMJIExecuteCandidate (Method m) {
101     if ((m.getModifiers() & MJI_MODS) == MJI_MODS) {
102       String JavaDoc name = m.getName();
103
104       return !(name.startsWith(EXEC_COND) || name.startsWith(DETERM_COND));
105     }
106
107     return false;
108   }
109
110   static String JavaDoc getSignature (Method m) {
111     String JavaDoc mname = m.getName();
112
113     if (mname.equals("$clinit") || mname.equals("$init")) {
114       // <2do> - if we want to be real good, we really have to treat ctors
115
return "()";
116     }
117
118     // bad, we have to do a reverse lookup from the target class
119
// (can't use our argTypes because we lost the object classes)
120
Method tm = getTargetMethod(m);
121
122     if (tm != null) {
123       // let's tinker us a signature
124
Class JavaDoc[] argTypes = tm.getParameterTypes();
125       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
126
127       sb.append('(');
128
129       for (int i = 0; i < argTypes.length; i++) {
130         Class JavaDoc t = argTypes[i];
131
132         while (t.isArray()) {
133           sb.append('[');
134           t = t.getComponentType();
135         }
136
137         if (t == Boolean.TYPE) {
138           sb.append('Z');
139         } else if (t == Byte.TYPE) {
140           sb.append('B');
141         } else if (t == Character.TYPE) {
142           sb.append('C');
143         } else if (t == Short.TYPE) {
144           sb.append('S');
145         } else if (t == Integer.TYPE) {
146           sb.append('I');
147         } else if (t == Long.TYPE) {
148           sb.append('J');
149         } else if (t == Float.TYPE) {
150           sb.append('F');
151         } else if (t == Double.TYPE) {
152           sb.append('D');
153         } else {
154           sb.append('L');
155           sb.append(t.getName().replace('.', '/'));
156           sb.append(';');
157         }
158       }
159
160       sb.append(')');
161
162       return sb.toString();
163     }
164
165     return "()"; // a bloody guess, probably will fail
166
}
167
168   static Method getTargetMethod (Method m) {
169     // <2do> - no non-default ctors support
170
String JavaDoc mname = m.getName();
171
172     if (tmethods == null) {
173       String JavaDoc tcn = m.getDeclaringClass().getName();
174       tcn = tcn.substring(tcn.indexOf("JPF") + 4);
175       tcn = tcn.replace('_', '.');
176
177       try {
178         // <2do> - doesn't work for bootclasspath candidates, of course!
179
Class JavaDoc tcls = Class.forName(tcn);
180         tmethods = tcls.getDeclaredMethods();
181       } catch (ClassNotFoundException JavaDoc cnfx) {
182         System.err.println("!! cannot find target class " + tcn +
183                            " to determine signature of: " + mname);
184
185         return null;
186       }
187     }
188
189     for (int i = 0; i < tmethods.length; i++) {
190       if (tmethods[i].getName().equals(mname)) {
191         return tmethods[i];
192       }
193     }
194
195     System.err.println(
196           "!! cannot find target method to determine signature of: " + mname);
197
198     return null;
199   }
200
201   static int calcStackSize (Class JavaDoc[] argTypes) {
202     int n = 0;
203
204     // the first two args are the MJIEnv object and the 'this' / class object ref
205
// we don't count them here
206
for (int i = 2; i < argTypes.length; i++) {
207       if ((argTypes[i] == Long.TYPE) || (argTypes[i] == Double.TYPE)) {
208         n += 2;
209       } else {
210         n++;
211       }
212     }
213
214     return n;
215   }
216
217   static void iprint (int level, String JavaDoc s) {
218     printIndent(level);
219     pw.print(s);
220   }
221
222   static void iprintln (int level, String JavaDoc s) {
223     printIndent(level);
224     pw.println(s);
225   }
226
227   static void printCall (Class JavaDoc cls, Method m) {
228     Class JavaDoc[] argTypes = m.getParameterTypes();
229     Class JavaDoc retType = m.getReturnType();
230     int stackOffset = calcStackSize(argTypes); // not counting this/class ref
231

232     pw.print(cls.getName());
233     pw.print('.');
234     pw.print(m.getName());
235     pw.print("( env, rThis");
236
237     if (argTypes.length > 2) {
238       pw.println(',');
239     }
240
241     for (int i = 2; i < argTypes.length;) {
242       stackOffset--;
243
244       if (argTypes[i] == Boolean.TYPE) {
245         iprint(7, "Types.intToBoolean( ti.peek(" + stackOffset + "))");
246       } else if (argTypes[i] == Byte.TYPE) {
247         iprint(7, "(byte) ti.peek(" + stackOffset + ")");
248       } else if (argTypes[i] == Character.TYPE) {
249         iprint(7, "(char) ti.peek(" + stackOffset + ")");
250       } else if (argTypes[i] == Short.TYPE) {
251         iprint(7, "(short) ti.peek(" + stackOffset + ")");
252       } else if (argTypes[i] == Integer.TYPE) {
253         iprint(7, "ti.peek(" + stackOffset + ")");
254       } else if (argTypes[i] == Long.TYPE) {
255         stackOffset--;
256         iprint(7, "ti.longPeek(" + stackOffset + ")");
257       } else if (argTypes[i] == Float.TYPE) {
258         iprint(7, "Types.intToFloat( ti.peek(" + stackOffset + "))");
259       } else if (argTypes[i] == Double.TYPE) {
260         stackOffset--;
261         iprint(7, "Types.longToDouble( ti.longPeek(" + stackOffset + "))");
262       } else {
263         iprint(7, "ti.peek(" + stackOffset + ")");
264       }
265
266       if ((++i) < argTypes.length) {
267         pw.println(',');
268       }
269     }
270
271     pw.print(")");
272   }
273
274   static void printCaseConst (Method m) {
275     String JavaDoc mname = m.getName();
276     String JavaDoc jniname = Types.getJNIMethodName(mname);
277
278     String JavaDoc id = jniname;
279
280     if (id.equals("$clinit")) {
281       id = "<clinit>";
282     } else if (id.equals("$init")) {
283       id = "<init>";
284     }
285
286     String JavaDoc argSig = Types.getJNIArgSignature(mname);
287
288     if (argSig != null) {
289       id += argSig;
290     } else {
291       // Ok, no type signature, we have to recreate this from the argTypes
292
id += getSignature(m);
293     }
294
295     iprint(3, "case ");
296     pw.print(id.hashCode());
297     pw.print(": // ");
298     pw.println(id);
299   }
300
301   static int printExecCallProlog (Method m) {
302     Class JavaDoc retType = m.getReturnType();
303
304     if (retType == Void.TYPE) {
305       iprintln(4, "retSize = 0;");
306       iprint(4, "");
307     } else if (retType == Boolean.TYPE) {
308       iprintln(4, "retSize = 1;");
309       iprint(4, "iret = Types.booleanToInt( ");
310
311       return 1;
312     } else if (retType == Byte.TYPE) {
313       iprintln(4, "retSize = 1;");
314       iprint(4, "iret = (int) ");
315     } else if (retType == Character.TYPE) {
316       iprintln(4, "retSize = 1;");
317       iprint(4, "iret = (int) ");
318     } else if (retType == Short.TYPE) {
319       iprintln(4, "retSize = 1;");
320       iprint(4, "iret = (int) ");
321     } else if (retType == Integer.TYPE) {
322       iprintln(4, "retSize = 1;");
323       iprint(4, "iret = ");
324     } else if (retType == Long.TYPE) {
325       iprintln(4, "retSize = 2;");
326       iprint(4, "lret = ");
327     } else if (retType == Float.TYPE) {
328       iprintln(4, "retSize = 1;");
329       iprint(4, "iret = Types.floatToInt( ");
330
331       return 1;
332     } else if (retType == Double.TYPE) {
333       iprintln(4, "retSize = 2;");
334       iprint(4, "lret = Types.doubleToLong( ");
335
336       return 1;
337     } else {
338       iprintln(4, "retSize = 1;");
339       iprint(4, "iret = ");
340     }
341
342     return 0;
343   }
344
345   static void printExecute (Class JavaDoc cls) {
346     Method[] mths = cls.getDeclaredMethods();
347
348     iprint(1, EXECUTE);
349     pw.println(" {");
350
351     iprintln(2, "int iret = 0;");
352     iprintln(2, "long lret = 0;");
353     iprintln(2, "int retSize = 0;");
354     iprintln(2, "String exception = null;");
355     iprintln(2, "int mid = mi.getUniqueName().hashCode();");
356     pw.println();
357
358     iprintln(2, "MJIEnv env = ti.getMJIEnv();");
359     iprintln(2,
360              "int rThis = (mi.isStatic()) ? ci.getClassObjectRef() : ti.getCalleeThis(mi);");
361     pw.println();
362
363     iprintln(2, "env.setCallEnvironment( mi);");
364     pw.println();
365
366     iprintln(2, "try {");
367
368     iprintln(3, "switch (mid) {");
369
370     for (int i = 0; i < mths.length; i++) {
371       Method m = mths[i];
372
373       if (isMJIExecuteCandidate(m)) {
374         printCaseConst(m);
375
376         int openFuncs = printExecCallProlog(m);
377         printCall(cls, m);
378
379         for (int j = 0; j < openFuncs; j++) {
380           pw.print(')');
381         }
382
383         pw.println(';');
384         iprintln(4, "break;");
385       }
386     }
387
388     iprintln(3, "default:");
389     iprintln(4,
390              "return ti.createAndThrowException( \"java.lang.UnsatisfiedLinkError\",");
391     iprintln(6, "\"cannot find: \" + ci.getName() + '.' + mi.getName());");
392
393     iprintln(3, "}");
394
395     iprintln(2, "} catch (Throwable x) {");
396     iprintln(3, "x.printStackTrace();");
397     iprintln(3,
398              "return ti.createAndThrowException( \"java.lang.reflect.InvocationTargetException\",");
399     iprintln(5, "ci.getName() + '.' + mi.getName());");
400     iprintln(2, "}");
401
402     pw.println();
403     iprintln(2, "if ((exception = env.getException()) != null) {");
404     iprintln(3, "return ti.createAndThrowException(exception);");
405     iprintln(2, "}");
406     pw.println();
407     iprintln(2, "if (env.getRepeat()) {");
408     iprintln(3, "return ti.getPC();");
409     iprintln(2, "}");
410     pw.println();
411     iprintln(2, "ti.removeArguments(mi);");
412     pw.println();
413     iprintln(2, "switch (retSize) {");
414     iprintln(2, "case 0: break; // nothing to return");
415     iprintln(2, "case 1: ti.push(iret, mi.isReferenceReturnType()); break;");
416     iprintln(2, "case 2: ti.longPush(lret); break;");
417     iprintln(2, "}");
418     pw.println();
419     iprintln(2, "return ti.getPC().getNext();");
420
421     iprintln(1, "}");
422   }
423
424   static void printFooter (Class JavaDoc cls) {
425     pw.println("}");
426   }
427
428   static void printHeader (Class JavaDoc cls) {
429     pw.print("package ");
430     pw.print(SYS_PKG);
431     pw.println(';');
432     pw.println();
433
434     String JavaDoc cname = cls.getName();
435     int idx = cname.lastIndexOf('.');
436
437     if (idx > 0) {
438       cname = cname.substring(idx + 1);
439     }
440
441     pw.println("import gov.nasa.jpf.JPFVMException;");
442     pw.println("import gov.nasa.jpf.jvm.bytecode.Instruction;");
443     pw.println();
444
445     pw.print("class ");
446     pw.print(cname);
447     pw.println("$ extends NativePeer {");
448   }
449
450   static void printIndent (int level) {
451     for (int i = 0; i < level; i++) {
452       pw.print(INDENT);
453     }
454   }
455
456   static void printIsCond (Class JavaDoc cls, String JavaDoc condPrefix) {
457     Method[] mths = cls.getDeclaredMethods();
458
459     iprint(1, condPrefix);
460     pw.println(" {");
461
462     iprintln(2, "boolean ret = false;");
463     iprintln(2, "int mid = mi.getUniqueName().hashCode();");
464     pw.println();
465
466     iprintln(2, "MJIEnv env = ti.getMJIEnv();");
467     iprintln(2,
468              "int rThis = (mi.isStatic()) ? ci.getClassObjectRef() : ti.getCalleeThis(mi);");
469     pw.println();
470
471     iprintln(2, "env.setCallEnvironment( mi);");
472     pw.println();
473
474     iprintln(2, "try {");
475
476     iprintln(3, "switch (mid) {");
477
478     for (int i = 0; i < mths.length; i++) {
479       Method m = mths[i];
480
481       if (((condPrefix == IS_COND_DETERMINISTIC) &&
482                 isMJIDetermCondCandidate(m)) ||
483               ((condPrefix == IS_COND_EXECUTABLE) &&
484                 isMJIExecCondCandidate(m))) {
485         printCaseConst(m);
486
487         iprint(4, "ret = ");
488         printCall(cls, m);
489         pw.println(';');
490       }
491     }
492
493     iprintln(3, "default:");
494
495     if (condPrefix == IS_COND_EXECUTABLE) {
496       iprintln(4,
497                "throw new JPFVMException(\"no isExecutable() condition: \" + mi.getName());");
498     } else {
499       iprintln(4,
500                "throw new JPFVMException(\"no isDeterministic() condition: \" + mi.getName());");
501     }
502
503     iprintln(3, "}");
504
505     iprintln(2, "} catch (Throwable x) {");
506     iprintln(3, "x.printStackTrace();");
507     iprintln(2, "}");
508     pw.println();
509
510     iprintln(2, "return ret;");
511     iprintln(1, "}");
512   }
513
514   static void printIsCondDeterministic (Class JavaDoc cls) {
515     printIsCond(cls, IS_COND_DETERMINISTIC);
516   }
517
518   static void printIsCondExecutable (Class JavaDoc cls) {
519     printIsCond(cls, IS_COND_EXECUTABLE);
520   }
521
522   static void printNativePeerDispatcher (Class JavaDoc cls) {
523     printHeader(cls);
524     pw.println();
525
526     printExecute(cls);
527     pw.println();
528     printIsCondDeterministic(cls);
529     pw.println();
530     printIsCondExecutable(cls);
531     pw.println();
532
533     printFooter(cls);
534   }
535
536   static boolean readOptions (String JavaDoc[] args) {
537     for (int i = 0; i < args.length; i++) {
538       String JavaDoc arg = args[i];
539
540       if (arg.charAt(0) == '-') {
541         System.err.println("unknown option: " + arg);
542         showUsage();
543
544         return false;
545       } else {
546         if (clsName == null) {
547           clsName = arg;
548         }
549       }
550     }
551
552     return (clsName != null);
553   }
554
555   static void showUsage () {
556     System.out.println("usage: 'GenPeerDispatcher <className>'");
557   }
558 }
Popular Tags