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