1 30 31 45 46 package jbet; 47 import java.util.*; 48 49 public final class Type { 50 public static final int VM_INT = 1; 51 public static final int VM_ADDRESS = 2; 52 public static final int VM_FLOAT = 3; 53 public static final int VM_LONG = 4; 54 public static final int VM_DOUBLE = 5; 55 public static final int VM_RETADDR = 6; 56 57 public char base; public int arraydepth = 0; public String cname = null; public Object extra = null; 62 Instruction target() { return (Instruction) extra; } 63 Instruction setTarget(Instruction i) { 64 return (Instruction)( extra = i ); 65 } 66 67 public static final Type VOID = new Type ('V'); 68 public static final Type INT = new Type ('I'); 69 public static final Type BOOLEAN = new Type ('Z'); 70 public static final Type BYTE = new Type ('B'); 71 public static final Type CHAR = new Type ('C'); 72 public static final Type SHORT = new Type ('S'); 73 public static final Type FLOAT = new Type ('F'); 74 public static final Type LONG = new Type ('J'); 75 public static final Type DOUBLE = new Type ('D'); 76 public static final Type RETADDR = new Type ('R'); 77 public static final Type DASH = new Type ('-'); public static final Type NULL = new Type ('N'); 79 public static final Type ARRAY = new Type ('-', 1); public static final Type SHORTARRAY = newType ("[S"); 81 public static final Type CHARARRAY = newType ("[C"); 82 public static final Type INTARRAY = newType ("[I"); 83 public static final Type BOOLARRAY = newType ("[Z"); 84 public static final Type BYTEARRAY = newType ("[B"); 85 public static final Type DOUBLEARRAY = newType ("[D"); 86 public static final Type FLOATARRAY = newType ("[F"); 87 public static final Type LONGARRAY = newType ("[J"); 88 public static final Type STRING = newType ("Ljava/lang/String;"); 89 public static final Type STRINGBUFFER= newType ("Ljava/lang/StringBuffer;"); 90 public static final Type OBJECT = newType ("Ljava/lang/Object;"); 91 public static final Type CLASS = newType ("Ljava/lang/Class;"); 92 public static final Type THROWABLE = newType ("Ljava/lang/Throwable;"); 93 public static final Type CLONEABLE = newType ("Ljava/lang/Cloneable;"); 94 public static final Type SERIALIZABLE= newType ("Ljava/io/Serializable;"); 95 public static final Type REFARRAY = newType ("[Ljava/lang/Object;"); 96 public static final Type CLASSARRAY = newType ("[Ljava/lang/Class;"); 97 public static final Type STRINGARRAY = newType ("[Ljava/lang/String;"); 98 public static final Type PRINTSTREAM = newType ("Ljava/io/PrintStream;"); 99 100 public String toClassRef() { 101 if (arraydepth != 0) return toString(); 102 if (equals (NULL)) 103 return "java/lang/Object"; 104 if (base != 'L') throw new IllegalStateException 105 ("no classref for non-class type " + toString()); 106 return cname; 107 } 108 109 public String declaration() { 111 String b; 112 113 switch (base) { 114 case 'I': b = "int"; break; 115 case 'J': b = "long"; break; 116 case 'F': b = "float"; break; 117 case 'D': b = "double"; break; 118 case 'L': case 'l': b = Util.srcClassName (cname); break; 119 case 'V': b = "void"; break; 120 case 'Z': b = "boolean"; break; 121 case 'S': b = "short"; break; 122 case 'C': b = "char"; break; 123 case 'B': b = "byte"; break; 124 case 'N': b = "Object"; break; 125 default: throw new IllegalStateException ("can't declare a " + toString()); 126 } 127 if (arraydepth == 0) 128 return b; 129 else { 130 StringBuffer out = new StringBuffer (b); 131 for (int i = 0; i < arraydepth; i++) 132 out.append ("[]"); 133 return out.toString(); 134 } 135 } 136 137 private static Type newType (String s) { 138 try { 139 return new Type (s); 140 } catch (ParseException e) { 141 throw new IllegalStateException ("bad type string: " + s); 142 } 143 } 144 145 private static Type newType (String s, int n) { 146 try { 147 return new Type (s, n); 148 } catch (ParseException e) { 149 throw new IllegalStateException ("bad type string: " + s); 150 } 151 } 152 153 public Type (ClassInfo cr) { 154 this('L', 0, cr.name()); 155 } 156 157 public Type (char ch) { 158 base = ch; 159 } 160 161 public Type (char ch, int d) { 162 this(ch); 163 arraydepth = d; 164 } 165 166 public Type (char ch, int d, String s) { 167 this(ch, d); 168 cname = s; 169 } 170 171 public Type (char ch, int d, String s, Object x) { 172 this(ch, d, s); 173 extra = x; 174 } 175 176 public Type (String s, int d) { 177 base = 'L'; 178 cname = s; 179 arraydepth = d; 180 } 181 182 public Type (Type t) { 183 base = t.base; 184 arraydepth = t.arraydepth; 185 cname = t.cname; 186 extra = t.extra; 187 } 188 189 Type () {} 190 191 public Type (String s) throws ParseException { 192 parse(s); 193 } 194 195 public Type (Object o) { 196 String cn = o.getClass().getName().replace ('.','/'); 197 198 if (cn.equals ("java/lang/Integer")) { base = 'I'; arraydepth = 0; } 199 else if (cn.equals ("java/lang/Long")) { base = 'J'; arraydepth = 0; } 200 else if (cn.equals ("java/lang/Float")) { base = 'F'; arraydepth = 0; } 201 else if (cn.equals ("java/lang/Double")) { base = 'D'; arraydepth = 0; } 202 else if (cn.startsWith ("[")) { 203 throw new IllegalStateException ("not implemented yet"); 204 } else { 205 cname = cn; 206 base = 'L'; 207 arraydepth = 0; 208 } 209 } 210 211 213 214 static Type newarray (int nat) 215 { 216 switch (nat) { 217 case Instruction.NAT_INT: 218 return Type.INTARRAY; 219 case Instruction.NAT_BYTE: 220 return Type.BYTEARRAY; 221 case Instruction.NAT_CHAR: 222 return Type.CHARARRAY; 223 case Instruction.NAT_BOOLEAN: 224 return Type.BOOLARRAY; 225 case Instruction.NAT_SHORT: 226 return Type.SHORTARRAY; 227 228 case Instruction.NAT_FLOAT: 229 return Type.FLOATARRAY; 230 case Instruction.NAT_DOUBLE: 231 return Type.DOUBLEARRAY; 232 case Instruction.NAT_LONG: 233 return Type.LONGARRAY; 234 } 235 236 throw new IllegalStateException ("invalid new array type " + nat); 237 } 238 239 244 public static Type merge (Type a, Type b) throws ClassFileException { 245 246 if (a==null || b==null) 247 return null; 248 249 if (a.equals (Type.ARRAY) && b.arraydepth > 0) 250 return a; 251 if (b.equals (Type.ARRAY) && a.arraydepth > 0) 252 return b; 253 254 256 if (a.base == 'l' || b.base=='l') { 257 if (a.base==b.base && a.target()==b.target() && 258 a.cname.equals(b.cname) && a.arraydepth==0 && 259 b.arraydepth==0) 260 return a; 261 else 262 return null; 263 } 264 265 269 if (a.equals(b)) { 270 if (a.equals(RETADDR)) 271 if (a.target() == b.target()) 272 return a; 273 else 274 return RETADDR; 275 return a; 276 } 277 278 279 if (a.isPrimitive() || b.isPrimitive()) 280 return null; 281 282 283 if (a.equals(NULL)) 284 return b; 285 if (b.equals(NULL)) 286 return a; 287 288 if (a.equals(OBJECT) || b.equals(OBJECT)) 289 return OBJECT; 290 291 if (a.arraydepth > 0 || b.arraydepth > 0) { 292 293 294 if (a.equals(CLONEABLE) || a.equals(SERIALIZABLE)) 295 return a; 296 if (b.equals(CLONEABLE) || b.equals(SERIALIZABLE)) 297 return b; 298 299 302 303 if (a.base != 'L') 304 a = new Type('L', a.arraydepth - 1, "java/lang/Object"); 305 if (b.base != 'L') 306 b = new Type('L', b.arraydepth - 1, "java/lang/Object"); 307 308 if (a.arraydepth == b.arraydepth) { 309 String newt = merge(a.cname, b.cname); 310 return new Type ('L', a.arraydepth, newt); 311 } else { 312 int arraydepth = a.arraydepth < b.arraydepth ? a.arraydepth : 313 b.arraydepth; 314 return new Type ('L', arraydepth, "java/lang/Object"); 315 } 316 } else { 317 String newt = merge (a.cname, b.cname); 318 return new Type ('L', 0, newt); 319 } 320 } 321 322 323 324 static String merge(String a, String b) throws ClassFileException { 325 326 if ( ClassInfo.isAncestor(a, b) ) return b; 327 if ( ClassInfo.isAncestor(b, a) ) return a; 328 return ClassInfo.allCommonAncestors (a, b); 329 } 330 331 public boolean isa(Type t) throws ClassFileException { 332 Type r = merge(this, t); 333 if (r==null) 334 return false; 335 336 return r.equals(t); 337 } 338 339 public boolean isUninitialized() { 340 return base=='l' && arraydepth==0; 341 } 342 343 Type initialize () 344 { 345 if (base != 'l' || arraydepth > 0) 346 throw new IllegalStateException ("can't initialize " + toString()); 347 return new Type ('L', 0, cname); 348 } 349 350 public Type merge(Type t) throws ClassFileException { 351 return merge(this, t); 352 } 353 354 public static Type class2type(String cname) { 355 if (cname.startsWith("[")) return new Type (cname); 357 else 358 return new Type (cname, 0); 359 } 360 361 public Type popbracket() throws RuntimeException { 362 if (arraydepth==0) 363 throw new RuntimeException ("popbracket called on non-array"); 364 Type ret = new Type(this); 365 ret.arraydepth--; 366 return ret; 367 } 368 369 public Type popbrackets() 370 { 371 if (arraydepth==0) 372 throw new RuntimeException ("popbrackets called on non-array"); 373 Type ret = new Type(this); 374 ret.arraydepth = 0; 375 return ret; 376 } 377 378 382 void relocate(Hashtable subs) { 383 384 if (cname == null) 385 return; 386 String newname = (String ) subs.get(cname); 387 if (newname==null || cname.equals(newname)) 388 return; 389 cname = newname; 390 } 391 392 397 Type relocate_new (Hashtable subs) { 398 Type t = new Type(this); 399 t.relocate(subs); 400 return t; 401 } 402 403 404 public boolean basicly_equalls(Type t) { 405 return base==t.base && arraydepth==t.arraydepth; 406 } 407 408 public boolean isPrimitive() { 409 return arraydepth==0 && base!='L' && base!='N'; 410 } 411 412 public boolean isRef() { 413 return base=='N' || arraydepth!=0 || base=='L'; 414 } 415 416 417 public String wrapperClass () { 418 if ( arraydepth!=0 || base=='L' ) 419 throw new RuntimeException ("wrapperClass called for non " + 420 "primitive type"); 421 switch (base) { 422 case 'Z': 423 return "java/lang/Boolean"; 424 case 'C': 425 return "java/lang/Character"; 426 case 'B': 427 return "java/lang/Byte"; 428 case 'S': 429 return "java/lang/Short"; 430 case 'I': 431 return "java/lang/Integer"; 432 case 'J': 433 return "java/lang/Long"; 434 case 'F': 435 return "java/lang/Float"; 436 case 'D': 437 return "java/lang/Double"; 438 } 439 return "unreachable code"; 440 } 441 442 public Type refType () { 443 if (arraydepth != 0 || base == 'L') 444 return this; 445 else 446 return new Type ('L', 0, wrapperClass()); 447 } 448 449 public String unpackMethod() { 450 if ( arraydepth!=0 || base=='L' ) 451 throw new RuntimeException ("getvalFunc called for non " + 452 "primitive type"); 453 switch (base) { 454 case 'Z': 455 return "booleanValue"; 456 case 'C': 457 return "charValue"; 458 case 'B': 459 return "byteValue"; 460 case 'S': 461 return "shortValue"; 462 case 'I': 463 return "intValue"; 464 case 'J': 465 return "longValue"; 466 case 'F': 467 return "floatValue"; 468 case 'D': 469 return "doubleValue"; 470 } 471 return "unreachable code"; 472 } 473 474 475 public int vmType () { 476 if (arraydepth > 0) 477 return VM_ADDRESS; 478 switch (base) 479 { 480 case 'Z': 481 case 'C': 482 case 'B': 483 case 'I': 484 case 'S': 485 return VM_INT; 486 case 'L': 487 case 'l': 488 case 'N': 489 return VM_ADDRESS; 490 case 'J': 491 return VM_LONG; 492 case 'D': 493 return VM_DOUBLE; 494 case 'F': 495 return VM_FLOAT; 496 case 'R': 497 return VM_RETADDR; 498 } 499 500 return 0; 501 } 502 503 504 public Type compType () { 505 if (arraydepth > 0) 506 return this; 507 switch (base) { 508 case 'Z': 509 case 'C': 510 case 'B': 511 case 'I': 512 case 'S': 513 return INT; 514 case 'L': 515 case 'l': 516 return this; 517 case 'J': 518 return LONG; 519 case 'D': 520 return DOUBLE; 521 case 'F': 522 return FLOAT; 523 case 'R': 524 return RETADDR; 525 } 526 return this; 527 } 528 529 public Type rawType () { 530 if (arraydepth > 0) 531 return OBJECT; 532 switch (base) { 533 case 'Z': 534 case 'C': 535 case 'B': 536 case 'I': 537 case 'S': 538 return INT; 539 case 'L': 540 case 'l': 541 case 'N': 542 return OBJECT; 543 case 'J': 544 return LONG; 545 case 'D': 546 return DOUBLE; 547 case 'F': 548 return FLOAT; 549 case 'R': 550 return RETADDR; 551 default: 552 throw new IllegalStateException ("bad type: " + toString()); 553 } 554 } 555 556 559 public int category() { 560 if ( equals(DASH) ) 561 return -1; 562 if ( arraydepth==0 && (base=='J' || base=='D')) 563 return 2; 564 else if (base == 'V') 565 return 0; 566 else 567 return 1; 568 } 569 570 private String stringCache = null; 572 573 int parse (String s) throws ParseException { 574 return parse (s, 0); 575 } 576 577 583 int parse (String s, int i) throws ParseException { 584 stringCache = null; 585 int j = i; 586 while (s.charAt(i) == '[') { 587 arraydepth++; 588 i++; 589 } 590 base = s.charAt(i++); 591 switch (base) { 592 case 'B': case 'C': case 'D': case 'F': case 'I': 593 case 'J': case 'L': case 'S': case 'Z': case 'V': 594 break; 595 default: 596 throw new ParseException ("bad basetype: " + base); 597 } 598 599 if (base == 'L' || base == 'l') { 600 StringBuffer cn = new StringBuffer (); 601 while (s.charAt(i) != ';') { 602 if ( i >= s.length()) 603 throw new ParseException ("unexpected end of string: " + s + "/" + cn.toString() +"/" + i + "/" + s.length()); 604 cn.append (s.charAt(i++)); 605 } 606 i++; 607 608 cname = cn.toString(); 609 } 610 return i - j; 611 } 612 613 618 public int count() { 619 if (arraydepth == 0 && (base == 'J' || base == 'D')) 620 return 2; 621 else 622 return 1; 623 } 624 625 public String toString() { 626 if (stringCache == null) { 627 StringBuffer out = new StringBuffer (); 628 for (int i = 0; i < arraydepth; i++) 629 out.append ('['); 630 out.append(base); 631 if (base == 'L' || base == 'l') { 632 out.append (cname); 633 out.append (';'); 634 } 635 stringCache = out.toString(); 636 } 637 return stringCache; 638 } 639 640 public boolean equals (Object o) { 641 if (! (o instanceof Type)) 642 return false; 643 644 Type t = (Type) o; 645 646 if (base != t.base || arraydepth != t.arraydepth) 647 return false; 648 if (cname != null) 649 return cname.equals(t.cname); 650 else 651 return t.cname == null; 652 } 653 654 657 String ref (CPInterface cp) throws RuntimeException { 658 if (isPrimitive()) 659 throw new RuntimeException ("ref() called on a primitive type"); 660 if (arraydepth == 0) 661 return cname; 662 else 663 return toString(); 664 } 665 666 public int hashCode() { 667 return 37 * base + 11 * arraydepth + 668 (cname==null ? 0 : cname.hashCode()); 669 } 670 671 public ClassInfo getClassInfo () throws ClassFileException 672 { 673 if ((base != 'L' && base != 'l') || arraydepth != 0) 674 throw new IllegalStateException (toString() + " has no class file"); 675 return Jbet.loader.getClass (cname); 676 } 677 678 public Class realclass() 679 { 680 if (arraydepth > 0) { 681 int[] n = new int [arraydepth]; 682 for (int i = 0; i < arraydepth; i++) 683 n[i] = 1; 684 Object dummy = java.lang.reflect.Array.newInstance (popbrackets().realclass(), n); 685 return dummy.getClass(); 686 } 687 switch (base) { 688 case 'I': 689 return Integer.TYPE; 690 case 'J': 691 return Long.TYPE; 692 case 'F': 693 return Float.TYPE; 694 case 'D': 695 return Double.TYPE; 696 case 'L': 697 try { 698 return Class.forName (declaration()); 699 } catch (ClassNotFoundException e) { 700 throw new IllegalStateException (e.getMessage()); 701 } 702 default: 703 throw new IllegalStateException ("type is not usable"); 704 } 705 } 706 707 708 709 public String jniType () 710 { 711 if (arraydepth == 1) { 712 switch (base) { 713 case 'B': return "jbyteArray"; 714 case 'C': return "jcharArray"; 715 case 'S': return "jshortArray"; 716 case 'I': return "jintArray"; 717 case 'Z': return "jbooleanArray"; 718 case 'F': return "jfloatArray"; 719 case 'J': return "jlongArray"; 720 case 'D': return "jdoubleArray"; 721 case 'L': return "jobjectArray"; 722 default: 723 throw new IllegalStateException ("bad array basetype " + base); 724 } 725 } 726 else if (arraydepth != 0) 727 return "jobjectArray"; 728 729 switch (base) { 730 case 'V': return "void"; 731 case 'B': return "jbyte"; 732 case 'S': return "jshort"; 733 case 'C': return "jchar"; 734 case 'Z': return "jboolean"; 735 case 'I': return "jint"; 736 case 'F': return "jfloat"; 737 case 'J': return "jlong"; 738 case 'D': return "jdouble"; 739 case 'L': 740 if (cname.equals ("java/lang/Class")) 741 return "jclass"; 742 else if (cname.equals ("java/lang/String")) 743 return "jstring"; 744 else 745 return "jobject"; 746 default: 747 throw new IllegalStateException ("bad basetype " + base); 748 } 749 } 750 } 751 752 753 754 | Popular Tags |