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 name of the accessed class. 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 * @see Const 639 */ 640 public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) { 641 final String signature = type.getSignature(); 642 final int index = cp.addFieldref(className, name, signature); 643 switch (kind) { 644 case Const.GETFIELD: 645 return new GETFIELD(index); 646 case Const.PUTFIELD: 647 return new PUTFIELD(index); 648 case Const.GETSTATIC: 649 return new GETSTATIC(index); 650 case Const.PUTSTATIC: 651 return new PUTSTATIC(index); 652 default: 653 throw new IllegalArgumentException("Unknown getfield kind:" + kind); 654 } 655 } 656 657 /** 658 * Creates a GETFIELD instruction. 659 * 660 * @param className the class name. 661 * @param name the field name. 662 * @param t the field type. 663 * @return the GETFIELD instruction. 664 */ 665 public GETFIELD createGetField(final String className, final String name, final Type t) { 666 return new GETFIELD(cp.addFieldref(className, name, t.getSignature())); 667 } 668 669 /** 670 * Creates a GETSTATIC instruction. 671 * 672 * @param className the class name. 673 * @param name the field name. 674 * @param t the field type. 675 * @return the GETSTATIC instruction. 676 */ 677 public GETSTATIC createGetStatic(final String className, final String name, final Type t) { 678 return new GETSTATIC(cp.addFieldref(className, name, t.getSignature())); 679 } 680 681 /** 682 * Creates an INSTANCEOF instruction. 683 * 684 * @param t the reference type. 685 * @return the INSTANCEOF instruction. 686 */ 687 public INSTANCEOF createInstanceOf(final ReferenceType t) { 688 if (t instanceof ArrayType) { 689 return new INSTANCEOF(cp.addArrayClass((ArrayType) t)); 690 } 691 return new INSTANCEOF(cp.addClass((ObjectType) t)); 692 } 693 694 private InvokeInstruction createInvoke(final MethodObject m, final short kind) { 695 return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind); 696 } 697 698 /** 699 * Create an invoke instruction. (Except for invokedynamic.) 700 * 701 * @param className name of the called class. 702 * @param name name of the called method. 703 * @param retType return type of method. 704 * @param argTypes argument types of method. 705 * @param kind how to invoke, that is, INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL. 706 * @return the invoke instruction. 707 * @see Const 708 */ 709 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) { 710 return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE); 711 } 712 713 /** 714 * Create an invoke instruction. (Except for invokedynamic.) 715 * 716 * @param className name of the called class. 717 * @param name name of the called method. 718 * @param retType return type of method. 719 * @param argTypes argument types of method. 720 * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL. 721 * @param useInterface force use of InterfaceMethodref. 722 * @return A new InvokeInstruction. 723 * @since 6.5.0 724 */ 725 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind, 726 final boolean useInterface) { 727 if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE 728 && kind != Const.INVOKEDYNAMIC) { 729 throw new IllegalArgumentException("Unknown invoke kind: " + kind); 730 } 731 final int index; 732 int nargs = 0; 733 final String signature = Type.getMethodSignature(retType, argTypes); 734 if (argTypes != null) { 735 for (final Type argType : argTypes) { 736 nargs += argType.getSize(); 737 } 738 } 739 if (useInterface) { 740 index = cp.addInterfaceMethodref(className, name, signature); 741 } else { 742 index = cp.addMethodref(className, name, signature); 743 } 744 switch (kind) { 745 case Const.INVOKESPECIAL: 746 return new INVOKESPECIAL(index); 747 case Const.INVOKEVIRTUAL: 748 return new INVOKEVIRTUAL(index); 749 case Const.INVOKESTATIC: 750 return new INVOKESTATIC(index); 751 case Const.INVOKEINTERFACE: 752 return new INVOKEINTERFACE(index, nargs + 1); 753 case Const.INVOKEDYNAMIC: 754 return new INVOKEDYNAMIC(index); 755 default: 756 // Can't happen 757 throw new IllegalStateException("Unknown invoke kind: " + kind); 758 } 759 } 760 761 /** 762 * Creates a NEW instruction. 763 * 764 * @param t the object type. 765 * @return the NEW instruction. 766 */ 767 public NEW createNew(final ObjectType t) { 768 return new NEW(cp.addClass(t)); 769 } 770 771 /** 772 * Creates a NEW instruction. 773 * 774 * @param s the class name. 775 * @return the NEW instruction. 776 */ 777 public NEW createNew(final String s) { 778 return createNew(ObjectType.getInstance(s)); 779 } 780 781 /** 782 * Create new array of given size and type. 783 * 784 * @param t the array element type. 785 * @param dim the array dimensions. 786 * @return an instruction that creates the corresponding array at runtime, for example is an AllocationInstruction. 787 */ 788 public Instruction createNewArray(final Type t, final short dim) { 789 if (dim == 1) { 790 if (t instanceof ObjectType) { 791 return new ANEWARRAY(cp.addClass((ObjectType) t)); 792 } 793 if (t instanceof ArrayType) { 794 return new ANEWARRAY(cp.addArrayClass((ArrayType) t)); 795 } 796 return new NEWARRAY(t.getType()); 797 } 798 final ArrayType at; 799 if (t instanceof ArrayType) { 800 at = (ArrayType) t; 801 } else { 802 at = new ArrayType(t, dim); 803 } 804 return new MULTIANEWARRAY(cp.addArrayClass(at), dim); 805 } 806 807 /** 808 * Create a call to the most popular System.out.println() method. 809 * 810 * @param s the string to print. 811 * @return the instruction list. 812 */ 813 public InstructionList createPrintln(final String s) { 814 final InstructionList il = new InstructionList(); 815 il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;"))); 816 il.append(new PUSH(cp, s)); 817 final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") }); 818 il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL)); 819 return il; 820 } 821 822 /** 823 * Creates a PUTFIELD instruction. 824 * 825 * @param className the class name. 826 * @param name the field name. 827 * @param t the field type. 828 * @return the PUTFIELD instruction. 829 */ 830 public PUTFIELD createPutField(final String className, final String name, final Type t) { 831 return new PUTFIELD(cp.addFieldref(className, name, t.getSignature())); 832 } 833 834 /** 835 * Creates a PUTSTATIC instruction. 836 * 837 * @param className the class name. 838 * @param name the field name. 839 * @param t the field type. 840 * @return the PUTSTATIC instruction. 841 */ 842 public PUTSTATIC createPutStatic(final String className, final String name, final Type t) { 843 return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature())); 844 } 845 846 /** 847 * Gets the class generator. 848 * 849 * @return the class generator. 850 */ 851 public ClassGen getClassGen() { 852 return cg; 853 } 854 855 /** 856 * Gets the constant pool generator. 857 * 858 * @return the constant pool generator. 859 */ 860 public ConstantPoolGen getConstantPool() { 861 return cp; 862 } 863 864 /** 865 * Sets the class generator. 866 * 867 * @param c the class generator. 868 */ 869 public void setClassGen(final ClassGen c) { 870 cg = c; 871 } 872 873 /** 874 * Sets the constant pool generator. 875 * 876 * @param c the constant pool generator. 877 */ 878 public void setConstantPool(final ConstantPoolGen c) { 879 cp = c; 880 } 881} 882