001: //
002: // Copyright (C) 2005 United States Government as represented by the
003: // Administrator of the National Aeronautics and Space Administration
004: // (NASA). All Rights Reserved.
005: //
006: // This software is distributed under the NASA Open Source Agreement
007: // (NOSA), version 1.3. The NOSA has been approved by the Open Source
008: // Initiative. See the file NOSA-1.3-JPF at the top of the distribution
009: // directory tree for the complete NOSA document.
010: //
011: // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
012: // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
013: // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
014: // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
015: // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
016: // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
017: // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
018: //
019: package gov.nasa.jpf.jvm;
020:
021: import gov.nasa.jpf.JPFException;
022:
023: import java.lang.reflect.Method;
024:
025: import org.apache.bcel.Constants;
026:
027: /**
028: * various type mangling/demangling routines
029: */
030: public class Types implements Constants {
031: public static byte[] getArgumentTypes(String signature) {
032: int i;
033: int j;
034: int nArgs;
035:
036: for (i = 1, nArgs = 0; signature.charAt(i) != ')'; nArgs++) {
037: i += getTypeLength(signature, i);
038: }
039:
040: byte[] args = new byte[nArgs];
041:
042: for (i = 1, j = 0; j < nArgs; j++) {
043: int end = i + getTypeLength(signature, i);
044: String arg = signature.substring(i, end);
045: i = end;
046:
047: args[j] = getBaseType(arg);
048: }
049:
050: return args;
051: }
052:
053: /**
054: * get size in stack slots (ints), excluding this
055: */
056: public static int getArgumentsSize(String signature) {
057: int i;
058: int n;
059: char c;
060:
061: for (i = 1, n = 0; (c = signature.charAt(i)) != ')'; n++) {
062: switch (c) {
063: case 'L':
064:
065: for (i++; signature.charAt(i) != ';'; i++) {
066: ;
067: }
068:
069: break;
070:
071: case '[':
072:
073: while ((c = signature.charAt(++i)) == '[') {
074: ;
075: }
076:
077: if (c == 'L') {
078: for (i++; signature.charAt(i) != ';'; i++) {
079: ;
080: }
081: }
082:
083: break;
084:
085: case 'J':
086: case 'D':
087:
088: // the two-slot types
089: n++;
090:
091: break;
092:
093: default:
094:
095: // just one slot entry
096: }
097:
098: i++;
099: }
100:
101: return n;
102: }
103:
104: public static String getArrayElementType(String type) {
105: if (type.charAt(0) != '[') {
106: throw new JPFException("not an array type");
107: }
108:
109: return type.substring(1);
110: }
111:
112: public static byte getBaseType(String type) {
113: switch (type.charAt(0)) {
114: case 'B':
115: return T_BYTE;
116:
117: case 'C':
118: return T_CHAR;
119:
120: case 'D':
121: return T_DOUBLE;
122:
123: case 'F':
124: return T_FLOAT;
125:
126: case 'I':
127: return T_INT;
128:
129: case 'J':
130: return T_LONG;
131:
132: case 'L':
133: return T_OBJECT; // T_REFERENCE is deprecated
134:
135: case 'S':
136: return T_SHORT;
137:
138: case 'V':
139: return T_VOID;
140:
141: case 'Z':
142: return T_BOOLEAN;
143:
144: case '[':
145: return T_ARRAY;
146: }
147:
148: throw new JPFException("invalid type string: " + type);
149: }
150:
151: /**
152: * get the argument type part of the signature out of a
153: * JNI mangled method name.
154: * Note this is not the complete signature, since we don't have a
155: * return type (which is superfluous since it's not overloading,
156: * but unfortunately part of the signature in the class file)
157: */
158: public static String getJNIArgSignature(String mangledName) {
159: int i = mangledName.indexOf("__");
160: String sig = null;
161:
162: if (i > 0) {
163: int len = mangledName.length();
164: char[] buf = new char[len + 1];
165: int j;
166: int k = 0;
167:
168: buf[k++] = '(';
169:
170: for (j = i + 2; j < len; j++) {
171: char c = mangledName.charAt(j);
172:
173: if (c == '_') {
174: j++;
175:
176: if (j < len) {
177: c = mangledName.charAt(j);
178:
179: switch (c) {
180: case '1':
181: buf[k++] = '_';
182:
183: break;
184:
185: case '2':
186: buf[k++] = ';';
187:
188: break;
189:
190: case '3':
191: buf[k++] = '[';
192:
193: break;
194:
195: default:
196: buf[k++] = '/';
197: buf[k++] = c;
198: }
199: } else {
200: buf[k++] = '/';
201: }
202: } else {
203: buf[k++] = c;
204: }
205: }
206:
207: buf[k++] = ')';
208: sig = new String(buf, 0, k);
209: }
210:
211: return sig;
212: }
213:
214: public static String getJNIMangledMethodName(Method m) {
215: String name = m.getName();
216: Class[] pt = m.getParameterTypes();
217: StringBuffer s = new StringBuffer(name.length()
218: + (pt.length * 16));
219:
220: s.append(name);
221: s.append("__");
222:
223: // <2do> not very efficient, but we don't care for now
224: for (int i = 0; i < pt.length; i++) {
225: s.append(getJNITypeCode(pt[i].getName()));
226: }
227:
228: return s.toString();
229: }
230:
231: public static String getJNIMangledMethodName(String cls,
232: String name, String signature) {
233: StringBuffer s = new StringBuffer(signature.length() + 10);
234: int i;
235: char c;
236:
237: if (cls != null) {
238: s.append(cls.replace('.', '_'));
239: }
240:
241: s.append(name);
242: s.append("__");
243:
244: // as defined in the JNI specs
245: for (i = 1; (c = signature.charAt(i)) != ')'; i++) {
246: switch (c) {
247: case '/':
248: s.append("_");
249:
250: break;
251:
252: case '_':
253: s.append("_1");
254:
255: break;
256:
257: case ';':
258: s.append("_2");
259:
260: break;
261:
262: case '[':
263: s.append("_3");
264:
265: break;
266:
267: default:
268: s.append(c);
269: }
270: }
271:
272: return s.toString();
273: }
274:
275: /**
276: * return the name part of a JNI mangled method name (which is of
277: * course not completely safe - you should only use it if you know
278: * this is a JNI name)
279: */
280: public static String getJNIMethodName(String mangledName) {
281: int i = mangledName.indexOf("__");
282:
283: if (i > 0) {
284: return mangledName.substring(0, i);
285: } else {
286: return mangledName;
287: }
288: }
289:
290: public static String getJNITypeCode(String type) {
291: StringBuffer sb = new StringBuffer(32);
292: int l = type.length() - 1;
293:
294: for (; type.charAt(l) == ']'; l -= 2) {
295: sb.append("_3");
296: }
297:
298: type = type.substring(0, l + 1);
299:
300: if (type.equals("int")) {
301: sb.append('I');
302: } else if (type.equals("long")) {
303: sb.append('J');
304: } else if (type.equals("boolean")) {
305: sb.append('Z');
306: } else if (type.equals("char")) {
307: sb.append('C');
308: } else if (type.equals("byte")) {
309: sb.append('B');
310: } else if (type.equals("short")) {
311: sb.append('S');
312: } else if (type.equals("double")) {
313: sb.append('D');
314: } else if (type.equals("float")) {
315: sb.append('F');
316: } else {
317: sb.append('L');
318:
319: for (int i = 0; i < type.length(); i++) {
320: char c = type.charAt(i);
321:
322: switch (c) {
323: case '.':
324: sb.append('_');
325:
326: break;
327:
328: case '_':
329: sb.append("_1");
330:
331: break;
332:
333: default:
334: sb.append(c);
335: }
336: }
337:
338: sb.append("_2");
339: }
340:
341: return sb.toString();
342: }
343:
344: public static int getNumberOfArguments(String signature) {
345: int i;
346: int n;
347: char c;
348:
349: for (i = 1, n = 0; (c = signature.charAt(i)) != ')'; n++) {
350: switch (c) {
351: case 'L':
352:
353: for (i++; signature.charAt(i) != ';'; i++) {
354: ;
355: }
356:
357: break;
358:
359: case '[':
360:
361: while ((c = signature.charAt(++i)) == '[') {
362: ;
363: }
364:
365: if (c == 'L') {
366: for (i++; signature.charAt(i) != ';'; i++) {
367: ;
368: }
369: }
370:
371: break;
372:
373: default:
374:
375: // just a single type char
376: }
377:
378: i++;
379: }
380:
381: return n;
382: }
383:
384: public static boolean isReference(String type) {
385: int t = getBaseType(type);
386:
387: return (t == T_ARRAY) || (t == T_REFERENCE);
388: }
389:
390: public static byte getReturnType(String signature) {
391: int i = signature.indexOf(')');
392:
393: return getBaseType(signature.substring(i + 1));
394: }
395:
396: public static String getTypeCode(String type) {
397: String t = null;
398: boolean isArray = type.endsWith("[]");
399:
400: if (isArray) {
401: type = type.substring(0, type.length() - 2);
402: }
403:
404: if (type.equals("byte")) {
405: t = "B";
406: } else if (type.equals("char")) {
407: t = "C";
408: } else if (type.equals("short")) {
409: t = "S";
410: } else if (type.equals("int")) {
411: t = "I";
412: } else if (type.equals("float")) {
413: t = "F";
414: } else if (type.equals("long")) {
415: t = "J";
416: } else if (type.equals("double")) {
417: t = "D";
418: } else if (type.equals("boolean")) {
419: t = "Z";
420: } else if (type.equals("void")) {
421: t = "V";
422: }
423:
424: if (t != null) {
425: if (isArray) {
426: t = "[" + t;
427: }
428: } else {
429: t = "L";
430:
431: if (isArray) {
432: t += '[';
433: }
434:
435: t += type.replace('.', '/');
436: t += ';';
437: }
438:
439: return t;
440: }
441:
442: public static boolean isTypeCode(String t) {
443: char c = t.charAt(0);
444:
445: if (c == '[') {
446: return true;
447: }
448:
449: if ((t.length() == 1)
450: && ((c == 'B') || (c == 'I') || (c == 'S')
451: || (c == 'C') || (c == 'F') || (c == 'J')
452: || (c == 'D') || (c == 'Z'))) {
453: return true;
454: }
455:
456: if (t.endsWith(";")) {
457: return true;
458: }
459:
460: return false;
461: }
462:
463: public static String getTypeName(String type) {
464: int len = type.length();
465: char c = type.charAt(0);
466:
467: if (len == 1) {
468: switch (c) {
469: case 'B':
470: return "byte";
471:
472: case 'C':
473: return "char";
474:
475: case 'D':
476: return "double";
477:
478: case 'F':
479: return "float";
480:
481: case 'I':
482: return "int";
483:
484: case 'J':
485: return "long";
486:
487: case 'S':
488: return "short";
489:
490: case 'V':
491: return "void";
492:
493: case 'Z':
494: return "boolean";
495: }
496: }
497:
498: if (c == '[') {
499: return getTypeName(type.substring(1)) + "[]";
500: }
501:
502: if (type.charAt(len - 1) == ';') {
503: return type.substring(1, type.indexOf(';')).replace('/',
504: '.');
505: }
506:
507: throw new JPFException("invalid type string: " + type);
508: }
509:
510: /**
511: * what would be the info size in bytes, not words
512: * (we ignore 64bit machines for now)
513: */
514: public static int getTypeSizeInBytes(String type) {
515: switch (type.charAt(0)) {
516: case 'V':
517: return 0;
518:
519: case 'Z': // that's a stretch, but we assume boolean uses the smallest addressable size
520: case 'B':
521: return 1;
522:
523: case 'S':
524: case 'C':
525: return 2;
526:
527: case 'L':
528: case '[':
529: case 'F':
530: case 'I':
531: return 4;
532:
533: case 'D':
534: case 'J':
535: return 8;
536: }
537:
538: throw new JPFException("invalid type string: " + type);
539: }
540:
541: public static int getTypeSize(String type) {
542: switch (type.charAt(0)) {
543: case 'V':
544: return 0;
545:
546: case 'B':
547: case 'C':
548: case 'F':
549: case 'I':
550: case 'L':
551: case 'S':
552: case 'Z':
553: case '[':
554: return 1;
555:
556: case 'D':
557: case 'J':
558: return 2;
559: }
560:
561: throw new JPFException("invalid type string: " + type);
562: }
563:
564: public static String asTypeName(String type) {
565: if (type.startsWith("[") || type.endsWith(";")) {
566: return getTypeName(type);
567: }
568:
569: return type;
570: }
571:
572: public static int booleanToInt(boolean b) {
573: return b ? 1 : 0;
574: }
575:
576: public static long doubleToLong(double d) {
577: return Double.doubleToLongBits(d);
578: }
579:
580: public static int floatToInt(float f) {
581: return Float.floatToIntBits(f);
582: }
583:
584: public static int hiDouble(double d) {
585: return hiLong(Double.doubleToLongBits(d));
586: }
587:
588: public static int hiLong(long l) {
589: return (int) (l >> 32);
590: }
591:
592: public static boolean instanceOf(String type, String ofType) {
593: int bType = getBaseType(type);
594:
595: if ((bType == T_ARRAY) && ofType.equals("Ljava/lang/Object;")) {
596: return true;
597: }
598:
599: int bOfType = getBaseType(ofType);
600:
601: if (bType != bOfType) {
602: return false;
603: }
604:
605: switch (bType) {
606: case T_ARRAY:
607: return instanceOf(type.substring(1), ofType.substring(1));
608:
609: case T_REFERENCE:
610: return ClassInfo.getClassInfo(getTypeName(type))
611: .instanceOf(getTypeName(ofType));
612:
613: default:
614: return true;
615: }
616: }
617:
618: public static boolean intToBoolean(int i) {
619: return i != 0;
620: }
621:
622: public static float intToFloat(int i) {
623: return Float.intBitsToFloat(i);
624: }
625:
626: public static double intsToDouble(int l, int h) {
627: return longToDouble(intsToLong(l, h));
628: }
629:
630: public static long intsToLong(int l, int h) {
631: return ((long) h << 32) | ((long) l & 0xFFFFFFFFL);
632: }
633:
634: public static int loDouble(double d) {
635: return loLong(Double.doubleToLongBits(d));
636: }
637:
638: public static int loLong(long l) {
639: return (int) (l & 0xFFFFFFFFL);
640: }
641:
642: public static double longToDouble(long l) {
643: return Double.longBitsToDouble(l);
644: }
645:
646: private static int getTypeLength(String signature, int idx) {
647: switch (signature.charAt(idx)) {
648: case 'B':
649: case 'C':
650: case 'D':
651: case 'F':
652: case 'I':
653: case 'J':
654: case 'S':
655: case 'V':
656: case 'Z':
657: return 1;
658:
659: case '[':
660: return 1 + getTypeLength(signature, idx + 1);
661:
662: case 'L':
663:
664: int semicolon = signature.indexOf(';', idx);
665:
666: if (semicolon == -1) {
667: throw new JPFException("invalid type signature: "
668: + signature);
669: }
670:
671: return semicolon - idx + 1;
672: }
673:
674: throw new JPFException("invalid type signature");
675: }
676: }
|