// // Copyright (C) 2006 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.tool; import java.io.PrintWriter; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import gov.nasa.jpf.vm.Types; /** * tool to automatically generate the framework of a native peer MJI class, * given it's model class. GenPeer collects all the native methods from the * model class, and creates the corresponding native peer methods */ public class GenPeer { static final String SYS_PKG = "gov.nasa.jpf.vm"; static final String MJI_ENV = "gov.nasa.jpf.vm.MJIEnv"; static final String NATIVEPEER = "gov.nasa.jpf.vm.NativePeer"; static final String INDENT = " "; static final String SUPERCLASS = "NativePeer"; static final String MJI_ANN = "@MJI"; static final String METHOD_PREFIX = "public"; static final String ENV_ARG = "MJIEnv env"; static final String OBJ_ARG = "int objRef"; static final String CLS_ARG = "int clsObjRef"; static final String REF_TYPE = "int"; static final String NULL = "MJIEnv.NULL"; static String clsName; static String[] mths; // our options static boolean isSystemPkg; static boolean allMethods; static boolean mangleNames; static boolean clinit; public static void main (String[] args) { if ((args.length == 0) || !readOptions(args)) { showUsage(); return; } PrintWriter pw = new PrintWriter(System.out, true); Class<?> cls = getClass(clsName); if (cls != null) { printNativePeer(cls, pw); } } static Class<?> getClass (String cname) { Class<?> clazz = null; try { clazz = Class.forName(cname); } catch (ClassNotFoundException cnfx) { System.err.println("target class not found: " + cname); } catch (Throwable x) { x.printStackTrace(); } return clazz; } static boolean isMJICandidate (Method m) { if (allMethods) { return true; } if (mths != null) { String name = m.getName(); for (int i = 0; i < mths.length; i++) { if (name.equals(mths[i])) { return true; } } } else { if ((m.getModifiers() & Modifier.NATIVE) != 0) { return true; } } return false; } static void getMangledName (Method m) { StringBuilder sb = new StringBuilder(50); sb.append(m.getName()); sb.append("__"); } static boolean isPrimitiveType (String t) { return ("int".equals(t) || "long".equals(t) || "boolean".equals(t) || "void".equals(t) || // not really, but useful for returnTypes "byte".equals(t) || "char".equals(t) || "short".equals(t) || "float".equals(t) || "double".equals(t)); } static void printClinit (PrintWriter pw) { pw.print(INDENT); pw.print(METHOD_PREFIX); pw.print(" void $clinit ("); pw.print(ENV_ARG); pw.print(", "); pw.print(CLS_ARG); pw.println(") {"); pw.print(INDENT); pw.println("}"); } static void printFooter (Class<?> cls, PrintWriter pw) { pw.println("}"); } static void printHeader (Class<?> cls, PrintWriter pw) { if (isSystemPkg) { pw.print("package "); pw.print(SYS_PKG); pw.println(';'); pw.println(); } pw.print("import "); pw.print(MJI_ENV); pw.println(";"); pw.print("import "); pw.print(NATIVEPEER); pw.println(";"); pw.println(); String cname = cls.getName().replace('.', '_'); pw.print("class "); pw.print("JPF_"); pw.print(cname); pw.print(" extends "); pw.print(SUPERCLASS); pw.println(" {"); } static void printMethodBody (String rt, String t, PrintWriter pw) { if (!"void".equals(rt)) { pw.print(INDENT); pw.print(INDENT); pw.print(rt); if ((rt == REF_TYPE) && (rt != t)) { pw.print(" r"); pw.print(t); pw.print(" = "); pw.print(NULL); pw.println(";"); pw.print(INDENT); pw.print(INDENT); pw.print("return r"); pw.print(t); pw.println(";"); } else { pw.print(" v = ("); pw.print(rt); pw.println(")0;"); pw.print(INDENT); pw.print(INDENT); pw.println("return v;"); } } } static void printMethodName (Method m, PrintWriter pw) { String name = null; if (mangleNames) { name = Types.getJNIMangledMethodName(m); } else { name = m.getName(); } pw.print(name); } static void printMJIAnnotation(PrintWriter pw) { pw.print(INDENT); pw.println(MJI_ANN); } static void printMethodStub (String condPrefix, Method m, PrintWriter pw) { String t = null; String rt; printMJIAnnotation(pw); pw.print(INDENT); pw.print(METHOD_PREFIX); pw.print(' '); if (condPrefix == null) { t = rt = stripType(m.getReturnType().getName()); if (!isPrimitiveType(rt)) { rt = REF_TYPE; } } else { rt = "boolean"; } pw.print(rt); pw.print(' '); if (condPrefix != null) { pw.print(condPrefix); } printMethodName(m, pw); pw.print(" ("); printStdArgs(m, pw); printTargetArgs(m, pw); pw.println(") {"); if (condPrefix == null) { printMethodBody(rt, stripType(null, t), pw); } else { pw.print(INDENT); pw.print(INDENT); pw.println("return true;"); } pw.print(INDENT); pw.println('}'); } static void printNativePeer (Class<?> cls, PrintWriter pw) { Method[] mths = cls.getDeclaredMethods(); printHeader(cls, pw); if (clinit) { printClinit(pw); } for (int i = 0; i < mths.length; i++) { Method m = mths[i]; if (isMJICandidate(m)) { pw.println(); printMethodStub(null, m, pw); } } printFooter(cls, pw); } static void printStdArgs (Method m, PrintWriter pw) { pw.print(ENV_ARG); pw.print(", "); if ((m.getModifiers() & Modifier.STATIC) != 0) { pw.print(CLS_ARG); } else { pw.print(OBJ_ARG); } } static void printTargetArgs (Method m, PrintWriter pw) { Class<?>[] pt = m.getParameterTypes(); for (int i = 0; i < pt.length; i++) { String t = stripType(pt[i].getName()); boolean isPrim = isPrimitiveType(t); pw.print(", "); if (isPrim) { pw.print(t); pw.print(" v"); pw.print(i); } else { pw.print(REF_TYPE); pw.print(" r"); pw.print(stripType(null, t)); pw.print(i); } } } static String[] readNames (String[] args, int i) { ArrayList<String> a = null; for (; (i < args.length) && (args[i].charAt(0) != '-'); i++) { if (a == null) { a = new ArrayList<String>(); } a.add(args[i]); } if (a != null) { String[] names = new String[a.size()]; a.toArray(names); return names; } return null; } static boolean readOptions (String[] args) { for (int i = 0; i < args.length; i++) { String arg = args[i]; if ("-s".equals(arg)) { isSystemPkg = true; } else if ("-m".equals(arg)) { mangleNames = true; } else if ("-a".equals(arg)) { allMethods = true; } else if ("-ci".equals(arg)) { clinit = true; } else if (arg.charAt(0) != '-') { // rather simple if (clsName == null) { clsName = arg; } else { mths = readNames(args, i); i += mths.length; } } else { System.err.println("unknown option: " + arg); showUsage(); return false; } } return (clsName != null); } static void showUsage () { System.out.println( "usage: 'GenPeer [<option>..] <className> [<method>..]'"); System.out.println("options: -s : system peer class (gov.nasa.jpf.vm)"); System.out.println(" -ci : create <clinit> MJI method"); System.out.println(" -m : create mangled method names"); System.out.println(" -a : create MJI methods for all target class methods"); } static String stripType (String s) { return stripType("java.lang", s); } static String stripType (String prefix, String s) { int i = s.lastIndexOf('.') + 1; int l = s.length() - 1; if (s.charAt(l) == ';') { s = s.substring(0, l); } if (prefix == null) { if (i == 0) { return s; } else { return s.substring(i); } } else { if (s.startsWith(prefix) && (prefix.length() + 1 == i)) { return s.substring(i); } else { return s; } } } }