PageRenderTime 33ms CodeModel.GetById 2ms app.highlight 27ms RepoModel.GetById 1ms app.codeStats 0ms

/src/kilim/analysis/TypeDesc.java

http://github.com/kilim/kilim
Java | 281 lines | 228 code | 29 blank | 24 comment | 88 complexity | 3636c535186d18134dac91b706bcf7a8 MD5 | raw file
  1/* Copyright (c) 2006, Sriram Srinivasan
  2 *
  3 * You may distribute this software under the terms of the license 
  4 * specified in the file "License"
  5 */
  6
  7package kilim.analysis;
  8
  9import static kilim.Constants.D_BOOLEAN;
 10import static kilim.Constants.D_BYTE;
 11import static kilim.Constants.D_CHAR;
 12import static kilim.Constants.D_DOUBLE;
 13import static kilim.Constants.D_FLOAT;
 14import static kilim.Constants.D_INT;
 15import static kilim.Constants.D_LONG;
 16import static kilim.Constants.D_NULL;
 17import static kilim.Constants.D_OBJECT;
 18import static kilim.Constants.D_SHORT;
 19import static kilim.Constants.D_STRING;
 20import static kilim.Constants.D_UNDEFINED;
 21
 22import java.lang.reflect.Field;
 23import java.util.HashMap;
 24
 25import kilim.Constants;
 26import kilim.mirrors.ClassMirrorNotFoundException;
 27import kilim.mirrors.Detector;
 28
 29import org.objectweb.asm.Type;
 30
 31/**
 32 * A utility class that provides static methods for interning type strings and merging type
 33 * descriptors.
 34 * 
 35 */
 36public class TypeDesc {
 37    static final HashMap<String, String> knownTypes = new HashMap<String, String>(30);
 38
 39    static {
 40        Field[] fields = Constants.class.getFields();
 41        try {
 42            for (int i = 0; i < fields.length; i++) {
 43                Field f = fields[i];
 44                if (f.getName().startsWith("D_")) {
 45                    String val = (String) f.get(null);
 46                    knownTypes.put(val, val);
 47                }
 48            }
 49        } catch (IllegalAccessException iae) {
 50            iae.printStackTrace();
 51        }
 52        knownTypes.put("java/lang/Object", D_OBJECT);
 53        knownTypes.put("java/lang/String", D_STRING);
 54    }
 55
 56    static boolean isDoubleWord(String desc) {
 57        return (desc == D_DOUBLE || desc == D_LONG);
 58    }
 59
 60    public static String getInterned(String desc) {
 61        String ret = knownTypes.get(desc);
 62        if (ret == null) {
 63            switch (desc.charAt(0)) {
 64            case 'L':
 65            case '[':
 66                return desc;
 67            default:
 68                return "L" + desc + ';';
 69            }
 70        } else {
 71            return ret;
 72        }
 73    }
 74
 75    public static String getReturnTypeDesc(String desc) {
 76        return getInterned(desc.substring(desc.indexOf(")") + 1));
 77    }
 78
 79    static boolean isSingleWord(String desc) {
 80        return !isDoubleWord(desc);
 81    }
 82
 83    public static String getComponentType(String t) {
 84        if (t.charAt(0) != '[') {
 85            throw new InternalError("Can't get component type of " + t);
 86        }
 87        return getInterned(t.substring(1));
 88    }
 89
 90    public static String getTypeDesc(Object object) {
 91        if (object instanceof Integer)
 92            return D_INT;
 93        if (object instanceof Long)
 94            return D_LONG;
 95        if (object instanceof Float)
 96            return D_FLOAT;
 97        if (object instanceof Double)
 98            return D_DOUBLE;
 99        if (object instanceof String)
100            return D_STRING;
101        if (object instanceof Boolean)
102            return D_BOOLEAN;
103        if (object instanceof Type)
104            return TypeDesc.getInterned(((Type) object).getDescriptor());
105        throw new InternalError("Unrecognized ldc constant: " + object);
106    }
107
108    private static int typelen(char[] buf, int off) {
109        int start = off;
110        switch (buf[off]) {
111        case 'L':
112            while (buf[off++] != ';') {}
113            return off - start;
114        case 'B':
115        case 'C':
116        case 'D':
117        case 'F':
118        case 'I':
119        case 'J':
120        case 'S':
121        case 'Z':
122        case 'V':
123            return 1;
124        case '[':
125            return typelen(buf, off + 1) + 1;
126        default:
127            throw new InternalError("Unknown descriptor type: " + buf[0]);
128        }
129    }
130
131    public static String[] getArgumentTypes(String methodDescriptor) {
132        char[] buf = methodDescriptor.toCharArray();
133        int size = getNumArgumentTypes(buf);
134        String[] args = new String[size];
135        size = 0;
136        int off = 1;
137        while (buf[off] != ')') {
138            int len = typelen(buf, off);
139            args[size] = getInterned(new String(buf, off, len));
140            off += len;
141            size += 1;
142        }
143        return args;
144    }
145
146    public static int getNumArgumentTypes(String desc) {
147        return getNumArgumentTypes(desc.toCharArray());
148    }
149
150    public static int getNumArgumentTypes(char[] buf) {
151        int off = 1;
152        int size = 0;
153        while (true) {
154            if (buf[off] == ')') {
155                break;
156            }
157            off += typelen(buf, off);
158            size++;
159        }
160        return size;
161    }
162
163    /**
164     * Given two type descriptors, it returns an appropriate merge: 1) If they are Array types, the
165     * result is a an array of the merged component types 2) If they are ref types, it returns the
166     * least common super type. If one of them is an interface, the result is D_OBJECT 3) All other
167     * types must match exactly in order to not raise an error.
168     */
169    public static String mergeType(Detector det,String a, String b) throws IncompatibleTypesException {
170        // given: a and b are different.
171        if (a == D_UNDEFINED)
172            return b;
173        if (b == D_UNDEFINED)
174            return a;
175        char ac = a.charAt(0);
176        char bc = b.charAt(0);
177        if (a == D_NULL) {
178            assert b == D_NULL || bc == 'L' || bc == '[' : "merging NULL type with non ref type: "
179                    + b;
180            return b;
181        }
182        if (b == D_NULL) {
183            assert b == D_NULL || bc == 'L' || bc == '[' : "merging NULL type with non ref type: "
184                    + a;
185            return a;
186        }
187        if (a == b || a.equals(b))
188            return a;
189        switch (ac) {
190        case 'N': // D_NULL
191            if (bc == 'L')
192                return b;
193            break;
194        case 'L':
195            if (bc == 'L') {
196                return commonSuperType(det,a, b);
197            } else if (bc == 'N') {
198                return a;
199            } else if (bc == '[') {
200                return D_OBJECT; // common supertype of Ref and ArrayRef
201            }
202            break;
203        case '[':
204            if (bc == '[') {
205                try {
206                    return "["
207                            + mergeType(det, TypeDesc.getComponentType(a), TypeDesc.getComponentType(b));
208                } catch (IncompatibleTypesException ite) {
209                    // The component types are incompatible, but two disparate arrays still
210                    // inherit from Object
211                    return D_OBJECT;
212                }
213            } else if (bc == 'L') {
214                return D_OBJECT; // common supertype of Ref and ArrayRef
215            }
216            break;
217        case 'I':
218        case 'Z':
219        case 'B':
220        case 'C':
221        case 'S':
222            // all int types are interchangeable
223            switch (bc) {
224            case 'I':
225            case 'Z':
226            case 'B':
227            case 'C':
228            case 'S':
229                return D_INT;
230            }
231            break;
232        }
233        throw new IncompatibleTypesException("" + a + "," + b);
234    }
235
236    static String JAVA_LANG_OBJECT = "java.lang.Object";
237
238
239    // public for testing purposes
240    public static String commonSuperType(Detector det,String oa, String ob) {
241        try {
242            if (oa == D_OBJECT || ob == D_OBJECT)
243                return D_OBJECT;
244            if (oa.equals(ob))
245                return oa;
246
247            String lub = det.commonSuperType(getInternalName(oa),getInternalName(ob));
248
249            if (lub.equals("java/lang/Object"))
250            	return D_OBJECT;
251            return "L" + lub + ";";
252
253        } catch (ClassMirrorNotFoundException cnfe) {
254            throw new InternalError(cnfe.getMessage());
255        }
256    }
257
258    public static boolean isIntType(String typeDesc) {
259        return (typeDesc == D_INT || typeDesc == D_CHAR || typeDesc == D_SHORT
260                || typeDesc == D_BYTE || typeDesc == D_BOOLEAN);
261    }
262
263    public static boolean isRefType(String typeDesc) {
264        char c = typeDesc.charAt(0);
265        return typeDesc == D_NULL || c == '[' || c == 'L';
266    }
267
268    public static String getInternalName(String desc) {
269        if (desc.charAt(0) == 'L') {
270            return desc.substring(1, desc.length() - 1);
271        } else {
272            assert desc.charAt(0) == '[' : "Unexpected internal name " + desc;
273            return desc;
274        }
275    }
276
277    // public static void main(String[] args) throws Exception {
278    // System.out.println(mergeType("Lkilim/test/ex/ExC;", "Lkilim/test/ex/ExD;"));
279    // }
280
281}