1 23 24 package org.objectweb.fractal.julia.asm; 25 26 import org.objectweb.fractal.julia.InitializationContext; 27 import org.objectweb.fractal.julia.loader.Initializable; 28 import org.objectweb.fractal.julia.loader.Tree; 29 30 import org.objectweb.asm.ClassVisitor; 31 import org.objectweb.asm.CodeVisitor; 32 import org.objectweb.asm.Constants; 33 import org.objectweb.asm.Label; 34 import org.objectweb.asm.Type; 35 import org.objectweb.asm.Attribute; 36 37 import java.lang.reflect.Method ; 38 import java.util.ArrayList ; 39 import java.util.List ; 40 41 145 146 public abstract class MetaCodeGenerator implements 147 Initializable, 148 CodeGenerator, 149 Constants 150 { 151 152 157 158 private Tree args; 159 160 163 164 private InterceptorClassGenerator icg; 165 166 169 170 private String delegateFieldName; 171 172 175 176 private String delegateFieldDesc; 177 178 181 182 private String owner; 183 184 187 188 private CodeVisitor clinit; 189 190 194 195 private int counter; 196 197 201 public void initialize (Tree args) { 202 this.args = args.getSubTree(0); 203 } 204 205 209 public int init (final InterceptorClassGenerator icg) { 210 this.icg = icg; 211 return IN; 212 } 213 214 public void generateInitCode (final CodeVisitor cv) 215 throws ClassGenerationException 216 { 217 String owner = null; 220 for (int i = 0; i < icg.controllerClasses.length; ++i) { 221 Class c = icg.controllerClasses[i]; 222 List params = new ArrayList (); 223 if (reifyInterfaceName()) { 224 params.add(String .class); 225 } 226 if (reifyTargetObject()) { 227 params.add(Object .class); 228 } 229 params.add(Method .class); 230 params.add(Object [].class); 231 Class [] paramClasses = (Class [])params.toArray(new Class [params.size()]); 232 try { 233 c.getMethod(getHandleMethodCallMethodName(), paramClasses); 234 owner = c.getName(); 235 break; 236 } catch (Exception e) { 237 } 238 } 239 if (owner == null) { 240 throw new ClassGenerationException( 241 null, 242 icg.args.toString(), 243 "Cannot find a controller class providing a '" + 244 getHandleMethodCallMethodName() + "' method with the good arguments"); 245 } 246 owner = owner.replace('.', '/'); 247 248 int hashcode = getControllerInterfaceName().hashCode(); 249 delegateFieldName = "d" + Integer.toHexString(hashcode); 250 delegateFieldDesc = "L" + owner + ";"; 251 252 icg.cw.visitField( 253 ACC_PRIVATE, delegateFieldName, delegateFieldDesc, null, null); 254 255 cv.visitVarInsn(ALOAD, 0); 256 cv.visitVarInsn(ALOAD, 1); 257 cv.visitLdcInsn(getControllerInterfaceName()); 258 cv.visitMethodInsn( 259 INVOKEVIRTUAL, 260 Type.getInternalName(InitializationContext.class), 261 "getInterface", 262 "(" + Type.getDescriptor(String .class) + ")" + 263 Type.getDescriptor(Object .class)); 264 cv.visitTypeInsn(CHECKCAST, owner); 265 cv.visitFieldInsn(PUTFIELD, icg.name, delegateFieldName, delegateFieldDesc); 266 } 267 268 public CodeVisitor generateInterceptionCode ( 269 final Method m, 270 final CodeVisitor cv) 271 { 272 if (intercept(m)) { 273 return new MetaCodeAdapter(cv, m); 274 } else { 275 return cv; 276 } 277 } 278 279 public void generateCloneCode (final CodeVisitor cv) { 280 cv.visitVarInsn(ALOAD, 1); 281 cv.visitVarInsn(ALOAD, 0); 282 cv.visitFieldInsn(GETFIELD, icg.name, delegateFieldName, delegateFieldDesc); 283 cv.visitFieldInsn(PUTFIELD, icg.name, delegateFieldName, delegateFieldDesc); 284 } 285 286 public void close () { 287 if (clinit != null) { 288 clinit.visitInsn(RETURN); 289 clinit.visitMaxs(0, 0); 290 } 291 } 292 293 297 304 305 protected abstract String getControllerInterfaceName (); 306 307 317 318 protected boolean intercept (final Method m) { 319 return true; 320 } 321 322 330 331 protected abstract String getHandleMethodCallMethodName (); 332 333 342 343 protected boolean reifyInterfaceName () { 344 return false; 345 } 346 347 355 356 private String getInterfaceName (Method m) { 357 if (args != null) { 358 String desc = m.getName()+Type.getMethodDescriptor(m); 359 List itfs = icg.interfaces; 360 for (int i = 0; i < itfs.size(); ++i) { 361 String itf = ((String )itfs.get(i)).replace('/', '.'); 362 Class c; 363 try { 364 c = icg.loader.loadClass(itf, icg.classLoader); 365 } catch (ClassNotFoundException e) { 366 continue; 367 } 368 Method [] meths = c.getMethods(); 369 for (int j = 0; j < meths.length; ++j) { 370 Method meth = meths[j]; 371 if (desc.equals(meth.getName()+Type.getMethodDescriptor(meth))) { 372 return args.getSubTree(i).toString(); 373 } 374 } 375 } 376 } 377 return null; 378 } 379 380 388 389 protected boolean reifyTargetObject () { 390 return false; 391 } 392 393 401 402 protected abstract String getIsReflectedCallMethodName (); 403 404 414 415 public static void generateMethodInitializerCode ( 416 final Method m, 417 final String owner, 418 final String field, 419 final ClassVisitor cv, 420 final CodeVisitor mv) 421 { 422 cv.visitField( 424 ACC_PRIVATE + ACC_STATIC, 425 field, 426 "Ljava/lang/reflect/Method;", 427 null, 428 null); 429 430 mv.visitLdcInsn(m.getDeclaringClass().getName()); 432 mv.visitMethodInsn( 433 INVOKESTATIC, 434 "java/lang/Class", 435 "forName", 436 "(Ljava/lang/String;)Ljava/lang/Class;"); 437 mv.visitLdcInsn(m.getName()); 439 Class [] formals = m.getParameterTypes(); 441 mv.visitIntInsn(SIPUSH, formals.length); 442 mv.visitTypeInsn(ANEWARRAY, "java/lang/Class"); 443 for (int i = 0; i < formals.length; ++i) { 444 mv.visitInsn(DUP); 445 mv.visitIntInsn(SIPUSH, i); 446 Class c = formals[i]; 447 if (c.isPrimitive()) { 448 String type; 449 if (c == Byte.TYPE) { 450 type = "java/lang/Byte"; 451 } else if (c == Integer.TYPE) { 452 type = "java/lang/Integer"; 453 } else if (c == Boolean.TYPE) { 454 type = "java/lang/Boolean"; 455 } else if (c == Double.TYPE) { 456 type = "java/lang/Double"; 457 } else if (c == Float.TYPE) { 458 type = "java/lang/Float"; 459 } else if (c == Long.TYPE) { 460 type = "java/lang/Long"; 461 } else if (c == Character.TYPE) { 462 type = "java/lang/Character"; 463 } else { 464 type = "java/lang/Short"; 465 } 466 mv.visitFieldInsn( 467 GETSTATIC, type, "TYPE", "Ljava/lang/Class;"); 468 } else { 469 String name; 470 if (c.isArray()) { 471 name = Type.getDescriptor(c).replace('/', '.'); 472 } else { 473 name = c.getName(); 474 } 475 mv.visitLdcInsn(name); 476 mv.visitMethodInsn( 477 INVOKESTATIC, 478 "java/lang/Class", 479 "forName", 480 "(Ljava/lang/String;)Ljava/lang/Class;"); 481 } 482 mv.visitInsn(AASTORE); 483 } 484 mv.visitMethodInsn( 486 INVOKEVIRTUAL, 487 "java/lang/Class", 488 "getMethod", 489 "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"); 490 mv.visitFieldInsn( 491 PUTSTATIC, 492 owner, 493 field, 494 "Ljava/lang/reflect/Method;"); 495 } 496 497 505 506 public static void generateParameterReifierCode ( 507 final Method m, 508 final CodeVisitor cv) 509 { 510 Class [] params = m.getParameterTypes(); 511 cv.visitIntInsn(SIPUSH, params.length); 512 cv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); 513 int localVarIndex = 1; 514 for (int i = 0; i < params.length; ++i) { 515 Class param = params[i]; 516 cv.visitInsn(DUP); 517 cv.visitIntInsn(SIPUSH, i); 518 if (param.isPrimitive()) { 519 int opcode = ILOAD; 520 String type; 521 String desc; 522 if (param == Byte.TYPE) { 523 type = "java/lang/Byte"; 524 desc = "B"; 525 } else if (param == Integer.TYPE) { 526 type = "java/lang/Integer"; 527 desc = "I"; 528 } else if (param == Boolean.TYPE) { 529 type = "java/lang/Boolean"; 530 desc = "Z"; 531 } else if (param == Double.TYPE) { 532 opcode = DLOAD; 533 type = "java/lang/Double"; 534 desc = "D"; 535 } else if (param == Float.TYPE) { 536 opcode = FLOAD; 537 type = "java/lang/Float"; 538 desc = "F"; 539 } else if (param == Long.TYPE) { 540 opcode = LLOAD; 541 type = "java/lang/Long"; 542 desc = "J"; 543 } else if (param == Character.TYPE) { 544 type = "java/lang/Character"; 545 desc = "C"; 546 } else { 547 type = "java/lang/Short"; 548 desc = "S"; 549 } 550 cv.visitTypeInsn(NEW, type); 551 cv.visitInsn(DUP); 552 cv.visitVarInsn(opcode, localVarIndex); 553 cv.visitMethodInsn( 554 INVOKESPECIAL, type, "<init>", "(" + desc + ")V"); 555 } else { 556 cv.visitVarInsn(ALOAD, localVarIndex); 557 } 558 cv.visitInsn(AASTORE); 559 localVarIndex += (param == Double.TYPE || param == Long.TYPE ? 2 : 1); 560 } 561 } 562 563 571 572 public static void generateReturnCode (final Method m, final CodeVisitor cv) { 573 Class result = m.getReturnType(); 574 if (result == Void.TYPE) { 575 cv.visitInsn(POP); 576 cv.visitInsn(RETURN); 577 } else if (result.isPrimitive()) { 578 int opcode = IRETURN; 579 String type; 580 String meth; 581 String desc; 582 if (result == Byte.TYPE) { 583 type = "java/lang/Byte"; 584 meth = "byteValue"; 585 desc = "B"; 586 } else if (result == Integer.TYPE) { 587 type = "java/lang/Integer"; 588 meth = "intValue"; 589 desc = "I"; 590 } else if (result == Boolean.TYPE) { 591 type = "java/lang/Boolean"; 592 meth = "booleanValue"; 593 desc = "Z"; 594 } else if (result == Double.TYPE) { 595 opcode = DRETURN; 596 type = "java/lang/Double"; 597 meth = "doubleValue"; 598 desc = "D"; 599 } else if (result == Float.TYPE) { 600 opcode = FRETURN; 601 type = "java/lang/Float"; 602 meth = "floatValue"; 603 desc = "F"; 604 } else if (result == Long.TYPE) { 605 opcode = LRETURN; 606 type = "java/lang/Long"; 607 meth = "longValue"; 608 desc = "J"; 609 } else if (result == Character.TYPE) { 610 type = "java/lang/Character"; 611 meth = "charValue"; 612 desc = "C"; 613 } else { 614 type = "java/lang/Short"; 615 meth = "shortValue"; 616 desc = "S"; 617 } 618 cv.visitTypeInsn(CHECKCAST, type); 619 cv.visitMethodInsn(INVOKEVIRTUAL, type, meth, "()" + desc); 620 cv.visitInsn(opcode); 621 } else { 622 cv.visitTypeInsn(CHECKCAST, Type.getInternalName(result)); 623 cv.visitInsn(ARETURN); 624 } 625 } 626 627 637 public List getImplementedInterfaces() throws ClassGenerationException { 638 return new ArrayList (); 639 } 640 641 645 649 650 class MetaCodeAdapter implements CodeVisitor { 651 652 655 656 private final CodeVisitor cv; 657 658 661 662 private final boolean mergeAll; 663 664 670 671 public MetaCodeAdapter ( 672 final CodeVisitor cv, 673 final Method m) 674 { 675 this.cv = cv; 676 this.mergeAll = icg.mergeAll; 677 678 if (owner == null) { 680 if (delegateFieldDesc == null) { 681 owner = icg.name; 682 } else { 683 owner = delegateFieldDesc.substring(1, delegateFieldDesc.length() - 1); 684 } 685 } 686 687 Label endLabel = null; 688 689 if (mergeAll) { 690 cv.visitVarInsn(ALOAD, 0); 692 cv.visitMethodInsn( 693 INVOKEVIRTUAL, 694 owner, 695 getIsReflectedCallMethodName(), 696 "()Z"); 697 endLabel = new Label(); 698 cv.visitJumpInsn(IFNE, endLabel); 699 } 700 701 cv.visitVarInsn(ALOAD, 0); 707 if (delegateFieldName != null) { 712 cv.visitFieldInsn( 713 GETFIELD, icg.name, delegateFieldName, delegateFieldDesc); 714 } 715 716 if (clinit == null) { 720 clinit = icg.cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 722 } 723 generateMethodInitializerCode(m, icg.name, "_M"+counter, icg.cw, clinit); 724 725 if (reifyInterfaceName()) { 726 String name = getInterfaceName(m); 727 if (name == null) { 728 cv.visitInsn(ACONST_NULL); 729 } else { 730 cv.visitLdcInsn(name); 731 } 732 } 733 734 if (reifyTargetObject()) { 735 cv.visitVarInsn(ALOAD, 0); 737 cv.visitFieldInsn( 738 GETFIELD, icg.name, icg.implFieldName, icg.implFieldDesc); 739 } 740 741 cv.visitFieldInsn( 744 GETSTATIC, icg.name, "_M" + counter, "Ljava/lang/reflect/Method;"); 745 746 generateParameterReifierCode(m, cv); 748 749 String desc = 751 "Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"; 752 if (reifyTargetObject()) { 753 desc = "Ljava/lang/Object;" + desc; 754 } 755 if (reifyInterfaceName()) { 756 desc = "Ljava/lang/String;" + desc; 757 } 758 cv.visitMethodInsn( 759 INVOKEVIRTUAL, 760 owner, 761 getHandleMethodCallMethodName(), 762 "(" + desc); 763 764 generateReturnCode(m, cv); 766 767 if (mergeAll) { 768 cv.visitLabel(endLabel); 769 } else { 770 cv.visitMaxs(0, 0); 771 } 772 773 ++counter; 774 } 775 776 780 public void visitInsn (final int opcode) { 781 if (mergeAll) { 782 cv.visitInsn(opcode); 783 } 784 } 785 786 public void visitIntInsn (final int opcode, final int operand) { 787 if (mergeAll) { 788 cv.visitIntInsn(opcode, operand); 789 } 790 } 791 792 public void visitVarInsn (final int opcode, final int var) { 793 if (mergeAll) { 794 cv.visitVarInsn(opcode, var); 795 } 796 } 797 798 public void visitTypeInsn (final int opcode, final String desc) { 799 if (mergeAll) { 800 cv.visitTypeInsn(opcode, desc); 801 } 802 } 803 804 public void visitFieldInsn ( 805 final int opcode, 806 final String owner, 807 final String name, 808 final String desc) 809 { 810 if (mergeAll) { 811 cv.visitFieldInsn(opcode, owner, name, desc); 812 } 813 } 814 815 public void visitMethodInsn ( 816 final int opcode, 817 final String owner, 818 final String name, 819 final String desc) 820 { 821 if (mergeAll) { 822 cv.visitMethodInsn(opcode, owner, name, desc); 823 } 824 } 825 826 public void visitJumpInsn (final int opcode, final Label label) { 827 if (mergeAll) { 828 cv.visitJumpInsn(opcode, label); 829 } 830 } 831 832 public void visitLabel (final Label label) { 833 if (mergeAll) { 834 cv.visitLabel(label); 835 } 836 } 837 838 public void visitLdcInsn (final Object cst) { 839 if (mergeAll) { 840 cv.visitLdcInsn(cst); 841 } 842 } 843 844 public void visitIincInsn (final int var, final int increment) { 845 if (mergeAll) { 846 cv.visitIincInsn(var, increment); 847 } 848 } 849 850 public void visitTableSwitchInsn ( 851 final int min, 852 final int max, 853 final Label dflt, 854 final Label labels[]) 855 { 856 if (mergeAll) { 857 cv.visitTableSwitchInsn(min, max, dflt, labels); 858 } 859 } 860 861 public void visitLookupSwitchInsn ( 862 final Label dflt, 863 final int keys[], 864 final Label labels[]) 865 { 866 if (mergeAll) { 867 cv.visitLookupSwitchInsn(dflt, keys, labels); 868 } 869 } 870 871 public void visitMultiANewArrayInsn (final String desc, final int dims) { 872 if (mergeAll) { 873 cv.visitMultiANewArrayInsn(desc, dims); 874 } 875 } 876 877 public void visitTryCatchBlock ( 878 final Label start, 879 final Label end, 880 final Label handler, 881 final String type) 882 { 883 if (mergeAll) { 884 cv.visitTryCatchBlock(start, end, handler, type); 885 } 886 } 887 888 public void visitMaxs (final int maxStack, final int maxLocals) { 889 if (mergeAll) { 890 cv.visitMaxs(maxStack, maxLocals); 891 } 892 } 893 894 public void visitAttribute (final Attribute attribute) { 895 cv.visitAttribute(attribute); 896 } 897 898 public void visitLocalVariable ( 899 final String name, 900 final String desc, 901 final Label start, 902 final Label end, 903 final int index) 904 { 905 if (mergeAll) { 906 cv.visitLocalVariable(name, desc, start, end, index); 907 } 908 } 909 910 public void visitLineNumber (final int line, final Label start) { 911 if (mergeAll) { 912 cv.visitLineNumber(line, start); 913 } 914 } 915 } 916 } 917 | Popular Tags |