1 package org.python.compiler; 3 4 import java.util.Hashtable ; 5 import java.util.Enumeration ; 6 import java.lang.reflect.Method ; 7 import java.lang.reflect.Modifier ; 8 import java.lang.reflect.Constructor ; 9 import java.io.*; 10 import org.python.core.Py; 11 12 public class ProxyMaker implements ClassConstants 13 { 14 public static final int tBoolean=0; 15 public static final int tByte=1; 16 public static final int tShort=2; 17 public static final int tInteger=3; 18 public static final int tLong=4; 19 public static final int tFloat=5; 20 public static final int tDouble=6; 21 public static final int tCharacter=7; 22 public static final int tVoid=8; 23 public static final int tOther=9; 24 public static final int tNone=10; 25 26 public static Hashtable types=fillTypes(); 27 28 public static Hashtable fillTypes() { 29 Hashtable types = new Hashtable (); 30 types.put(Boolean.TYPE, new Integer (tBoolean)); 31 types.put(Byte.TYPE, new Integer (tByte)); 32 types.put(Short.TYPE, new Integer (tShort)); 33 types.put(Integer.TYPE, new Integer (tInteger)); 34 types.put(Long.TYPE, new Integer (tLong)); 35 types.put(Float.TYPE, new Integer (tFloat)); 36 types.put(Double.TYPE, new Integer (tDouble)); 37 types.put(Character.TYPE, new Integer (tCharacter)); 38 types.put(Void.TYPE, new Integer (tVoid)); 39 return types; 40 } 41 42 public static int getType(Class c) { 43 if (c == null) return tNone; 44 Object i = types.get(c); 45 if (i == null) return tOther; 46 else return ((Integer )i).intValue(); 47 } 48 49 Class superclass; 50 Class [] interfaces; 51 Hashtable names; 52 Hashtable supernames = new Hashtable (); 53 public ClassFile classfile; 54 public String myClass; 55 public boolean isAdapter=false; 56 57 public ProxyMaker(String classname, Class superclass) { 59 this.myClass = "org.python.proxies."+classname; 60 if (superclass.isInterface()) { 61 this.superclass = Object .class; 62 this.interfaces = new Class [] {superclass}; 63 } else { 64 this.superclass = superclass; 65 this.interfaces = new Class [0]; 66 } 67 } 68 69 public ProxyMaker(String myClass, Class superclass, Class [] interfaces) { 71 this.myClass = myClass; 72 if (superclass == null) 73 superclass = Object .class; 74 this.superclass = superclass; 75 if (interfaces == null) 76 interfaces = new Class [0]; 77 this.interfaces = interfaces; 78 } 79 80 public static String mapClass(Class c) { 81 String name = c.getName(); 82 int index = name.indexOf("."); 83 if (index == -1) 84 return name; 85 86 StringBuffer buf = new StringBuffer (name.length()); 87 int last_index = 0; 88 while (index != -1) { 89 buf.append(name.substring(last_index, index)); 90 buf.append("/"); 91 last_index = index+1; 92 index = name.indexOf(".", last_index); 93 } 94 buf.append(name.substring(last_index, name.length())); 95 return buf.toString(); 96 } 97 98 public static String mapType(Class type) { 99 if (type.isArray()) 100 return "["+mapType(type.getComponentType()); 101 102 switch (getType(type)) { 103 case tByte: return "B"; 104 case tCharacter: return "C"; 105 case tDouble: return "D"; 106 case tFloat: return "F"; 107 case tInteger: return "I"; 108 case tLong: return "J"; 109 case tShort: return "S"; 110 case tBoolean: return "Z"; 111 case tVoid: return "V"; 112 default: 113 return "L"+mapClass(type)+";"; 114 } 115 } 116 117 public static String makeSignature(Class [] sig, Class ret) { 118 StringBuffer buf=new StringBuffer (); 119 buf.append("("); 120 for (int i=0; i<sig.length; i++) { 121 buf.append(mapType(sig[i])); 122 } 123 buf.append(")"); 124 buf.append(mapType(ret)); 125 return buf.toString(); 126 } 127 128 129 public void doConstants() throws Exception { 130 Code code = classfile.addMethod("<clinit>", "()V", Modifier.STATIC); 131 code.return_(); 132 } 133 134 public static void doReturn(Code code, Class type) throws Exception { 135 switch (getType(type)) { 136 case tNone: 137 break; 138 case tCharacter: 139 case tBoolean: 140 case tByte: 141 case tShort: 142 case tInteger: 143 code.ireturn(); 144 break; 145 case tLong: 146 code.lreturn(); 147 break; 148 case tFloat: 149 code.freturn(); 150 break; 151 case tDouble: 152 code.dreturn(); 153 break; 154 case tVoid: 155 code.return_(); 156 break; 157 default: 158 code.areturn(); 159 break; 160 } 161 } 162 163 public static void doNullReturn(Code code, Class type) throws Exception { 164 switch (getType(type)) { 165 case tNone: 166 break; 167 case tCharacter: 168 case tBoolean: 169 case tByte: 170 case tShort: 171 case tInteger: 172 code.iconst(0); 173 code.ireturn(); 174 break; 175 case tLong: 176 code.ldc(code.pool.Long(0)); 177 code.lreturn(); 178 break; 179 case tFloat: 180 code.ldc(code.pool.Float((float)0.)); 181 code.freturn(); 182 break; 183 case tDouble: 184 code.ldc(code.pool.Double(0.)); 185 code.dreturn(); 186 break; 187 case tVoid: 188 code.return_(); 189 break; 190 default: 191 code.aconst_null(); 192 code.areturn(); 193 break; 194 } 195 } 196 197 public void callSuper(Code code, String name, String superclass, 198 Class [] parameters, Class ret, 199 String sig) 200 throws Exception 201 { 202 code.aload(0); 203 int local_index; 204 int i; 205 for (i=0, local_index=1; i<parameters.length; i++) { 206 switch(getType(parameters[i])) { 207 case tCharacter: 208 case tBoolean: 209 case tByte: 210 case tShort: 211 case tInteger: 212 code.iload(local_index); 213 local_index += 1; 214 break; 215 case tLong: 216 code.lload(local_index); 217 local_index += 2; 218 break; 219 case tFloat: 220 code.fload(local_index); 221 local_index += 1; 222 break; 223 case tDouble: 224 code.dload(local_index); 225 local_index += 2; 226 break; 227 default: 228 code.aload(local_index); 229 local_index += 1; 230 break; 231 } 232 } 233 int meth = code.pool.Methodref(superclass, name, sig); 234 code.invokespecial(meth); 235 doReturn(code, ret); 236 } 237 238 public void doJavaCall(Code code, String name, String type, 239 String jcallName) 240 throws Exception 241 { 242 int jcall = code.pool.Methodref( 243 "org/python/core/PyObject", jcallName, 244 "(" + $objArr + ")" + $pyObj); 245 246 int py2j = code.pool.Methodref( 247 "org/python/core/Py", "py2"+name, 248 "(" + $pyObj + ")"+type); 249 250 code.invokevirtual(jcall); 251 code.invokestatic(py2j); 252 } 253 254 255 public void getArgs(Code code, Class [] parameters) throws Exception { 256 if (parameters.length == 0) { 257 int EmptyObjects = code.pool.Fieldref( 258 "org/python/core/Py", "EmptyObjects", $pyObjArr); 259 code.getstatic(EmptyObjects); 260 } 261 else { 262 code.iconst(parameters.length); 263 code.anewarray(code.pool.Class("java/lang/Object")); 264 int array = code.getLocal("[org/python/core/PyObject"); 265 code.astore(array); 266 267 int local_index; 268 int i; 269 for (i=0, local_index=1; i<parameters.length; i++) { 270 code.aload(array); 271 code.iconst(i); 272 273 switch (getType(parameters[i])) { 274 case tBoolean: 275 case tByte: 276 case tShort: 277 case tInteger: 278 code.iload(local_index); 279 local_index += 1; 280 281 int newInteger = code.pool.Methodref( 282 "org/python/core/Py", 283 "newInteger", "(I)" + $pyInteger); 284 code.invokestatic(newInteger); 285 break; 286 case tLong: 287 code.lload(local_index); 288 local_index += 2; 289 290 int newInteger1 = code.pool.Methodref( 291 "org/python/core/Py", 292 "newInteger", "(J)" + $pyObj); 293 code.invokestatic(newInteger1); 294 break; 295 case tFloat: 296 code.fload(local_index); 297 local_index += 1; 298 299 int newFloat = code.pool.Methodref( 300 "org/python/core/Py", 301 "newFloat", "(F)" + $pyFloat); 302 code.invokestatic(newFloat); 303 break; 304 case tDouble: 305 code.dload(local_index); 306 local_index += 2; 307 308 int newFloat1 = code.pool.Methodref( 309 "org/python/core/Py", 310 "newFloat", "(D)" + $pyFloat); 311 code.invokestatic(newFloat1); 312 break; 313 case tCharacter: 314 code.iload(local_index); 315 local_index += 1; 316 int newString = code.pool.Methodref( 317 "org/python/core/Py", 318 "newString", "(C)" + $pyStr); 319 code.invokestatic(newString); 320 break; 321 default: 322 code.aload(local_index); 323 local_index += 1; 324 break; 325 } 326 code.aastore(); 327 } 328 code.aload(array); 329 } 330 } 331 332 public void callMethod(Code code, String name, Class [] parameters, 333 Class ret, Class [] exceptions) 334 throws Exception 335 { 336 Label start = null; 337 Label end = null; 338 339 String jcallName = "_jcall"; 340 int instLocal = 0; 341 342 if (exceptions.length > 0) { 343 start = code.getLabel(); 344 end = code.getLabel(); 345 jcallName = "_jcallexc"; 346 instLocal = code.getLocal("org/python/core/PyObject"); 347 code.astore(instLocal); 348 start.setPosition(); 349 code.aload(instLocal); 350 } 351 352 getArgs(code, parameters); 353 354 switch (getType(ret)) { 355 case tCharacter: 356 doJavaCall(code, "char", "C", jcallName); 357 break; 358 case tBoolean: 359 doJavaCall(code, "boolean", "Z", jcallName); 360 break; 361 case tByte: 362 case tShort: 363 case tInteger: 364 doJavaCall(code, "int", "I", jcallName); 365 break; 366 case tLong: 367 doJavaCall(code, "long", "J", jcallName); 368 break; 369 case tFloat: 370 doJavaCall(code, "float", "F", jcallName); 371 break; 372 case tDouble: 373 doJavaCall(code, "double", "D", jcallName); 374 break; 375 case tVoid: 376 doJavaCall(code, "void", "V", jcallName); 377 break; 378 default: 379 int jcall = code.pool.Methodref( 380 "org/python/core/PyObject", jcallName, 381 "(" + $objArr + ")" + $pyObj); 382 code.invokevirtual(jcall); 383 390 int forname = code.pool.Methodref( 391 "java/lang/Class","forName", 392 "(" + $str + ")" + $clss); 393 code.ldc(ret.getName()); 394 code.invokestatic(forname); 395 410 int tojava = code.pool.Methodref( 411 "org/python/core/Py", "tojava", 412 "(" + $pyObj + $clss + ")" + $obj); 413 code.invokestatic(tojava); 414 code.checkcast(code.pool.Class(mapClass(ret))); 416 break; 417 } 418 if (exceptions.length > 0) 419 end.setPosition(); 420 421 doReturn(code, ret); 422 423 if (exceptions.length > 0) { 424 boolean throwableFound = false; 425 426 Label handlerStart = null; 427 for (int i = 0; i < exceptions.length; i++) { 428 handlerStart = code.getLabel(); 429 handlerStart.setPosition(); 430 code.stack = 1; 431 int excLocal = code.getLocal("java/lang/Throwable"); 432 code.astore(excLocal); 433 434 code.aload(excLocal); 435 code.athrow(); 436 437 code.addExceptionHandler(start, end, handlerStart, 438 code.pool.Class(mapClass(exceptions[i]))); 439 doNullReturn(code, ret); 440 441 code.freeLocal(excLocal); 442 if (exceptions[i] == Throwable .class) 443 throwableFound = true; 444 } 445 446 if (!throwableFound) { 447 handlerStart = code.getLabel(); 449 handlerStart.setPosition(); 450 code.stack = 1; 451 int excLocal = code.getLocal("java/lang/Throwable"); 452 code.astore(excLocal); 453 code.aload(instLocal); 454 code.aload(excLocal); 455 456 int jthrow = code.pool.Methodref( 457 "org/python/core/PyObject", "_jthrow", 458 "(" + $throwable + ")V"); 459 code.invokevirtual(jthrow); 460 461 code.addExceptionHandler(start, end, handlerStart, 462 code.pool.Class("java/lang/Throwable")); 463 code.freeLocal(excLocal); 464 doNullReturn(code, ret); 465 } 466 code.freeLocal(instLocal); 467 } 468 } 469 470 471 public void addMethod(Method method, int access) throws Exception { 472 boolean isAbstract = false; 473 474 if (Modifier.isAbstract(access)) { 475 access = access & ~Modifier.ABSTRACT; 476 isAbstract = true; 477 } 478 479 Class [] parameters = method.getParameterTypes(); 480 Class ret = method.getReturnType(); 481 String sig = makeSignature(parameters, ret); 482 483 String name = method.getName(); 484 names.put(name, name); 486 487 Code code = classfile.addMethod(name, sig, access); 488 489 code.aload(0); 490 code.ldc(name); 491 492 if (!isAbstract) { 493 int tmp = code.getLocal("org/python/core/PyObject"); 494 int jfindattr = code.pool.Methodref( 495 "org/python/core/Py", 496 "jfindattr", 497 "(" + $pyProxy + $str + ")" + $pyObj); 498 code.invokestatic(jfindattr); 499 500 code.astore(tmp); 501 code.aload(tmp); 502 503 Label callPython = code.getLabel(); 504 505 code.ifnonnull(callPython); 506 507 String superclass = mapClass(method.getDeclaringClass()); 508 509 callSuper(code, name, superclass, parameters, ret, sig); 510 callPython.setPosition(); 511 code.aload(tmp); 512 callMethod(code, name, parameters, ret, 513 method.getExceptionTypes()); 514 515 addSuperMethod("super__"+name, name, superclass, parameters, 516 ret, sig, access); 517 } 518 else { 519 if (!isAdapter) { 520 int jgetattr = code.pool.Methodref( 521 "org/python/core/Py", 522 "jgetattr", 523 "(" + $pyProxy + $str + ")" + $pyObj); 524 code.invokestatic(jgetattr); 525 callMethod(code, name, parameters, ret, 526 method.getExceptionTypes()); 527 } 528 else { 529 int jfindattr = code.pool.Methodref( 530 "org/python/core/Py", 531 "jfindattr", 532 "(" + $pyProxy + $str + ")" + $pyObj); 533 code.invokestatic(jfindattr); 534 code.dup(); 535 Label returnNull = code.getLabel(); 536 code.ifnull(returnNull); 537 callMethod(code, name, parameters, ret, 538 method.getExceptionTypes()); 539 returnNull.setPosition(); 540 code.pop(); 541 doNullReturn(code, ret); 542 } 543 } 544 } 545 546 private String methodString(Method m) { 547 StringBuffer buf = new StringBuffer (m.getName()); 548 buf.append(":"); 549 Class [] params = m.getParameterTypes(); 550 for (int i=0; i<params.length; i++) { 551 buf.append(params[i].getName()); 552 buf.append(","); 553 } 554 return buf.toString(); 555 } 556 557 protected void addMethods(Class c, Hashtable t) throws Exception { 558 Method [] methods = c.getDeclaredMethods(); 559 for (int i=0; i<methods.length; i++) { 560 Method method = methods[i]; 561 String s = methodString(method); 562 if (t.containsKey(s)) 563 continue; 564 t.put(s, s); 565 566 int access = method.getModifiers(); 567 if (Modifier.isStatic(access) || Modifier.isPrivate(access)) { 568 continue; 569 } 570 571 if (Modifier.isNative(access)) { 572 access = access & ~Modifier.NATIVE; 573 } 574 575 if (Modifier.isProtected(access)) { 576 access = (access & ~Modifier.PROTECTED) | Modifier.PUBLIC; 577 if (Modifier.isFinal(access)) { 578 addSuperMethod(methods[i], access); 579 continue; 580 } 581 } 582 else if (Modifier.isFinal(access)) { 583 continue; 584 } 585 addMethod(methods[i], access); 586 } 587 588 Class sc = c.getSuperclass(); 589 if (sc != null) 590 addMethods(sc, t); 591 592 Class [] interfaces = c.getInterfaces(); 593 for (int j=0; j<interfaces.length; j++) { 594 addMethods(interfaces[j], t); 595 } 596 } 597 598 public void addConstructor(String name, Class [] parameters, Class ret, 599 String sig, int access) 600 throws Exception 601 { 602 Code code = classfile.addMethod("<init>", sig, access); 603 callSuper(code, "<init>", name, parameters, Void.TYPE, sig); 604 } 605 606 public void addConstructors(Class c) throws Exception { 607 Constructor [] constructors = c.getDeclaredConstructors(); 608 String name = mapClass(c); 609 for (int i=0; i<constructors.length; i++) { 610 int access = constructors[i].getModifiers(); 611 if (Modifier.isPrivate(access)) 612 continue; 613 if (Modifier.isNative(access)) 614 access = access & ~Modifier.NATIVE; 615 if (Modifier.isProtected(access)) 616 access = access & ~Modifier.PROTECTED | Modifier.PUBLIC; 617 Class [] parameters = constructors[i].getParameterTypes(); 618 String sig = makeSignature(parameters, Void.TYPE); 619 addConstructor(name, parameters, Void.TYPE, sig, access); 620 } 621 } 622 623 public void addSuperMethod(Method method, int access) throws Exception { 638 Class [] parameters = method.getParameterTypes(); 639 Class ret = method.getReturnType(); 640 String sig = makeSignature(parameters, ret); 641 String superclass = mapClass(method.getDeclaringClass()); 642 String superName = method.getName(); 643 String methodName = superName; 644 if (Modifier.isFinal(access)) { 645 methodName = "super__"+superName; 646 access &= ~Modifier.FINAL; 647 } 648 addSuperMethod(methodName, superName, superclass, parameters, 649 ret, sig, access); 650 } 651 652 public void addSuperMethod(String methodName, String superName, 653 String declClass, Class [] parameters, 654 Class ret, String sig, int access) 655 throws Exception 656 { 657 if (methodName.startsWith("super__")) { 658 664 try { 665 superclass.getMethod(methodName,parameters); 666 return; 667 } catch(NoSuchMethodException e) { 668 } catch(SecurityException e) { 669 return; 670 } 671 } 672 supernames.put(methodName, methodName); 673 Code code = classfile.addMethod(methodName, sig, access); 674 callSuper(code, superName, declClass, parameters, ret, sig); 675 } 676 677 public void addProxy() throws Exception { 678 classfile.addField("__proxy", "Lorg/python/core/PyInstance;", 680 Modifier.PROTECTED); 681 Code code = classfile.addMethod("_setPyInstance", 683 "(Lorg/python/core/PyInstance;)V", 684 Modifier.PUBLIC); 685 686 int field = code.pool.Fieldref(classfile.name, "__proxy", 687 "Lorg/python/core/PyInstance;"); 688 code.aload(0); 689 code.aload(1); 690 code.putfield(field); 691 code.return_(); 692 693 code = classfile.addMethod("_getPyInstance", 695 "()Lorg/python/core/PyInstance;", 696 Modifier.PUBLIC); 697 code.aload(0); 698 code.getfield(field); 699 code.areturn(); 700 701 classfile.addField("__systemState", 703 "Lorg/python/core/PySystemState;", 704 Modifier.PROTECTED | Modifier.TRANSIENT); 705 706 code = classfile.addMethod("_setPySystemState", 708 "(Lorg/python/core/PySystemState;)V", 709 Modifier.PUBLIC); 710 711 field = code.pool.Fieldref(classfile.name, "__systemState", 712 "Lorg/python/core/PySystemState;"); 713 code.aload(0); 714 code.aload(1); 715 code.putfield(field); 716 code.return_(); 717 718 code = classfile.addMethod("_getPySystemState", 720 "()Lorg/python/core/PySystemState;", 721 Modifier.PUBLIC); 722 code.aload(0); 723 code.getfield(field); 724 code.areturn(); 725 } 726 727 public void addClassDictInit() throws Exception { 728 int n = supernames.size(); 729 730 classfile.addInterface(mapClass(org.python.core.ClassDictInit.class)); 732 Code code = classfile.addMethod("classDictInit", 733 "(" + $pyObj + ")V", 734 Modifier.PUBLIC | Modifier.STATIC); 735 code.aload(0); 736 code.ldc("__supernames__"); 737 738 String [] names = new String [n]; 739 Enumeration e = supernames.keys(); 740 for (int i = 0; e.hasMoreElements(); ) 741 names[i++] = (String ) e.nextElement(); 742 CodeCompiler.makeStrings(code, names, n); 743 int j2py = code.pool.Methodref( 744 "org/python/core/Py", "java2py", 745 "(" + $obj + ")" + $pyObj); 746 code.invokestatic(j2py); 747 748 int setitem = code.pool.Methodref( 749 "org/python/core/PyObject", "__setitem__", 750 "(" + $str + $pyObj + ")V"); 751 code.invokevirtual(setitem); 752 code.return_(); 753 754 } 755 756 public void build() throws Exception { 757 names = new Hashtable (); 758 int access = superclass.getModifiers(); 759 if ((access & Modifier.FINAL) != 0) { 760 throw new InstantiationException ("can't subclass final class"); 761 } 762 access = Modifier.PUBLIC | Modifier.SYNCHRONIZED; 763 764 classfile = new ClassFile(myClass, mapClass(superclass), access); 765 addProxy(); 766 addConstructors(superclass); 767 classfile.addInterface("org/python/core/PyProxy"); 768 769 Hashtable seenmethods = new Hashtable (); 770 for (int i=0; i<interfaces.length; i++) { 771 if (interfaces[i].isAssignableFrom(superclass)) { 772 Py.writeWarning("compiler", 773 "discarding redundant interface: "+ 774 interfaces[i].getName()); 775 continue; 776 } 777 classfile.addInterface(mapClass(interfaces[i])); 778 addMethods(interfaces[i], seenmethods); 779 } 780 addMethods(superclass, seenmethods); 781 doConstants(); 782 addClassDictInit(); 783 } 784 785 public static String makeProxy(Class superclass, OutputStream ostream) 786 throws Exception 787 { 788 ProxyMaker pm = new ProxyMaker(superclass.getName(), superclass); 789 pm.build(); 790 pm.classfile.write(ostream); 791 return pm.myClass; 792 } 793 794 public static File makeFilename(String name, File dir) { 795 int index = name.indexOf("."); 796 if (index == -1) 797 return new File(dir, name+".class"); 798 799 return makeFilename(name.substring(index+1, name.length()), 800 new File(dir, name.substring(0, index))); 801 } 802 803 public static OutputStream getFile(String d, String name) 805 throws IOException 806 { 807 File dir = new File(d); 808 File file = makeFilename(name, dir); 809 new File(file.getParent()).mkdirs(); 810 return new FileOutputStream(file); 812 } 813 } 814 | Popular Tags |