001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.generic; 020 021import org.apache.bcel.Const; 022 023/** 024 * Instances of this class may be used, for example, to generate typed versions of instructions. Its main purpose is to be used 025 * as the byte code generating backend of a compiler. You can subclass it to add your own create methods. 026 * <p> 027 * Note: The static createXXX methods return singleton instances from the {@link InstructionConst} class. 028 * </p> 029 * 030 * @see Const 031 * @see InstructionConst 032 */ 033public class InstructionFactory implements InstructionConstants { 034 035 private static final class MethodObject { 036 037 final Type[] argTypes; 038 final Type resultType; 039 final String className; 040 final String name; 041 042 MethodObject(final String c, final String n, final Type r, final Type[] a) { 043 this.className = c; 044 this.name = n; 045 this.resultType = r; 046 this.argTypes = a; 047 } 048 } 049 050 private static final String APPEND = "append"; 051 052 private static final String FQCN_STRING_BUFFER = "java.lang.StringBuffer"; 053 054 /** 055 * These must agree with the order of Constants.T_CHAR through T_LONG. 056 */ 057 private static final String[] SHORT_NAMES = {"C", "F", "D", "B", "S", "I", "L"}; 058 059 private static final MethodObject[] APPEND_METHOD_OBJECTS = { 060 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.STRING }), 061 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.OBJECT }), null, null, // indices 2, 3 062 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.BOOLEAN }), 063 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.CHAR }), 064 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.FLOAT }), 065 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.DOUBLE }), 066 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), 067 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(byte) 068 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.INT }), // No append(short) 069 new MethodObject(FQCN_STRING_BUFFER, APPEND, Type.STRINGBUFFER, new Type[] { Type.LONG })}; 070 071 /** 072 * Creates an array load instruction for the given type. 073 * 074 * @param type type of elements of array, that is, array.getElementType(). 075 * @return The array load instruction. 076 */ 077 public static ArrayInstruction createArrayLoad(final Type type) { 078 switch (type.getType()) { 079 case Const.T_BOOLEAN: 080 case Const.T_BYTE: 081 return InstructionConst.BALOAD; 082 case Const.T_CHAR: 083 return InstructionConst.CALOAD; 084 case Const.T_SHORT: 085 return InstructionConst.SALOAD; 086 case Const.T_INT: 087 return InstructionConst.IALOAD; 088 case Const.T_FLOAT: 089 return InstructionConst.FALOAD; 090 case Const.T_DOUBLE: 091 return InstructionConst.DALOAD; 092 case Const.T_LONG: 093 return InstructionConst.LALOAD; 094 case Const.T_ARRAY: 095 case Const.T_OBJECT: 096 return InstructionConst.AALOAD; 097 default: 098 throw new IllegalArgumentException("Invalid type " + type); 099 } 100 } 101 102 /** 103 * Creates an array store instruction for the given type. 104 * 105 * @param type type of elements of array, that is, array.getElementType(). 106 * @return The array store instruction. 107 */ 108 public static ArrayInstruction createArrayStore(final Type type) { 109 switch (type.getType()) { 110 case Const.T_BOOLEAN: 111 case Const.T_BYTE: 112 return InstructionConst.BASTORE; 113 case Const.T_CHAR: 114 return InstructionConst.CASTORE; 115 case Const.T_SHORT: 116 return InstructionConst.SASTORE; 117 case Const.T_INT: 118 return InstructionConst.IASTORE; 119 case Const.T_FLOAT: 120 return InstructionConst.FASTORE; 121 case Const.T_DOUBLE: 122 return InstructionConst.DASTORE; 123 case Const.T_LONG: 124 return InstructionConst.LASTORE; 125 case Const.T_ARRAY: 126 case Const.T_OBJECT: 127 return InstructionConst.AASTORE; 128 default: 129 throw new IllegalArgumentException("Invalid type " + type); 130 } 131 } 132 133 private static ArithmeticInstruction createBinaryDoubleOp(final char op) { 134 switch (op) { 135 case '-': 136 return InstructionConst.DSUB; 137 case '+': 138 return InstructionConst.DADD; 139 case '*': 140 return InstructionConst.DMUL; 141 case '/': 142 return InstructionConst.DDIV; 143 case '%': 144 return InstructionConst.DREM; 145 default: 146 throw new IllegalArgumentException("Invalid operand " + op); 147 } 148 } 149 150 private static ArithmeticInstruction createBinaryFloatOp(final char op) { 151 switch (op) { 152 case '-': 153 return InstructionConst.FSUB; 154 case '+': 155 return InstructionConst.FADD; 156 case '*': 157 return InstructionConst.FMUL; 158 case '/': 159 return InstructionConst.FDIV; 160 case '%': 161 return InstructionConst.FREM; 162 default: 163 throw new IllegalArgumentException("Invalid operand " + op); 164 } 165 } 166 167 private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) { 168 switch (first) { 169 case '-': 170 return InstructionConst.ISUB; 171 case '+': 172 return InstructionConst.IADD; 173 case '%': 174 return InstructionConst.IREM; 175 case '*': 176 return InstructionConst.IMUL; 177 case '/': 178 return InstructionConst.IDIV; 179 case '&': 180 return InstructionConst.IAND; 181 case '|': 182 return InstructionConst.IOR; 183 case '^': 184 return InstructionConst.IXOR; 185 case '<': 186 return InstructionConst.ISHL; 187 case '>': 188 return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR; 189 default: 190 throw new IllegalArgumentException("Invalid operand " + op); 191 } 192 } 193 194 /** 195 * Create an invokedynamic instruction. 196 * 197 * @param bootstrap_index index into the bootstrap_methods array. 198 * @param name name of the called method. 199 * @param ret_type return type of method. 200 * @param argTypes argument types of method. 201 * @see Const 202 */ 203 204 /* 205 * createInvokeDynamic only needed if instrumentation code wants to generate a new invokedynamic instruction. I don't 206 * think we need. 207 * 208 * public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, Type[] argTypes) { 209 * int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, argTypes); for (int i = 0; i < 210 * argTypes.length; i++) { nargs += argTypes[i].getSize(); } // UNDONE - needs to be added to ConstantPoolGen //index 211 * = cp.addInvokeDynamic(bootstrap_index, name, signature); index = 0; return new INVOKEDYNAMIC(index); } 212 */ 213 214 private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) { 215 switch (first) { 216 case '-': 217 return InstructionConst.LSUB; 218 case '+': 219 return InstructionConst.LADD; 220 case '%': 221 return InstructionConst.LREM; 222 case '*': 223 return InstructionConst.LMUL; 224 case '/': 225 return InstructionConst.LDIV; 226 case '&': 227 return InstructionConst.LAND; 228 case '|': 229 return InstructionConst.LOR; 230 case '^': 231 return InstructionConst.LXOR; 232 case '<': 233 return InstructionConst.LSHL; 234 case '>': 235 return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR; 236 default: 237 throw new IllegalArgumentException("Invalid operand " + op); 238 } 239 } 240 241 /** 242 * Create binary operation for simple basic types, such as int and float. 243 * 244 * @param op operation, such as "+", "*", "<<", etc. 245 * @param type The operand type. 246 * @return The binary arithmetic instruction. 247 */ 248 public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) { 249 final char first = op.charAt(0); 250 switch (type.getType()) { 251 case Const.T_BYTE: 252 case Const.T_SHORT: 253 case Const.T_INT: 254 case Const.T_CHAR: 255 return createBinaryIntOp(first, op); 256 case Const.T_LONG: 257 return createBinaryLongOp(first, op); 258 case Const.T_FLOAT: 259 return createBinaryFloatOp(first); 260 case Const.T_DOUBLE: 261 return createBinaryDoubleOp(first); 262 default: 263 throw new IllegalArgumentException("Invalid type " + type); 264 } 265 } 266 267 /** 268 * Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH 269 * compound instruction. 270 * 271 * @param opcode The branch opcode. 272 * @param target The target instruction handle. 273 * @return The branch instruction. 274 */ 275 public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) { 276 switch (opcode) { 277 case Const.IFEQ: 278 return new IFEQ(target); 279 case Const.IFNE: 280 return new IFNE(target); 281 case Const.IFLT: 282 return new IFLT(target); 283 case Const.IFGE: 284 return new IFGE(target); 285 case Const.IFGT: 286 return new IFGT(target); 287 case Const.IFLE: 288 return new IFLE(target); 289 case Const.IF_ICMPEQ: 290 return new IF_ICMPEQ(target); 291 case Const.IF_ICMPNE: 292 return new IF_ICMPNE(target); 293 case Const.IF_ICMPLT: 294 return new IF_ICMPLT(target); 295 case Const.IF_ICMPGE: 296 return new IF_ICMPGE(target); 297 case Const.IF_ICMPGT: 298 return new IF_ICMPGT(target); 299 case Const.IF_ICMPLE: 300 return new IF_ICMPLE(target); 301 case Const.IF_ACMPEQ: 302 return new IF_ACMPEQ(target); 303 case Const.IF_ACMPNE: 304 return new IF_ACMPNE(target); 305 case Const.GOTO: 306 return new GOTO(target); 307 case Const.JSR: 308 return new JSR(target); 309 case Const.IFNULL: 310 return new IFNULL(target); 311 case Const.IFNONNULL: 312 return new IFNONNULL(target); 313 case Const.GOTO_W: 314 return new GOTO_W(target); 315 case Const.JSR_W: 316 return new JSR_W(target); 317 default: 318 throw new IllegalArgumentException("Invalid opcode: " + opcode); 319 } 320 } 321 322 /** 323 * Creates a DUP instruction. 324 * 325 * @param size size of operand, either 1 (int, for example) or 2 (double). 326 * @return The DUP instruction. 327 */ 328 public static StackInstruction createDup(final int size) { 329 return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP; 330 } 331 332 /** 333 * Creates a DUP_X1 instruction. 334 * 335 * @param size size of operand, either 1 (int, for example) or 2 (double). 336 * @return The DUP instruction. 337 */ 338 public static StackInstruction createDup_1(final int size) { 339 return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1; 340 } 341 342 /** 343 * Creates a DUP_X2 instruction. 344 * 345 * @param size size of operand, either 1 (int, for example) or 2 (double). 346 * @return The DUP instruction. 347 */ 348 public static StackInstruction createDup_2(final int size) { 349 return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2; 350 } 351 352 /** 353 * Creates a load instruction for the given type. 354 * 355 * @param type The variable type. 356 * @param index index of local variable. 357 * @return The load instruction. 358 */ 359 public static LocalVariableInstruction createLoad(final Type type, final int index) { 360 switch (type.getType()) { 361 case Const.T_BOOLEAN: 362 case Const.T_CHAR: 363 case Const.T_BYTE: 364 case Const.T_SHORT: 365 case Const.T_INT: 366 return new ILOAD(index); 367 case Const.T_FLOAT: 368 return new FLOAD(index); 369 case Const.T_DOUBLE: 370 return new DLOAD(index); 371 case Const.T_LONG: 372 return new LLOAD(index); 373 case Const.T_ARRAY: 374 case Const.T_OBJECT: 375 return new ALOAD(index); 376 default: 377 throw new IllegalArgumentException("Invalid type " + type); 378 } 379 } 380 381 /** 382 * Create "null" value for reference types, 0 for basic types like int. 383 * 384 * @param type The type. 385 * @return The null or zero instruction. 386 */ 387 public static Instruction createNull(final Type type) { 388 switch (type.getType()) { 389 case Const.T_ARRAY: 390 case Const.T_OBJECT: 391 return InstructionConst.ACONST_NULL; 392 case Const.T_INT: 393 case Const.T_SHORT: 394 case Const.T_BOOLEAN: 395 case Const.T_CHAR: 396 case Const.T_BYTE: 397 return InstructionConst.ICONST_0; 398 case Const.T_FLOAT: 399 return InstructionConst.FCONST_0; 400 case Const.T_DOUBLE: 401 return InstructionConst.DCONST_0; 402 case Const.T_LONG: 403 return InstructionConst.LCONST_0; 404 case Const.T_VOID: 405 return InstructionConst.NOP; 406 default: 407 throw new IllegalArgumentException("Invalid type: " + type); 408 } 409 } 410 411 /** 412 * Creates a pop instruction. 413 * 414 * @param size size of operand, either 1 (int, for example) or 2 (double). 415 * @return The pop instruction. 416 */ 417 public static StackInstruction createPop(final int size) { 418 return size == 2 ? InstructionConst.POP2 : InstructionConst.POP; 419 } 420 421 /** 422 * Create typed return. 423 * 424 * @param type The return type. 425 * @return The return instruction. 426 */ 427 public static ReturnInstruction createReturn(final Type type) { 428 switch (type.getType()) { 429 case Const.T_ARRAY: 430 case Const.T_OBJECT: 431 return InstructionConst.ARETURN; 432 case Const.T_INT: 433 case Const.T_SHORT: 434 case Const.T_BOOLEAN: 435 case Const.T_CHAR: 436 case Const.T_BYTE: 437 return InstructionConst.IRETURN; 438 case Const.T_FLOAT: 439 return InstructionConst.FRETURN; 440 case Const.T_DOUBLE: 441 return InstructionConst.DRETURN; 442 case Const.T_LONG: 443 return InstructionConst.LRETURN; 444 case Const.T_VOID: 445 return InstructionConst.RETURN; 446 default: 447 throw new IllegalArgumentException("Invalid type: " + type); 448 } 449 } 450 451 /** 452 * Creates a store instruction. 453 * 454 * @param type The variable type. 455 * @param index index of local variable. 456 * @return The store instruction. 457 */ 458 public static LocalVariableInstruction createStore(final Type type, final int index) { 459 switch (type.getType()) { 460 case Const.T_BOOLEAN: 461 case Const.T_CHAR: 462 case Const.T_BYTE: 463 case Const.T_SHORT: 464 case Const.T_INT: 465 return new ISTORE(index); 466 case Const.T_FLOAT: 467 return new FSTORE(index); 468 case Const.T_DOUBLE: 469 return new DSTORE(index); 470 case Const.T_LONG: 471 return new LSTORE(index); 472 case Const.T_ARRAY: 473 case Const.T_OBJECT: 474 return new ASTORE(index); 475 default: 476 throw new IllegalArgumentException("Invalid type " + type); 477 } 478 } 479 480 /** 481 * Create reference to 'this'. 482 * 483 * @return reference to 'this'. 484 */ 485 public static Instruction createThis() { 486 return new ALOAD(0); 487 } 488 489 private static boolean isString(final Type type) { 490 return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String"); 491 } 492 493 /** 494 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 495 */ 496 @Deprecated 497 protected ClassGen cg; 498 499 /** 500 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 501 */ 502 @Deprecated 503 protected ConstantPoolGen cp; 504 505 /** 506 * Initialize with ClassGen object. 507 * 508 * @param cg The class generator. 509 */ 510 public InstructionFactory(final ClassGen cg) { 511 this(cg, cg.getConstantPool()); 512 } 513 514 /** 515 * Constructs an InstructionFactory. 516 * 517 * @param cg The class generator. 518 * @param cp The constant pool generator. 519 */ 520 public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) { 521 this.cg = cg; 522 this.cp = cp; 523 } 524 525 /** 526 * Initialize just with ConstantPoolGen object. 527 * 528 * @param cp The constant pool generator. 529 */ 530 public InstructionFactory(final ConstantPoolGen cp) { 531 this(null, cp); 532 } 533 534 /** 535 * Creates an append instruction for the given type. 536 * 537 * @param type The type to append. 538 * @return The append instruction. 539 */ 540 public Instruction createAppend(final Type type) { 541 final byte t = type.getType(); 542 if (isString(type)) { 543 return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL); 544 } 545 switch (t) { 546 case Const.T_BOOLEAN: 547 case Const.T_CHAR: 548 case Const.T_FLOAT: 549 case Const.T_DOUBLE: 550 case Const.T_BYTE: 551 case Const.T_SHORT: 552 case Const.T_INT: 553 case Const.T_LONG: 554 return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL); 555 case Const.T_ARRAY: 556 case Const.T_OBJECT: 557 return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL); 558 default: 559 throw new IllegalArgumentException("No append for this type? " + type); 560 } 561 } 562 563 /** 564 * Create conversion operation for two stack operands, this may be an I2C, instruction, for example, if the operands are basic 565 * types and CHECKCAST if they are reference types. 566 * 567 * @param srcType The source type. 568 * @param destType The destination type. 569 * @return The conversion instruction. 570 */ 571 public Instruction createCast(final Type srcType, final Type destType) { 572 if (srcType instanceof BasicType && destType instanceof BasicType) { 573 final byte dest = destType.getType(); 574 byte src = srcType.getType(); 575 if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) { 576 src = Const.T_INT; 577 } 578 final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR]; 579 Instruction i = null; 580 try { 581 i = (Instruction) Class.forName(name).getConstructor().newInstance(); 582 } catch (final Exception e) { 583 throw new IllegalArgumentException("Could not find instruction: " + name, e); 584 } 585 return i; 586 } 587 if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) { 588 throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType); 589 } 590 if (destType instanceof ArrayType) { 591 return new CHECKCAST(cp.addArrayClass((ArrayType) destType)); 592 } 593 return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName())); 594 } 595 596 /** 597 * Creates a CHECKCAST instruction. 598 * 599 * @param t The reference type. 600 * @return The CHECKCAST instruction. 601 */ 602 public CHECKCAST createCheckCast(final ReferenceType t) { 603 if (t instanceof ArrayType) { 604 return new CHECKCAST(cp.addArrayClass((ArrayType) t)); 605 } 606 return new CHECKCAST(cp.addClass((ObjectType) t)); 607 } 608 609 /** 610 * Uses PUSH to push a constant value onto the stack. 611 * 612 * @param value must be of type Number, Boolean, Character or String. 613 * @return The instruction. 614 */ 615 public Instruction createConstant(final Object value) { 616 final PUSH push; 617 if (value instanceof Number) { 618 push = new PUSH(cp, (Number) value); 619 } else if (value instanceof String) { 620 push = new PUSH(cp, (String) value); 621 } else if (value instanceof Boolean) { 622 push = new PUSH(cp, (Boolean) value); 623 } else if (value instanceof Character) { 624 push = new PUSH(cp, (Character) value); 625 } else { 626 throw new ClassGenException("Illegal type: " + value.getClass()); 627 } 628 return push.getInstruction(); 629 } 630 631 /** 632 * Create a field instruction. 633 * 634 * @param className class name containing the field. 635 * @param name name of the referenced field. 636 * @param type type of field. 637 * @param kind how to access, that is, GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC. 638 * @return A field instruction. 639 * @see Const 640 */ 641 public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) { 642 final String signature = type.getSignature(); 643 final int index = cp.addFieldref(className, name, signature); 644 switch (kind) { 645 case Const.GETFIELD: 646 return new GETFIELD(index); 647 case Const.PUTFIELD: 648 return new PUTFIELD(index); 649 case Const.GETSTATIC: 650 return new GETSTATIC(index); 651 case Const.PUTSTATIC: 652 return new PUTSTATIC(index); 653 default: 654 throw new IllegalArgumentException("Unknown getfield kind:" + kind); 655 } 656 } 657 658 /** 659 * Creates a GETFIELD instruction. 660 * 661 * @param className The class name. 662 * @param name The field name. 663 * @param t The field type. 664 * @return The GETFIELD instruction. 665 */ 666 public GETFIELD createGetField(final String className, final String name, final Type t) { 667 return new GETFIELD(cp.addFieldref(className, name, t.getSignature())); 668 } 669 670 /** 671 * Creates a GETSTATIC instruction. 672 * 673 * @param className The class name. 674 * @param name The field name. 675 * @param t The field type. 676 * @return The GETSTATIC instruction. 677 */ 678 public GETSTATIC createGetStatic(final String className, final String name, final Type t) { 679 return new GETSTATIC(cp.addFieldref(className, name, t.getSignature())); 680 } 681 682 /** 683 * Creates an INSTANCEOF instruction. 684 * 685 * @param t The reference type. 686 * @return The INSTANCEOF instruction. 687 */ 688 public INSTANCEOF createInstanceOf(final ReferenceType t) { 689 if (t instanceof ArrayType) { 690 return new INSTANCEOF(cp.addArrayClass((ArrayType) t)); 691 } 692 return new INSTANCEOF(cp.addClass((ObjectType) t)); 693 } 694 695 private InvokeInstruction createInvoke(final MethodObject m, final short kind) { 696 return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind); 697 } 698 699 /** 700 * Create an invoke instruction. (Except for invokedynamic.) 701 * 702 * @param className name of the called class. 703 * @param name name of the called method. 704 * @param retType return type of method. 705 * @param argTypes argument types of method. 706 * @param kind how to invoke, that is, INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL. 707 * @return The invoke instruction. 708 * @see Const 709 */ 710 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) { 711 return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE); 712 } 713 714 /** 715 * Create an invoke instruction. (Except for invokedynamic.) 716 * 717 * @param className name of the called class. 718 * @param name name of the called method. 719 * @param retType return type of method. 720 * @param argTypes argument types of method. 721 * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL. 722 * @param useInterface force use of InterfaceMethodref. 723 * @return A new InvokeInstruction. 724 * @since 6.5.0 725 */ 726 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind, 727 final boolean useInterface) { 728 if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE 729 && kind != Const.INVOKEDYNAMIC) { 730 throw new IllegalArgumentException("Unknown invoke kind: " + kind); 731 } 732 final int index; 733 int nargs = 0; 734 final String signature = Type.getMethodSignature(retType, argTypes); 735 if (argTypes != null) { 736 for (final Type argType : argTypes) { 737 nargs += argType.getSize(); 738 } 739 } 740 if (useInterface) { 741 index = cp.addInterfaceMethodref(className, name, signature); 742 } else { 743 index = cp.addMethodref(className, name, signature); 744 } 745 switch (kind) { 746 case Const.INVOKESPECIAL: 747 return new INVOKESPECIAL(index); 748 case Const.INVOKEVIRTUAL: 749 return new INVOKEVIRTUAL(index); 750 case Const.INVOKESTATIC: 751 return new INVOKESTATIC(index); 752 case Const.INVOKEINTERFACE: 753 return new INVOKEINTERFACE(index, nargs + 1); 754 case Const.INVOKEDYNAMIC: 755 return new INVOKEDYNAMIC(index); 756 default: 757 // Can't happen 758 throw new IllegalStateException("Unknown invoke kind: " + kind); 759 } 760 } 761 762 /** 763 * Creates a NEW instruction. 764 * 765 * @param t The object type. 766 * @return The NEW instruction. 767 */ 768 public NEW createNew(final ObjectType t) { 769 return new NEW(cp.addClass(t)); 770 } 771 772 /** 773 * Creates a NEW instruction. 774 * 775 * @param s The class name. 776 * @return The NEW instruction. 777 */ 778 public NEW createNew(final String s) { 779 return createNew(ObjectType.getInstance(s)); 780 } 781 782 /** 783 * Create new array of given size and type. 784 * 785 * @param t The array element type. 786 * @param dim The array dimensions. 787 * @return An instruction that creates the corresponding array at runtime, for example is an AllocationInstruction. 788 */ 789 public Instruction createNewArray(final Type t, final short dim) { 790 if (dim == 1) { 791 if (t instanceof ObjectType) { 792 return new ANEWARRAY(cp.addClass((ObjectType) t)); 793 } 794 if (t instanceof ArrayType) { 795 return new ANEWARRAY(cp.addArrayClass((ArrayType) t)); 796 } 797 return new NEWARRAY(t.getType()); 798 } 799 final ArrayType at; 800 if (t instanceof ArrayType) { 801 at = (ArrayType) t; 802 } else { 803 at = new ArrayType(t, dim); 804 } 805 return new MULTIANEWARRAY(cp.addArrayClass(at), dim); 806 } 807 808 /** 809 * Create a call to the most popular System.out.println() method. 810 * 811 * @param s The string to print. 812 * @return The instruction list. 813 */ 814 public InstructionList createPrintln(final String s) { 815 final InstructionList il = new InstructionList(); 816 il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;"))); 817 il.append(new PUSH(cp, s)); 818 final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") }); 819 il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL)); 820 return il; 821 } 822 823 /** 824 * Creates a PUTFIELD instruction. 825 * 826 * @param className The class name. 827 * @param name The field name. 828 * @param t The field type. 829 * @return The PUTFIELD instruction. 830 */ 831 public PUTFIELD createPutField(final String className, final String name, final Type t) { 832 return new PUTFIELD(cp.addFieldref(className, name, t.getSignature())); 833 } 834 835 /** 836 * Creates a PUTSTATIC instruction. 837 * 838 * @param className The class name. 839 * @param name The field name. 840 * @param t The field type. 841 * @return The PUTSTATIC instruction. 842 */ 843 public PUTSTATIC createPutStatic(final String className, final String name, final Type t) { 844 return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature())); 845 } 846 847 /** 848 * Gets the class generator. 849 * 850 * @return The class generator. 851 */ 852 public ClassGen getClassGen() { 853 return cg; 854 } 855 856 /** 857 * Gets the constant pool generator. 858 * 859 * @return The constant pool generator. 860 */ 861 public ConstantPoolGen getConstantPool() { 862 return cp; 863 } 864 865 /** 866 * Sets the class generator. 867 * 868 * @param c The class generator. 869 */ 870 public void setClassGen(final ClassGen c) { 871 cg = c; 872 } 873 874 /** 875 * Sets the constant pool generator. 876 * 877 * @param c The constant pool generator. 878 */ 879 public void setConstantPool(final ConstantPoolGen c) { 880 cp = c; 881 } 882} 883