Home | History | Annotate | Download | only in evaluation
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.evaluation;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.CodeAttribute;
     25 import proguard.classfile.instruction.*;
     26 import proguard.classfile.instruction.visitor.InstructionVisitor;
     27 import proguard.evaluation.value.*;
     28 
     29 /**
     30  * This InstructionVisitor executes the instructions that it visits on a given
     31  * local variable frame and stack.
     32  *
     33  * @author Eric Lafortune
     34  */
     35 public class Processor
     36 implements   InstructionVisitor
     37 {
     38     private final Variables      variables;
     39     private final Stack          stack;
     40     private final ValueFactory   valueFactory;
     41     private final BranchUnit     branchUnit;
     42     private final InvocationUnit invocationUnit;
     43     private final boolean        alwaysCast;
     44 
     45     private final ConstantValueFactory      constantValueFactory;
     46     private final ClassConstantValueFactory classConstantValueFactory;
     47 
     48 
     49     /**
     50      * Creates a new processor that operates on the given environment.
     51      * @param variables      the local variable frame.
     52      * @param stack          the local stack.
     53      * @param branchUnit     the class that can affect the program counter.
     54      * @param invocationUnit the class that can access other program members.
     55      * @param alwaysCast     a flag that specifies whether downcasts or casts
     56      *                       of null values should always be performed.
     57      */
     58     public Processor(Variables      variables,
     59                      Stack          stack,
     60                      ValueFactory   valueFactory,
     61                      BranchUnit     branchUnit,
     62                      InvocationUnit invocationUnit,
     63                      boolean        alwaysCast)
     64     {
     65         this.variables      = variables;
     66         this.stack          = stack;
     67         this.valueFactory   = valueFactory;
     68         this.branchUnit     = branchUnit;
     69         this.invocationUnit = invocationUnit;
     70         this.alwaysCast    = alwaysCast;
     71 
     72         constantValueFactory      = new ConstantValueFactory(valueFactory);
     73         classConstantValueFactory = new ClassConstantValueFactory(valueFactory);
     74     }
     75 
     76 
     77     // Implementations for InstructionVisitor.
     78 
     79     public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
     80     {
     81         switch (simpleInstruction.opcode)
     82         {
     83             case InstructionConstants.OP_NOP:
     84                 break;
     85 
     86             case InstructionConstants.OP_ACONST_NULL:
     87                 stack.push(valueFactory.createReferenceValueNull());
     88                 break;
     89 
     90             case InstructionConstants.OP_ICONST_M1:
     91             case InstructionConstants.OP_ICONST_0:
     92             case InstructionConstants.OP_ICONST_1:
     93             case InstructionConstants.OP_ICONST_2:
     94             case InstructionConstants.OP_ICONST_3:
     95             case InstructionConstants.OP_ICONST_4:
     96             case InstructionConstants.OP_ICONST_5:
     97             case InstructionConstants.OP_BIPUSH:
     98             case InstructionConstants.OP_SIPUSH:
     99                 stack.push(valueFactory.createIntegerValue(simpleInstruction.constant));
    100                 break;
    101 
    102             case InstructionConstants.OP_LCONST_0:
    103             case InstructionConstants.OP_LCONST_1:
    104                 stack.push(valueFactory.createLongValue(simpleInstruction.constant));
    105                 break;
    106 
    107             case InstructionConstants.OP_FCONST_0:
    108             case InstructionConstants.OP_FCONST_1:
    109             case InstructionConstants.OP_FCONST_2:
    110                 stack.push(valueFactory.createFloatValue((float)simpleInstruction.constant));
    111                 break;
    112 
    113             case InstructionConstants.OP_DCONST_0:
    114             case InstructionConstants.OP_DCONST_1:
    115                 stack.push(valueFactory.createDoubleValue((double)simpleInstruction.constant));
    116                 break;
    117 
    118             case InstructionConstants.OP_IALOAD:
    119             case InstructionConstants.OP_BALOAD:
    120             case InstructionConstants.OP_CALOAD:
    121             case InstructionConstants.OP_SALOAD:
    122             {
    123                 IntegerValue   arrayIndex     = stack.ipop();
    124                 ReferenceValue arrayReference = stack.apop();
    125                 stack.push(arrayReference.integerArrayLoad(arrayIndex, valueFactory));
    126                 break;
    127             }
    128             case InstructionConstants.OP_LALOAD:
    129             {
    130                 IntegerValue   arrayIndex     = stack.ipop();
    131                 ReferenceValue arrayReference = stack.apop();
    132                 stack.push(arrayReference.longArrayLoad(arrayIndex, valueFactory));
    133                 break;
    134             }
    135             case InstructionConstants.OP_FALOAD:
    136             {
    137                 IntegerValue   arrayIndex     = stack.ipop();
    138                 ReferenceValue arrayReference = stack.apop();
    139                 stack.push(arrayReference.floatArrayLoad(arrayIndex, valueFactory));
    140                 break;
    141             }
    142             case InstructionConstants.OP_DALOAD:
    143             {
    144                 IntegerValue   arrayIndex     = stack.ipop();
    145                 ReferenceValue arrayReference = stack.apop();
    146                 stack.push(arrayReference.doubleArrayLoad(arrayIndex, valueFactory));
    147                 break;
    148             }
    149             case InstructionConstants.OP_AALOAD:
    150             {
    151                 IntegerValue   arrayIndex     = stack.ipop();
    152                 ReferenceValue arrayReference = stack.apop();
    153                 stack.push(arrayReference.referenceArrayLoad(arrayIndex, valueFactory));
    154                 break;
    155             }
    156             case InstructionConstants.OP_IASTORE:
    157             case InstructionConstants.OP_BASTORE:
    158             case InstructionConstants.OP_CASTORE:
    159             case InstructionConstants.OP_SASTORE:
    160             {
    161                 Value          value          = stack.ipop();
    162                 IntegerValue   arrayIndex     = stack.ipop();
    163                 ReferenceValue arrayReference = stack.apop();
    164                 arrayReference.arrayStore(arrayIndex, value);
    165                 break;
    166             }
    167             case InstructionConstants.OP_LASTORE:
    168             {
    169                 Value          value          = stack.lpop();
    170                 IntegerValue   arrayIndex     = stack.ipop();
    171                 ReferenceValue arrayReference = stack.apop();
    172                 arrayReference.arrayStore(arrayIndex, value);
    173                 break;
    174             }
    175             case InstructionConstants.OP_FASTORE:
    176             {
    177                 Value          value          = stack.fpop();
    178                 IntegerValue   arrayIndex     = stack.ipop();
    179                 ReferenceValue arrayReference = stack.apop();
    180                 arrayReference.arrayStore(arrayIndex, value);
    181                 break;
    182             }
    183             case InstructionConstants.OP_DASTORE:
    184             {
    185                 Value          value          = stack.dpop();
    186                 IntegerValue   arrayIndex     = stack.ipop();
    187                 ReferenceValue arrayReference = stack.apop();
    188                 arrayReference.arrayStore(arrayIndex, value);
    189                 break;
    190             }
    191             case InstructionConstants.OP_AASTORE:
    192             {
    193                 Value          value          = stack.apop();
    194                 IntegerValue   arrayIndex     = stack.ipop();
    195                 ReferenceValue arrayReference = stack.apop();
    196                 arrayReference.arrayStore(arrayIndex, value);
    197                 break;
    198             }
    199             case InstructionConstants.OP_POP:
    200                 stack.pop1();
    201                 break;
    202 
    203             case InstructionConstants.OP_POP2:
    204                 stack.pop2();
    205                 break;
    206 
    207             case InstructionConstants.OP_DUP:
    208                 stack.dup();
    209                 break;
    210 
    211             case InstructionConstants.OP_DUP_X1:
    212                 stack.dup_x1();
    213                 break;
    214 
    215             case InstructionConstants.OP_DUP_X2:
    216                 stack.dup_x2();
    217                 break;
    218 
    219             case InstructionConstants.OP_DUP2:
    220                 stack.dup2();
    221                 break;
    222 
    223             case InstructionConstants.OP_DUP2_X1:
    224                 stack.dup2_x1();
    225                 break;
    226 
    227             case InstructionConstants.OP_DUP2_X2:
    228                 stack.dup2_x2();
    229                 break;
    230 
    231             case InstructionConstants.OP_SWAP:
    232                 stack.swap();
    233                 break;
    234 
    235             case InstructionConstants.OP_IADD:
    236                 stack.push(stack.ipop().add(stack.ipop()));
    237                 break;
    238 
    239             case InstructionConstants.OP_LADD:
    240                 stack.push(stack.lpop().add(stack.lpop()));
    241                 break;
    242 
    243             case InstructionConstants.OP_FADD:
    244                 stack.push(stack.fpop().add(stack.fpop()));
    245                 break;
    246 
    247             case InstructionConstants.OP_DADD:
    248                 stack.push(stack.dpop().add(stack.dpop()));
    249                 break;
    250 
    251             case InstructionConstants.OP_ISUB:
    252                 stack.push(stack.ipop().subtractFrom(stack.ipop()));
    253                 break;
    254 
    255             case InstructionConstants.OP_LSUB:
    256                 stack.push(stack.lpop().subtractFrom(stack.lpop()));
    257                 break;
    258 
    259             case InstructionConstants.OP_FSUB:
    260                 stack.push(stack.fpop().subtractFrom(stack.fpop()));
    261                 break;
    262 
    263             case InstructionConstants.OP_DSUB:
    264                 stack.push(stack.dpop().subtractFrom(stack.dpop()));
    265                 break;
    266 
    267             case InstructionConstants.OP_IMUL:
    268                 stack.push(stack.ipop().multiply(stack.ipop()));
    269                 break;
    270 
    271             case InstructionConstants.OP_LMUL:
    272                 stack.push(stack.lpop().multiply(stack.lpop()));
    273                 break;
    274 
    275             case InstructionConstants.OP_FMUL:
    276                 stack.push(stack.fpop().multiply(stack.fpop()));
    277                 break;
    278 
    279             case InstructionConstants.OP_DMUL:
    280                 stack.push(stack.dpop().multiply(stack.dpop()));
    281                 break;
    282 
    283             case InstructionConstants.OP_IDIV:
    284                 try
    285                 {
    286                     stack.push(stack.ipop().divideOf(stack.ipop()));
    287                 }
    288                 catch (ArithmeticException ex)
    289                 {
    290                     stack.push(valueFactory.createIntegerValue());
    291                     // TODO: Forward ArithmeticExceptions.
    292                     //stack.clear();
    293                     //stack.push(valueFactory.createReference(false));
    294                     //branchUnit.throwException();
    295                 }
    296                 break;
    297 
    298             case InstructionConstants.OP_LDIV:
    299                 try
    300                 {
    301                     stack.push(stack.lpop().divideOf(stack.lpop()));
    302                 }
    303                 catch (ArithmeticException ex)
    304                 {
    305                     stack.push(valueFactory.createLongValue());
    306                     // TODO: Forward ArithmeticExceptions.
    307                     //stack.clear();
    308                     //stack.push(valueFactory.createReference(false));
    309                     //branchUnit.throwException();
    310                 }
    311                 break;
    312 
    313             case InstructionConstants.OP_FDIV:
    314                 stack.push(stack.fpop().divideOf(stack.fpop()));
    315                 break;
    316 
    317             case InstructionConstants.OP_DDIV:
    318                 stack.push(stack.dpop().divideOf(stack.dpop()));
    319                 break;
    320 
    321             case InstructionConstants.OP_IREM:
    322                 try
    323                 {
    324                     stack.push(stack.ipop().remainderOf(stack.ipop()));
    325                 }
    326                 catch (ArithmeticException ex)
    327                 {
    328                     stack.push(valueFactory.createIntegerValue());
    329                     // TODO: Forward ArithmeticExceptions.
    330                     //stack.clear();
    331                     //stack.push(valueFactory.createReference(false));
    332                     //branchUnit.throwException();
    333                 }
    334                 break;
    335 
    336             case InstructionConstants.OP_LREM:
    337                 try
    338                 {
    339                     stack.push(stack.lpop().remainderOf(stack.lpop()));
    340                 }
    341                 catch (ArithmeticException ex)
    342                 {
    343                     stack.push(valueFactory.createLongValue());
    344                     // TODO: Forward ArithmeticExceptions.
    345                     //stack.clear();
    346                     //stack.push(valueFactory.createReference(false));
    347                     //branchUnit.throwException();
    348                 }
    349                 break;
    350 
    351             case InstructionConstants.OP_FREM:
    352                 stack.push(stack.fpop().remainderOf(stack.fpop()));
    353                 break;
    354 
    355             case InstructionConstants.OP_DREM:
    356                 stack.push(stack.dpop().remainderOf(stack.dpop()));
    357                 break;
    358 
    359             case InstructionConstants.OP_INEG:
    360                 stack.push(stack.ipop().negate());
    361                 break;
    362 
    363             case InstructionConstants.OP_LNEG:
    364                 stack.push(stack.lpop().negate());
    365                 break;
    366 
    367             case InstructionConstants.OP_FNEG:
    368                 stack.push(stack.fpop().negate());
    369                 break;
    370 
    371             case InstructionConstants.OP_DNEG:
    372                 stack.push(stack.dpop().negate());
    373                 break;
    374 
    375             case InstructionConstants.OP_ISHL:
    376                 stack.push(stack.ipop().shiftLeftOf(stack.ipop()));
    377                 break;
    378 
    379             case InstructionConstants.OP_LSHL:
    380                 stack.push(stack.ipop().shiftLeftOf(stack.lpop()));
    381                 break;
    382 
    383             case InstructionConstants.OP_ISHR:
    384                 stack.push(stack.ipop().shiftRightOf(stack.ipop()));
    385                 break;
    386 
    387             case InstructionConstants.OP_LSHR:
    388                 stack.push(stack.ipop().shiftRightOf(stack.lpop()));
    389                 break;
    390 
    391             case InstructionConstants.OP_IUSHR:
    392                 stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop()));
    393                 break;
    394 
    395             case InstructionConstants.OP_LUSHR:
    396                 stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop()));
    397                 break;
    398 
    399             case InstructionConstants.OP_IAND:
    400                 stack.push(stack.ipop().and(stack.ipop()));
    401                 break;
    402 
    403             case InstructionConstants.OP_LAND:
    404                 stack.push(stack.lpop().and(stack.lpop()));
    405                 break;
    406 
    407             case InstructionConstants.OP_IOR:
    408                 stack.push(stack.ipop().or(stack.ipop()));
    409                 break;
    410 
    411             case InstructionConstants.OP_LOR:
    412                 stack.push(stack.lpop().or(stack.lpop()));
    413                 break;
    414 
    415             case InstructionConstants.OP_IXOR:
    416                 stack.push(stack.ipop().xor(stack.ipop()));
    417                 break;
    418 
    419             case InstructionConstants.OP_LXOR:
    420                 stack.push(stack.lpop().xor(stack.lpop()));
    421                 break;
    422 
    423             case InstructionConstants.OP_I2L:
    424                 stack.push(stack.ipop().convertToLong());
    425                 break;
    426 
    427             case InstructionConstants.OP_I2F:
    428                 stack.push(stack.ipop().convertToFloat());
    429                 break;
    430 
    431             case InstructionConstants.OP_I2D:
    432                 stack.push(stack.ipop().convertToDouble());
    433                 break;
    434 
    435             case InstructionConstants.OP_L2I:
    436                 stack.push(stack.lpop().convertToInteger());
    437                 break;
    438 
    439             case InstructionConstants.OP_L2F:
    440                 stack.push(stack.lpop().convertToFloat());
    441                 break;
    442 
    443             case InstructionConstants.OP_L2D:
    444                 stack.push(stack.lpop().convertToDouble());
    445                 break;
    446 
    447             case InstructionConstants.OP_F2I:
    448                 stack.push(stack.fpop().convertToInteger());
    449                 break;
    450 
    451             case InstructionConstants.OP_F2L:
    452                 stack.push(stack.fpop().convertToLong());
    453                 break;
    454 
    455             case InstructionConstants.OP_F2D:
    456                 stack.push(stack.fpop().convertToDouble());
    457                 break;
    458 
    459             case InstructionConstants.OP_D2I:
    460                 stack.push(stack.dpop().convertToInteger());
    461                 break;
    462 
    463             case InstructionConstants.OP_D2L:
    464                 stack.push(stack.dpop().convertToLong());
    465                 break;
    466 
    467             case InstructionConstants.OP_D2F:
    468                 stack.push(stack.dpop().convertToFloat());
    469                 break;
    470 
    471             case InstructionConstants.OP_I2B:
    472                 stack.push(stack.ipop().convertToByte());
    473                 break;
    474 
    475             case InstructionConstants.OP_I2C:
    476                 stack.push(stack.ipop().convertToCharacter());
    477                 break;
    478 
    479             case InstructionConstants.OP_I2S:
    480                 stack.push(stack.ipop().convertToShort());
    481                 break;
    482 
    483             case InstructionConstants.OP_LCMP:
    484 //                stack.push(stack.lpop().compareReverse(stack.lpop()));
    485 
    486                 LongValue longValue1 = stack.lpop();
    487                 LongValue longValue2 = stack.lpop();
    488                 stack.push(longValue2.compare(longValue1));
    489                 break;
    490 
    491             case InstructionConstants.OP_FCMPL:
    492                 FloatValue floatValue1 = stack.fpop();
    493                 FloatValue floatValue2 = stack.fpop();
    494                 stack.push(floatValue2.compare(floatValue1));
    495                 break;
    496 
    497             case InstructionConstants.OP_FCMPG:
    498                 stack.push(stack.fpop().compareReverse(stack.fpop()));
    499                 break;
    500 
    501             case InstructionConstants.OP_DCMPL:
    502                 DoubleValue doubleValue1 = stack.dpop();
    503                 DoubleValue doubleValue2 = stack.dpop();
    504                 stack.push(doubleValue2.compare(doubleValue1));
    505                 break;
    506 
    507             case InstructionConstants.OP_DCMPG:
    508                 stack.push(stack.dpop().compareReverse(stack.dpop()));
    509                 break;
    510 
    511             case InstructionConstants.OP_IRETURN:
    512                 invocationUnit.exitMethod(clazz, method, stack.ipop());
    513                 branchUnit.returnFromMethod();
    514                 break;
    515 
    516             case InstructionConstants.OP_LRETURN:
    517                 invocationUnit.exitMethod(clazz, method, stack.lpop());
    518                 branchUnit.returnFromMethod();
    519                 break;
    520 
    521             case InstructionConstants.OP_FRETURN:
    522                 invocationUnit.exitMethod(clazz, method, stack.fpop());
    523                 branchUnit.returnFromMethod();
    524                 break;
    525 
    526             case InstructionConstants.OP_DRETURN:
    527                 invocationUnit.exitMethod(clazz, method, stack.dpop());
    528                 branchUnit.returnFromMethod();
    529                 break;
    530 
    531             case InstructionConstants.OP_ARETURN:
    532                 invocationUnit.exitMethod(clazz, method, stack.apop());
    533                 branchUnit.returnFromMethod();
    534                 break;
    535 
    536             case InstructionConstants.OP_RETURN:
    537                 branchUnit.returnFromMethod();
    538                 break;
    539 
    540             case InstructionConstants.OP_NEWARRAY:
    541                 IntegerValue arrayLength = stack.ipop();
    542                 stack.push(valueFactory.createArrayReferenceValue(String.valueOf(InstructionUtil.internalTypeFromArrayType((byte)simpleInstruction.constant)),
    543                                                                   null,
    544                                                                   arrayLength));
    545                 break;
    546 
    547             case InstructionConstants.OP_ARRAYLENGTH:
    548                 ReferenceValue referenceValue = stack.apop();
    549                 stack.push(referenceValue.arrayLength(valueFactory));
    550                 break;
    551 
    552             case InstructionConstants.OP_ATHROW:
    553                 ReferenceValue exceptionReferenceValue = stack.apop();
    554                 stack.clear();
    555                 stack.push(exceptionReferenceValue);
    556                 branchUnit.throwException();
    557                 break;
    558 
    559             case InstructionConstants.OP_MONITORENTER:
    560             case InstructionConstants.OP_MONITOREXIT:
    561                 stack.apop();
    562                 break;
    563 
    564             default:
    565                 throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]");
    566         }
    567     }
    568 
    569 
    570     public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
    571     {
    572         int constantIndex = constantInstruction.constantIndex;
    573 
    574         switch (constantInstruction.opcode)
    575         {
    576             case InstructionConstants.OP_LDC:
    577             case InstructionConstants.OP_LDC_W:
    578             case InstructionConstants.OP_LDC2_W:
    579                 stack.push(classConstantValueFactory.constantValue(clazz, constantIndex));
    580                 break;
    581 
    582             case InstructionConstants.OP_GETSTATIC:
    583             case InstructionConstants.OP_PUTSTATIC:
    584             case InstructionConstants.OP_GETFIELD:
    585             case InstructionConstants.OP_PUTFIELD:
    586             case InstructionConstants.OP_INVOKEVIRTUAL:
    587             case InstructionConstants.OP_INVOKESPECIAL:
    588             case InstructionConstants.OP_INVOKESTATIC:
    589             case InstructionConstants.OP_INVOKEINTERFACE:
    590             case InstructionConstants.OP_INVOKEDYNAMIC:
    591                 invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack);
    592                 break;
    593 
    594             case InstructionConstants.OP_NEW:
    595                 stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
    596                 break;
    597 
    598             case InstructionConstants.OP_ANEWARRAY:
    599             {
    600                 ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
    601 
    602                 stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(),
    603                                                                   referenceValue.getReferencedClass(),
    604                                                                   stack.ipop()));
    605                 break;
    606             }
    607 
    608             case InstructionConstants.OP_CHECKCAST:
    609                 // TODO: Check cast.
    610                 ReferenceValue castValue = stack.apop();
    611                 ReferenceValue castResultValue =
    612                     !alwaysCast &&
    613                     castValue.isNull() == Value.ALWAYS ? castValue :
    614                     castValue.isNull() == Value.NEVER  ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() :
    615                                                          constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull());
    616                 stack.push(castResultValue);
    617                 break;
    618 
    619             case InstructionConstants.OP_INSTANCEOF:
    620             {
    621                 ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue();
    622 
    623                 int instanceOf = stack.apop().instanceOf(referenceValue.getType(),
    624                                                          referenceValue.getReferencedClass());
    625 
    626                 stack.push(instanceOf == Value.NEVER  ? valueFactory.createIntegerValue(0) :
    627                            instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) :
    628                                                         valueFactory.createIntegerValue());
    629                 break;
    630             }
    631 
    632             case InstructionConstants.OP_MULTIANEWARRAY:
    633             {
    634                 int dimensionCount = constantInstruction.constant;
    635                 for (int dimension = 0; dimension < dimensionCount; dimension++)
    636                 {
    637                     // TODO: Use array lengths.
    638                     IntegerValue arrayLength = stack.ipop();
    639                 }
    640 
    641                 stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue());
    642                 break;
    643             }
    644 
    645             default:
    646                 throw new IllegalArgumentException("Unknown constant pool instruction ["+constantInstruction.opcode+"]");
    647         }
    648     }
    649 
    650 
    651     public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
    652     {
    653         int variableIndex = variableInstruction.variableIndex;
    654 
    655         switch (variableInstruction.opcode)
    656         {
    657             case InstructionConstants.OP_ILOAD:
    658             case InstructionConstants.OP_ILOAD_0:
    659             case InstructionConstants.OP_ILOAD_1:
    660             case InstructionConstants.OP_ILOAD_2:
    661             case InstructionConstants.OP_ILOAD_3:
    662                 stack.push(variables.iload(variableIndex));
    663                 break;
    664 
    665             case InstructionConstants.OP_LLOAD:
    666             case InstructionConstants.OP_LLOAD_0:
    667             case InstructionConstants.OP_LLOAD_1:
    668             case InstructionConstants.OP_LLOAD_2:
    669             case InstructionConstants.OP_LLOAD_3:
    670                 stack.push(variables.lload(variableIndex));
    671                 break;
    672 
    673             case InstructionConstants.OP_FLOAD:
    674             case InstructionConstants.OP_FLOAD_0:
    675             case InstructionConstants.OP_FLOAD_1:
    676             case InstructionConstants.OP_FLOAD_2:
    677             case InstructionConstants.OP_FLOAD_3:
    678                 stack.push(variables.fload(variableIndex));
    679                 break;
    680 
    681             case InstructionConstants.OP_DLOAD:
    682             case InstructionConstants.OP_DLOAD_0:
    683             case InstructionConstants.OP_DLOAD_1:
    684             case InstructionConstants.OP_DLOAD_2:
    685             case InstructionConstants.OP_DLOAD_3:
    686                 stack.push(variables.dload(variableIndex));
    687                 break;
    688 
    689             case InstructionConstants.OP_ALOAD:
    690             case InstructionConstants.OP_ALOAD_0:
    691             case InstructionConstants.OP_ALOAD_1:
    692             case InstructionConstants.OP_ALOAD_2:
    693             case InstructionConstants.OP_ALOAD_3:
    694                 stack.push(variables.aload(variableIndex));
    695                 break;
    696 
    697             case InstructionConstants.OP_ISTORE:
    698             case InstructionConstants.OP_ISTORE_0:
    699             case InstructionConstants.OP_ISTORE_1:
    700             case InstructionConstants.OP_ISTORE_2:
    701             case InstructionConstants.OP_ISTORE_3:
    702                 variables.store(variableIndex, stack.ipop());
    703                 break;
    704 
    705             case InstructionConstants.OP_LSTORE:
    706             case InstructionConstants.OP_LSTORE_0:
    707             case InstructionConstants.OP_LSTORE_1:
    708             case InstructionConstants.OP_LSTORE_2:
    709             case InstructionConstants.OP_LSTORE_3:
    710                 variables.store(variableIndex, stack.lpop());
    711                 break;
    712 
    713             case InstructionConstants.OP_FSTORE:
    714             case InstructionConstants.OP_FSTORE_0:
    715             case InstructionConstants.OP_FSTORE_1:
    716             case InstructionConstants.OP_FSTORE_2:
    717             case InstructionConstants.OP_FSTORE_3:
    718                 variables.store(variableIndex, stack.fpop());
    719                 break;
    720 
    721             case InstructionConstants.OP_DSTORE:
    722             case InstructionConstants.OP_DSTORE_0:
    723             case InstructionConstants.OP_DSTORE_1:
    724             case InstructionConstants.OP_DSTORE_2:
    725             case InstructionConstants.OP_DSTORE_3:
    726                 variables.store(variableIndex, stack.dpop());
    727                 break;
    728 
    729             case InstructionConstants.OP_ASTORE:
    730             case InstructionConstants.OP_ASTORE_0:
    731             case InstructionConstants.OP_ASTORE_1:
    732             case InstructionConstants.OP_ASTORE_2:
    733             case InstructionConstants.OP_ASTORE_3:
    734                 // The operand on the stack can be a reference or a return
    735                 // address, so we'll relax the pop operation.
    736                 //variables.store(variableIndex, stack.apop());
    737                 variables.store(variableIndex, stack.pop());
    738                 break;
    739 
    740             case InstructionConstants.OP_IINC:
    741                 variables.store(variableIndex,
    742                                 variables.iload(variableIndex).add(
    743                                 valueFactory.createIntegerValue(variableInstruction.constant)));
    744                 break;
    745 
    746             case InstructionConstants.OP_RET:
    747                 // The return address should be in the last offset of the
    748                 // given instruction offset variable (even though there may
    749                 // be other offsets).
    750                 InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex);
    751                 branchUnit.branch(clazz,
    752                                   codeAttribute,
    753                                   offset,
    754                                   instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1));
    755                 break;
    756 
    757             default:
    758                 throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]");
    759         }
    760     }
    761 
    762 
    763     public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
    764     {
    765         int branchTarget = offset + branchInstruction.branchOffset;
    766 
    767         switch (branchInstruction.opcode)
    768         {
    769             case InstructionConstants.OP_IFEQ:
    770                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    771                     stack.ipop().equal(valueFactory.createIntegerValue(0)));
    772                 break;
    773 
    774             case InstructionConstants.OP_IFNE:
    775                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    776                     stack.ipop().notEqual(valueFactory.createIntegerValue(0)));
    777                 break;
    778 
    779             case InstructionConstants.OP_IFLT:
    780                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    781                     stack.ipop().lessThan(valueFactory.createIntegerValue(0)));
    782                 break;
    783 
    784             case InstructionConstants.OP_IFGE:
    785                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    786                     stack.ipop().greaterThanOrEqual(valueFactory.createIntegerValue(0)));
    787                 break;
    788 
    789             case InstructionConstants.OP_IFGT:
    790                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    791                     stack.ipop().greaterThan(valueFactory.createIntegerValue(0)));
    792                 break;
    793 
    794             case InstructionConstants.OP_IFLE:
    795                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    796                     stack.ipop().lessThanOrEqual(valueFactory.createIntegerValue(0)));
    797                 break;
    798 
    799 
    800             case InstructionConstants.OP_IFICMPEQ:
    801                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    802                     stack.ipop().equal(stack.ipop()));
    803                 break;
    804 
    805             case InstructionConstants.OP_IFICMPNE:
    806                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    807                     stack.ipop().notEqual(stack.ipop()));
    808                 break;
    809 
    810             case InstructionConstants.OP_IFICMPLT:
    811                 // Note that the stack entries are popped in reverse order.
    812                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    813                     stack.ipop().greaterThan(stack.ipop()));
    814                 break;
    815 
    816             case InstructionConstants.OP_IFICMPGE:
    817                 // Note that the stack entries are popped in reverse order.
    818                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    819                     stack.ipop().lessThanOrEqual(stack.ipop()));
    820                 break;
    821 
    822             case InstructionConstants.OP_IFICMPGT:
    823                 // Note that the stack entries are popped in reverse order.
    824                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    825                     stack.ipop().lessThan(stack.ipop()));
    826                 break;
    827 
    828             case InstructionConstants.OP_IFICMPLE:
    829                 // Note that the stack entries are popped in reverse order.
    830                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    831                     stack.ipop().greaterThanOrEqual(stack.ipop()));
    832                 break;
    833 
    834             case InstructionConstants.OP_IFACMPEQ:
    835                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    836                     stack.apop().equal(stack.apop()));
    837                 break;
    838 
    839             case InstructionConstants.OP_IFACMPNE:
    840                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    841                     stack.apop().notEqual(stack.apop()));
    842                 break;
    843 
    844             case InstructionConstants.OP_GOTO:
    845             case InstructionConstants.OP_GOTO_W:
    846                 branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
    847                 break;
    848 
    849 
    850             case InstructionConstants.OP_JSR:
    851             case InstructionConstants.OP_JSR_W:
    852                 stack.push(new InstructionOffsetValue(offset +
    853                                                       branchInstruction.length(offset)));
    854                 branchUnit.branch(clazz, codeAttribute, offset, branchTarget);
    855                 break;
    856 
    857             case InstructionConstants.OP_IFNULL:
    858                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    859                     stack.apop().isNull());
    860                 break;
    861 
    862             case InstructionConstants.OP_IFNONNULL:
    863                 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget,
    864                     stack.apop().isNotNull());
    865                 break;
    866 
    867             default:
    868                 throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]");
    869         }
    870     }
    871 
    872 
    873     public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
    874     {
    875         IntegerValue indexValue = stack.ipop();
    876 
    877         // If there is no definite branch in any of the cases below,
    878         // branch to the default offset.
    879         branchUnit.branch(clazz, codeAttribute,
    880                           offset,
    881                           offset + tableSwitchInstruction.defaultOffset);
    882 
    883         for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++)
    884         {
    885             int conditional = indexValue.equal(valueFactory.createIntegerValue(
    886                 tableSwitchInstruction.lowCase + index));
    887             branchUnit.branchConditionally(clazz, codeAttribute,
    888                                            offset,
    889                                            offset + tableSwitchInstruction.jumpOffsets[index],
    890                                            conditional);
    891 
    892             // If this branch is always taken, we can skip the rest.
    893             if (conditional == Value.ALWAYS)
    894             {
    895                 break;
    896             }
    897         }
    898     }
    899 
    900 
    901     public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
    902     {
    903         IntegerValue indexValue = stack.ipop();
    904 
    905         // If there is no definite branch in any of the cases below,
    906         // branch to the default offset.
    907         branchUnit.branch(clazz, codeAttribute,
    908                           offset,
    909                           offset + lookUpSwitchInstruction.defaultOffset);
    910 
    911         for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++)
    912         {
    913             int conditional = indexValue.equal(valueFactory.createIntegerValue(
    914                 lookUpSwitchInstruction.cases[index]));
    915             branchUnit.branchConditionally(clazz, codeAttribute,
    916                                            offset,
    917                                            offset + lookUpSwitchInstruction.jumpOffsets[index],
    918                                            conditional);
    919 
    920             // If this branch is always taken, we can skip the rest.
    921             if (conditional == Value.ALWAYS)
    922             {
    923                 break;
    924             }
    925         }
    926     }
    927 }
    928