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