2 * Copyright (C) 2014, United States Government, as represented by the
3 * Administrator of the National Aeronautics and Space Administration.
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
10 * http://www.apache.org/licenses/LICENSE-2.0.
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.
18 package gov.nasa.jpf.vm;
20 import gov.nasa.jpf.JPFException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
27 * various type mangling/demangling routines
29 * This reflects the general type id mess in Java. We support the following:
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;"
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
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;
54 public static byte[] getArgumentTypes (String signature) {
59 for (i = 1, nArgs = 0; signature.charAt(i) != ')'; nArgs++) {
60 i += getTypeLength(signature, i);
63 byte[] args = new byte[nArgs];
65 for (i = 1, j = 0; j < nArgs; j++) {
66 int end = i + getTypeLength(signature, i);
67 String arg = signature.substring(i, end);
70 args[j] = getBuiltinTypeFromSignature(arg);
76 public static String[] getArgumentTypeNames (String signature) {
77 int len = signature.length();
79 if ((len > 1) && (signature.charAt(1) == ')')) {
80 return new String[0]; // 'no args' shortcut
83 ArrayList<String> a = new ArrayList<String>();
85 for (int i = 1; signature.charAt(i) != ')';) {
86 int end = i + getTypeLength(signature,i);
87 String arg = signature.substring(i, end);
90 a.add(getTypeName(arg));
93 String[] typeNames = new String[a.size()];
99 public static String dequalify (String typeName){
100 int idx = typeName.lastIndexOf('.');
102 return typeName.substring(idx + 1);
108 public static String getDequalifiedMethodSignature (String mName){
109 int idx = mName.indexOf('(');
110 String sig = mName.substring(idx);
112 return mName.substring(0, idx) + getDequalifiedArgumentSignature(sig);
115 public static String getDequalifiedArgumentSignature (String sig){
116 String[] argTypes = getArgumentTypeNames(sig);
117 StringBuilder sb = new StringBuilder();
119 for (int i=0; i<argTypes.length; i++){
123 sb.append(dequalify(argTypes[i]));
126 return sb.toString();
129 public static String getDequalifiedTypeName (String sig){
130 String tn = getTypeName(sig);
131 return dequalify(tn);
134 public static String getArgumentSignature (String[] typeNames, boolean qualified){
135 StringBuilder sb = new StringBuilder();
137 for (int i=0; i<typeNames.length; i++){
142 String tn = getTypeName(typeNames[i]);
144 int idx = tn.lastIndexOf('.');
146 tn = tn.substring(idx+1);
153 return sb.toString();
157 * get size in stack slots (ints), excluding this
159 public static int getArgumentsSize (String sig) {
161 for (int i = 1; sig.charAt(i) != ')'; i++) {
162 switch (sig.charAt(i)) {
164 do i++; while (sig.charAt(i) != ';');
168 do i++; while (sig.charAt(i) == '[');
169 if (sig.charAt(i) == 'L') {
170 do i++; while (sig.charAt(i) != ';');
176 // the two-slot types
180 // just one slot entry
187 public static String getArrayElementType (String type) {
188 if (type.charAt(0) != '[') {
189 throw new JPFException("not an array type: " + type);
192 return type.substring(1);
195 public static String getComponentTerminal (String type) {
196 if (type.charAt(0) != '[') {
197 throw new JPFException("not an array type: " + type);
200 if(isReferenceSignature(type)) {
201 return type.substring(type.indexOf('L') + 1 , type.indexOf(';'));
203 return type.substring(type.lastIndexOf('[') + 1);
207 public static byte getBuiltinTypeFromSignature (String signature) {
208 switch (signature.charAt(0)) {
243 throw new JPFException("invalid type string: " + signature);
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)
253 public static String getJNISignature (String mangledName) {
254 int i = mangledName.indexOf("__");
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];
266 for (i += 2; i < len; i++) {
268 if (i == r) { // here comes the return type part (that's not JNI, only MJI
272 gotReturnType = true;
279 char c = mangledName.charAt(i);
284 c = mangledName.charAt(i);
314 if (!gotReturnType) {
315 // if there was no return type spec, assume 'void'
320 sig = new String(buf, 0, k);
323 // Hmm, maybe we should return "()V" instead of null, but that seems a bit too assuming
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));
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()));
340 // the return type part, which is not in JNI, but is required for
341 // handling covariant return types
342 Class<?> rt = m.getReturnType();
344 s.append(getJNITypeCode(rt.getName()));
349 public static String getJNIMangledMethodName (String cls, String name,
351 StringBuilder s = new StringBuilder(signature.length() + 10);
354 int slen = signature.length();
357 s.append(cls.replace('.', '_'));
363 // as defined in the JNI specs
364 for (i = 1; i<slen; i++) {
365 c = signature.charAt(i);
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
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)
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("__");
407 return mangledName.substring(0, i);
414 * type is supposed to be Class.getName conforming, i.e.
418 * String -> java/lang/String
419 * String[] -> [Ljava/lang/String;
420 * String[][] -> [[Ljava/lang/String;
422 * <2do> this is really not very efficient
424 public static String getJNITypeCode (String type) {
425 StringBuilder sb = new StringBuilder(32);
426 int l = type.length() - 1;
429 // Class.getName arrays "[...type"
430 for ( i=0; type.charAt(i) == '['; i++){
434 // conventional arrays "type[]..."
435 for (; type.charAt(l) == ']'; l -= 2) {
439 type = type.substring(i, l + 1);
441 if (type.equals("int") || type.equals("I")) {
443 } else if (type.equals("long") || type.equals("J")) {
445 } else if (type.equals("boolean") || type.equals("Z")) {
447 } else if (type.equals("char") || type.equals("C")) {
449 } else if (type.equals("byte") || type.equals("B")) {
451 } else if (type.equals("short") || type.equals("S")) {
453 } else if (type.equals("double") || type.equals("D")) {
455 } else if (type.equals("float") || type.equals("F")) {
457 } else if (type.equals("void") || type.equals("V")) { // for return types
459 } else { // reference type
460 if (type.charAt(0) != 'L'){
465 for (i=0; i < l; i++) {
466 char c = type.charAt(i);
489 return sb.toString();
492 // this includes the return type part
493 public static int getNumberOfStackSlots (String signature, boolean isStatic) {
495 int n = isStatic ? 0 : 1;
496 int sigLen = signature.length();
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
504 case 'L': // reference = 1 slot
505 i = signature.indexOf(';', i);
509 do i++; while (signature.charAt(i) == '[');
510 if (signature.charAt(i) == 'L') {
511 i = signature.indexOf(';', i);
524 return Math.max(n, nArgSlots);
527 public static int getNumberOfArguments (String signature) {
529 int sigLen = signature.length();
531 for (i = 1, n = 0; i<sigLen; n++) {
532 switch (signature.charAt(i)) {
536 do i++; while (signature.charAt(i) != ';');
540 do i++; while (signature.charAt(i) == '[');
541 if (signature.charAt(i) == 'L') {
542 do i++; while (signature.charAt(i) != ';');
547 // just a single type char
553 assert (false) : "malformed signature: " + signature;
554 return n; // that would be a malformed signature
557 public static boolean isReferenceSignature(String signature){
558 return signature.charAt(signature.length()-1) == ';';
561 public static boolean isReference (String type) {
562 int t = getBuiltinTypeFromSignature(type);
564 return (t == T_ARRAY) || (t == T_REFERENCE);
567 public static boolean isArray (String type) {
568 int t = getBuiltinTypeFromSignature(type);
570 return (t == T_ARRAY);
573 public static byte getReturnBuiltinType (String signature) {
574 int i = signature.indexOf(')');
576 return getBuiltinTypeFromSignature(signature.substring(i + 1));
579 public static String getReturnTypeSignature(String signature){
580 int i = signature.indexOf(')');
581 return signature.substring(i + 1);
584 public static String getReturnTypeName (String signature){
585 int i = signature.indexOf(')');
586 return getTypeName(signature.substring(i+1));
589 public static String getTypeSignature (String type, boolean asDotNotation) {
593 type = asDotNotation ? type.replace('/', '.') : type.replace('.', '/');
595 if ((type.charAt(0) == '[') || (type.endsWith(";"))) { // [[[L...;
600 while (type.endsWith("[]")) { // type[][][]
601 type = type.substring(0, type.length() - 2);
605 if (type.equals("byte")) {
607 } else if (type.equals("char")) {
609 } else if (type.equals("short")) {
611 } else if (type.equals("int")) {
613 } else if (type.equals("float")) {
615 } else if (type.equals("long")) {
617 } else if (type.equals("double")) {
619 } else if (type.equals("boolean")) {
621 } else if (type.equals("void")) {
623 } else if (type.endsWith(";")) {
627 t = "L" + type + ';';
630 while (arrayDim-- > 0) {
638 public static byte getBuiltinType(String typeName){
639 if (typeName.equals("byte")) {
641 } else if (typeName.equals("char")) {
643 } else if (typeName.equals("short")) {
645 } else if (typeName.equals("int")) {
647 } else if (typeName.equals("float")) {
649 } else if (typeName.equals("long")) {
651 } else if (typeName.equals("double")) {
653 } else if (typeName.equals("boolean")) {
655 } else if (typeName.equals("void")) {
658 if (typeName.charAt(typeName.length()-1) == ']'){
666 public static String getBoxedType (byte type) {
668 case Types.T_BOOLEAN:
689 public static byte getUnboxedType (String typeName){
690 if (typeName.startsWith("java.lang.")){
691 typeName = typeName.substring(10);
692 if (typeName.equals("Boolean")){
694 } else if (typeName.equals("Byte")){
696 } else if (typeName.equals("Character")){
698 } else if (typeName.equals("Short")){
700 } else if (typeName.equals("Integer")){
702 } else if (typeName.equals("Long")){
704 } else if (typeName.equals("Float")){
706 } else if (typeName.equals("Double")){
711 // everything else can't be a box type
712 if (typeName.charAt(0) == '[' || typeName.charAt(typeName.length()-1) == ']'){
719 public static String getClassNameFromSignature (String signature){
720 if (signature.charAt(signature.length()-1) == ';'){ // reference
721 return signature.replace('/', '.');
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";
734 throw new JPFException("illegal type signature: " + signature);
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;")
745 * not sure if we need to support internal class names (which use '/'
746 * instead of '.' as separators
748 * no idea what's the logic behind this, but let's implement it
750 public static String getClassNameFromTypeName (String typeName) {
751 typeName = typeName.replace('/','.');
752 int n = typeName.length()-1;
754 if (typeName.charAt(0) == '['){ // the "[<type>" notation
755 if (typeName.charAt(1) == 'L'){
756 if (typeName.charAt(n) != ';'){
757 typeName = typeName + ';';
764 int i=typeName.indexOf('[');
765 if (i>0){ // the sort of "<type>[]"
766 StringBuilder sb = new StringBuilder();
768 for (int j=i; (j=typeName.indexOf('[',j+1)) >0;){
772 typeName = typeName.substring(0,i);
773 if (isBasicType(typeName)){
774 sb.append( getTypeSignature(typeName, true));
781 return sb.toString();
784 if (typeName.charAt(n) == ';') {
785 return typeName.substring(1,n);
792 public static boolean isTypeCode (String t) {
793 char c = t.charAt(0);
799 if ((t.length() == 1) &&
800 ((c == 'B') || (c == 'I') || (c == 'S') || (c == 'C') ||
801 (c == 'F') || (c == 'J') || (c == 'D') || (c == 'Z'))) {
805 if (t.endsWith(";")) {
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));
823 public static byte getTypeCode (String signature){
824 char c = signature.charAt(0);
861 throw new JPFException("unknow typecode: " + signature);
866 * return the qualified signature name according to JLS 6.7 (e.g. "int", "x.Y[]")
868 public static String getTypeName (String signature) {
869 int len = signature.length();
870 char c = signature.charAt(0);
904 return getTypeName(signature.substring(1)) + "[]";
908 if (signature.charAt(len1) == ';') {
909 return signature.substring(1, len1).replace('/', '.');
912 throw new JPFException("invalid type string: " + signature);
915 /** thoses are according to the arrayType codes of the newarray JVMS definition */
916 public static String getElementDescriptorOfType (int arrayType){
931 * what would be the info size in bytes, not words
932 * (we ignore 64bit machines for now)
934 public static int getTypeSizeInBytes (String signature) {
935 switch (signature.charAt(0)) {
939 case 'Z': // that's a stretch, but we assume boolean uses the smallest addressable size
958 throw new JPFException("invalid type string: " + signature);
961 public static int getTypeSize (String signature) {
962 switch (signature.charAt(0)) {
981 throw new JPFException("invalid type string: " + signature);
984 public static int getTypeSize (byte typeCategory){
985 if (typeCategory == T_LONG || typeCategory == T_DOUBLE){
992 public static String asTypeName (String type) {
993 if (type.startsWith("[") || type.endsWith(";")) {
994 return getTypeName(type);
1000 public static int booleanToInt (boolean b) {
1004 public static long doubleToLong (double d) {
1005 return Double.doubleToLongBits(d);
1008 public static int floatToInt (float f) {
1009 return Float.floatToIntBits(f);
1012 public static int hiDouble (double d) {
1013 return hiLong(Double.doubleToLongBits(d));
1016 public static int hiLong (long l) {
1017 return (int) (l >> 32);
1020 public static boolean instanceOf (String type, String ofType) {
1021 int bType = getBuiltinTypeFromSignature(type);
1023 if ((bType == T_ARRAY) && ofType.equals("Ljava/lang/Object;")) {
1027 int bOfType = getBuiltinTypeFromSignature(ofType);
1029 if (bType != bOfType) {
1035 return instanceOf(type.substring(1), ofType.substring(1));
1038 ClassInfo ci = ClassLoaderInfo.getCurrentResolvedClassInfo(getTypeName(type));
1039 return ci.isInstanceOf(getTypeName(ofType));
1046 public static boolean intToBoolean (int i) {
1050 public static float intToFloat (int i) {
1051 return Float.intBitsToFloat(i);
1054 public static double intsToDouble (int l, int h) {
1055 long bits = ((long) h << 32) | (/*(long)*/ l & 0xFFFFFFFFL);
1056 return Double.longBitsToDouble(bits);
1059 public static long intsToLong (int l, int h) {
1060 return ((long) h << 32) | (/*(long)*/ l & 0xFFFFFFFFL);
1063 public static int loDouble (double d) {
1064 return loLong(Double.doubleToLongBits(d));
1067 public static int loLong (long l) {
1068 return (int) (l & 0xFFFFFFFFL);
1071 public static double longToDouble (long l) {
1072 return Double.longBitsToDouble(l);
1075 private static int getTypeLength (String signature, int idx) {
1076 switch (signature.charAt(idx)) {
1089 return 1 + getTypeLength(signature, idx + 1);
1093 int semicolon = signature.indexOf(';', idx);
1095 if (semicolon == -1) {
1096 throw new JPFException("invalid type signature: " +
1100 return semicolon - idx + 1;
1103 throw new JPFException("invalid type signature");
1107 * return the JPF internal representation of a method signature that is given
1108 * in dot-notation (like javap),
1110 * e.g. "int foo(int[],java.lang.String)" -> "foo([ILjava/lang/String;)I"
1113 public static String getSignatureName (String methodDecl) {
1115 StringBuffer sb = new StringBuffer(128);
1116 String retType = null;
1118 int i = methodDecl.indexOf('(');
1121 //--- name and return type
1122 String[] a = methodDecl.substring(0, i).split(" ");
1124 sb.append(a[a.length-1]);
1127 retType = getTypeSignature(a[a.length-2], false);
1131 //--- argument types
1132 int j = methodDecl.lastIndexOf(')');
1135 for (String type : methodDecl.substring(i+1,j).split(",")){
1136 if (!type.isEmpty()){
1138 if (!type.isEmpty()){
1139 sb.append( getTypeSignature(type,false));
1145 if (retType != null){
1149 return sb.toString();
1153 throw new JPFException("invalid method declaration: " + methodDecl);