1 /*
   2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 package com.sun.org.apache.bcel.internal.generic;
  21 
  22 import com.sun.org.apache.bcel.internal.Const;
  23 
  24 /**
  25  * Instances of this class may be used, e.g., to generate typed
  26  * versions of instructions. Its main purpose is to be used as the
  27  * byte code generating backend of a compiler. You can subclass it to
  28  * add your own create methods.
  29  * <p>
  30  * Note: The static createXXX methods return singleton instances
  31  * from the {@link InstructionConst} class.
  32  *
  33  * @version $Id$
  34  * @see Const
  35  * @see InstructionConst
  36  * @LastModified: Jun 2019
  37  */
  38 public class InstructionFactory {
  39 
  40     // N.N. These must agree with the order of Constants.T_CHAR through T_LONG
  41     private static final String[] short_names = {
  42             "C", "F", "D", "B", "S", "I", "L"
  43     };
  44 
  45     private ClassGen cg;
  46     private ConstantPoolGen cp;
  47 
  48     public InstructionFactory(final ClassGen cg, final ConstantPoolGen cp) {
  49         this.cg = cg;
  50         this.cp = cp;
  51     }
  52 
  53 
  54     /** Initialize with ClassGen object
  55      */
  56     public InstructionFactory(final ClassGen cg) {
  57         this(cg, cg.getConstantPool());
  58     }
  59 
  60 
  61     /** Initialize just with ConstantPoolGen object
  62      */
  63     public InstructionFactory(final ConstantPoolGen cp) {
  64         this(null, cp);
  65     }
  66 
  67 
  68     /** Create an invoke instruction. (Except for invokedynamic.)
  69      *
  70      * @param class_name name of the called class
  71      * @param name name of the called method
  72      * @param ret_type return type of method
  73      * @param arg_types argument types of method
  74      * @param kind how to invoke, i.e., INVOKEINTERFACE, INVOKESTATIC, INVOKEVIRTUAL,
  75      * or INVOKESPECIAL
  76      * @see Const
  77      */
  78     public InvokeInstruction createInvoke( final String class_name, final String name,
  79             final Type ret_type, final Type[] arg_types, final short kind ) {
  80         int index;
  81         int nargs = 0;
  82         final String signature = Type.getMethodSignature(ret_type, arg_types);
  83         for (final Type arg_type : arg_types) {
  84             nargs += arg_type.getSize();
  85         }
  86         if (kind == Const.INVOKEINTERFACE) {
  87             index = cp.addInterfaceMethodref(class_name, name, signature);
  88         } else {
  89             index = cp.addMethodref(class_name, name, signature);
  90         }
  91         switch (kind) {
  92             case Const.INVOKESPECIAL:
  93                 return new INVOKESPECIAL(index);
  94             case Const.INVOKEVIRTUAL:
  95                 return new INVOKEVIRTUAL(index);
  96             case Const.INVOKESTATIC:
  97                 return new INVOKESTATIC(index);
  98             case Const.INVOKEINTERFACE:
  99                 return new INVOKEINTERFACE(index, nargs + 1);
 100             case Const.INVOKEDYNAMIC:
 101                 return new INVOKEDYNAMIC(index);
 102             default:
 103                 throw new RuntimeException("Oops: Unknown invoke kind: " + kind);
 104         }
 105     }
 106 
 107     /** Create an invokedynamic instruction.
 108      *
 109      * @param bootstrap_index index into the bootstrap_methods array
 110      * @param name name of the called method
 111      * @param ret_type return type of method
 112      * @param arg_types argument types of method
 113      * @see Constants
 114      */
 115 /*
 116  * createInvokeDynamic only needed if instrumention code wants to generate
 117  * a new invokedynamic instruction.  I don't think we need.  (markro)
 118  *
 119     public InvokeInstruction createInvokeDynamic( int bootstrap_index, String name, Type ret_type,
 120             Type[] arg_types) {
 121         int index;
 122         int nargs = 0;
 123         String signature = Type.getMethodSignature(ret_type, arg_types);
 124         for (int i = 0; i < arg_types.length; i++) {
 125             nargs += arg_types[i].getSize();
 126         }
 127         // UNDONE - needs to be added to ConstantPoolGen
 128         //index = cp.addInvokeDynamic(bootstrap_index, name, signature);
 129         index = 0;
 130         return new INVOKEDYNAMIC(index);
 131     }
 132  */
 133 
 134     /** Create a call to the most popular System.out.println() method.
 135      *
 136      * @param s the string to print
 137      */
 138     public InstructionList createPrintln( final String s ) {
 139         final InstructionList il = new InstructionList();
 140         final int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
 141         final int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
 142         il.append(new GETSTATIC(out));
 143         il.append(new PUSH(cp, s));
 144         il.append(new INVOKEVIRTUAL(println));
 145         return il;
 146     }
 147 
 148 
 149     /** Uses PUSH to push a constant value onto the stack.
 150      * @param value must be of type Number, Boolean, Character or String
 151      */
 152     public Instruction createConstant( final Object value ) {
 153         PUSH push;
 154         if (value instanceof Number) {
 155             push = new PUSH(cp, (Number) value);
 156         } else if (value instanceof String) {
 157             push = new PUSH(cp, (String) value);
 158         } else if (value instanceof Boolean) {
 159             push = new PUSH(cp, (Boolean) value);
 160         } else if (value instanceof Character) {
 161             push = new PUSH(cp, (Character) value);
 162         } else {
 163             throw new ClassGenException("Illegal type: " + value.getClass());
 164         }
 165         return push.getInstruction();
 166     }
 167 
 168     private static class MethodObject {
 169 
 170         final Type[] arg_types;
 171         final Type result_type;
 172         final String class_name;
 173         final String name;
 174 
 175 
 176         MethodObject(final String c, final String n, final Type r, final Type[] a) {
 177             class_name = c;
 178             name = n;
 179             result_type = r;
 180             arg_types = a;
 181         }
 182     }
 183 
 184 
 185     private InvokeInstruction createInvoke( final MethodObject m, final short kind ) {
 186         return createInvoke(m.class_name, m.name, m.result_type, m.arg_types, kind);
 187     }
 188 
 189     private static final MethodObject[] append_mos = {
 190             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 191                 Type.STRING
 192             }),
 193             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 194                 Type.OBJECT
 195             }),
 196             null,
 197             null, // indices 2, 3
 198             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 199                 Type.BOOLEAN
 200             }),
 201             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 202                 Type.CHAR
 203             }),
 204             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 205                 Type.FLOAT
 206             }),
 207             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 208                 Type.DOUBLE
 209             }),
 210             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 211                 Type.INT
 212             }),
 213             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(byte)
 214                     new Type[] {
 215                         Type.INT
 216                     }),
 217             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, // No append(short)
 218                     new Type[] {
 219                         Type.INT
 220                     }),
 221             new MethodObject("java.lang.StringBuffer", "append", Type.STRINGBUFFER, new Type[] {
 222                 Type.LONG
 223             })
 224     };
 225 
 226 
 227     private static boolean isString( final Type type ) {
 228         return (type instanceof ObjectType) &&
 229               ((ObjectType) type).getClassName().equals("java.lang.String");
 230     }
 231 
 232 
 233     public Instruction createAppend( final Type type ) {
 234         final byte t = type.getType();
 235         if (isString(type)) {
 236             return createInvoke(append_mos[0], Const.INVOKEVIRTUAL);
 237         }
 238         switch (t) {
 239             case Const.T_BOOLEAN:
 240             case Const.T_CHAR:
 241             case Const.T_FLOAT:
 242             case Const.T_DOUBLE:
 243             case Const.T_BYTE:
 244             case Const.T_SHORT:
 245             case Const.T_INT:
 246             case Const.T_LONG:
 247                 return createInvoke(append_mos[t], Const.INVOKEVIRTUAL);
 248             case Const.T_ARRAY:
 249             case Const.T_OBJECT:
 250                 return createInvoke(append_mos[1], Const.INVOKEVIRTUAL);
 251             default:
 252                 throw new RuntimeException("Oops: No append for this type? " + type);
 253         }
 254     }
 255 
 256 
 257     /** Create a field instruction.
 258      *
 259      * @param class_name name of the accessed class
 260      * @param name name of the referenced field
 261      * @param type  type of field
 262      * @param kind how to access, i.e., GETFIELD, PUTFIELD, GETSTATIC, PUTSTATIC
 263      * @see Const
 264      */
 265     public FieldInstruction createFieldAccess( final String class_name,
 266             final String name, final Type type, final short kind ) {
 267         int index;
 268         final String signature = type.getSignature();
 269         index = cp.addFieldref(class_name, name, signature);
 270         switch (kind) {
 271             case Const.GETFIELD:
 272                 return new GETFIELD(index);
 273             case Const.PUTFIELD:
 274                 return new PUTFIELD(index);
 275             case Const.GETSTATIC:
 276                 return new GETSTATIC(index);
 277             case Const.PUTSTATIC:
 278                 return new PUTSTATIC(index);
 279             default:
 280                 throw new RuntimeException("Oops: Unknown getfield kind:" + kind);
 281         }
 282     }
 283 
 284 
 285     /** Create reference to `this'
 286      */
 287     public static Instruction createThis() {
 288         return new ALOAD(0);
 289     }
 290 
 291 
 292     /** Create typed return
 293      */
 294     public static ReturnInstruction createReturn( final Type type ) {
 295         switch (type.getType()) {
 296             case Const.T_ARRAY:
 297             case Const.T_OBJECT:
 298                 return InstructionConst.ARETURN;
 299             case Const.T_INT:
 300             case Const.T_SHORT:
 301             case Const.T_BOOLEAN:
 302             case Const.T_CHAR:
 303             case Const.T_BYTE:
 304                 return InstructionConst.IRETURN;
 305             case Const.T_FLOAT:
 306                 return InstructionConst.FRETURN;
 307             case Const.T_DOUBLE:
 308                 return InstructionConst.DRETURN;
 309             case Const.T_LONG:
 310                 return InstructionConst.LRETURN;
 311             case Const.T_VOID:
 312                 return InstructionConst.RETURN;
 313             default:
 314                 throw new RuntimeException("Invalid type: " + type);
 315         }
 316     }
 317 
 318 
 319     private static ArithmeticInstruction createBinaryIntOp( final char first, final String op ) {
 320         switch (first) {
 321             case '-':
 322                 return InstructionConst.ISUB;
 323             case '+':
 324                 return InstructionConst.IADD;
 325             case '%':
 326                 return InstructionConst.IREM;
 327             case '*':
 328                 return InstructionConst.IMUL;
 329             case '/':
 330                 return InstructionConst.IDIV;
 331             case '&':
 332                 return InstructionConst.IAND;
 333             case '|':
 334                 return InstructionConst.IOR;
 335             case '^':
 336                 return InstructionConst.IXOR;
 337             case '<':
 338                 return InstructionConst.ISHL;
 339             case '>':
 340                 return op.equals(">>>") ? InstructionConst.IUSHR : InstructionConst.ISHR;
 341             default:
 342                 throw new RuntimeException("Invalid operand " + op);
 343         }
 344     }
 345 
 346 
 347     private static ArithmeticInstruction createBinaryLongOp( final char first, final String op ) {
 348         switch (first) {
 349             case '-':
 350                 return InstructionConst.LSUB;
 351             case '+':
 352                 return InstructionConst.LADD;
 353             case '%':
 354                 return InstructionConst.LREM;
 355             case '*':
 356                 return InstructionConst.LMUL;
 357             case '/':
 358                 return InstructionConst.LDIV;
 359             case '&':
 360                 return InstructionConst.LAND;
 361             case '|':
 362                 return InstructionConst.LOR;
 363             case '^':
 364                 return InstructionConst.LXOR;
 365             case '<':
 366                 return InstructionConst.LSHL;
 367             case '>':
 368                 return op.equals(">>>") ? InstructionConst.LUSHR : InstructionConst.LSHR;
 369             default:
 370                 throw new RuntimeException("Invalid operand " + op);
 371         }
 372     }
 373 
 374 
 375     private static ArithmeticInstruction createBinaryFloatOp( final char op ) {
 376         switch (op) {
 377             case '-':
 378                 return InstructionConst.FSUB;
 379             case '+':
 380                 return InstructionConst.FADD;
 381             case '*':
 382                 return InstructionConst.FMUL;
 383             case '/':
 384                 return InstructionConst.FDIV;
 385             case '%':
 386                 return InstructionConst.FREM;
 387             default:
 388                 throw new RuntimeException("Invalid operand " + op);
 389         }
 390     }
 391 
 392 
 393     private static ArithmeticInstruction createBinaryDoubleOp( final char op ) {
 394         switch (op) {
 395             case '-':
 396                 return InstructionConst.DSUB;
 397             case '+':
 398                 return InstructionConst.DADD;
 399             case '*':
 400                 return InstructionConst.DMUL;
 401             case '/':
 402                 return InstructionConst.DDIV;
 403             case '%':
 404                 return InstructionConst.DREM;
 405             default:
 406                 throw new RuntimeException("Invalid operand " + op);
 407         }
 408     }
 409 
 410 
 411     /**
 412      * Create binary operation for simple basic types, such as int and float.
 413      *
 414      * @param op operation, such as "+", "*", "&lt;&lt;", etc.
 415      */
 416     public static ArithmeticInstruction createBinaryOperation( final String op, final Type type ) {
 417         final char first = op.charAt(0);
 418         switch (type.getType()) {
 419             case Const.T_BYTE:
 420             case Const.T_SHORT:
 421             case Const.T_INT:
 422             case Const.T_CHAR:
 423                 return createBinaryIntOp(first, op);
 424             case Const.T_LONG:
 425                 return createBinaryLongOp(first, op);
 426             case Const.T_FLOAT:
 427                 return createBinaryFloatOp(first);
 428             case Const.T_DOUBLE:
 429                 return createBinaryDoubleOp(first);
 430             default:
 431                 throw new RuntimeException("Invalid type " + type);
 432         }
 433     }
 434 
 435 
 436     /**
 437      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
 438      */
 439     public static StackInstruction createPop( final int size ) {
 440         return (size == 2) ? InstructionConst.POP2 : InstructionConst.POP;
 441     }
 442 
 443 
 444     /**
 445      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
 446      */
 447     public static StackInstruction createDup( final int size ) {
 448         return (size == 2) ? InstructionConst.DUP2 : InstructionConst.DUP;
 449     }
 450 
 451 
 452     /**
 453      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
 454      */
 455     public static StackInstruction createDup_2( final int size ) {
 456         return (size == 2) ? InstructionConst.DUP2_X2 : InstructionConst.DUP_X2;
 457     }
 458 
 459 
 460     /**
 461      * @param size size of operand, either 1 (int, e.g.) or 2 (double)
 462      */
 463     public static StackInstruction createDup_1( final int size ) {
 464         return (size == 2) ? InstructionConst.DUP2_X1 : InstructionConst.DUP_X1;
 465     }
 466 
 467 
 468     /**
 469      * @param index index of local variable
 470      */
 471     public static LocalVariableInstruction createStore( final Type type, final int index ) {
 472         switch (type.getType()) {
 473             case Const.T_BOOLEAN:
 474             case Const.T_CHAR:
 475             case Const.T_BYTE:
 476             case Const.T_SHORT:
 477             case Const.T_INT:
 478                 return new ISTORE(index);
 479             case Const.T_FLOAT:
 480                 return new FSTORE(index);
 481             case Const.T_DOUBLE:
 482                 return new DSTORE(index);
 483             case Const.T_LONG:
 484                 return new LSTORE(index);
 485             case Const.T_ARRAY:
 486             case Const.T_OBJECT:
 487                 return new ASTORE(index);
 488             default:
 489                 throw new RuntimeException("Invalid type " + type);
 490         }
 491     }
 492 
 493 
 494     /**
 495      * @param index index of local variable
 496      */
 497     public static LocalVariableInstruction createLoad( final Type type, final int index ) {
 498         switch (type.getType()) {
 499             case Const.T_BOOLEAN:
 500             case Const.T_CHAR:
 501             case Const.T_BYTE:
 502             case Const.T_SHORT:
 503             case Const.T_INT:
 504                 return new ILOAD(index);
 505             case Const.T_FLOAT:
 506                 return new FLOAD(index);
 507             case Const.T_DOUBLE:
 508                 return new DLOAD(index);
 509             case Const.T_LONG:
 510                 return new LLOAD(index);
 511             case Const.T_ARRAY:
 512             case Const.T_OBJECT:
 513                 return new ALOAD(index);
 514             default:
 515                 throw new RuntimeException("Invalid type " + type);
 516         }
 517     }
 518 
 519 
 520     /**
 521      * @param type type of elements of array, i.e., array.getElementType()
 522      */
 523     public static ArrayInstruction createArrayLoad( final Type type ) {
 524         switch (type.getType()) {
 525             case Const.T_BOOLEAN:
 526             case Const.T_BYTE:
 527                 return InstructionConst.BALOAD;
 528             case Const.T_CHAR:
 529                 return InstructionConst.CALOAD;
 530             case Const.T_SHORT:
 531                 return InstructionConst.SALOAD;
 532             case Const.T_INT:
 533                 return InstructionConst.IALOAD;
 534             case Const.T_FLOAT:
 535                 return InstructionConst.FALOAD;
 536             case Const.T_DOUBLE:
 537                 return InstructionConst.DALOAD;
 538             case Const.T_LONG:
 539                 return InstructionConst.LALOAD;
 540             case Const.T_ARRAY:
 541             case Const.T_OBJECT:
 542                 return InstructionConst.AALOAD;
 543             default:
 544                 throw new RuntimeException("Invalid type " + type);
 545         }
 546     }
 547 
 548 
 549     /**
 550      * @param type type of elements of array, i.e., array.getElementType()
 551      */
 552     public static ArrayInstruction createArrayStore( final Type type ) {
 553         switch (type.getType()) {
 554             case Const.T_BOOLEAN:
 555             case Const.T_BYTE:
 556                 return InstructionConst.BASTORE;
 557             case Const.T_CHAR:
 558                 return InstructionConst.CASTORE;
 559             case Const.T_SHORT:
 560                 return InstructionConst.SASTORE;
 561             case Const.T_INT:
 562                 return InstructionConst.IASTORE;
 563             case Const.T_FLOAT:
 564                 return InstructionConst.FASTORE;
 565             case Const.T_DOUBLE:
 566                 return InstructionConst.DASTORE;
 567             case Const.T_LONG:
 568                 return InstructionConst.LASTORE;
 569             case Const.T_ARRAY:
 570             case Const.T_OBJECT:
 571                 return InstructionConst.AASTORE;
 572             default:
 573                 throw new RuntimeException("Invalid type " + type);
 574         }
 575     }
 576 
 577     /**
 578      * Create conversion operation for two stack operands, this may be an I2C,
 579      * instruction, e.g., if the operands are basic types and CHECKCAST if they
 580      * are reference types.
 581      */
 582     public Instruction createCast( final Type src_type, final Type dest_type ) {
 583         if ((src_type instanceof BasicType) && (dest_type instanceof BasicType)) {
 584             final byte dest = dest_type.getType();
 585             byte src = src_type.getType();
 586             if (dest == Const.T_LONG
 587                     && (src == Const.T_CHAR || src == Const.T_BYTE || src == Const.T_SHORT)) {
 588                 src = Const.T_INT;
 589             }
 590             final String name = "com.sun.org.apache.bcel.internal.generic." + short_names[src - Const.T_CHAR] + "2"
 591                     + short_names[dest - Const.T_CHAR];
 592             Instruction i = null;
 593             try {
 594                 i = (Instruction) java.lang.Class.forName(name).getDeclaredConstructor().newInstance();
 595             } catch (final Exception e) {
 596                 throw new RuntimeException("Could not find instruction: " + name, e);
 597             }
 598             return i;
 599         } else if ((src_type instanceof ReferenceType) && (dest_type instanceof ReferenceType)) {
 600             if (dest_type instanceof ArrayType) {
 601                 return new CHECKCAST(cp.addArrayClass((ArrayType) dest_type));
 602             }
 603             return new CHECKCAST(cp.addClass(((ObjectType) dest_type).getClassName()));
 604         } else {
 605             throw new RuntimeException("Can not cast " + src_type + " to " + dest_type);
 606         }
 607     }
 608 
 609 
 610     public GETFIELD createGetField( final String class_name, final String name, final Type t ) {
 611         return new GETFIELD(cp.addFieldref(class_name, name, t.getSignature()));
 612     }
 613 
 614 
 615     public GETSTATIC createGetStatic( final String class_name, final String name, final Type t ) {
 616         return new GETSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
 617     }
 618 
 619 
 620     public PUTFIELD createPutField( final String class_name, final String name, final Type t ) {
 621         return new PUTFIELD(cp.addFieldref(class_name, name, t.getSignature()));
 622     }
 623 
 624 
 625     public PUTSTATIC createPutStatic( final String class_name, final String name, final Type t ) {
 626         return new PUTSTATIC(cp.addFieldref(class_name, name, t.getSignature()));
 627     }
 628 
 629 
 630     public CHECKCAST createCheckCast( final ReferenceType t ) {
 631         if (t instanceof ArrayType) {
 632             return new CHECKCAST(cp.addArrayClass((ArrayType) t));
 633         }
 634         return new CHECKCAST(cp.addClass((ObjectType) t));
 635     }
 636 
 637 
 638     public INSTANCEOF createInstanceOf( final ReferenceType t ) {
 639         if (t instanceof ArrayType) {
 640             return new INSTANCEOF(cp.addArrayClass((ArrayType) t));
 641         }
 642         return new INSTANCEOF(cp.addClass((ObjectType) t));
 643     }
 644 
 645 
 646     public NEW createNew( final ObjectType t ) {
 647         return new NEW(cp.addClass(t));
 648     }
 649 
 650 
 651     public NEW createNew( final String s ) {
 652         return createNew(ObjectType.getInstance(s));
 653     }
 654 
 655     /**
 656      * Create new array of given size and type.
 657      *
 658      * @return an instruction that creates the corresponding array at runtime,
 659      * i.e. is an AllocationInstruction
 660      */
 661     public Instruction createNewArray( final Type t, final short dim ) {
 662         if (dim == 1) {
 663             if (t instanceof ObjectType) {
 664                 return new ANEWARRAY(cp.addClass((ObjectType) t));
 665             } else if (t instanceof ArrayType) {
 666                 return new ANEWARRAY(cp.addArrayClass((ArrayType) t));
 667             } else {
 668                 return new NEWARRAY(t.getType());
 669             }
 670         }
 671         ArrayType at;
 672         if (t instanceof ArrayType) {
 673             at = (ArrayType) t;
 674         } else {
 675             at = new ArrayType(t, dim);
 676         }
 677         return new MULTIANEWARRAY(cp.addArrayClass(at), dim);
 678     }
 679 
 680     /**
 681      * Create "null" value for reference types, 0 for basic types like int
 682      */
 683     public static Instruction createNull( final Type type ) {
 684         switch (type.getType()) {
 685             case Const.T_ARRAY:
 686             case Const.T_OBJECT:
 687                 return InstructionConst.ACONST_NULL;
 688             case Const.T_INT:
 689             case Const.T_SHORT:
 690             case Const.T_BOOLEAN:
 691             case Const.T_CHAR:
 692             case Const.T_BYTE:
 693                 return InstructionConst.ICONST_0;
 694             case Const.T_FLOAT:
 695                 return InstructionConst.FCONST_0;
 696             case Const.T_DOUBLE:
 697                 return InstructionConst.DCONST_0;
 698             case Const.T_LONG:
 699                 return InstructionConst.LCONST_0;
 700             case Const.T_VOID:
 701                 return InstructionConst.NOP;
 702             default:
 703                 throw new RuntimeException("Invalid type: " + type);
 704         }
 705     }
 706 
 707     /**
 708      * Create branch instruction by given opcode, except LOOKUPSWITCH and
 709      * TABLESWITCH. For those you should use the SWITCH compound instruction.
 710      */
 711     public static BranchInstruction createBranchInstruction( final short opcode,
 712             final InstructionHandle target ) {
 713         switch (opcode) {
 714             case Const.IFEQ:
 715                 return new IFEQ(target);
 716             case Const.IFNE:
 717                 return new IFNE(target);
 718             case Const.IFLT:
 719                 return new IFLT(target);
 720             case Const.IFGE:
 721                 return new IFGE(target);
 722             case Const.IFGT:
 723                 return new IFGT(target);
 724             case Const.IFLE:
 725                 return new IFLE(target);
 726             case Const.IF_ICMPEQ:
 727                 return new IF_ICMPEQ(target);
 728             case Const.IF_ICMPNE:
 729                 return new IF_ICMPNE(target);
 730             case Const.IF_ICMPLT:
 731                 return new IF_ICMPLT(target);
 732             case Const.IF_ICMPGE:
 733                 return new IF_ICMPGE(target);
 734             case Const.IF_ICMPGT:
 735                 return new IF_ICMPGT(target);
 736             case Const.IF_ICMPLE:
 737                 return new IF_ICMPLE(target);
 738             case Const.IF_ACMPEQ:
 739                 return new IF_ACMPEQ(target);
 740             case Const.IF_ACMPNE:
 741                 return new IF_ACMPNE(target);
 742             case Const.GOTO:
 743                 return new GOTO(target);
 744             case Const.JSR:
 745                 return new JSR(target);
 746             case Const.IFNULL:
 747                 return new IFNULL(target);
 748             case Const.IFNONNULL:
 749                 return new IFNONNULL(target);
 750             case Const.GOTO_W:
 751                 return new GOTO_W(target);
 752             case Const.JSR_W:
 753                 return new JSR_W(target);
 754             default:
 755                 throw new RuntimeException("Invalid opcode: " + opcode);
 756         }
 757     }
 758 
 759 
 760     public void setClassGen( final ClassGen c ) {
 761         cg = c;
 762     }
 763 
 764 
 765     public ClassGen getClassGen() {
 766         return cg;
 767     }
 768 
 769 
 770     public void setConstantPool( final ConstantPoolGen c ) {
 771         cp = c;
 772     }
 773 
 774 
 775     public ConstantPoolGen getConstantPool() {
 776         return cp;
 777     }
 778 }