1 23 24 package org.objectweb.fractal.julia.asm; 25 26 import org.objectweb.fractal.api.control.BindingController; 27 import org.objectweb.fractal.api.control.LifeCycleController; 28 29 import org.objectweb.fractal.julia.control.binding.ContentBindingController; 30 import org.objectweb.fractal.julia.control.lifecycle.ContentLifeCycleController; 31 import org.objectweb.fractal.julia.loader.Generated; 32 import org.objectweb.fractal.julia.loader.Loader; 33 import org.objectweb.fractal.julia.loader.Tree; 34 import org.objectweb.fractal.julia.loader.Initializable; 35 36 import org.objectweb.asm.ClassAdapter; 37 import org.objectweb.asm.ClassReader; 38 import org.objectweb.asm.ClassVisitor; 39 import org.objectweb.asm.ClassWriter; 40 import org.objectweb.asm.CodeAdapter; 41 import org.objectweb.asm.CodeVisitor; 42 import org.objectweb.asm.Constants; 43 import org.objectweb.asm.Type; 44 import org.objectweb.asm.Attribute; 45 46 import java.io.IOException ; 47 import java.lang.reflect.Method ; 48 import java.lang.reflect.Modifier ; 49 import java.util.ArrayList ; 50 import java.util.HashMap ; 51 import java.util.List ; 52 import java.util.Map ; 53 54 123 124 public class MergeClassGenerator implements ClassGenerator, Constants { 125 126 129 130 public Loader loader; 131 132 135 136 public ClassLoader classLoader; 137 138 141 142 public String parameters; 143 144 147 148 String mergedClassName; 149 150 154 155 List interfaces; 156 157 160 161 int currentClassIndex; 162 163 167 168 String currentClassName; 169 170 173 174 Class currentClass; 175 176 180 181 List inheritedClasses; 182 183 189 190 Map counters; 191 192 195 196 CodeVisitor inicv; 197 198 201 202 CodeVisitor icv; 203 204 220 221 public byte[] generateClass ( 222 final String name, 223 final Tree args, 224 final Loader loader, 225 final ClassLoader classLoader) throws ClassGenerationException 226 { 227 this.loader = loader; 228 this.classLoader = classLoader; 229 String superClassName = args.getSubTree(1).toString().replace('.', '/'); 230 mergedClassName = name.replace('.', '/'); 231 232 Class [] classes = new Class [args.getSize() - 2]; 233 interfaces = new ArrayList (); 234 interfaces.add(Generated.class); 235 interfaces.add(Initializable.class); 236 for (int i = 0; i < classes.length; ++i) { 237 try { 238 classes[i] = loader.loadClass(args.getSubTree(i + 2), classLoader); 239 } catch (ClassNotFoundException e) { 240 throw new ClassGenerationException( 241 e, 242 args.toString(), 243 "Cannot load the '" + args.getSubTree(i + 2) + "' class"); 244 } 245 Class c = classes[i]; 246 while (c != Object .class) { 247 Class [] citfs = c.getInterfaces(); 248 for (int j = 0; j < citfs.length; ++j) { 249 if (!interfaces.contains(citfs[j])) { 250 interfaces.add(citfs[j]); 251 } 252 } 253 c = c.getSuperclass(); 254 } 255 } 256 Class superClass; 260 try { 261 superClass = loader.loadClass(args.getSubTree(1), classLoader); 262 } catch (ClassNotFoundException e) { 263 throw new ClassGenerationException( 264 e, 265 args.toString(), 266 "Cannot load the '" + args.getSubTree(1) + "' class"); 267 } 268 if (LifeCycleController.class.isAssignableFrom(superClass)) { 269 interfaces.add(ContentLifeCycleController.class); 270 } 271 if (BindingController.class.isAssignableFrom(superClass)) { 272 interfaces.add(ContentBindingController.class); 273 } 274 275 ClassWriter cw = new ClassWriter(false); 277 String [] itfs = new String [interfaces.size()]; 278 for (int i = 0; i < itfs.length; ++i) { 279 itfs[i] = Type.getInternalName((Class )interfaces.get(i)); 280 } 281 cw.visit(V1_1, ACC_PUBLIC, mergedClassName, superClassName, itfs, "MERGED"); 282 283 CodeVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 285 mw.visitVarInsn(ALOAD, 0); 286 mw.visitMethodInsn(INVOKESPECIAL, superClassName, "<init>", "()V"); 287 mw.visitInsn(RETURN); 288 mw.visitMaxs(1, 1); 289 290 parameters = args.toString(); 292 String mName = "getFcGeneratorParameters"; 293 String mDesc = "()Ljava/lang/String;"; 294 CodeVisitor mv = cw.visitMethod(ACC_PUBLIC, mName, mDesc, null, null); 295 mv.visitLdcInsn(parameters); 296 mv.visitInsn(ARETURN); 297 mv.visitMaxs(1, 1); 298 299 inicv = cw.visitMethod( 301 ACC_PUBLIC, 302 "initialize", 303 "(Lorg/objectweb/fractal/julia/loader/Tree;)V", 304 null, 305 null); 306 307 icv = cw.visitMethod( 309 ACC_PUBLIC, 310 "initFcController", 311 "(Lorg/objectweb/fractal/julia/InitializationContext;)V", 312 null, 313 null); 314 315 for (int i = 0; i < classes.length; ++i) { 317 inheritedClasses = new ArrayList (); 318 counters = new HashMap (); 319 320 Class c = classes[i]; 321 while (c != Object .class) { 322 inheritedClasses.add(Type.getInternalName(c)); 323 c = c.getSuperclass(); 324 } 325 326 c = classes[i]; 327 while (c != Object .class) { 328 currentClass = c; 329 currentClassIndex = i; 330 currentClassName = Type.getInternalName(c); 331 MergeClassAdapter mca = new MergeClassAdapter(cw); 332 try { 333 getClassReader(c).accept(mca, false); 334 } catch (IOException e) { 335 throw new ClassGenerationException( 336 e, args.toString(), "Cannot read the '" + c.getName() + "' class"); 337 } catch (VisitException e) { 338 throw e.getException(); 339 } 340 updateCounters(c); 341 c = c.getSuperclass(); 342 } 343 } 344 345 inicv.visitInsn(RETURN); 346 inicv.visitMaxs(3, 2); 347 348 icv.visitInsn(RETURN); 349 icv.visitMaxs(2, 2); 350 351 if (LifeCycleController.class.isAssignableFrom(superClass)) { 354 mName = "startFcContent"; 356 mv = cw.visitMethod(ACC_PUBLIC, mName, "()V", null, null); 357 mv.visitVarInsn(ALOAD, 0); 358 mv.visitMethodInsn(INVOKESPECIAL, superClassName, "startFc", "()V"); 359 mv.visitInsn(RETURN); 360 mv.visitMaxs(1, 1); 361 mName = "stopFcContent"; 363 mv = cw.visitMethod(ACC_PUBLIC, mName, "()V", null, null); 364 mv.visitVarInsn(ALOAD, 0); 365 mv.visitMethodInsn(INVOKESPECIAL, superClassName, "stopFc", "()V"); 366 mv.visitInsn(RETURN); 367 mv.visitMaxs(1, 1); 368 } 369 370 if (BindingController.class.isAssignableFrom(superClass)) { 373 mName = "listFcContent"; 375 mv = cw.visitMethod( 376 ACC_PUBLIC, mName, "()[Ljava/lang/String;", null, null); 377 mv.visitVarInsn(ALOAD, 0); 378 mv.visitMethodInsn( 379 INVOKESPECIAL, superClassName, "listFc", "()[Ljava/lang/String;"); 380 mv.visitInsn(ARETURN); 381 mv.visitMaxs(1, 1); 382 mName = "lookupFcContent"; 384 mv = cw.visitMethod( 385 ACC_PUBLIC, mName, "(Ljava/lang/String;)Ljava/lang/Object;", null, null); 386 mv.visitVarInsn(ALOAD, 0); 387 mv.visitVarInsn(ALOAD, 1); 388 mv.visitMethodInsn( 389 INVOKESPECIAL, 390 superClassName, 391 "lookupFc", 392 "(Ljava/lang/String;)Ljava/lang/Object;"); 393 mv.visitInsn(ARETURN); 394 mv.visitMaxs(2, 2); 395 mName = "bindFcContent"; 397 mv = cw.visitMethod( 398 ACC_PUBLIC, mName, "(Ljava/lang/String;Ljava/lang/Object;)V", null, null); 399 mv.visitVarInsn(ALOAD, 0); 400 mv.visitVarInsn(ALOAD, 1); 401 mv.visitVarInsn(ALOAD, 2); 402 mv.visitMethodInsn( 403 INVOKESPECIAL, 404 superClassName, 405 "bindFc", 406 "(Ljava/lang/String;Ljava/lang/Object;)V"); 407 mv.visitInsn(RETURN); 408 mv.visitMaxs(3, 3); 409 mName = "unbindFcContent"; 411 mv = cw.visitMethod( 412 ACC_PUBLIC, mName, "(Ljava/lang/String;)V", null, null); 413 mv.visitVarInsn(ALOAD, 0); 414 mv.visitVarInsn(ALOAD, 1); 415 mv.visitMethodInsn( 416 INVOKESPECIAL, superClassName, "unbindFc", "(Ljava/lang/String;)V"); 417 mv.visitInsn(RETURN); 418 mv.visitMaxs(2, 2); 419 } 420 421 return cw.toByteArray(); 423 } 424 425 432 433 ClassReader getClassReader (final Class c) throws IOException { 434 try { 435 return new ClassReader(c.getName()); 436 } catch (IOException e) { 437 String s = Type.getInternalName(c) + ".class"; 440 return new ClassReader(c.getClassLoader().getResourceAsStream(s)); 441 } 442 } 443 444 451 452 int getCounter (final String name, final String desc) { 453 Integer value = (Integer )counters.get(name + desc); 454 return value == null ? -1 : value.intValue(); 455 } 456 457 464 465 void updateCounters (final Class c) { 466 Method [] meths = c.getDeclaredMethods(); 467 for (int i = 0; i < meths.length; ++i) { 468 Method meth = meths[i]; 469 if (!Modifier.isStatic(meth.getModifiers())) { 470 String key = meth.getName() + Type.getMethodDescriptor(meth); 471 Integer value = (Integer )counters.get(key); 472 int count = value == null ? 0 : value.intValue() + 1; 473 counters.put(key, new Integer (count)); 474 } 475 } 476 } 477 478 487 488 static boolean declares (final String m, final Class c) { 489 Method [] meths = c.getDeclaredMethods(); 490 for (int i = 0; i < meths.length; ++i) { 491 if (m.equals(meths[i].getName() + Type.getMethodDescriptor(meths[i]))) { 492 return true; 493 } 494 } 495 return false; 496 } 497 498 501 502 class MergeClassAdapter extends ClassAdapter implements Constants { 503 504 509 510 public MergeClassAdapter (final ClassVisitor cv) { 511 super(cv); 512 } 513 514 public void visit ( 515 final int version, 516 final int access, 517 final String name, 518 final String superName, 519 final String [] interfaces, 520 final String sourceFile) 521 { 522 } 524 525 public void visitField ( 526 final int access, 527 final String name, 528 final String desc, 529 final Object value, 530 final Attribute attrs) 531 { 532 if ((access & ACC_STATIC) == 0) { 533 if (!name.startsWith("weaveable")) { 534 super.visitField(access, name, desc, value, attrs); 535 } 536 } 537 } 538 539 public CodeVisitor visitMethod ( 540 final int access, 541 final String name, 542 final String desc, 543 final String [] exceptions, 544 final Attribute attrs) 545 { 546 if ((access & ACC_STATIC) != 0 || 547 (access & ACC_ABSTRACT) != 0 || 548 name.equals("<init>") || 549 name.startsWith("getFcGeneratorParameters")) 550 { 551 return null; 552 } 553 CodeVisitor mv; 554 int count = getCounter(name, desc); 555 if (count == -1) { 556 if (name.equals("initFcController")) { 557 icv.visitVarInsn(ALOAD, 0); 558 icv.visitVarInsn(ALOAD, 1); 559 icv.visitMethodInsn( 560 INVOKESPECIAL, 561 mergedClassName, 562 "$" + currentClassIndex + "$" + name, 563 "(Lorg/objectweb/fractal/julia/InitializationContext;)V"); 564 } 565 if (name.equals("initialize") 566 && desc.equals("(Lorg/objectweb/fractal/julia/loader/Tree;)V")) 567 { 568 inicv.visitVarInsn(ALOAD, 0); 569 inicv.visitVarInsn(ALOAD, 1); 570 inicv.visitIntInsn(SIPUSH, currentClassIndex); 571 inicv.visitMethodInsn( 572 INVOKEVIRTUAL, 573 "org/objectweb/fractal/julia/loader/Tree", 574 "getSubTree", 575 "(I)Lorg/objectweb/fractal/julia/loader/Tree;"); 576 inicv.visitMethodInsn( 577 INVOKESPECIAL, 578 mergedClassName, 579 "$" + currentClassIndex + "$" + name, 580 desc); 581 } 582 583 if (name.startsWith("initFcController") 584 || (name.startsWith("initialize") 585 && desc.equals("(Lorg/objectweb/fractal/julia/loader/Tree;)V"))) 586 { 587 mv = cv.visitMethod( 588 ACC_PRIVATE, 589 "$" + currentClassIndex + "$" + name, 590 desc, 591 exceptions, 592 attrs); 593 } else { 594 mv = cv.visitMethod(access, name, desc, exceptions, attrs); 595 } 596 } else { 597 int newAccess = access & ~(ACC_PUBLIC | ACC_PROTECTED) | ACC_PRIVATE; 598 String newName = name + "$" + count; 599 if (name.startsWith("initFcController") 600 || (name.startsWith("initialize") 601 && desc.equals("(Lorg/objectweb/fractal/julia/loader/Tree;)V"))) 602 { 603 mv = cv.visitMethod( 604 ACC_PRIVATE, 605 "$" + currentClassIndex + "$" + newName, 606 desc, 607 exceptions, 608 attrs); 609 } else { 610 mv = cv.visitMethod(newAccess, newName, desc, exceptions, attrs); 611 } 612 } 613 return new MergeCodeAdapter(mv); 614 } 615 } 616 617 620 621 class MergeCodeAdapter extends CodeAdapter implements Constants { 622 623 628 629 public MergeCodeAdapter (final CodeVisitor cv) { 630 super(cv); 631 } 632 633 public void visitFieldInsn ( 634 final int opcode, 635 final String owner, 636 final String name, 637 final String desc) 638 { 639 if (opcode == GETFIELD) { 640 if (inheritedClasses.contains(owner)) { 641 boolean remove = false; 642 boolean replaceNull = false; 643 if (name.startsWith("weaveable")) { 644 remove = true; 645 String s = desc.substring(1, desc.length() - 1).replace('/', '.'); 646 Class c; 647 try { 648 c = loader.loadClass(s, classLoader); 649 } catch (ClassNotFoundException e) { 650 throw new VisitException(new ClassGenerationException( 651 e, 652 parameters, 653 "Cannot load the '" + s + 654 "' interface required by one the classes to be merged")); 655 } 656 replaceNull = true; 657 for (int i = 0; i < interfaces.size(); ++i) { 658 if (c.isAssignableFrom((Class )interfaces.get(i))) { 659 replaceNull = false; 660 break; 661 } 662 } 663 if (!name.startsWith("weaveableOpt") && replaceNull) { 664 throw new VisitException(new ClassGenerationException( 665 null, 666 parameters, 667 "The required interface '" + name + 668 "' is not provided by any of the classes to be merged")); 669 } 670 } 671 if (remove) { 672 if (replaceNull) { 673 visitInsn(POP); 674 visitInsn(ACONST_NULL); 675 } 676 } else { 677 super.visitFieldInsn(opcode, mergedClassName, name, desc); 678 } 679 } else { 680 super.visitFieldInsn(opcode, owner, name, desc); 681 } 682 } else if (opcode == PUTFIELD) { 683 if (inheritedClasses.contains(owner)) { 684 if (name.startsWith("weaveable")) { 685 visitInsn(POP2); 686 } else { 687 super.visitFieldInsn(opcode, mergedClassName, name, desc); 688 } 689 } else { 690 super.visitFieldInsn(opcode, owner, name, desc); 691 } 692 } else { 693 super.visitFieldInsn(opcode, owner, name, desc); 694 } 695 } 696 697 public void visitMethodInsn ( 698 final int opcode, 699 final String owner, 700 final String name, 701 final String desc) 702 { 703 if (opcode != INVOKESTATIC && inheritedClasses.contains(owner)) { 704 if (opcode == INVOKESPECIAL && !owner.equals(currentClassName)) { 706 String superName; 708 if (declares(name + desc, currentClass)) { 709 superName = name + "$" + (getCounter(name, desc) + 1); 710 } else if (getCounter(name, desc) >= 0) { 711 superName = name + "$" + getCounter(name, desc); 712 } else { 713 superName = name; 714 } 715 super.visitMethodInsn(opcode, mergedClassName, superName, desc); 716 } else { 717 if (name.startsWith("initFcController") 718 || (name.startsWith("initialize") 719 && desc.equals("(Lorg/objectweb/fractal/julia/loader/Tree;)V"))) 720 { 721 super.visitMethodInsn( 722 opcode, 723 mergedClassName, 724 "$" + currentClassIndex + "$" + name, 725 desc); 726 } else { 727 super.visitMethodInsn(opcode, mergedClassName, name, desc); 729 } 730 } 731 } else { 732 super.visitMethodInsn(opcode, owner, name, desc); 733 } 734 } 735 } 736 } 737 | Popular Tags |