1 18 package org.objectweb.speedo.generation.enhancer; 19 20 import org.objectweb.asm.CodeAdapter; 21 import org.objectweb.asm.CodeVisitor; 22 import org.objectweb.asm.Constants; 23 import org.objectweb.asm.ClassVisitor; 24 import org.objectweb.asm.Label; 25 import org.objectweb.asm.Type; 26 import org.objectweb.asm.Attribute; 27 import org.objectweb.speedo.metadata.SpeedoField; 28 import org.objectweb.speedo.metadata.SpeedoClass; 29 import org.objectweb.speedo.generation.lib.NamingRules; 30 import org.objectweb.util.monolog.api.Logger; 31 import org.objectweb.util.monolog.api.BasicLevel; 32 33 import java.util.List ; 34 import java.util.ArrayList ; 35 import java.util.Collection ; 36 37 42 public class ClassAccessorModifier extends LoggedClassAdapter { 43 44 49 50 final static int[] SIZE; 51 52 56 57 static { 58 int i; 59 int[] b = new int[202]; 60 String s = 61 "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEE" + 62 "EEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEF" + 63 "DDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE"; 64 for (i = 0; i < b.length; ++i) { 65 b[i] = s.charAt(i) - 'E'; 66 } 67 SIZE = b; 68 } 69 70 73 private final Collection xmlDescriptors; 74 75 78 String owner; 79 80 83 String fieldsOwner; 84 85 int nbfields = 128; 86 87 93 public ClassAccessorModifier(final ClassVisitor cv, 94 final Collection xmlDescriptors, 95 Logger logger) { 96 super(cv, logger); 97 this.xmlDescriptors = xmlDescriptors; 98 } 99 100 103 public void visit(final int version, final int access, 104 final String name, 105 final String superName, 106 final String [] interfaces, 107 final String sourceFile) { 108 cv.visit(version, access, name, superName, interfaces, sourceFile); 109 owner = name; 110 nbfields = Util.isPersistentCapable(owner.replace('/', '.'), xmlDescriptors).computeFieldNumbers(); 111 fieldsOwner = NamingRules.fieldsName(owner); 112 } 113 114 public CodeVisitor visitMethod(final int access, 115 final String name, 116 final String desc, 117 final String [] exceptions, 118 final Attribute attrs) { 119 CodeVisitor _cv = this.cv.visitMethod(access, name, desc, exceptions, attrs); 120 if ((access & Constants.ACC_ABSTRACT) != 0) { 121 logger.log(BasicLevel.DEBUG, 123 "ignore the abstract method " + name + " " + desc); 124 return _cv; 125 } 126 if (name.startsWith("jdo") 127 && !name.equals("jdoPreDelete") 128 && !name.equals("jdoPreStore") 129 && !name.equals("jdoPreClear") 130 && !name.equals("jdoPostLoad") 131 ) { 132 logger.log(BasicLevel.DEBUG, 134 "ignoe the method " + name + " " + desc); 135 return _cv; 136 } 137 if (name.equals("<clinit>") || (access & Constants.ACC_STATIC) != 0) { 138 return new DefaultCodeAccessorModifier(desc, false, _cv, name, this); 141 } else { 142 return new OptimisticCodeAccessorModifier(desc, _cv, name, this); 148 } 149 } 150 151 154 161 SpeedoField fetchJDOField(final String name, final String className) { 162 SpeedoClass c = Util.isPersistentCapable(className, xmlDescriptors); 163 if (c != null) { 164 SpeedoField speedoField = null; 165 while (speedoField == null && c != null) { 168 speedoField = (SpeedoField) c.jdoField.get(name); 169 c = c.getSuper(); 170 } 171 return speedoField; 172 } else { 173 return null; 174 } 175 } 176 177 } 178 184 class DefaultCodeAccessorModifier extends CodeAdapter { 185 186 189 protected String desc; 190 191 194 protected Type[] types; 195 196 199 protected int params; 200 201 204 private Label start; 205 206 209 private Label header; 210 211 218 protected List insns; 219 220 229 protected List stack; 230 231 235 protected long[] readFields; 236 237 241 protected long[] writtenFields; 242 243 244 boolean isConstructor; 245 246 boolean firstIns = false; 247 248 ClassAccessorModifier cam; 249 250 258 public DefaultCodeAccessorModifier(final String desc, 259 final boolean hasHeader, 260 final CodeVisitor cv, 261 final String name, 262 final ClassAccessorModifier _cam) { 263 super(cv); 264 this.cam = _cam; 265 isConstructor = name.equals("<init>"); 266 cam.logger.log(BasicLevel.INFO, "visit the method " + name + " " + desc 267 + " (const=" + isConstructor 268 + ", header=" + hasHeader + ")"); 269 firstIns = true; 270 int size = (cam.nbfields/64) + ((cam.nbfields % 64) > 0 ? 1 : 0); 271 writtenFields = new long[size]; 272 readFields = new long[size]; 273 this.desc = desc; 274 this.types = Type.getArgumentTypes(desc); 275 params = 1; 276 for (int i = 0; i < types.length; ++i) { 277 params += types[i].getSize(); 278 } 279 this.insns = new ArrayList (); 280 this.stack = new ArrayList (); 281 if (hasHeader && !isConstructor) { 282 cam.logger.log(BasicLevel.DEBUG, "Add Jump at the begin of method: " + name); 283 addJumpHeader(); 284 } 285 } 286 287 protected void addJumpHeader() { 288 start = new Label(); 289 header = new Label(); 290 flushInsns(); 291 cv.visitJumpInsn(Constants.GOTO, header); 292 visitLabel(start); 293 } 294 295 298 public void visitInsn(final int opcode) { 299 if ((opcode >= Constants.IRETURN && opcode <= Constants.RETURN) || 300 opcode == Constants.ATHROW) { 301 flushInsns(); 302 cv.visitInsn(opcode); 303 } else { 304 if (opcode == Constants.DUP && stack.size() > 0) { 305 stack.add(stack.get(stack.size() - 1)); 307 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 308 } else { 309 updateStack(ClassAccessorModifier.SIZE[opcode]); 310 } 311 insns.add(new Insn(opcode)); 312 } 313 } 314 315 public void visitIntInsn(final int opcode, final int operand) { 316 updateStack(ClassAccessorModifier.SIZE[opcode]); 317 insns.add(new Insn(true, opcode, operand)); 318 } 319 320 public void visitVarInsn(final int opcode, final int var) { 321 if (opcode == Constants.RET) { 322 flushInsns(); 323 cv.visitVarInsn(opcode, var); 324 } else { 325 if (opcode == Constants.ALOAD && var == 0) { 326 stack.add(new Integer (insns.size())); 327 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 328 } else { 329 updateStack(ClassAccessorModifier.SIZE[opcode]); 330 } 331 insns.add(new Insn(false, opcode, var)); 332 } 333 } 334 335 public void visitTypeInsn(final int opcode, final String desc) { 336 updateStack(ClassAccessorModifier.SIZE[opcode]); 337 insns.add(new Insn(opcode, desc)); 338 } 339 340 public void visitFieldInsn(final int opcode, 341 final String owner, 342 final String name, 343 final String desc) { 344 SpeedoField jdofield = cam.fetchJDOField(name, owner.replace('/', '.')); 345 char c = desc.charAt(0); 346 int fieldSize = (c == 'D' || c == 'J' ? 2 : 1); 347 boolean directFieldAccess = c != 'L' || desc.startsWith("Ljava/lang/") || desc.startsWith("Ljava/math/"); 351 int stackSizeVariation; 352 int thisInsnIndex = -1; 353 switch (opcode) { 354 case Constants.GETSTATIC: 355 stackSizeVariation = fieldSize; 356 break; 358 case Constants.PUTSTATIC: 359 stackSizeVariation = -fieldSize; 360 break; 362 case Constants.GETFIELD: 363 stackSizeVariation = fieldSize - 1; 364 if (jdofield == null) { 365 break; 366 } 367 if (directFieldAccess) { 368 thisInsnIndex = getThisInsnIndex(0); 369 directFieldAccess = thisInsnIndex != -1; 371 } 372 if (directFieldAccess) { readFields[jdofield.number / 64] |= (1L << (jdofield.number % 64)); 374 visitThisFieldInsn( 375 opcode, owner, name, desc, thisInsnIndex); 376 cam.logger.log(BasicLevel.DEBUG, "direct field use: " + name); 377 } else { String getterName = NamingRules.getterName(jdofield); 379 String getterDesc = "()" + desc; 380 insns.add(new Insn(Constants.INVOKEVIRTUAL, 381 owner, getterName, getterDesc)); 382 cam.logger.log(BasicLevel.DEBUG, "getter assignment: " + getterName); 383 } 384 updateStack(stackSizeVariation); 385 return; 386 case Constants.PUTFIELD: 387 stackSizeVariation = 0 - (fieldSize + 1); 388 if (jdofield == null) { 389 break; 390 } 391 if (directFieldAccess) { 392 thisInsnIndex = getThisInsnIndex(fieldSize); 393 directFieldAccess = thisInsnIndex != -1; 395 } 396 if (directFieldAccess) { writtenFields[jdofield.number / 64] |= (1L << (jdofield.number % 64)); 398 visitThisFieldInsn(opcode, owner, name, desc, thisInsnIndex); 399 cam.logger.log(BasicLevel.DEBUG, "direct field assignment: " + name); 400 } else { String setterName = NamingRules.setterName(jdofield); 402 String setterDesc = "(" + desc + ")V"; 403 insns.add(new Insn(Constants.INVOKEVIRTUAL, 404 owner, setterName, setterDesc)); 405 cam.logger.log(BasicLevel.DEBUG, "setter assignment: " + setterName); 406 } 407 updateStack(stackSizeVariation); 408 return; 409 default: 410 stackSizeVariation = - fieldSize -1; 411 } 412 updateStack(stackSizeVariation); 413 insns.add(new Insn(opcode, owner, name, desc)); 414 } 415 416 421 private int getThisInsnIndex(int fieldidx) { 422 int stackSize = stack.size(); 423 if (stackSize > 0 && stackSize > fieldidx) { 424 Integer i = (Integer ) stack.get(stackSize - 1 - fieldidx); 425 if (i != null) { 426 return i.intValue(); 427 } else { 428 cam.logger.log(BasicLevel.DEBUG, "i is null (stack: " + stack + ")"); 429 } 430 } else { 431 cam.logger.log(BasicLevel.DEBUG, "stack size: " + stackSize); 432 } 433 return -1; 434 } 435 public void visitMethodInsn(final int opcode, 436 final String owner, 437 final String name, 438 final String desc) { 439 int size = opcode == Constants.INVOKESTATIC ? 0 : 1; 441 int c = 1; 442 while (true) { 443 char car = desc.charAt(c++); 444 if (car == ')') { 445 car = desc.charAt(c); 446 if (car == 'V') { 447 size = -size; 448 } else { 449 size = (car == 'D' || car == 'J' ? 2 : 1) - size; 450 } 451 break; 452 } else if (car == 'L') { 453 while (desc.charAt(c++) != ';') { 454 } 455 size += 1; 456 } else if (car == '[') { 457 while ((car = desc.charAt(c)) == '[') { 458 ++c; 459 } 460 if (car == 'D' || car == 'J') { 461 size -= 1; 462 } 463 } else if (car == 'D' || car == 'J') { 464 size += 2; 465 } else { 466 size += 1; 467 } 468 } 469 updateStack(size); 470 insns.add(new Insn(opcode, owner, name, desc)); 471 if (firstIns && isConstructor) { 472 if (opcode == Constants.INVOKESPECIAL) { 473 firstIns = false; 474 generateConstructorHeader(); 475 } 476 } 477 } 478 479 public void visitJumpInsn(final int opcode, final Label label) { 480 flushInsns(); 481 cv.visitJumpInsn(opcode, label); 482 } 483 484 public void visitLabel(final Label label) { 485 insns.add(new Insn(label)); 486 } 487 488 public void visitLdcInsn(final Object cst) { 489 int size; 490 if (cst instanceof Double || cst instanceof Long ) { 491 size = 2; 492 } else { 493 size = 1; 494 } 495 updateStack(size); 496 insns.add(new Insn(cst)); 497 } 498 499 public void visitIincInsn(final int var, final int increment) { 500 insns.add(new Insn(var, increment)); 502 } 503 504 public void visitTableSwitchInsn(final int min, 505 final int max, 506 final Label dflt, 507 final Label labels[]) { 508 flushInsns(); 509 cv.visitTableSwitchInsn(min, max, dflt, labels); 510 } 511 512 public void visitLookupSwitchInsn(final Label dflt, 513 final int keys[], 514 final Label labels[]) { 515 flushInsns(); 516 cv.visitLookupSwitchInsn(dflt, keys, labels); 517 } 518 519 public void visitMultiANewArrayInsn(final String desc, 520 final int dims) { 521 updateStack(1 - dims); 522 insns.add(new Insn(desc, dims)); 523 } 524 525 public void visitTryCatchBlock(final Label start, 526 final Label end, 527 final Label handler, 528 final String type) { 529 flushInsns(); 530 super.visitTryCatchBlock(start, end, handler, type); 531 } 532 533 public void visitMaxs(final int maxStack, final int maxLocals) { 534 flushInsns(); 535 if (header != null) { 536 cv.visitLabel(header); 537 generateMethodHeader(); 538 cv.visitJumpInsn(Constants.GOTO, start); 539 } 540 cv.visitMaxs(maxStack, maxLocals); 541 } 542 543 public void visitLocalVariable(final String name, 544 final String desc, 545 final Label start, 546 final Label end, 547 final int index) { 548 flushInsns(); 549 super.visitLocalVariable(name, desc, start, end, index); 550 } 551 552 public void visitLineNumber(final int line, final Label start) { 553 flushInsns(); 554 super.visitLineNumber(line, start); 555 } 556 557 560 564 protected void generateMethodHeader() { 565 } 567 568 protected void generateConstructorHeader() { 569 } 571 572 584 protected void visitThisFieldInsn(final int opcode, 585 final String owner, 586 final String name, 587 final String desc, 588 final int pushThisInsn) { 589 insns.add(new Insn(opcode, owner, name, desc)); 591 } 592 593 604 protected void flushInsns() { 605 int n = insns.size(); 606 for (int i = 0; i < n; ++i) { 607 ((Insn) insns.get(i)).accept(cv); 608 } 609 insns.clear(); 610 stack.clear(); 611 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 612 } 613 614 620 private void updateStack(final int n) { 621 int size = stack.size(); 622 if (n > 0) { 623 for (int i = 0; i < n; ++i) { 624 stack.add(null); 625 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 626 } 627 } else { 628 int m = -n; 629 if (m >= size) { 630 stack.clear(); 631 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 632 } else { 633 for (int i = 0; i < m; ++i) { 634 stack.remove(--size); 635 cam.logger.log(BasicLevel.DEBUG, "stack=" + stack); 636 } 637 } 638 } 639 } 640 } 641 642 648 class OptimisticCodeAccessorModifier extends DefaultCodeAccessorModifier { 649 650 657 public OptimisticCodeAccessorModifier(final String desc, 658 final CodeVisitor cv, 659 String name, 660 ClassAccessorModifier cam) { 661 super(desc, true, cv, name, cam); 662 } 663 664 667 public void visitVarInsn(final int opcode, final int var) { 668 super.visitVarInsn(opcode, var >= params ? var + 1 : var); 672 } 673 674 public void visitIincInsn(final int var, final int increment) { 675 super.visitIincInsn(var >= params ? var + 1 : var, increment); 679 } 680 681 public void visitMaxs(final int maxStack, final int maxLocals) { 682 boolean allUnmodified = true; 683 for (int i=0; allUnmodified && i<cam.nbfields; i++) { 684 allUnmodified &= readFields[i/64] == 0 & writtenFields[i/64] == 0; 685 } 686 if (allUnmodified) { 687 super.visitMaxs(maxStack, maxLocals + (cam.nbfields/64) + 1); 688 } else { 689 super.visitMaxs(Math.max(maxStack, 4), maxLocals + (cam.nbfields/64) + 1); 690 } 691 } 692 693 protected void generateConstructorHeader() { 694 cam.logger.log(BasicLevel.DEBUG, "Create reference state after the super in the constructor"); 695 flushInsns(); 696 697 cv.visitVarInsn(Constants.ALOAD, 0); 699 cv.visitMethodInsn(Constants.INVOKEVIRTUAL, cam.owner, 700 "getReferenceAccessor", 701 "()Lorg/objectweb/speedo/mim/api/SpeedoAccessor;"); 702 Label afterSetState = new Label(); 703 cv.visitJumpInsn(Constants.IFNONNULL, afterSetState); 704 705 cv.visitVarInsn(Constants.ALOAD, 0); 708 cv.visitVarInsn(Constants.ALOAD, 0); 709 cv.visitMethodInsn(Constants.INVOKEVIRTUAL, cam.owner, 710 "createAccessor", 711 "()Lorg/objectweb/speedo/mim/api/SpeedoAccessor;"); 712 cv.visitMethodInsn(Constants.INVOKEVIRTUAL, cam.owner, 713 "setReferenceAccessor", 714 "(Lorg/objectweb/speedo/mim/api/SpeedoAccessor;)V"); 715 716 cv.visitLabel(afterSetState); 717 718 cv.visitVarInsn(Constants.ALOAD, 0); 720 cv.visitMethodInsn(Constants.INVOKEVIRTUAL, cam.owner, 721 "getReferenceAccessor", 722 "()Lorg/objectweb/speedo/mim/api/SpeedoAccessor;"); 723 cv.visitTypeInsn(Constants.CHECKCAST, NamingRules.fieldsName(cam.owner)); 724 cv.visitVarInsn(Constants.ASTORE, params); 725 } 726 727 protected void generateMethodHeader() { 728 boolean allUnmodified = true; 729 boolean hasWritten = false; 730 for (int i=0; allUnmodified && i<cam.nbfields; i++) { 731 hasWritten |= writtenFields[i/64] != 0; 732 allUnmodified &= readFields[i/64] == 0 & writtenFields[i/64] == 0; 733 } 734 cam.logger.log(BasicLevel.DEBUG, "allUnmodified=" + allUnmodified); 735 if (allUnmodified) { 736 return; 737 } 738 cv.visitVarInsn(Constants.ALOAD, 0); 741 745 Util.visitIntConstant(cv, readFields.length); 747 cv.visitIntInsn(Constants.NEWARRAY, Constants.T_LONG); 748 StringBuffer sb = new StringBuffer (); 749 sb.append(hasWritten ? "jdoWriteIntention" : "jdoReadIntention"); 750 sb.append("(new long[]{"); 751 String sep = ""; 752 for(int i=0; i<readFields.length; i++) { 753 cv.visitInsn(Constants.DUP); 754 Util.visitIntConstant(cv, i); 755 Util.visitLongConstant(cv, readFields[i] | writtenFields[i]); 756 sb.append(sep); 757 sep = ", "; 758 sb.append(readFields[i] | writtenFields[i]); 759 sb.append("L"); 760 cv.visitInsn(Constants.LASTORE); 761 } 762 sb.append(")"); 763 cam.logger.log(BasicLevel.INFO, sb.toString()); 764 cv.visitMethodInsn( 765 Constants.INVOKEVIRTUAL, 766 cam.owner, 767 hasWritten ? "jdoWriteIntention" : "jdoReadIntention", 768 "([J)Lorg/objectweb/speedo/mim/api/SpeedoAccessor;"); 769 cv.visitTypeInsn(Constants.CHECKCAST, NamingRules.fieldsName(cam.owner)); 771 cv.visitVarInsn(Constants.ASTORE, params); 772 } 773 protected void visitThisFieldInsn(final int opcode, 774 final String owner, 775 final String name, 776 final String desc, 777 final int pushThisInsn) { 778 cam.logger.log(BasicLevel.DEBUG, "replace ALOAD0 at " + pushThisInsn); 781 insns.set(pushThisInsn, new Insn(false, Constants.ALOAD, params)); 782 insns.add(new Insn(opcode, cam.fieldsOwner, name, desc)); 783 } 784 } 785 786 793 class Insn { 794 795 final static int INSN = 1; 797 final static int INT_INSN = 2; 798 final static int VAR_INSN = 3; 799 final static int TYPE_INSN = 4; 800 final static int FIELD_INSN = 5; 801 final static int METH_INSN = 6; 802 final static int LABEL_INSN = 7; 803 final static int LDC_INSN = 8; 804 final static int IINC_INSN = 9; 805 final static int MANA_INSN = 10; 806 807 810 private int type; 811 812 815 private int opcode; 816 817 819 private int int1, int2; 820 private String str1, str2, str3; 821 private Object obj; 822 823 public Insn(final int opcode) { 824 this.type = INSN; 825 this.opcode = opcode; 826 } 827 828 public Insn(final boolean intInsn, final int opcode, final int val) { 829 this.type = intInsn ? INT_INSN : VAR_INSN; 830 this.opcode = opcode; 831 this.int1 = val; 832 } 833 834 public Insn(final int opcode, final String desc) { 835 this.type = TYPE_INSN; 836 this.opcode = opcode; 837 this.str1 = desc; 838 } 839 840 public Insn(final int opcode, 841 final String owner, 842 final String name, 843 final String desc) { 844 this.type = opcode <= Constants.PUTFIELD ? FIELD_INSN : METH_INSN; 845 this.opcode = opcode; 846 this.str1 = owner; 847 this.str2 = name; 848 this.str3 = desc; 849 } 850 851 public Insn(final Label label) { 852 this.type = LABEL_INSN; 853 this.obj = label; 854 } 855 856 public Insn(final Object cst) { 857 this.type = LDC_INSN; 858 this.obj = cst; 859 } 860 861 public Insn(final int var, final int inc) { 862 this.type = IINC_INSN; 863 this.int1 = var; 864 this.int2 = inc; 865 } 866 867 public Insn(final String desc, final int dims) { 868 this.type = MANA_INSN; 869 this.str1 = desc; 870 this.int1 = dims; 871 } 872 873 878 public void accept(final CodeVisitor cv) { 879 switch (type) { 880 case INSN: 881 cv.visitInsn(opcode); 882 break; 883 case INT_INSN: 884 cv.visitIntInsn(opcode, int1); 885 break; 886 case VAR_INSN: 887 cv.visitVarInsn(opcode, int1); 888 break; 889 case TYPE_INSN: 890 cv.visitTypeInsn(opcode, str1); 891 break; 892 case FIELD_INSN: 893 cv.visitFieldInsn(opcode, str1, str2, str3); 894 break; 895 case METH_INSN: 896 cv.visitMethodInsn(opcode, str1, str2, str3); 897 break; 898 case LABEL_INSN: 899 cv.visitLabel((Label) obj); 900 break; 901 case LDC_INSN: 902 cv.visitLdcInsn(obj); 903 break; 904 case IINC_INSN: 905 cv.visitIincInsn(int1, int2); 906 break; 907 default: 908 cv.visitMultiANewArrayInsn(str1, int1); 909 } 910 } 911 } 912 | Popular Tags |