FIX: java.lang.Object should be java/lang/Object.
[jpf-core.git] / src / main / gov / nasa / jpf / vm / Types.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import gov.nasa.jpf.JPFException;
21
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24
25
26 /**
27  * various type mangling/demangling routines
28  *
29  * This reflects the general type id mess in Java. We support the following:
30  *
31  *  builtin type: byte - T_BOOLEAN and the like
32  *  type name: String - according to JLS 6.7 ("int", "x.Y[]")
33  *  type signature: String - like JNI ("I", "[Lx/Y;")
34  *  type classname: String - e.g. "int", "[I", "x.Y", "[Lx.Y;"
35  */
36 public class Types {
37
38   // these have the same values as the BCEL Constants since we don't want to break compiled code
39   public static final byte T_NONE      = 0; // illegal type
40   
41   public static final byte T_BOOLEAN   = 4;
42   public static final byte T_BYTE      = 8;
43   public static final byte T_CHAR      = 5;
44   public static final byte T_SHORT     = 9;
45   public static final byte T_INT       = 10;
46   public static final byte T_LONG      = 11;
47   public static final byte T_FLOAT     = 6;
48   public static final byte T_DOUBLE    = 7;
49   public static final byte T_REFERENCE = 14;
50   public static final byte T_ARRAY     = 13;  // <2do> do we need this in addition to T_REFERENCE?
51   public static final byte T_VOID      = 12;
52
53   
54   public static byte[] getArgumentTypes (String signature) {
55     int i;
56     int j;
57     int nArgs;
58
59     for (i = 1, nArgs = 0; signature.charAt(i) != ')'; nArgs++) {
60       i += getTypeLength(signature, i);
61     }
62
63     byte[] args = new byte[nArgs];
64
65     for (i = 1, j = 0; j < nArgs; j++) {
66       int    end = i + getTypeLength(signature, i);
67       String arg = signature.substring(i, end);
68       i = end;
69
70       args[j] = getBuiltinTypeFromSignature(arg);
71     }
72
73     return args;
74   }
75
76   public static String[] getArgumentTypeNames (String signature) {
77     int len = signature.length();
78
79     if ((len > 1) && (signature.charAt(1) == ')')) {
80       return new String[0]; // 'no args' shortcut
81     }
82     
83     ArrayList<String> a = new ArrayList<String>();
84
85     for (int i = 1; signature.charAt(i) != ')';) {
86       int end = i + getTypeLength(signature,i);
87       String arg = signature.substring(i, end);
88       i = end;
89
90       a.add(getTypeName(arg));
91     }
92
93     String[] typeNames = new String[a.size()];
94     a.toArray(typeNames);
95     
96     return typeNames;
97   }
98   
99   public static String dequalify (String typeName){
100     int idx = typeName.lastIndexOf('.');
101     if (idx > 0) {
102       return typeName.substring(idx + 1);
103     } else {
104       return typeName;
105     }    
106   }
107   
108   public static String getDequalifiedMethodSignature (String mName){
109     int idx = mName.indexOf('(');
110     String sig = mName.substring(idx);
111     
112     return mName.substring(0, idx) + getDequalifiedArgumentSignature(sig);
113   }
114   
115   public static String getDequalifiedArgumentSignature (String sig){
116     String[] argTypes = getArgumentTypeNames(sig);
117     StringBuilder sb = new StringBuilder();
118     sb.append('(');
119     for (int i=0; i<argTypes.length; i++){
120       if (i>0){
121         sb.append(',');
122       }
123       sb.append(dequalify(argTypes[i]));
124     }
125     sb.append(')');
126     return sb.toString();
127   }
128   
129   public static String getDequalifiedTypeName (String sig){
130     String tn = getTypeName(sig);
131     return dequalify(tn);
132   }
133   
134   public static String getArgumentSignature (String[] typeNames, boolean qualified){
135     StringBuilder sb = new StringBuilder();
136     sb.append('(');
137     for (int i=0; i<typeNames.length; i++){
138       if (i>0){
139         sb.append(',');
140       }
141       
142       String tn = getTypeName(typeNames[i]);
143       if (!qualified){
144         int idx = tn.lastIndexOf('.');
145         if (idx >0){
146           tn = tn.substring(idx+1);
147         }
148       }
149       
150       sb.append( tn);
151     }
152     sb.append(')');
153     return sb.toString();
154   }
155   
156   /**
157    * get size in stack slots (ints), excluding this
158    */
159   public static int getArgumentsSize (String sig) {
160     int  n = 0;
161     for (int i = 1; sig.charAt(i) != ')'; i++) {
162       switch (sig.charAt(i)) {
163       case 'L':
164         do i++; while (sig.charAt(i) != ';');
165         n++;
166         break;
167       case '[':
168         do i++; while (sig.charAt(i) == '[');
169         if (sig.charAt(i) == 'L') {
170           do i++; while (sig.charAt(i) != ';');
171         }
172         n++;
173         break;
174       case 'J':
175       case 'D':
176         // the two-slot types
177         n += 2;
178         break;
179       default:
180         // just one slot entry
181         n++;
182       }
183     }
184     return n;
185   }
186
187   public static String getArrayElementType (String type) {
188     if (type.charAt(0) != '[') {
189       throw new JPFException("not an array type: " + type);
190     }
191
192     return type.substring(1);
193   }
194
195   public static String getComponentTerminal (String type) {
196     if (type.charAt(0) != '[') {
197       throw new JPFException("not an array type: " + type);
198     }
199
200     if(isReferenceSignature(type)) {
201       return type.substring(type.indexOf('L') + 1 , type.indexOf(';'));
202     } else {
203       return type.substring(type.lastIndexOf('[') + 1);
204     }
205   }
206
207   public static byte getBuiltinTypeFromSignature (String signature) {
208     switch (signature.charAt(0)) {
209     case 'B':
210       return T_BYTE;
211
212     case 'C':
213       return T_CHAR;
214
215     case 'D':
216       return T_DOUBLE;
217
218     case 'F':
219       return T_FLOAT;
220
221     case 'I':
222       return T_INT;
223
224     case 'J':
225       return T_LONG;
226
227     case 'L':
228       return T_REFERENCE;
229
230     case 'S':
231       return T_SHORT;
232
233     case 'V':
234       return T_VOID;
235
236     case 'Z':
237       return T_BOOLEAN;
238
239     case '[':
240       return T_ARRAY;
241     }
242
243     throw new JPFException("invalid type string: " + signature);
244   }
245
246   /**
247    * get the argument type part of the signature out of a
248    * JNI mangled method name.
249    * Note this is not the complete signature, since we don't have a
250    * return type (which is superfluous since it's not overloading,
251    * but unfortunately part of the signature in the class file)
252    */
253   public static String getJNISignature (String mangledName) {
254     int    i = mangledName.indexOf("__");
255     String sig = null;
256
257     if (i > 0) {
258       int k = 0;      
259       int r = mangledName.indexOf("__", i+2); // maybe there is a return type part
260       boolean gotReturnType = false;
261       int len = mangledName.length();
262       char[] buf = new char[len + 2];
263
264       buf[k++] = '(';
265
266       for (i += 2; i < len; i++) {
267
268         if (i == r) { // here comes the return type part (that's not JNI, only MJI
269           if ((i + 2) < len) {
270             i++;
271             buf[k++] = ')';
272             gotReturnType = true;
273             continue;
274           } else {
275             break;
276           }
277         }
278         
279         char c = mangledName.charAt(i);
280         if (c == '_') {
281           i++;
282
283           if (i < len) {
284             c = mangledName.charAt(i);
285
286             switch (c) {
287             case '1':
288               buf[k++] = '_';
289
290               break;
291
292             case '2':
293               buf[k++] = ';';
294
295               break;
296
297             case '3':
298               buf[k++] = '[';
299
300               break;
301
302             default:
303               buf[k++] = '/';
304               buf[k++] = c;
305             }
306           } else {
307             buf[k++] = '/';
308           }
309         } else {
310           buf[k++] = c;
311         }
312       }
313
314       if (!gotReturnType) {
315         // if there was no return type spec, assume 'void'
316         buf[k++] = ')';
317         buf[k++] = 'V';
318       }
319         
320       sig = new String(buf, 0, k);
321     }
322
323     // Hmm, maybe we should return "()V" instead of null, but that seems a bit too assuming
324     return sig;
325   }
326
327   public static String getJNIMangledMethodName (Method m) {
328     String      name = m.getName();
329     Class<?>[]    pt = m.getParameterTypes();
330     StringBuilder  s = new StringBuilder(name.length() + (pt.length * 16));
331
332     s.append(name);
333     s.append("__");
334
335     // <2do> not very efficient, but we don't care for now
336     for (int i = 0; i < pt.length; i++) {
337       s.append(getJNITypeCode(pt[i].getName()));
338     }
339
340     // the return type part, which is not in JNI, but is required for
341     // handling covariant return types
342     Class<?> rt = m.getReturnType();
343     s.append("__");
344     s.append(getJNITypeCode(rt.getName()));
345     
346     return s.toString();
347   }
348
349   public static String getJNIMangledMethodName (String cls, String name,
350                                                 String signature) {
351     StringBuilder s = new StringBuilder(signature.length() + 10);
352     int           i;
353     char          c;
354     int           slen = signature.length();
355     
356     if (cls != null) {
357       s.append(cls.replace('.', '_'));
358     }
359
360     s.append(name);
361     s.append("__");
362
363     // as defined in the JNI specs
364     for (i = 1; i<slen; i++) {
365       c = signature.charAt(i);
366       switch (c) {
367       case '/':
368         s.append('_');
369         break;
370
371       case '_':
372         s.append("_1");
373         break;
374
375       case ';':
376         s.append("_2");
377         break;
378
379       case '[':
380         s.append("_3");
381         break;
382
383       case ')':
384         // the return type part - note this is not JNI, but saves us a lot of trouble with
385         // the covariant return types of Java 1.5        
386         s.append("__");
387         break;
388         
389       default:
390         s.append(c);
391       }
392     }
393
394     return s.toString();
395   }
396
397   /**
398    * return the name part of a JNI mangled method name (which is of
399    * course not completely safe - you should only use it if you know
400    * this is a JNI name)
401    */
402   public static String getJNIMethodName (String mangledName) {
403     // note that's the first '__' group, which marks the beginning of the arg types
404     int i = mangledName.indexOf("__");
405
406     if (i > 0) {
407       return mangledName.substring(0, i);
408     } else {
409       return mangledName;
410     }
411   }
412
413   /**
414    * type is supposed to be Class.getName conforming, i.e.
415    * 
416    * int    -> int
417    * int[]  -> [I
418    * String -> java/lang/String
419    * String[] -> [Ljava/lang/String;
420    * String[][] -> [[Ljava/lang/String;
421    * 
422    * <2do> this is really not very efficient
423    */
424   public static String getJNITypeCode (String type) {
425     StringBuilder sb = new StringBuilder(32);
426     int l = type.length() - 1;
427     int i;
428
429     // Class.getName arrays "[...type"
430     for ( i=0; type.charAt(i) == '['; i++){
431       sb.append("_3");
432     }
433     
434     // conventional arrays "type[]..."
435     for (; type.charAt(l) == ']'; l -= 2) {
436       sb.append("_3");
437     }
438
439     type = type.substring(i, l + 1);
440
441     if (type.equals("int") || type.equals("I")) {
442       sb.append('I');
443     } else if (type.equals("long") || type.equals("J")) {
444       sb.append('J');
445     } else if (type.equals("boolean") || type.equals("Z")) {
446       sb.append('Z');
447     } else if (type.equals("char") || type.equals("C")) {
448       sb.append('C');
449     } else if (type.equals("byte")  || type.equals("B")) {
450       sb.append('B');
451     } else if (type.equals("short") || type.equals("S")) {
452       sb.append('S');
453     } else if (type.equals("double") || type.equals("D")) {
454       sb.append('D');
455     } else if (type.equals("float") || type.equals("F")) {
456       sb.append('F');
457     } else if (type.equals("void") || type.equals("V")) {  // for return types
458       sb.append('V');
459     } else { // reference type
460       if (type.charAt(0) != 'L'){
461         sb.append('L');
462       }
463
464       l = type.length();
465       for (i=0; i < l; i++) {
466         char c = type.charAt(i);
467
468         switch (c) {
469         case '.':
470           sb.append('_');
471           break;
472
473         case '_':
474           sb.append("_1");
475           break;
476           
477         case ';':
478           break;
479           
480         default:
481           sb.append(c);
482         }
483       }
484
485       sb.append("_2");
486       
487     }
488
489     return sb.toString();
490   }
491
492   // this includes the return type part
493   public static int getNumberOfStackSlots (String signature, boolean isStatic) {
494     int nArgSlots = 0;
495     int n = isStatic ? 0 : 1;
496     int sigLen = signature.length();
497
498     for (int i = 1; i < sigLen; i++) {
499       switch (signature.charAt(i)) {
500       case ')' : // end of arg part, but there still might be a return type
501         nArgSlots = n;
502         n = 0;
503         break;
504       case 'L':   // reference = 1 slot
505         i = signature.indexOf(';', i);
506         n++;
507         break;
508       case '[':
509         do i++; while (signature.charAt(i) == '[');
510         if (signature.charAt(i) == 'L') {
511           i = signature.indexOf(';', i);
512         }
513         n++;
514         break;
515       case 'J':
516       case 'D':
517         n+=2;
518         break;
519       default:
520         n++;
521       }
522     }
523     
524     return Math.max(n, nArgSlots);
525   }
526   
527   public static int getNumberOfArguments (String signature) {
528     int  i,n;
529     int sigLen = signature.length();
530
531     for (i = 1, n = 0; i<sigLen; n++) {
532       switch (signature.charAt(i)) {
533       case ')' :
534         return n;
535       case 'L':
536         do i++; while (signature.charAt(i) != ';');
537         break;
538
539       case '[':
540         do i++; while (signature.charAt(i) == '[');
541         if (signature.charAt(i) == 'L') {
542           do i++; while (signature.charAt(i) != ';');
543         }
544         break;
545
546       default:
547         // just a single type char
548       }
549
550       i++;
551     }
552
553     assert (false) : "malformed signature: " + signature;
554     return n; // that would be a malformed signature
555   }
556
557   public static boolean isReferenceSignature(String signature){
558     return signature.charAt(signature.length()-1) == ';';
559   }
560
561   public static boolean isReference (String type) {
562     int t = getBuiltinTypeFromSignature(type);
563
564     return (t == T_ARRAY) || (t == T_REFERENCE);
565   }
566
567   public static boolean isArray (String type) {
568     int t = getBuiltinTypeFromSignature(type);
569
570     return (t == T_ARRAY);
571   }
572
573   public static byte getReturnBuiltinType (String signature) {
574     int i = signature.indexOf(')');
575
576     return getBuiltinTypeFromSignature(signature.substring(i + 1));
577   }
578
579   public static String getReturnTypeSignature(String signature){
580     int i = signature.indexOf(')');
581     return signature.substring(i + 1);
582   }
583
584   public static String getReturnTypeName (String signature){
585     int i = signature.indexOf(')');
586     return getTypeName(signature.substring(i+1));
587   }
588   
589   public static String getTypeSignature (String type, boolean asDotNotation) {
590     String  t = null;
591     int arrayDim = 0;
592     
593     type = asDotNotation ? type.replace('/', '.') : type.replace('.', '/');
594     
595     if ((type.charAt(0) == '[') || (type.endsWith(";"))) {  // [[[L...;
596       t = type;
597       
598     } else {
599       
600       while (type.endsWith("[]")) { // type[][][]
601         type = type.substring(0, type.length() - 2);
602         arrayDim++;
603       }
604       
605       if (type.equals("byte")) {
606         t = "B";
607       } else if (type.equals("char")) {
608         t = "C";
609       } else if (type.equals("short")) {
610         t = "S";
611       } else if (type.equals("int")) {
612         t = "I";
613       } else if (type.equals("float")) {
614         t = "F";
615       } else if (type.equals("long")) {
616         t = "J";
617       } else if (type.equals("double")) {
618         t = "D";
619       } else if (type.equals("boolean")) {
620         t = "Z";
621       } else if (type.equals("void")) {
622         t = "V";
623       } else if (type.endsWith(";")) {
624         t = type;
625         
626       } else {
627         t = "L" + type + ';';
628       }
629       
630       while (arrayDim-- > 0) {
631         t = "[" + t;
632       }
633     }
634
635     return t;
636   }
637
638   public static byte getBuiltinType(String typeName){
639       if (typeName.equals("byte")) {
640         return T_BYTE;
641       } else if (typeName.equals("char")) {
642         return T_CHAR;
643       } else if (typeName.equals("short")) {
644         return T_SHORT;
645       } else if (typeName.equals("int")) {
646         return T_INT;
647       } else if (typeName.equals("float")) {
648         return T_FLOAT;
649       } else if (typeName.equals("long")) {
650         return T_LONG;
651       } else if (typeName.equals("double")) {
652         return T_DOUBLE;
653       } else if (typeName.equals("boolean")) {
654         return T_BOOLEAN;
655       } else if (typeName.equals("void")) {
656         return T_VOID;
657       } else {
658         if (typeName.charAt(typeName.length()-1) == ']'){
659           return T_ARRAY;
660         } else {
661           return T_REFERENCE;
662         }
663       }
664   }
665
666   public static String getBoxedType (byte type) {
667           switch (type) {
668           case Types.T_BOOLEAN:
669                   return "Boolean";
670           case Types.T_BYTE:
671                   return "Byte";
672           case Types.T_CHAR:
673                   return "Character";
674           case Types.T_SHORT:
675                   return "Short";
676           case Types.T_INT:
677                   return "Integer";
678           case Types.T_LONG:
679                   return "Long";
680           case Types.T_FLOAT:
681                   return "Float";
682           case Types.T_DOUBLE:
683                   return "Double";
684           default:
685                   return null;
686           }
687   }
688   
689   public static byte getUnboxedType (String typeName){
690     if (typeName.startsWith("java.lang.")){
691       typeName = typeName.substring(10);
692       if (typeName.equals("Boolean")){
693         return T_BOOLEAN;
694       } else if (typeName.equals("Byte")){
695         return T_BYTE;
696       } else if (typeName.equals("Character")){
697         return T_CHAR;
698       } else if (typeName.equals("Short")){
699         return T_SHORT;
700       } else if (typeName.equals("Integer")){
701         return T_INT;
702       } else if (typeName.equals("Long")){
703         return T_LONG;
704       } else if (typeName.equals("Float")){
705         return T_FLOAT;
706       } else if (typeName.equals("Double")){
707         return T_DOUBLE;
708       }
709     }
710     
711     // everything else can't be a box type
712     if (typeName.charAt(0) == '[' || typeName.charAt(typeName.length()-1) == ']'){
713       return T_ARRAY;
714     } else {
715       return T_REFERENCE;
716     }
717   }
718   
719   public static String getClassNameFromSignature (String signature){
720     if (signature.charAt(signature.length()-1) == ';'){ // reference
721       return signature.replace('/', '.');
722
723     } else { // builtin
724       switch (signature.charAt(0)){
725         case 'Z': return "boolean";
726         case 'B': return "byte";
727         case 'C': return "char";
728         case 'S': return "short";
729         case 'I': return "int";
730         case 'J': return "long";
731         case 'F': return "float";
732         case 'D': return "double";
733         default:
734           throw new JPFException("illegal type signature: " + signature);
735       }
736     }
737   }
738
739   /**
740    * get the canonical representation of a type name, which happens to be
741    *  (1) the name of the builtin type (e.g. "int")
742    *  (2) the normal dot name for ordinary classes (e.g. "java.lang.String")
743    *  (3) the coded dot name for arrays (e.g. "[B", "[[C", or "[Ljava.lang.String;")
744    *  
745    * not sure if we need to support internal class names (which use '/'
746    * instead of '.' as separators
747    *  
748    * no idea what's the logic behind this, but let's implement it
749    */
750   public static String getClassNameFromTypeName (String typeName) {
751     typeName = typeName.replace('/','.');
752     int n = typeName.length()-1;
753     
754     if (typeName.charAt(0) == '['){ // the "[<type>" notation
755       if (typeName.charAt(1) == 'L'){
756         if (typeName.charAt(n) != ';'){
757           typeName = typeName + ';';
758         }
759       }
760       
761       return typeName;
762     }
763     
764     int i=typeName.indexOf('[');
765     if (i>0){ // the sort of "<type>[]"
766       StringBuilder sb = new StringBuilder();
767       sb.append('[');
768       for (int j=i; (j=typeName.indexOf('[',j+1)) >0;){
769         sb.append('[');
770       }
771       
772       typeName = typeName.substring(0,i);
773       if (isBasicType(typeName)){
774         sb.append( getTypeSignature(typeName, true));
775       } else {
776         sb.append('L');
777         sb.append(typeName);
778         sb.append(';');
779       }
780       
781       return sb.toString();
782     }
783     
784     if (typeName.charAt(n) == ';') {
785       return typeName.substring(1,n);
786     }
787     
788     return typeName;
789   }
790
791   
792   public static boolean isTypeCode (String t) {
793     char c = t.charAt(0);
794
795     if (c == '[') {
796       return true;
797     }
798
799     if ((t.length() == 1) &&
800             ((c == 'B') || (c == 'I') || (c == 'S') || (c == 'C') ||
801               (c == 'F') || (c == 'J') || (c == 'D') || (c == 'Z'))) {
802       return true;
803     }
804
805     if (t.endsWith(";")) {
806       return true;
807     }
808
809     return false;
810   }
811
812   public static boolean isBasicType (String typeName){
813     return ("boolean".equals(typeName) ||
814         "byte".equals(typeName) ||
815         "char".equals(typeName) ||
816         "int".equals(typeName) ||
817         "long".equals(typeName) ||
818         "double".equals(typeName) ||
819         "short".equals(typeName) ||
820         "float".equals(typeName));
821   }
822
823   public static byte getTypeCode (String signature){
824     char c = signature.charAt(0);
825
826     switch (c) {
827       case 'B':
828         return T_BYTE;
829
830       case 'C':
831         return T_CHAR;
832
833       case 'D':
834         return T_DOUBLE;
835
836       case 'F':
837         return T_FLOAT;
838
839       case 'I':
840         return T_INT;
841
842       case 'J':
843         return T_LONG;
844
845       case 'L':
846         return T_REFERENCE;
847
848       case 'S':
849         return T_SHORT;
850
851       case 'V':
852         return T_VOID;
853
854       case 'Z':
855         return T_BOOLEAN;
856
857       case '[':
858         return T_ARRAY;
859
860       default:
861         throw new JPFException("unknow typecode: " + signature);
862     }
863   }
864   
865   /**
866    * return the qualified signature name according to JLS 6.7 (e.g. "int", "x.Y[]")
867    */
868   public static String getTypeName (String signature) {
869     int  len = signature.length();
870     char c = signature.charAt(0);
871
872     if (len == 1) {
873       switch (c) {
874       case 'B':
875         return "byte";
876
877       case 'C':
878         return "char";
879
880       case 'D':
881         return "double";
882
883       case 'F':
884         return "float";
885
886       case 'I':
887         return "int";
888
889       case 'J':
890         return "long";
891
892       case 'S':
893         return "short";
894
895       case 'V':
896         return "void";
897
898       case 'Z':
899         return "boolean";
900       }
901     }
902
903     if (c == '[') {
904       return getTypeName(signature.substring(1)) + "[]";
905     }
906
907     int len1 = len-1;
908     if (signature.charAt(len1) == ';') {
909       return signature.substring(1, len1).replace('/', '.');
910     }
911
912     throw new JPFException("invalid type string: " + signature);
913   }
914
915   /** thoses are according to the arrayType codes of the newarray JVMS definition */
916   public static String getElementDescriptorOfType (int arrayType){
917     switch (arrayType){
918       case 4: return "Z";
919       case 5: return "C";
920       case 6: return "F";
921       case 7: return "D";
922       case 8: return "B";
923       case 9: return "S";
924       case 10: return "I";
925       case 11: return "J";
926     }
927     return null;
928   }
929
930   /**
931    * what would be the info size in bytes, not words
932    * (we ignore 64bit machines for now)
933    */
934   public static int getTypeSizeInBytes (String signature) {
935     switch (signature.charAt(0)) {
936       case 'V':
937         return 0;
938         
939       case 'Z': // that's a stretch, but we assume boolean uses the smallest addressable size
940       case 'B':
941         return 1;
942         
943       case 'S':
944       case 'C':
945         return 2;
946         
947       case 'L':
948       case '[':
949       case 'F':
950       case 'I':
951         return 4;
952         
953       case 'D':
954       case 'J':
955         return 8;
956     }
957
958     throw new JPFException("invalid type string: " + signature);
959   }
960   
961   public static int getTypeSize (String signature) {
962     switch (signature.charAt(0)) {
963     case 'V':
964       return 0;
965
966     case 'B':
967     case 'C':
968     case 'F':
969     case 'I':
970     case 'L':
971     case 'S':
972     case 'Z':
973     case '[':
974       return 1;
975
976     case 'D':
977     case 'J':
978       return 2;
979     }
980
981     throw new JPFException("invalid type string: " + signature);
982   }
983
984   public static int getTypeSize (byte typeCategory){
985     if (typeCategory == T_LONG || typeCategory == T_DOUBLE){
986       return 2;
987     } else {
988       return 1;
989     }
990   }
991   
992   public static String asTypeName (String type) {
993     if (type.startsWith("[") || type.endsWith(";")) {
994       return getTypeName(type);
995     }
996
997     return type;
998   }
999
1000   public static int booleanToInt (boolean b) {
1001     return b ? 1 : 0;
1002   }
1003
1004   public static long doubleToLong (double d) {
1005     return Double.doubleToLongBits(d);
1006   }
1007
1008   public static int floatToInt (float f) {
1009     return Float.floatToIntBits(f);
1010   }
1011
1012   public static int hiDouble (double d) {
1013     return hiLong(Double.doubleToLongBits(d));
1014   }
1015
1016   public static int hiLong (long l) {
1017     return (int) (l >> 32);
1018   }
1019
1020   public static boolean instanceOf (String type, String ofType) {
1021     int bType = getBuiltinTypeFromSignature(type);
1022
1023     if ((bType == T_ARRAY) && ofType.equals("Ljava/lang/Object;")) {
1024       return true;
1025     }
1026
1027     int bOfType = getBuiltinTypeFromSignature(ofType);
1028
1029     if (bType != bOfType) {
1030       return false;
1031     }
1032
1033     switch (bType) {
1034     case T_ARRAY:
1035       return instanceOf(type.substring(1), ofType.substring(1));
1036
1037     case T_REFERENCE:
1038       ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(getTypeName(type));
1039       return ci.isInstanceOf(getTypeName(ofType));
1040
1041     default:
1042       return true;
1043     }
1044   }
1045
1046   public static boolean intToBoolean (int i) {
1047     return i != 0;
1048   }
1049
1050   public static float intToFloat (int i) {
1051     return Float.intBitsToFloat(i);
1052   }
1053
1054   public static double intsToDouble (int l, int h) {
1055     long bits = ((long) h << 32) | (/*(long)*/ l & 0xFFFFFFFFL);
1056     return Double.longBitsToDouble(bits);
1057   }
1058
1059   public static long intsToLong (int l, int h) {
1060     return ((long) h << 32) | (/*(long)*/ l & 0xFFFFFFFFL);
1061   }
1062
1063   public static int loDouble (double d) {
1064     return loLong(Double.doubleToLongBits(d));
1065   }
1066
1067   public static int loLong (long l) {
1068     return (int) (l & 0xFFFFFFFFL);
1069   }
1070
1071   public static double longToDouble (long l) {
1072     return Double.longBitsToDouble(l);
1073   }
1074
1075   private static int getTypeLength (String signature, int idx) {
1076     switch (signature.charAt(idx)) {
1077     case 'B':
1078     case 'C':
1079     case 'D':
1080     case 'F':
1081     case 'I':
1082     case 'J':
1083     case 'S':
1084     case 'V':
1085     case 'Z':
1086       return 1;
1087
1088     case '[':
1089       return 1 + getTypeLength(signature, idx + 1);
1090
1091     case 'L':
1092
1093       int semicolon = signature.indexOf(';', idx);
1094
1095       if (semicolon == -1) {
1096         throw new JPFException("invalid type signature: " +
1097                                          signature);
1098       }
1099
1100       return semicolon - idx + 1;
1101     }
1102
1103     throw new JPFException("invalid type signature");
1104   }
1105
1106   /**
1107    * return the JPF internal representation of a method signature that is given
1108    * in dot-notation (like javap),
1109    *
1110    *  e.g.  "int foo(int[],java.lang.String)" -> "foo([ILjava/lang/String;)I"
1111    *
1112    */
1113   public static String getSignatureName (String methodDecl) {
1114
1115     StringBuffer sb = new StringBuffer(128);
1116     String retType = null;
1117
1118     int i = methodDecl.indexOf('(');
1119     if (i>0){
1120
1121       //--- name and return type
1122       String[] a = methodDecl.substring(0, i).split(" ");
1123       if (a.length > 0){
1124         sb.append(a[a.length-1]);
1125
1126         if (a.length > 1){
1127           retType = getTypeSignature(a[a.length-2], false);
1128         }
1129       }
1130
1131       //--- argument types
1132       int j = methodDecl.lastIndexOf(')');
1133       if (j > 0){
1134         sb.append('(');
1135         for (String type : methodDecl.substring(i+1,j).split(",")){
1136           if (!type.isEmpty()){
1137             type = type.trim();
1138             if (!type.isEmpty()){
1139               sb.append( getTypeSignature(type,false));
1140             }
1141           }
1142         }
1143         sb.append(')');
1144
1145         if (retType != null){
1146           sb.append(retType);
1147         }
1148
1149         return sb.toString();
1150       }
1151     }
1152
1153     throw new JPFException("invalid method declaration: " + methodDecl);
1154   }
1155   
1156 }