1 cananian 1.1.2.1 // DefaultNameMap.java, created Tue Aug 10 17:47:50 1999 by cananian
  2 cananian 1.1.2.1 // Copyright (C) 1999 Felix S. Klock II <pnkfelix@mit.edu>
  3 cananian 1.1.2.1 // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1 package harpoon.Backend.Maps;
  5 cananian 1.1.2.1 
  6 cananian 1.1.2.1 import harpoon.ClassFile.HClass;
  7 cananian 1.1.2.1 import harpoon.ClassFile.HField;
  8 cananian 1.1.2.1 import harpoon.ClassFile.HMethod;
  9 cananian 1.1.2.1 import harpoon.Util.Util;
 10 cananian 1.1.2.1 
 11 cananian 1.1.2.1 /**
 12 cananian 1.1.2.1  * <code>DefaultNameMap</code> implements a
 13 cananian 1.1.2.1  * <A HREF="http://java.sun.com/products/jdk/1.2/docs/guide/jni/index.html"
 14 cananian 1.1.2.1  * >JNI</a>-compliant method name mangling, and class and field name mangling
 15 cananian 1.1.2.1  * "in the spirit of" the JNI.<p>
 16 cananian 1.1.2.1  * The resulting names are C-compliant; that is, they can be referenced
 17 cananian 1.1.2.1  * from native code written in C.
 18 cananian 1.1.2.1  *
 19 cananian 1.1.2.1  * @author  Felix S. Klock II <pnkfelix@mit.edu>
 20 cananian 1.1.2.1  * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 21 cananian 1.4      * @version $Id: DefaultNameMap.java,v 1.4 2002/04/10 03:03:02 cananian Exp $
 22 cananian 1.1.2.1  */
 23 cananian 1.1.2.1 public class DefaultNameMap extends NameMap {
 24 cananian 1.1.2.5     private final boolean prependUnderscore;
 25 cananian 1.1.2.5 
 26 cananian 1.1.2.4     private static final String member_prefix = "_Flex_";
 27 cananian 1.1.2.1     private static final String class_prefix = "_Class_";
 28 cananian 1.1.2.3     private static final String primitive_prefix = "_Primitive_";
 29 cananian 1.1.2.1     private static final String string_prefix = "_String_";
 30 cananian 1.1.2.1     private static final String suffix_sep = "_9"; // "$" is another option.
 31 cananian 1.1.2.1 
 32 cananian 1.1.2.5     /** Creates a <code>DefaultNameMap</code>.  If 
 33 cananian 1.1.2.5      *  <code>prependUnderscore</code> is <code>true</code>, then
 34 cananian 1.1.2.5      *  underscores are prepended to c function names.  Otherwise,
 35 cananian 1.1.2.5      *  the appear in the assembly output exactly as they do in C.
 36 cananian 1.1.2.5      */
 37 cananian 1.1.2.5     public DefaultNameMap(boolean prependUnderscore) {
 38 cananian 1.1.2.5         this.prependUnderscore = prependUnderscore;
 39 cananian 1.1.2.5     }
 40 cananian 1.1.2.5 
 41 cananian 1.1.2.5     /* Map C function names to assembly label strings. */
 42 cananian 1.1.2.5     public String c_function_name(String fn) {
 43 cananian 1.1.2.5         if (prependUnderscore) return "_"+fn; else return fn;
 44 cananian 1.1.2.5     }
 45 cananian 1.1.2.1 
 46 cananian 1.1.2.1     /** Mangle a method name. */
 47 cananian 1.1.2.1     public String mangle(HMethod hm, String suffix) {
 48 cananian 1.1.2.1         String desc = hm.getDescriptor();
 49 cananian 1.1.2.1         return member_prefix +
 50 cananian 1.1.2.1             encode(hm.getDeclaringClass().getName()) + "_" +
 51 cananian 1.1.2.1             encode(hm.getName()) + "__" +
 52 cananian 1.1.2.1             encode(desc.substring(1,desc.lastIndexOf(')'))) +
 53 cananian 1.1.2.1             (suffix==null?"":(suffix_sep+encode(suffix)));
 54 cananian 1.1.2.1     }
 55 cananian 1.1.2.1     /** Mangle a field name. */
 56 cananian 1.1.2.1     public String mangle(HField hf, String suffix) {
 57 cananian 1.1.2.1         // won't conflict with method names because of "__" in
 58 cananian 1.1.2.1         // method name (see above). A field "_" of class "foo" would
 59 cananian 1.1.2.1         // be manged as "foo__1", and since there are not type
 60 cananian 1.1.2.1         // descriptor strings starting with a number, this can
 61 cananian 1.1.2.1         // not be confused with a method named "foo".
 62 cananian 1.1.2.1         return member_prefix +
 63 cananian 1.1.2.1             encode(hf.getDeclaringClass().getName()) + "_" +
 64 cananian 1.1.2.1             encode(hf.getName()) +
 65 cananian 1.1.2.1             (suffix==null?"":(suffix_sep+encode(suffix)));
 66 cananian 1.1.2.1     }
 67 cananian 1.1.2.1     /** Mangle a class name. */
 68 cananian 1.1.2.1     public String mangle(HClass hc, String suffix) {
 69 cananian 1.1.2.3         String sufstr = (suffix==null?"":(suffix_sep+encode(suffix)));
 70 cananian 1.1.2.3         if (hc.isPrimitive())
 71 cananian 1.1.2.3             return primitive_prefix + hc.getName() + sufstr;
 72 cananian 1.1.2.3         else
 73 cananian 1.1.2.3             return class_prefix + encode(hc.getName()) + sufstr;
 74 cananian 1.1.2.1     }
 75 cananian 1.1.2.1 
 76 cananian 1.1.2.1     /** Mangle a string constant reference. */
 77 cananian 1.1.2.1     public String mangle(String string_constant, String suffix) {
 78 cananian 1.1.2.1         String base = string_prefix + toHex(string_constant.hashCode(), 8);
 79 cananian 1.1.2.1         String r = base;
 80 cananian 1.1.2.1         for (int i=0;
 81 cananian 1.1.2.1              strMap.containsKey(r) && !strMap.get(r).equals(string_constant);
 82 cananian 1.1.2.1              r = base + "x" + i++)
 83 cananian 1.1.2.1             /* do nothing */;
 84 cananian 1.3.2.1         assert !strMap.containsKey(r) ||
 85 cananian 1.3.2.1                     strMap.get(r).equals(string_constant);
 86 cananian 1.1.2.1         strMap.put(r, string_constant);
 87 cananian 1.1.2.1         return r + (suffix==null?"":(suffix_sep+encode(suffix)));
 88 cananian 1.1.2.1     }
 89 cananian 1.1.2.1     private final java.util.Map strMap = new java.util.HashMap();
 90 cananian 1.1.2.1     
 91 cananian 1.1.2.1     //----------------------------------------------------------
 92 cananian 1.1.2.1     /** Apply the JNI-standard unicode-to-C encoding. */
 93 cananian 1.1.2.1     private static String encode(String s) {
 94 cananian 1.1.2.1         StringBuffer sb = new StringBuffer();
 95 cananian 1.1.2.1         for(int i=0; i<s.length(); i++) {
 96 cananian 1.1.2.1             switch(s.charAt(i)) {
 97 cananian 1.1.2.1             case '.':
 98 cananian 1.1.2.1             case '/':
 99 cananian 1.1.2.1                 sb.append("_");
100 cananian 1.1.2.1                 break;
101 cananian 1.1.2.1             case '_':
102 cananian 1.1.2.1                 sb.append("_1");
103 cananian 1.1.2.1                 break;
104 cananian 1.1.2.1             case ';':
105 cananian 1.1.2.1                 sb.append("_2");
106 cananian 1.1.2.1                 break;
107 cananian 1.1.2.1             case '[':
108 cananian 1.1.2.1                 sb.append("_3");
109 cananian 1.1.2.2                 break;
110 cananian 1.1.2.1             default:
111 cananian 1.1.2.1                 if ((s.charAt(i) >= 'a' &&
112 cananian 1.1.2.1                      s.charAt(i) <= 'z') ||
113 cananian 1.1.2.1                     (s.charAt(i) >= 'A' &&
114 cananian 1.1.2.1                      s.charAt(i) <= 'Z') ||
115 cananian 1.1.2.1                     (s.charAt(i) >= '0' &&
116 cananian 1.1.2.1                      s.charAt(i) <= '9')) {
117 cananian 1.1.2.1                     sb.append(s.charAt(i));
118 cananian 1.1.2.1                 } else {
119 cananian 1.1.2.1                     sb.append("_0" + toHex(s.charAt(i), 4));
120 cananian 1.1.2.1                 }
121 cananian 1.1.2.2                 break;
122 cananian 1.1.2.1             }
123 cananian 1.1.2.1         }
124 cananian 1.1.2.1         return sb.toString();
125 cananian 1.1.2.1     }
126 cananian 1.1.2.1     /** Convert the integer <code>value</code> into a hexadecimal 
127 cananian 1.1.2.1      *  string with at least <code>num_digits</code> digits. */
128 cananian 1.1.2.1     private static String toHex(int value, int num_digits) {
129 cananian 1.1.2.1         String hexval= // javah puts all hex vals in lowercase.
130 cananian 1.1.2.1             Integer.toHexString(value).toLowerCase();
131 cananian 1.1.2.1         while(hexval.length()<num_digits) hexval="0"+hexval;
132 cananian 1.1.2.1         return hexval;
133 cananian 1.1.2.1     }
134 cananian 1.2     }