1 54 package org.logicalcobwebs.cglib.core; 55 56 import java.io.*; 57 import java.lang.reflect.Method ; 58 import java.util.*; 59 import org.logicalcobwebs.asm.*; 60 61 64 public class CodeEmitter extends RemappingCodeVisitor { 65 private static final Signature BOOLEAN_VALUE = 66 TypeUtils.parseSignature("boolean booleanValue()"); 67 private static final Signature CHAR_VALUE = 68 TypeUtils.parseSignature("char charValue()"); 69 private static final Signature LONG_VALUE = 70 TypeUtils.parseSignature("long longValue()"); 71 private static final Signature DOUBLE_VALUE = 72 TypeUtils.parseSignature("double doubleValue()"); 73 private static final Signature FLOAT_VALUE = 74 TypeUtils.parseSignature("float floatValue()"); 75 private static final Signature INT_VALUE = 76 TypeUtils.parseSignature("int intValue()"); 77 private static final Signature CSTRUCT_NULL = 78 TypeUtils.parseConstructor(""); 79 private static final Signature CSTRUCT_STRING = 80 TypeUtils.parseConstructor("String"); 81 82 public static final int ADD = Constants.IADD; 83 public static final int MUL = Constants.IMUL; 84 public static final int XOR = Constants.IXOR; 85 public static final int USHR = Constants.IUSHR; 86 public static final int SUB = Constants.ISUB; 87 public static final int DIV = Constants.IDIV; 88 public static final int NEG = Constants.INEG; 89 public static final int REM = Constants.IREM; 90 public static final int AND = Constants.IAND; 91 public static final int OR = Constants.IOR; 92 93 public static final int GT = Constants.IFGT; 94 public static final int LT = Constants.IFLT; 95 public static final int GE = Constants.IFGE; 96 public static final int LE = Constants.IFLE; 97 public static final int NE = Constants.IFNE; 98 public static final int EQ = Constants.IFEQ; 99 100 private ClassEmitter ce; 101 private State state; 102 103 private static class State { 104 int access; 105 Signature sig; 106 Type[] argumentTypes; 107 int localOffset; 108 Type[] exceptionTypes; 109 110 State(int access, Signature sig, Type[] exceptionTypes) { 111 this.access = access; 112 this.sig = sig; 113 this.exceptionTypes = exceptionTypes; 114 localOffset = TypeUtils.isStatic(access) ? 0 : 1; 115 argumentTypes = sig.getArgumentTypes(); 116 } 117 } 118 119 CodeEmitter(ClassEmitter ce, CodeVisitor cv, int access, Signature sig, Type[] exceptionTypes) { 120 super(cv, access, sig.getArgumentTypes()); 121 this.ce = ce; 122 state = new State(access, sig, exceptionTypes); 123 } 124 125 public CodeEmitter(CodeEmitter wrap) { 126 super(wrap); 127 this.ce = wrap.ce; 128 this.state = wrap.state; 129 } 130 131 public boolean isStaticHook() { 132 return false; 133 } 134 135 public Signature getSignature() { 136 return state.sig; 137 } 138 139 public Type getReturnType() { 140 return state.sig.getReturnType(); 141 } 142 143 152 153 public ClassEmitter getClassEmitter() { 154 return ce; 155 } 156 157 public void end_method() { 158 visitMaxs(0, 0); 159 } 160 161 public Block begin_block() { 162 return new Block(this); 163 } 164 165 public void catch_exception(Block block, Type exception) { 166 if (block.getEnd() == null) { 167 throw new IllegalStateException ("end of block is unset"); 168 } 169 cv.visitTryCatchBlock(block.getStart(), 170 block.getEnd(), 171 mark(), 172 exception.getInternalName()); 173 } 174 175 public void goTo(Label label) { cv.visitJumpInsn(Constants.GOTO, label); } 176 public void ifnull(Label label) { cv.visitJumpInsn(Constants.IFNULL, label); } 177 public void ifnonnull(Label label) { cv.visitJumpInsn(Constants.IFNONNULL, label); } 178 179 public void if_jump(int mode, Label label) { 180 cv.visitJumpInsn(mode, label); 181 } 182 183 public void if_icmp(int mode, Label label) { 184 if_cmp(Type.INT_TYPE, mode, label); 185 } 186 187 public void if_cmp(Type type, int mode, Label label) { 188 int intOp = -1; 189 int jumpmode = mode; 190 switch (mode) { 191 case GE: jumpmode = LT; break; 192 case LE: jumpmode = GT; break; 193 } 194 switch (type.getSort()) { 195 case Type.LONG: 196 cv.visitInsn(Constants.LCMP); 197 break; 198 case Type.DOUBLE: 199 cv.visitInsn(Constants.DCMPG); 200 break; 201 case Type.FLOAT: 202 cv.visitInsn(Constants.FCMPG); 203 break; 204 case Type.ARRAY: 205 case Type.OBJECT: 206 switch (mode) { 207 case EQ: 208 cv.visitJumpInsn(Constants.IF_ACMPEQ, label); 209 return; 210 case NE: 211 cv.visitJumpInsn(Constants.IF_ACMPNE, label); 212 return; 213 } 214 throw new IllegalArgumentException ("Bad comparison for type " + type); 215 default: 216 switch (mode) { 217 case EQ: intOp = Constants.IF_ICMPEQ; break; 218 case NE: intOp = Constants.IF_ICMPNE; break; 219 case GE: swap(); 220 case LT: intOp = Constants.IF_ICMPLT; break; 221 case LE: swap(); 222 case GT: intOp = Constants.IF_ICMPGT; break; 223 } 224 cv.visitJumpInsn(intOp, label); 225 return; 226 } 227 if_jump(jumpmode, label); 228 } 229 230 public void pop() { cv.visitInsn(Constants.POP); } 231 public void pop2() { cv.visitInsn(Constants.POP2); } 232 public void dup() { cv.visitInsn(Constants.DUP); } 233 public void dup2() { cv.visitInsn(Constants.DUP2); } 234 public void dup_x1() { cv.visitInsn(Constants.DUP_X1); } 235 public void dup_x2() { cv.visitInsn(Constants.DUP_X2); } 236 public void dup2_x1() { cv.visitInsn(Constants.DUP2_X1); } 237 public void dup2_x2() { cv.visitInsn(Constants.DUP2_X2); } 238 public void swap() { cv.visitInsn(Constants.SWAP); } 239 public void aconst_null() { cv.visitInsn(Constants.ACONST_NULL); } 240 241 public void swap(Type prev, Type type) { 242 if (type.getSize() == 1) { 243 if (prev.getSize() == 1) { 244 swap(); } else { 246 dup_x2(); 247 pop(); 248 } 249 } else { 250 if (prev.getSize() == 1) { 251 dup2_x1(); 252 pop2(); 253 } else { 254 dup2_x2(); 255 pop2(); 256 } 257 } 258 } 259 260 public void monitorenter() { cv.visitInsn(Constants.MONITORENTER); } 261 public void monitorexit() { cv.visitInsn(Constants.MONITOREXIT); } 262 263 public void math(int op, Type type) { cv.visitInsn(type.getOpcode(op)); } 264 265 public void array_load(Type type) { cv.visitInsn(type.getOpcode(Constants.IALOAD)); } 266 public void array_store(Type type) { cv.visitInsn(type.getOpcode(Constants.IASTORE)); } 267 268 271 public void cast_numeric(Type from, Type to) { 272 if (from != to) { 273 if (from == Type.DOUBLE_TYPE) { 274 if (to == Type.FLOAT_TYPE) { 275 cv.visitInsn(Constants.D2F); 276 } else if (to == Type.LONG_TYPE) { 277 cv.visitInsn(Constants.D2L); 278 } else { 279 cv.visitInsn(Constants.D2I); 280 cast_numeric(Type.INT_TYPE, to); 281 } 282 } else if (from == Type.FLOAT_TYPE) { 283 if (to == Type.DOUBLE_TYPE) { 284 cv.visitInsn(Constants.F2D); 285 } else if (to == Type.LONG_TYPE) { 286 cv.visitInsn(Constants.F2L); 287 } else { 288 cv.visitInsn(Constants.F2I); 289 cast_numeric(Type.INT_TYPE, to); 290 } 291 } else if (from == Type.LONG_TYPE) { 292 if (to == Type.DOUBLE_TYPE) { 293 cv.visitInsn(Constants.L2D); 294 } else if (to == Type.FLOAT_TYPE) { 295 cv.visitInsn(Constants.L2F); 296 } else { 297 cv.visitInsn(Constants.L2I); 298 cast_numeric(Type.INT_TYPE, to); 299 } 300 } else { 301 if (to == Type.BYTE_TYPE) { 302 cv.visitInsn(Constants.I2B); 303 } else if (to == Type.CHAR_TYPE) { 304 cv.visitInsn(Constants.I2C); 305 } else if (to == Type.DOUBLE_TYPE) { 306 cv.visitInsn(Constants.I2D); 307 } else if (to == Type.FLOAT_TYPE) { 308 cv.visitInsn(Constants.I2F); 309 } else if (to == Type.LONG_TYPE) { 310 cv.visitInsn(Constants.I2L); 311 } else if (to == Type.SHORT_TYPE) { 312 cv.visitInsn(Constants.I2S); 313 } 314 } 315 } 316 } 317 318 public void push(int i) { 319 if (i < -1) { 320 cv.visitLdcInsn(new Integer (i)); 321 } else if (i <= 5) { 322 cv.visitInsn(TypeUtils.ICONST(i)); 323 } else if (i <= Byte.MAX_VALUE) { 324 cv.visitIntInsn(Constants.BIPUSH, i); 325 } else if (i <= Short.MAX_VALUE) { 326 cv.visitIntInsn(Constants.SIPUSH, i); 327 } else { 328 cv.visitLdcInsn(new Integer (i)); 329 } 330 } 331 332 public void push(long value) { 333 if (value == 0L || value == 1L) { 334 cv.visitInsn(TypeUtils.LCONST(value)); 335 } else { 336 cv.visitLdcInsn(new Long (value)); 337 } 338 } 339 340 public void push(float value) { 341 if (value == 0f || value == 1f || value == 2f) { 342 cv.visitInsn(TypeUtils.FCONST(value)); 343 } else { 344 cv.visitLdcInsn(new Float (value)); 345 } 346 } 347 public void push(double value) { 348 if (value == 0d || value == 1d) { 349 cv.visitInsn(TypeUtils.DCONST(value)); 350 } else { 351 cv.visitLdcInsn(new Double (value)); 352 } 353 } 354 355 public void push(String value) { 356 cv.visitLdcInsn(value); 357 } 358 359 public void newarray() { 360 newarray(Constants.TYPE_OBJECT); 361 } 362 363 public void newarray(Type type) { 364 if (TypeUtils.isPrimitive(type)) { 365 cv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type)); 366 } else { 367 emit_type(Constants.ANEWARRAY, type); 368 } 369 } 370 371 public void arraylength() { 372 cv.visitInsn(Constants.ARRAYLENGTH); 373 } 374 375 public void load_this() { 376 if (TypeUtils.isStatic(state.access)) { 377 throw new IllegalStateException ("no 'this' pointer within static method"); 378 } 379 cv.visitVarInsn(Constants.ALOAD, 0); 380 } 381 382 385 public void load_args() { 386 load_args(0, state.argumentTypes.length); 387 } 388 389 393 public void load_arg(int index) { 394 load_local(state.argumentTypes[index], 395 state.localOffset + skipArgs(index)); 396 } 397 398 public void load_args(int fromArg, int count) { 400 int pos = state.localOffset + skipArgs(fromArg); 401 for (int i = 0; i < count; i++) { 402 Type t = state.argumentTypes[fromArg + i]; 403 load_local(t, pos); 404 pos += t.getSize(); 405 } 406 } 407 408 private int skipArgs(int numArgs) { 409 int amount = 0; 410 for (int i = 0; i < numArgs; i++) { 411 amount += state.argumentTypes[i].getSize(); 412 } 413 return amount; 414 } 415 416 private void load_local(Type t, int pos) { 417 cv.visitVarInsn(t.getOpcode(Constants.ILOAD), pos); 419 } 420 421 private void store_local(Type t, int pos) { 422 cv.visitVarInsn(t.getOpcode(Constants.ISTORE), pos); 424 } 425 426 public void iinc(Local local, int amount) { 427 cv.visitIincInsn(local.getIndex(), amount); 428 } 429 430 public void store_local(Local local) { 431 store_local(local.getType(), local.getIndex()); 432 } 433 434 public void load_local(Local local) { 435 load_local(local.getType(), local.getIndex()); 436 } 437 438 public void return_value() { 439 cv.visitInsn(state.sig.getReturnType().getOpcode(Constants.IRETURN)); 440 } 441 442 public void getfield(String name) { 443 ClassEmitter.FieldInfo info = ce.getFieldInfo(name); 444 int opcode = TypeUtils.isStatic(info.access) ? Constants.GETSTATIC : Constants.GETFIELD; 445 emit_field(opcode, ce.getClassType(), name, info.type); 446 } 447 448 public void putfield(String name) { 449 ClassEmitter.FieldInfo info = ce.getFieldInfo(name); 450 int opcode = TypeUtils.isStatic(info.access) ? Constants.PUTSTATIC : Constants.PUTFIELD; 451 emit_field(opcode, ce.getClassType(), name, info.type); 452 } 453 454 public void super_getfield(String name, Type type) { 455 emit_field(Constants.GETFIELD, ce.getSuperType(), name, type); 456 } 457 458 public void super_putfield(String name, Type type) { 459 emit_field(Constants.PUTFIELD, ce.getSuperType(), name, type); 460 } 461 462 public void super_getstatic(String name, Type type) { 463 emit_field(Constants.GETSTATIC, ce.getSuperType(), name, type); 464 } 465 466 public void super_putstatic(String name, Type type) { 467 emit_field(Constants.PUTSTATIC, ce.getSuperType(), name, type); 468 } 469 470 public void getfield(Type owner, String name, Type type) { 471 emit_field(Constants.GETFIELD, owner, name, type); 472 } 473 474 public void putfield(Type owner, String name, Type type) { 475 emit_field(Constants.PUTFIELD, owner, name, type); 476 } 477 478 public void getstatic(Type owner, String name, Type type) { 479 emit_field(Constants.GETSTATIC, owner, name, type); 480 } 481 482 public void putstatic(Type owner, String name, Type type) { 483 emit_field(Constants.PUTSTATIC, owner, name, type); 484 } 485 486 void emit_field(int opcode, Type ctype, String name, Type ftype) { 488 cv.visitFieldInsn(opcode, 489 ctype.getInternalName(), 490 name, 491 ftype.getDescriptor()); 492 } 493 494 public void super_invoke() { 495 super_invoke(state.sig); 496 } 497 498 public void super_invoke(Signature sig) { 499 emit_invoke(Constants.INVOKESPECIAL, ce.getSuperType(), sig); 500 } 501 502 public void invoke_constructor(Type type) { 503 invoke_constructor(type, CSTRUCT_NULL); 504 } 505 506 public void super_invoke_constructor() { 507 invoke_constructor(ce.getSuperType()); 508 } 509 510 public void invoke_constructor_this() { 511 invoke_constructor(ce.getClassType()); 512 } 513 514 private void emit_invoke(int opcode, Type type, Signature sig) { 515 if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) && 516 ((opcode == Constants.INVOKEVIRTUAL) || 517 (opcode == Constants.INVOKESTATIC))) { 518 } 520 cv.visitMethodInsn(opcode, 521 type.getInternalName(), 522 sig.getName(), 523 sig.getDescriptor()); 524 } 525 526 public void invoke_interface(Type owner, Signature sig) { 527 emit_invoke(Constants.INVOKEINTERFACE, owner, sig); 528 } 529 530 public void invoke_virtual(Type owner, Signature sig) { 531 emit_invoke(Constants.INVOKEVIRTUAL, owner, sig); 532 } 533 534 public void invoke_static(Type owner, Signature sig) { 535 emit_invoke(Constants.INVOKESTATIC, owner, sig); 536 } 537 538 public void invoke_virtual_this(Signature sig) { 539 invoke_virtual(ce.getClassType(), sig); 540 } 541 542 public void invoke_static_this(Signature sig) { 543 invoke_static(ce.getClassType(), sig); 544 } 545 546 public void invoke_constructor(Type type, Signature sig) { 547 emit_invoke(Constants.INVOKESPECIAL, type, sig); 548 } 549 550 public void invoke_constructor_this(Signature sig) { 551 invoke_constructor(ce.getClassType(), sig); 552 } 553 554 public void super_invoke_constructor(Signature sig) { 555 invoke_constructor(ce.getSuperType(), sig); 556 } 557 558 public void new_instance_this() { 559 new_instance(ce.getClassType()); 560 } 561 562 public void new_instance(Type type) { 563 emit_type(Constants.NEW, type); 564 } 565 566 private void emit_type(int opcode, Type type) { 567 String desc; 568 if (TypeUtils.isArray(type)) { 569 desc = type.getDescriptor(); 570 } else { 571 desc = type.getInternalName(); 572 } 573 cv.visitTypeInsn(opcode, desc); 574 } 575 576 public void aaload(int index) { 577 push(index); 578 aaload(); 579 } 580 581 public void aaload() { cv.visitInsn(Constants.AALOAD); } 582 public void aastore() { cv.visitInsn(Constants.AASTORE); } 583 public void athrow() { cv.visitInsn(Constants.ATHROW); } 584 585 public Label make_label() { 586 return new Label(); 587 } 588 589 public Local make_local() { 590 return make_local(Constants.TYPE_OBJECT); 591 } 592 593 public Local make_local(Type type) { 594 return new Local(nextLocal(type.getSize()), type); 595 } 596 597 public void checkcast_this() { 598 checkcast(ce.getClassType()); 599 } 600 601 public void checkcast(Type type) { 602 if (!type.equals(Constants.TYPE_OBJECT)) { 603 emit_type(Constants.CHECKCAST, type); 604 } 605 } 606 607 public void instance_of(Type type) { 608 emit_type(Constants.INSTANCEOF, type); 609 } 610 611 public void instance_of_this() { 612 instance_of(ce.getClassType()); 613 } 614 615 public void process_switch(int[] keys, ProcessSwitchCallback callback) { 616 float density; 617 if (keys.length == 0) { 618 density = 0; 619 } else { 620 density = (float)keys.length / (keys[keys.length - 1] - keys[0] + 1); 621 } 622 process_switch(keys, callback, density >= 0.5f); 623 } 624 625 public void process_switch(int[] keys, ProcessSwitchCallback callback, boolean useTable) { 626 if (!isSorted(keys)) 627 throw new IllegalArgumentException ("keys to switch must be sorted ascending"); 628 Label def = make_label(); 629 Label end = make_label(); 630 631 try { 632 if (keys.length > 0) { 633 int len = keys.length; 634 int min = keys[0]; 635 int max = keys[len - 1]; 636 int range = max - min + 1; 637 638 if (useTable) { 639 Label[] labels = new Label[range]; 640 Arrays.fill(labels, def); 641 for (int i = 0; i < len; i++) { 642 labels[keys[i] - min] = make_label(); 643 } 644 cv.visitTableSwitchInsn(min, max, def, labels); 645 for (int i = 0; i < range; i++) { 646 Label label = labels[i]; 647 if (label != def) { 648 mark(label); 649 callback.processCase(i + min, end); 650 } 651 } 652 } else { 653 Label[] labels = new Label[len]; 654 for (int i = 0; i < len; i++) { 655 labels[i] = make_label(); 656 } 657 cv.visitLookupSwitchInsn(def, keys, labels); 658 for (int i = 0; i < len; i++) { 659 mark(labels[i]); 660 callback.processCase(keys[i], end); 661 } 662 } 663 } 664 665 mark(def); 666 callback.processDefault(); 667 mark(end); 668 669 } catch (RuntimeException e) { 670 throw e; 671 } catch (Error e) { 672 throw e; 673 } catch (Exception e) { 674 throw new CodeGenerationException(e); 675 } 676 } 677 678 private static boolean isSorted(int[] keys) { 679 for (int i = 1; i < keys.length; i++) { 680 if (keys[i] < keys[i - 1]) 681 return false; 682 } 683 return true; 684 } 685 686 public void mark(Label label) { 687 cv.visitLabel(label); 688 } 689 690 Label mark() { 691 Label label = make_label(); 692 cv.visitLabel(label); 693 return label; 694 } 695 696 public void push(boolean value) { 697 push(value ? 1 : 0); 698 } 699 700 703 public void not() { 704 push(1); 705 math(XOR, Type.INT_TYPE); 706 } 707 708 public void throw_exception(Type type, String msg) { 709 new_instance(type); 710 dup(); 711 push(msg); 712 invoke_constructor(type, CSTRUCT_STRING); 713 athrow(); 714 } 715 716 723 public void box(Type type) { 724 if (TypeUtils.isPrimitive(type)) { 725 if (type == Type.VOID_TYPE) { 726 aconst_null(); 727 } else { 728 Type boxed = TypeUtils.getBoxedType(type); 729 new_instance(boxed); 730 if (type.getSize() == 2) { 731 dup_x2(); 733 dup_x2(); 734 pop(); 735 } else { 736 dup_x1(); 738 swap(); 739 } 740 invoke_constructor(boxed, new Signature(Constants.CONSTRUCTOR_NAME, Type.VOID_TYPE, new Type[]{ type })); 741 } 742 } 743 } 744 745 752 public void unbox(Type type) { 753 Type t = Constants.TYPE_NUMBER; 754 Signature sig = null; 755 switch (type.getSort()) { 756 case Type.VOID: 757 return; 758 case Type.CHAR: 759 t = Constants.TYPE_CHARACTER; 760 sig = CHAR_VALUE; 761 break; 762 case Type.BOOLEAN: 763 t = Constants.TYPE_BOOLEAN; 764 sig = BOOLEAN_VALUE; 765 break; 766 case Type.DOUBLE: 767 sig = DOUBLE_VALUE; 768 break; 769 case Type.FLOAT: 770 sig = FLOAT_VALUE; 771 break; 772 case Type.LONG: 773 sig = LONG_VALUE; 774 break; 775 case Type.INT: 776 case Type.SHORT: 777 case Type.BYTE: 778 sig = INT_VALUE; 779 } 780 781 if (sig == null) { 782 checkcast(type); 783 } else { 784 checkcast(t); 785 invoke_virtual(t, sig); 786 } 787 } 788 789 794 public void create_arg_array() { 795 798 799 push(state.argumentTypes.length); 800 newarray(); 801 for (int i = 0; i < state.argumentTypes.length; i++) { 802 dup(); 803 push(i); 804 load_arg(i); 805 box(state.argumentTypes[i]); 806 aastore(); 807 } 808 } 809 810 811 814 public void zero_or_null(Type type) { 815 if (TypeUtils.isPrimitive(type)) { 816 switch (type.getSort()) { 817 case Type.DOUBLE: 818 push(0d); 819 break; 820 case Type.LONG: 821 push(0L); 822 break; 823 case Type.FLOAT: 824 push(0f); 825 break; 826 case Type.VOID: 827 aconst_null(); 828 default: 829 push(0); 830 } 831 } else { 832 aconst_null(); 833 } 834 } 835 836 840 public void unbox_or_zero(Type type) { 841 if (TypeUtils.isPrimitive(type)) { 842 if (type != Type.VOID_TYPE) { 843 Label nonNull = make_label(); 844 Label end = make_label(); 845 dup(); 846 ifnonnull(nonNull); 847 pop(); 848 zero_or_null(type); 849 goTo(end); 850 mark(nonNull); 851 unbox(type); 852 mark(end); 853 } 854 } else { 855 checkcast(type); 856 } 857 } 858 859 public void visitMaxs(int maxStack, int maxLocals) { 860 if (!TypeUtils.isAbstract(state.access)) { 861 cv.visitMaxs(0, 0); 862 } 863 } 864 865 public void invoke(Method method) { 866 Class declaring = method.getDeclaringClass(); 867 Type owner = Type.getType(declaring); 868 Signature sig = TypeUtils.getSignature(method); 869 if (declaring.isInterface()) { 870 invoke_interface(owner, sig); 871 } else if (TypeUtils.isStatic(method.getModifiers())) { 872 invoke_static(owner, sig); 873 } else { 874 invoke_virtual(owner, sig); 875 } 876 } 877 878 public void define_attribute(Attribute attrs) { 879 cv.visitAttribute(attrs); 880 } 881 } 882 | Popular Tags |