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 * @param type type of elements of array, i.e., array.getElementType() 073 */ 074 public static ArrayInstruction createArrayLoad(final Type type) { 075 switch (type.getType()) { 076 case Const.T_BOOLEAN: 077 case Const.T_BYTE: 078 return InstructionConst.BALOAD; 079 case Const.T_CHAR: 080 return InstructionConst.CALOAD; 081 case Const.T_SHORT: 082 return InstructionConst.SALOAD; 083 case Const.T_INT: 084 return InstructionConst.IALOAD; 085 case Const.T_FLOAT: 086 return InstructionConst.FALOAD; 087 case Const.T_DOUBLE: 088 return InstructionConst.DALOAD; 089 case Const.T_LONG: 090 return InstructionConst.LALOAD; 091 case Const.T_ARRAY: 092 case Const.T_OBJECT: 093 return InstructionConst.AALOAD; 094 default: 095 throw new IllegalArgumentException("Invalid type " + type); 096 } 097 } 098 099 /** 100 * @param type type of elements of array, i.e., array.getElementType() 101 */ 102 public static ArrayInstruction createArrayStore(final Type type) { 103 switch (type.getType()) { 104 case Const.T_BOOLEAN: 105 case Const.T_BYTE: 106 return InstructionConst.BASTORE; 107 case Const.T_CHAR: 108 return InstructionConst.CASTORE; 109 case Const.T_SHORT: 110 return InstructionConst.SASTORE; 111 case Const.T_INT: 112 return InstructionConst.IASTORE; 113 case Const.T_FLOAT: 114 return InstructionConst.FASTORE; 115 case Const.T_DOUBLE: 116 return InstructionConst.DASTORE; 117 case Const.T_LONG: 118 return InstructionConst.LASTORE; 119 case Const.T_ARRAY: 120 case Const.T_OBJECT: 121 return InstructionConst.AASTORE; 122 default: 123 throw new IllegalArgumentException("Invalid type " + type); 124 } 125 } 126 127 private static ArithmeticInstruction createBinaryDoubleOp(final char op) { 128 switch (op) { 129 case '-': 130 return InstructionConst.DSUB; 131 case '+': 132 return InstructionConst.DADD; 133 case '*': 134 return InstructionConst.DMUL; 135 case '/': 136 return InstructionConst.DDIV; 137 case '%': 138 return InstructionConst.DREM; 139 default: 140 throw new IllegalArgumentException("Invalid operand " + op); 141 } 142 } 143 144 private static ArithmeticInstruction createBinaryFloatOp(final char op) { 145 switch (op) { 146 case '-': 147 return InstructionConst.FSUB; 148 case '+': 149 return InstructionConst.FADD; 150 case '*': 151 return InstructionConst.FMUL; 152 case '/': 153 return InstructionConst.FDIV; 154 case '%': 155 return InstructionConst.FREM; 156 default: 157 throw new IllegalArgumentException("Invalid operand " + op); 158 } 159 } 160 161 private static ArithmeticInstruction createBinaryIntOp(final char first, final String op) { 162 switch (first) { 163 case '-': 164 return InstructionConst.ISUB; 165 case '+': 166 return InstructionConst.IADD; 167 case '%': 168 return InstructionConst.IREM; 169 case '*': 170 return InstructionConst.IMUL; 171 case '/': 172 return InstructionConst.IDIV; 173 case '&': 174 return InstructionConst.IAND; 175 case '|': 176 return InstructionConst.IOR; 177 case '^': 178 return InstructionConst.IXOR; 179 case '<': 180 return InstructionConst.ISHL; 181 case '>': 182 return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR; 183 default: 184 throw new IllegalArgumentException("Invalid operand " + op); 185 } 186 } 187 188 /** 189 * Create an invokedynamic instruction. 190 * 191 * @param bootstrap_index index into the bootstrap_methods array 192 * @param name name of the called method 193 * @param ret_type return type of method 194 * @param argTypes argument types of method 195 * @see Const 196 */ 197 198 /* 199 * createInvokeDynamic only needed if instrumentation code wants to generate a new invokedynamic instruction. I don't 200 * think we need. 201 * 202 * public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type, Type[] argTypes) { 203 * int index; int nargs = 0; String signature = Type.getMethodSignature(ret_type, argTypes); for (int i = 0; i < 204 * argTypes.length; i++) { nargs += argTypes[i].getSize(); } // UNDONE - needs to be added to ConstantPoolGen //index 205 * = cp.addInvokeDynamic(bootstrap_index, name, signature); index = 0; return new INVOKEDYNAMIC(index); } 206 */ 207 208 private static ArithmeticInstruction createBinaryLongOp(final char first, final String op) { 209 switch (first) { 210 case '-': 211 return InstructionConst.LSUB; 212 case '+': 213 return InstructionConst.LADD; 214 case '%': 215 return InstructionConst.LREM; 216 case '*': 217 return InstructionConst.LMUL; 218 case '/': 219 return InstructionConst.LDIV; 220 case '&': 221 return InstructionConst.LAND; 222 case '|': 223 return InstructionConst.LOR; 224 case '^': 225 return InstructionConst.LXOR; 226 case '<': 227 return InstructionConst.LSHL; 228 case '>': 229 return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR; 230 default: 231 throw new IllegalArgumentException("Invalid operand " + op); 232 } 233 } 234 235 /** 236 * Create binary operation for simple basic types, such as int and float. 237 * 238 * @param op operation, such as "+", "*", "<<", etc. 239 */ 240 public static ArithmeticInstruction createBinaryOperation(final String op, final Type type) { 241 final char first = op.charAt(0); 242 switch (type.getType()) { 243 case Const.T_BYTE: 244 case Const.T_SHORT: 245 case Const.T_INT: 246 case Const.T_CHAR: 247 return createBinaryIntOp(first, op); 248 case Const.T_LONG: 249 return createBinaryLongOp(first, op); 250 case Const.T_FLOAT: 251 return createBinaryFloatOp(first); 252 case Const.T_DOUBLE: 253 return createBinaryDoubleOp(first); 254 default: 255 throw new IllegalArgumentException("Invalid type " + type); 256 } 257 } 258 259 /** 260 * Create branch instruction by given opcode, except LOOKUPSWITCH and TABLESWITCH. For those you should use the SWITCH 261 * compound instruction. 262 */ 263 public static BranchInstruction createBranchInstruction(final short opcode, final InstructionHandle target) { 264 switch (opcode) { 265 case Const.IFEQ: 266 return new IFEQ(target); 267 case Const.IFNE: 268 return new IFNE(target); 269 case Const.IFLT: 270 return new IFLT(target); 271 case Const.IFGE: 272 return new IFGE(target); 273 case Const.IFGT: 274 return new IFGT(target); 275 case Const.IFLE: 276 return new IFLE(target); 277 case Const.IF_ICMPEQ: 278 return new IF_ICMPEQ(target); 279 case Const.IF_ICMPNE: 280 return new IF_ICMPNE(target); 281 case Const.IF_ICMPLT: 282 return new IF_ICMPLT(target); 283 case Const.IF_ICMPGE: 284 return new IF_ICMPGE(target); 285 case Const.IF_ICMPGT: 286 return new IF_ICMPGT(target); 287 case Const.IF_ICMPLE: 288 return new IF_ICMPLE(target); 289 case Const.IF_ACMPEQ: 290 return new IF_ACMPEQ(target); 291 case Const.IF_ACMPNE: 292 return new IF_ACMPNE(target); 293 case Const.GOTO: 294 return new GOTO(target); 295 case Const.JSR: 296 return new JSR(target); 297 case Const.IFNULL: 298 return new IFNULL(target); 299 case Const.IFNONNULL: 300 return new IFNONNULL(target); 301 case Const.GOTO_W: 302 return new GOTO_W(target); 303 case Const.JSR_W: 304 return new JSR_W(target); 305 default: 306 throw new IllegalArgumentException("Invalid opcode: " + opcode); 307 } 308 } 309 310 /** 311 * @param size size of operand, either 1 (int, for example) or 2 (double) 312 */ 313 public static StackInstruction createDup(final int size) { 314 return size == 2 ? InstructionConst.DUP2 : InstructionConst.DUP; 315 } 316 317 /** 318 * @param size size of operand, either 1 (int, for example) or 2 (double) 319 */ 320 public static StackInstruction createDup_1(final int size) { 321 return size == 2 ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1; 322 } 323 324 /** 325 * @param size size of operand, either 1 (int, for example) or 2 (double) 326 */ 327 public static StackInstruction createDup_2(final int size) { 328 return size == 2 ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2; 329 } 330 331 /** 332 * @param index index of local variable 333 */ 334 public static LocalVariableInstruction createLoad(final Type type, final int index) { 335 switch (type.getType()) { 336 case Const.T_BOOLEAN: 337 case Const.T_CHAR: 338 case Const.T_BYTE: 339 case Const.T_SHORT: 340 case Const.T_INT: 341 return new ILOAD(index); 342 case Const.T_FLOAT: 343 return new FLOAD(index); 344 case Const.T_DOUBLE: 345 return new DLOAD(index); 346 case Const.T_LONG: 347 return new LLOAD(index); 348 case Const.T_ARRAY: 349 case Const.T_OBJECT: 350 return new ALOAD(index); 351 default: 352 throw new IllegalArgumentException("Invalid type " + type); 353 } 354 } 355 356 /** 357 * Create "null" value for reference types, 0 for basic types like int 358 */ 359 public static Instruction createNull(final Type type) { 360 switch (type.getType()) { 361 case Const.T_ARRAY: 362 case Const.T_OBJECT: 363 return InstructionConst.ACONST_NULL; 364 case Const.T_INT: 365 case Const.T_SHORT: 366 case Const.T_BOOLEAN: 367 case Const.T_CHAR: 368 case Const.T_BYTE: 369 return InstructionConst.ICONST_0; 370 case Const.T_FLOAT: 371 return InstructionConst.FCONST_0; 372 case Const.T_DOUBLE: 373 return InstructionConst.DCONST_0; 374 case Const.T_LONG: 375 return InstructionConst.LCONST_0; 376 case Const.T_VOID: 377 return InstructionConst.NOP; 378 default: 379 throw new IllegalArgumentException("Invalid type: " + type); 380 } 381 } 382 383 /** 384 * @param size size of operand, either 1 (int, for example) or 2 (double) 385 */ 386 public static StackInstruction createPop(final int size) { 387 return size == 2 ? InstructionConst.POP2 : InstructionConst.POP; 388 } 389 390 /** 391 * Create typed return 392 */ 393 public static ReturnInstruction createReturn(final Type type) { 394 switch (type.getType()) { 395 case Const.T_ARRAY: 396 case Const.T_OBJECT: 397 return InstructionConst.ARETURN; 398 case Const.T_INT: 399 case Const.T_SHORT: 400 case Const.T_BOOLEAN: 401 case Const.T_CHAR: 402 case Const.T_BYTE: 403 return InstructionConst.IRETURN; 404 case Const.T_FLOAT: 405 return InstructionConst.FRETURN; 406 case Const.T_DOUBLE: 407 return InstructionConst.DRETURN; 408 case Const.T_LONG: 409 return InstructionConst.LRETURN; 410 case Const.T_VOID: 411 return InstructionConst.RETURN; 412 default: 413 throw new IllegalArgumentException("Invalid type: " + type); 414 } 415 } 416 417 /** 418 * @param index index of local variable 419 */ 420 public static LocalVariableInstruction createStore(final Type type, final int index) { 421 switch (type.getType()) { 422 case Const.T_BOOLEAN: 423 case Const.T_CHAR: 424 case Const.T_BYTE: 425 case Const.T_SHORT: 426 case Const.T_INT: 427 return new ISTORE(index); 428 case Const.T_FLOAT: 429 return new FSTORE(index); 430 case Const.T_DOUBLE: 431 return new DSTORE(index); 432 case Const.T_LONG: 433 return new LSTORE(index); 434 case Const.T_ARRAY: 435 case Const.T_OBJECT: 436 return new ASTORE(index); 437 default: 438 throw new IllegalArgumentException("Invalid type " + type); 439 } 440 } 441 442 /** 443 * Create reference to 'this' 444 */ 445 public static Instruction createThis() { 446 return new ALOAD(0); 447 } 448 449 private static boolean isString(final Type type) { 450 return type instanceof ObjectType && ((ObjectType) type).getClassName().equals("java.lang.String"); 451 } 452 453 /** 454 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 455 */ 456 @Deprecated 457 protected ClassGen cg; 458 459 /** 460 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 461 */ 462 @Deprecated 463 protected ConstantPoolGen cp; 464 465 /** 466 * Initialize with ClassGen object 467 */ 468 public InstructionFactory(final ClassGen cg) { 469 this(cg, cg.getConstantPool()); 470 } 471 472 public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) { 473 this.cg = cg; 474 this.cp = cp; 475 } 476 477 /** 478 * Initialize just with ConstantPoolGen object 479 */ 480 public InstructionFactory(final ConstantPoolGen cp) { 481 this(null, cp); 482 } 483 484 public Instruction createAppend(final Type type) { 485 final byte t = type.getType(); 486 if (isString(type)) { 487 return createInvoke(APPEND_METHOD_OBJECTS[0], Const.INVOKEVIRTUAL); 488 } 489 switch (t) { 490 case Const.T_BOOLEAN: 491 case Const.T_CHAR: 492 case Const.T_FLOAT: 493 case Const.T_DOUBLE: 494 case Const.T_BYTE: 495 case Const.T_SHORT: 496 case Const.T_INT: 497 case Const.T_LONG: 498 return createInvoke(APPEND_METHOD_OBJECTS[t], Const.INVOKEVIRTUAL); 499 case Const.T_ARRAY: 500 case Const.T_OBJECT: 501 return createInvoke(APPEND_METHOD_OBJECTS[1], Const.INVOKEVIRTUAL); 502 default: 503 throw new IllegalArgumentException("No append for this type? " + type); 504 } 505 } 506 507 /** 508 * Create conversion operation for two stack operands, this may be an I2C, instruction, for example, if the operands are basic 509 * types and CHECKCAST if they are reference types. 510 */ 511 public Instruction createCast(final Type srcType, final Type destType) { 512 if (srcType instanceof BasicType && destType instanceof BasicType) { 513 final byte dest = destType.getType(); 514 byte src = srcType.getType(); 515 if (dest == Const.T_LONG && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) { 516 src = Const.T_INT; 517 } 518 final String name = "org.apache.bcel.generic." + SHORT_NAMES[src - Const.T_CHAR] + "2" + SHORT_NAMES[dest - Const.T_CHAR]; 519 Instruction i = null; 520 try { 521 i = (Instruction) Class.forName(name).getConstructor().newInstance(); 522 } catch (final Exception e) { 523 throw new IllegalArgumentException("Could not find instruction: " + name, e); 524 } 525 return i; 526 } 527 if (!(srcType instanceof ReferenceType) || !(destType instanceof ReferenceType)) { 528 throw new IllegalArgumentException("Cannot cast " + srcType + " to " + destType); 529 } 530 if (destType instanceof ArrayType) { 531 return new CHECKCAST(cp.addArrayClass((ArrayType) destType)); 532 } 533 return new CHECKCAST(cp.addClass(((ObjectType) destType).getClassName())); 534 } 535 536 public CHECKCAST createCheckCast(final ReferenceType t) { 537 if (t instanceof ArrayType) { 538 return new CHECKCAST(cp.addArrayClass((ArrayType) t)); 539 } 540 return new CHECKCAST(cp.addClass((ObjectType) t)); 541 } 542 543 /** 544 * Uses PUSH to push a constant value onto the stack. 545 * 546 * @param value must be of type Number, Boolean, Character or String 547 */ 548 public Instruction createConstant(final Object value) { 549 final PUSH push; 550 if (value instanceof Number) { 551 push = new PUSH(cp, (Number) value); 552 } else if (value instanceof String) { 553 push = new PUSH(cp, (String) value); 554 } else if (value instanceof Boolean) { 555 push = new PUSH(cp, (Boolean) value); 556 } else if (value instanceof Character) { 557 push = new PUSH(cp, (Character) value); 558 } else { 559 throw new ClassGenException("Illegal type: " + value.getClass()); 560 } 561 return push.getInstruction(); 562 } 563 564 /** 565 * Create a field instruction. 566 * 567 * @param className name of the accessed class 568 * @param name name of the referenced field 569 * @param type type of field 570 * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC 571 * @see Const 572 */ 573 public FieldInstruction createFieldAccess(final String className, final String name, final Type type, final short kind) { 574 final String signature = type.getSignature(); 575 final int index = cp.addFieldref(className, name, signature); 576 switch (kind) { 577 case Const.GETFIELD: 578 return new GETFIELD(index); 579 case Const.PUTFIELD: 580 return new PUTFIELD(index); 581 case Const.GETSTATIC: 582 return new GETSTATIC(index); 583 case Const.PUTSTATIC: 584 return new PUTSTATIC(index); 585 default: 586 throw new IllegalArgumentException("Unknown getfield kind:" + kind); 587 } 588 } 589 590 public GETFIELD createGetField(final String className, final String name, final Type t) { 591 return new GETFIELD(cp.addFieldref(className, name, t.getSignature())); 592 } 593 594 public GETSTATIC createGetStatic(final String className, final String name, final Type t) { 595 return new GETSTATIC(cp.addFieldref(className, name, t.getSignature())); 596 } 597 598 public INSTANCEOF createInstanceOf(final ReferenceType t) { 599 if (t instanceof ArrayType) { 600 return new INSTANCEOF(cp.addArrayClass((ArrayType) t)); 601 } 602 return new INSTANCEOF(cp.addClass((ObjectType) t)); 603 } 604 605 private InvokeInstruction createInvoke(final MethodObject m, final short kind) { 606 return createInvoke(m.className, m.name, m.resultType, m.argTypes, kind); 607 } 608 609 /** 610 * Create an invoke instruction. (Except for invokedynamic.) 611 * 612 * @param className name of the called class 613 * @param name name of the called method 614 * @param retType return type of method 615 * @param argTypes argument types of method 616 * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL 617 * @see Const 618 */ 619 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind) { 620 return createInvoke(className, name, retType, argTypes, kind, kind == Const.INVOKEINTERFACE); 621 } 622 623 /** 624 * Create an invoke instruction. (Except for invokedynamic.) 625 * 626 * @param className name of the called class 627 * @param name name of the called method 628 * @param retType return type of method 629 * @param argTypes argument types of method 630 * @param kind how to invoke: INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL, or INVOKESPECIAL 631 * @param useInterface force use of InterfaceMethodref 632 * @return A new InvokeInstruction. 633 * @since 6.5.0 634 */ 635 public InvokeInstruction createInvoke(final String className, final String name, final Type retType, final Type[] argTypes, final short kind, 636 final boolean useInterface) { 637 if (kind != Const.INVOKESPECIAL && kind != Const.INVOKEVIRTUAL && kind != Const.INVOKESTATIC && kind != Const.INVOKEINTERFACE 638 && kind != Const.INVOKEDYNAMIC) { 639 throw new IllegalArgumentException("Unknown invoke kind: " + kind); 640 } 641 final int index; 642 int nargs = 0; 643 final String signature = Type.getMethodSignature(retType, argTypes); 644 if (argTypes != null) { 645 for (final Type argType : argTypes) { 646 nargs += argType.getSize(); 647 } 648 } 649 if (useInterface) { 650 index = cp.addInterfaceMethodref(className, name, signature); 651 } else { 652 index = cp.addMethodref(className, name, signature); 653 } 654 switch (kind) { 655 case Const.INVOKESPECIAL: 656 return new INVOKESPECIAL(index); 657 case Const.INVOKEVIRTUAL: 658 return new INVOKEVIRTUAL(index); 659 case Const.INVOKESTATIC: 660 return new INVOKESTATIC(index); 661 case Const.INVOKEINTERFACE: 662 return new INVOKEINTERFACE(index, nargs + 1); 663 case Const.INVOKEDYNAMIC: 664 return new INVOKEDYNAMIC(index); 665 default: 666 // Can't happen 667 throw new IllegalStateException("Unknown invoke kind: " + kind); 668 } 669 } 670 671 public NEW createNew(final ObjectType t) { 672 return new NEW(cp.addClass(t)); 673 } 674 675 public NEW createNew(final String s) { 676 return createNew(ObjectType.getInstance(s)); 677 } 678 679 /** 680 * Create new array of given size and type. 681 * 682 * @return an instruction that creates the corresponding array at runtime, i.e. is an AllocationInstruction 683 */ 684 public Instruction createNewArray(final Type t, final short dim) { 685 if (dim == 1) { 686 if (t instanceof ObjectType) { 687 return new ANEWARRAY(cp.addClass((ObjectType) t)); 688 } 689 if (t instanceof ArrayType) { 690 return new ANEWARRAY(cp.addArrayClass((ArrayType) t)); 691 } 692 return new NEWARRAY(t.getType()); 693 } 694 final ArrayType at; 695 if (t instanceof ArrayType) { 696 at = (ArrayType) t; 697 } else { 698 at = new ArrayType(t, dim); 699 } 700 return new MULTIANEWARRAY(cp.addArrayClass(at), dim); 701 } 702 703 /** 704 * Create a call to the most popular System.out.println() method. 705 * 706 * @param s the string to print 707 */ 708 public InstructionList createPrintln(final String s) { 709 final InstructionList il = new InstructionList(); 710 il.append(createGetStatic("java.lang.System", "out", Type.getType("Ljava/io/PrintStream;"))); 711 il.append(new PUSH(cp, s)); 712 final MethodObject methodObject = new MethodObject("java.io.PrintStream", "println", Type.VOID, new Type[] { Type.getType("Ljava/lang/String;") }); 713 il.append(createInvoke(methodObject, Const.INVOKEVIRTUAL)); 714 return il; 715 } 716 717 public PUTFIELD createPutField(final String className, final String name, final Type t) { 718 return new PUTFIELD(cp.addFieldref(className, name, t.getSignature())); 719 } 720 721 public PUTSTATIC createPutStatic(final String className, final String name, final Type t) { 722 return new PUTSTATIC(cp.addFieldref(className, name, t.getSignature())); 723 } 724 725 public ClassGen getClassGen() { 726 return cg; 727 } 728 729 public ConstantPoolGen getConstantPool() { 730 return cp; 731 } 732 733 public void setClassGen(final ClassGen c) { 734 cg = c; 735 } 736 737 public void setConstantPool(final ConstantPoolGen c) { 738 cp = c; 739 } 740}