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