1 23 24 package org.objectweb.fractal.julia.asm; 25 26 import org.objectweb.fractal.api.control.ContentController; 27 import org.objectweb.fractal.julia.InitializationContext; 28 import org.objectweb.fractal.julia.Interceptor; 29 import org.objectweb.fractal.julia.loader.Initializable; 30 import org.objectweb.fractal.julia.loader.Loader; 31 import org.objectweb.fractal.julia.loader.Tree; 32 33 import org.objectweb.asm.CodeVisitor; 34 import org.objectweb.asm.Type; 35 import org.objectweb.asm.ClassReader; 36 import org.objectweb.asm.ClassAdapter; 37 import org.objectweb.asm.ClassVisitor; 38 import org.objectweb.asm.Attribute; 39 import org.objectweb.asm.CodeAdapter; 40 41 import java.lang.reflect.Method ; 42 import java.util.ArrayList ; 43 import java.util.List ; 44 import java.util.Arrays ; 45 import java.util.Map ; 46 import java.util.HashMap ; 47 import java.io.IOException ; 48 49 213 214 public class InterceptorClassGenerator 215 extends AbstractClassGenerator 216 implements Initializable 217 { 218 219 223 224 private final static List FRACTAL_METHODS = Arrays.asList(new String [] { 225 "listFc", "lookupFc", "bindFc", "unbindFc", 226 "getFcState", "startFc", "stopFc" 227 }); 228 229 232 233 public Tree args; 234 235 238 239 public Tree codeGenDescs; 240 241 244 245 public CodeGenerator[] codeGens; 246 247 250 251 public ClassTransformer[] classTransformers; 252 253 256 257 public Class [] controllerClasses; 258 259 266 267 public boolean in; 268 269 273 274 public boolean mergeInterceptors; 275 276 279 280 public boolean mergeAll; 281 282 287 288 public boolean isComposite; 289 290 293 294 private boolean transformContentClass; 295 296 300 301 private Class mergedControllerClass; 302 303 308 309 private Class contentClass; 310 311 314 315 public String implFieldName; 316 317 320 321 public String implFieldDesc; 322 323 331 332 public void initialize (final Tree args) { 333 codeGenDescs = args; 334 } 335 336 356 357 public byte[] generateClass ( 358 final String name, 359 final Tree args, 360 final Loader loader, 361 final ClassLoader classLoader) throws ClassGenerationException 362 { 363 this.args = args; 364 365 this.superClass = args.getSubTree(1).toString().replace('.', '/'); 366 Tree controllerDescs = args.getSubTree(3); 367 controllerClasses = new Class [controllerDescs.getSize()]; 368 for (int i = 0; i < controllerClasses.length; ++i) { 369 try { 370 controllerClasses[i] = 371 loader.loadClass(controllerDescs.getSubTree(i), classLoader); 372 } catch (Exception e) { 373 throw new ClassGenerationException( 374 e, args.toString(), "Cannot load one of the controller class"); 375 } 376 } 377 mergeInterceptors = controllerClasses.length == 0; 379 if (mergeInterceptors) { 380 try { 381 mergedControllerClass = 382 loader.loadClass(args.getSubTree(1), classLoader); 383 } catch (ClassNotFoundException e) { 384 throw new ClassGenerationException( 385 e, 386 args.toString(), 387 "Cannot load the '" + args.getSubTree(1) + "' class"); 388 } 389 isComposite = ContentController.class.isAssignableFrom(mergedControllerClass); 390 contentClass = mergedControllerClass.getSuperclass(); 391 mergeAll = !contentClass.equals(Object .class); 392 } 393 394 in = args.getSubTree(4).toString().equals("in"); 396 List codeGenList = new ArrayList (); 397 List classTransformList = new ArrayList (); 398 for (int i = 0; i < codeGenDescs.getSize(); ++i) { 399 Object o; 400 try { 401 o = loader.newObject(codeGenDescs.getSubTree(i), classLoader); 402 } catch (Exception e) { 403 throw new ClassGenerationException( 404 e, 405 args.toString(), 406 "Cannot find the '" + codeGenDescs.getSubTree(i) + 407 "' code generator class"); 408 } 409 if (o instanceof ClassTransformer) { 410 classTransformList.add(o); 411 } else if (o instanceof CodeGenerator) { 412 int type = ((CodeGenerator)o).init(this); 413 if (type == CodeGenerator.IN_OUT || (type == CodeGenerator.IN) == in) { 414 codeGenList.add(o); 415 } 416 } else { 417 throw new ClassGenerationException( 418 null, 419 args.toString(), 420 codeGenDescs.getSubTree(i) 421 + " is not a ClassTransformer or a CodeGenerator"); 422 } 423 } 424 if (codeGenList.size() == 0) { 425 throw new IllegalClassDescriptorException( 426 args.toString(), "no applicable code generator"); 427 } 428 codeGens = new CodeGenerator[codeGenList.size()]; 429 classTransformers = new ClassTransformer[classTransformList.size()]; 430 codeGenList.toArray(codeGens); 431 classTransformList.toArray(classTransformers); 432 433 if (classTransformers.length > 0) { 434 if (!mergeAll) { 435 throw new ClassGenerationException( 436 null, 437 args.toString(), 438 "Class transformers cannot be used without the " 439 + "mergeControllersInterceptorsAndContent optimization option"); 440 } 441 transformContentClass = true; 442 } 443 444 return super.generateClass(name, args, loader, classLoader); 445 } 446 447 protected void parseArgs (final Tree args) { 448 super.parseArgs(args); 449 if (transformContentClass) { 450 superClass = "java/lang/Object"; 451 } 452 } 453 454 459 460 protected boolean computeMaxs () { 461 return true; 462 } 463 464 471 472 protected String getSource () { 473 String s = interfaces.get(0).toString(); 474 if (s.lastIndexOf('/') != -1) { 475 s = s.substring(s.lastIndexOf('/') + 1); 476 } 477 return "INTERCEPTOR[" + s + "]"; 478 } 479 480 488 489 protected List getImplementedInterfaces () throws ClassGenerationException { 490 List itfs = super.getImplementedInterfaces(); 491 if (transformContentClass) { 492 for (int p = 0; p < 2; ++p) { 495 Class [] classes; 496 if (p == 0) { 497 classes = contentClass.getInterfaces(); 498 } else { 499 classes = mergedControllerClass.getInterfaces(); 500 } 501 for (int i = 0; i < classes.length; i++) { 502 String s = Type.getInternalName(classes[i]); 503 if (!itfs.contains(s)) { 504 itfs.add(s); 505 } 506 } 507 } 508 } else if (!mergeInterceptors || isComposite) { 509 itfs.add(Type.getInternalName(Interceptor.class)); 510 } 511 if (codeGens!=null) { 512 for (int cg=0; cg<codeGens.length; cg++) { 513 List itfsCG = codeGens[cg].getImplementedInterfaces(); 514 for (int itf=0; itf<itfsCG.size(); itf++) { 515 String itfName = (String )itfsCG.get(itf); 516 if (!itfs.contains(itfName)) { 517 itfs.add(itfName); 518 } 519 } 520 } 521 } 522 return itfs; 523 } 524 525 protected void generateConstructor () throws ClassGenerationException { 526 if (transformContentClass) { 527 return; 530 } 531 super.generateConstructor(); 532 CodeVisitor mv = cw.visitMethod( 533 ACC_PUBLIC, "<init>", "(Ljava/lang/Object;)V", null, null); 534 mv.visitVarInsn(ALOAD, 0); 536 mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "()V"); 537 mv.visitVarInsn(ALOAD, 0); 539 mv.visitVarInsn(ALOAD, 1); 540 mv.visitMethodInsn( 541 INVOKEINTERFACE, 542 "org/objectweb/fractal/julia/Interceptor", 543 "setFcItfDelegate", 544 "(Ljava/lang/Object;)V"); 545 mv.visitInsn(RETURN); 546 mv.visitMaxs(2, 2); 547 } 548 549 560 561 protected void generateDefaultMethods () throws ClassGenerationException { 562 super.generateDefaultMethods(); 563 564 if (mergeInterceptors && !isComposite) { 565 implFieldName = "fcContent"; 566 implFieldDesc = "Ljava/lang/Object;"; 567 return; 568 } 569 570 572 implFieldName = "impl"; 573 if (interfaces.size() == 1) { 574 implFieldDesc = "L" + (String )interfaces.get(0) + ";"; 575 } else { 576 implFieldDesc = "Ljava/lang/Object;"; 577 } 578 cw.visitField(ACC_PRIVATE, implFieldName, implFieldDesc, null, null); 579 580 582 String mName; 583 String mDesc; 584 CodeVisitor mv; 585 586 if (!mergeInterceptors || !isComposite) { 587 mName = "initFcController"; 588 mDesc = "(" + Type.getDescriptor(InitializationContext.class) + ")V"; 589 mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null); 590 for (int i = 0; i < codeGens.length; ++i) { 591 codeGens[i].generateInitCode(mv); 592 } 593 mv.visitInsn(RETURN); 594 mv.visitMaxs(0, 0); 595 } 596 597 599 mName = "getFcItfDelegate"; 600 mDesc = "()Ljava/lang/Object;"; 601 mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null); 602 mv.visitVarInsn(ALOAD, 0); 603 mv.visitFieldInsn(GETFIELD, name, implFieldName, implFieldDesc); 604 mv.visitInsn(ARETURN); 605 mv.visitMaxs(1, 1); 606 607 mName = "setFcItfDelegate"; 608 mDesc = "(Ljava/lang/Object;)V"; 609 mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null); 610 mv.visitVarInsn(ALOAD, 0); 611 mv.visitVarInsn(ALOAD,1); 612 if (interfaces.size() == 1) { 613 mv.visitTypeInsn(CHECKCAST, (String )interfaces.get(0)); 614 } 615 mv.visitFieldInsn(PUTFIELD, name, implFieldName, implFieldDesc); 616 mv.visitInsn(RETURN); 617 mv.visitMaxs(2, 2); 618 619 mName = "clone"; 620 mDesc = "()Ljava/lang/Object;"; 621 mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null); 622 if (mergeInterceptors) { 623 mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); 624 mv.visitInsn(DUP); 625 mv.visitLdcInsn("Cannot use merged interceptors with collection interfaces"); 626 mv.visitMethodInsn( 627 INVOKESPECIAL, 628 "java/lang/RuntimeException", 629 "<init>", 630 "(Ljava/lang/String;)V"); 631 mv.visitInsn(ATHROW); 632 mv.visitMaxs(2, 2); 633 } else { 634 mv.visitTypeInsn(NEW, name); 637 mv.visitInsn(DUP); 638 mv.visitVarInsn(ALOAD, 0); 639 mv.visitMethodInsn( 640 INVOKEINTERFACE, 641 "org/objectweb/fractal/julia/Interceptor", 642 "getFcItfDelegate", 643 "()Ljava/lang/Object;"); 644 mv.visitMethodInsn(INVOKESPECIAL, name, "<init>", "(Ljava/lang/Object;)V"); 645 mv.visitVarInsn(ASTORE, 1); 646 for (int i = 0; i < codeGens.length; ++i) { 647 codeGens[i].generateCloneCode(mv); 648 } 649 mv.visitVarInsn(ALOAD, 1); 650 mv.visitInsn(ARETURN); 651 mv.visitMaxs(2, 2); 652 } 653 } 654 655 protected void generateInterfaceMethods () throws ClassGenerationException { 656 if (transformContentClass) { 657 Map methods = new HashMap (); 658 for (int i = 0; i < interfaces.size(); ++i) { 659 String s = ((String )interfaces.get(i)).replace('/', '.'); 660 Class itf; 661 try { 662 itf = loader.loadClass(s, classLoader); 663 } catch (ClassNotFoundException e) { 664 throw new ClassGenerationException( 665 e, parameters, "Cannot load the '" + s + "' interface"); 666 } 667 Method [] meths = itf.getMethods(); 668 for (int j = 0; j < meths.length; ++j) { 669 Method meth = meths[j]; 670 String desc = meth.getName() + Type.getMethodDescriptor(meth); 671 methods.put(desc, meth); 672 } 673 } 674 675 ClassVisitor cv = new FilterClassAdapter(methods, cw); 678 for (int i = classTransformers.length - 1; i >= 0; --i) { 679 classTransformers[i].setClassVisitor(cv); 680 cv = classTransformers[i]; 681 } 682 try { 683 getClassReader(contentClass).accept(cv, false); 684 } catch (IOException e) { 685 throw new ClassGenerationException( 686 e, 687 args.toString(), 688 "Cannot read the '" + contentClass.getName() + "' class"); 689 } catch (VisitException e) { 690 throw e.getException(); 691 } 692 693 cv = new FilterClassAdapter(null, cw); 695 try { 696 getClassReader(mergedControllerClass).accept(cv, false); 697 } catch (IOException e) { 698 throw new ClassGenerationException( 699 e, 700 args.toString(), 701 "Cannot read the '" + mergedControllerClass.getName() + "' class"); 702 } catch (VisitException e) { 703 throw e.getException(); 704 } 705 } else { 706 super.generateInterfaceMethods(); 707 } 708 for (int i = 0; i < codeGens.length; ++i) { 709 codeGens[i].close(); 710 } 711 } 712 713 719 720 protected void generateMethod (final Method m) 721 throws ClassGenerationException 722 { 723 String itf = Type.getInternalName(m.getDeclaringClass()); 725 String mName = m.getName(); 726 String mDesc = Type.getMethodDescriptor(m); 727 Class [] params = m.getParameterTypes(); 728 Class result = m.getReturnType(); 729 Class [] exceptions = m.getExceptionTypes(); 730 String [] excepts = new String [exceptions.length]; 731 for (int i = 0; i < exceptions.length; ++i) { 732 excepts[i] = Type.getInternalName(exceptions[i]); 733 } 734 CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, excepts, null); 735 736 for (int i = 0; i < codeGens.length; ++i) { 739 mv = codeGens[i].generateInterceptionCode(m, mv); 740 } 741 742 mv.visitVarInsn(ALOAD, 0); 744 if (!mergeAll) { 745 mv.visitFieldInsn(GETFIELD, name, implFieldName, implFieldDesc); 746 if (interfaces.size() > 1 || !superClass.equals("java/lang/Object")) { 747 mv.visitTypeInsn(CHECKCAST, itf); 748 } 749 } 750 int offset = 1; 752 for (int i = 0; i < params.length; ++i) { 753 mv.visitVarInsn(ILOAD + getOpcodeOffset(params[i]), offset); 754 offset += getSize(params[i]); 755 } 756 if (mergeAll) { 758 mv.visitMethodInsn(INVOKESPECIAL, superClass, mName, mDesc); 759 } else { 760 mv.visitMethodInsn(INVOKEINTERFACE, itf, mName, mDesc); 761 } 762 if (result == Void.TYPE) { 764 mv.visitInsn(RETURN); 765 } else { 766 mv.visitInsn(IRETURN + getOpcodeOffset(result)); 767 } 768 769 mv.visitMaxs(0, 0); 771 } 772 773 780 781 private ClassReader getClassReader (final Class c) throws IOException { 782 try { 783 return new ClassReader(c.getName()); 784 } catch (IOException e) { 785 String s = Type.getInternalName(c) + ".class"; 788 return new ClassReader(c.getClassLoader().getResourceAsStream(s)); 789 } 790 } 791 792 796 797 private class FilterClassAdapter extends ClassAdapter { 798 799 804 805 private Map methods; 806 807 811 812 private boolean content; 813 814 818 819 private List oldNames; 820 821 public FilterClassAdapter (final Map methods, final ClassVisitor cv) { 822 super(cv); 823 this.methods = methods; 824 if (methods != null) { 825 content = true; 826 oldNames = Arrays.asList(new String [] { 827 Type.getInternalName(contentClass) 828 }); 829 } else { 830 content = false; 831 oldNames = Arrays.asList(new String [] { 832 Type.getInternalName(contentClass), 833 Type.getInternalName(mergedControllerClass) 834 }); 835 } 836 } 837 838 public void visit ( 839 final int version, 840 final int access, 841 final String name, 842 final String superName, 843 final String [] interfaces, 844 final String sourceFile) 845 { 846 } 848 849 public CodeVisitor visitMethod ( 850 final int access, 851 final String name, 852 final String desc, 853 final String [] exceptions, 854 final Attribute attrs) 855 { 856 int newAccess = access; 857 String newName = name; 858 if (content) { 859 if (FRACTAL_METHODS.contains(name)) { 860 newAccess = ACC_PRIVATE; 861 newName = "super$" + name; 862 } 863 } else { 864 if (name.equals("<init>") || name.equals("getFcGeneratorParameters")) { 865 return null; 866 } 867 } 868 CodeVisitor v = cv.visitMethod(newAccess, newName, desc, exceptions, attrs); 869 if (content) { 870 Method m = (Method )methods.get(name + desc); 871 if (m != null) { 872 for (int i = 0; i < codeGens.length; ++i) { 873 try { 874 v = codeGens[i].generateInterceptionCode(m, v); 875 } catch (ClassGenerationException e) { 876 throw new VisitException(e); 877 } 878 } 879 } 880 } 881 return new FilterCodeAdapter(oldNames, v); 882 } 883 884 public void visitEnd () { 885 } 887 } 888 889 890 893 894 private class FilterCodeAdapter extends CodeAdapter { 895 896 899 900 private List oldNames; 901 902 public FilterCodeAdapter (final List oldNames, final CodeVisitor cv) { 903 super(cv); 904 this.oldNames = oldNames; 905 } 906 907 public void visitFieldInsn ( 908 final int opcode, 909 final String owner, 910 final String name, 911 final String desc) 912 { 913 String newOwner = owner; 914 if (oldNames.contains(owner)) { 915 newOwner = InterceptorClassGenerator.this.name; 916 } 917 cv.visitFieldInsn(opcode, newOwner, name, desc); 918 } 919 920 public void visitMethodInsn ( 921 final int opcode, 922 final String owner, 923 final String name, 924 final String desc) 925 { 926 String newOwner = owner; 927 String newName = name; 928 if (oldNames.contains(owner)) { 929 newOwner = InterceptorClassGenerator.this.name; 930 } 931 if (oldNames.size() == 2 && owner.equals(oldNames.get(0))) { 932 if (FRACTAL_METHODS.contains(name)) { 934 newName = "super$" + name; 935 } 936 } 937 cv.visitMethodInsn(opcode, newOwner, newName, desc); 938 } 939 } 940 } 941 | Popular Tags |