Package alt.jiapi.reflect

Source Code of alt.jiapi.reflect.InstructionParser

package alt.jiapi.reflect;

import java.util.List;
import java.util.LinkedList;

import alt.jiapi.file.ConstantPool;
import alt.jiapi.reflect.instruction.Opcodes;
import alt.jiapi.reflect.instruction.Invocation;
import alt.jiapi.reflect.instruction.FieldAccess;
import alt.jiapi.reflect.instruction.CPInstruction;

/**
* Class InstructionParser.
*
* @author Mika Riekkinen
*/
class InstructionParser {
    /**
     * Parse bytecode and create a List of Instructions out
     * of it.
     *
     * @param byteCode Bytecode to be parsed.
     * @return a List of Instructions.
     * @exception
     */
    List createInstructionList(byte[] byteCode, ConstantPool cp) {
        List list = new LinkedList();
        boolean branchesFound = false;

        /*
         * First loop through bytecode and create raw instructions.
         * After loop, resolve branch/switch targets.
         */
        for (int i = 0; i < byteCode.length; i++) {
            byte opcode = byteCode[i];
            Instruction ins = null;
            int iMod = 0;

            //System.out.println("Instruction " + Opcodes.opcodeStrings[opcode&0xff]);
            switch(opcode) {
            case Opcodes.NOP:
            case Opcodes.ACONST_NULL:
            case Opcodes.ICONST_M1:
            case Opcodes.ICONST_0:
            case Opcodes.ICONST_1:
            case Opcodes.ICONST_2:
            case Opcodes.ICONST_3:
            case Opcodes.ICONST_4:
            case Opcodes.ICONST_5:
            case Opcodes.LCONST_0:
            case Opcodes.LCONST_1:
            case Opcodes.FCONST_0:
            case Opcodes.FCONST_1:
            case Opcodes.FCONST_2:
            case Opcodes.DCONST_0:
            case Opcodes.DCONST_1:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.BIPUSH:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1] });
                iMod = 1;//i++;
                break;
            case Opcodes.SIPUSH:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1],
                                                   byteCode[i+2] });
                iMod = 2;//i += 2;
                break;
            case Opcodes.LDC:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1] }, cp);
                iMod = 1;//i++;
                break;
            case Opcodes.LDC_W:
            case Opcodes.LDC2_W:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1],
                                                     byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.ILOAD:
            case Opcodes.LLOAD:
            case Opcodes.FLOAD:
            case Opcodes.DLOAD:
            case Opcodes.ALOAD:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1] });
                iMod = 1;//i++;
                break;
            case Opcodes.ILOAD_0:
            case Opcodes.ILOAD_1:
            case Opcodes.ILOAD_2:
            case Opcodes.ILOAD_3:
            case Opcodes.LLOAD_0:
            case Opcodes.LLOAD_1:
            case Opcodes.LLOAD_2:
            case Opcodes.LLOAD_3:
            case Opcodes.FLOAD_0:
            case Opcodes.FLOAD_1:
            case Opcodes.FLOAD_2:
            case Opcodes.FLOAD_3:
            case Opcodes.DLOAD_0:
            case Opcodes.DLOAD_1:
            case Opcodes.DLOAD_2:
            case Opcodes.DLOAD_3:
            case Opcodes.ALOAD_0:
            case Opcodes.ALOAD_1:
            case Opcodes.ALOAD_2:
            case Opcodes.ALOAD_3:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.IALOAD:
            case Opcodes.LALOAD:
            case Opcodes.FALOAD:
            case Opcodes.DALOAD:
            case Opcodes.AALOAD:
            case Opcodes.BALOAD:
            case Opcodes.CALOAD:
            case Opcodes.SALOAD:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.ISTORE:
            case Opcodes.LSTORE:
            case Opcodes.FSTORE:
            case Opcodes.DSTORE:
            case Opcodes.ASTORE:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1] });
                iMod = 1;//i++;
                break;
            case Opcodes.ISTORE_0:
            case Opcodes.ISTORE_1:
            case Opcodes.ISTORE_2:
            case Opcodes.ISTORE_3:
            case Opcodes.LSTORE_0:
            case Opcodes.LSTORE_1:
            case Opcodes.LSTORE_2:
            case Opcodes.LSTORE_3:
            case Opcodes.FSTORE_0:
            case Opcodes.FSTORE_1:
            case Opcodes.FSTORE_2:
            case Opcodes.FSTORE_3:
            case Opcodes.DSTORE_0:
            case Opcodes.DSTORE_1:
            case Opcodes.DSTORE_2:
            case Opcodes.DSTORE_3:
            case Opcodes.ASTORE_0:
            case Opcodes.ASTORE_1:
            case Opcodes.ASTORE_2:
            case Opcodes.ASTORE_3:
            case Opcodes.IASTORE:
            case Opcodes.LASTORE:
            case Opcodes.FASTORE:
            case Opcodes.DASTORE:
            case Opcodes.AASTORE:
            case Opcodes.BASTORE:
            case Opcodes.CASTORE:
            case Opcodes.SASTORE:
            case Opcodes.POP:
            case Opcodes.POP2:
            case Opcodes.DUP:
            case Opcodes.DUP_X1:
            case Opcodes.DUP_X2:
            case Opcodes.DUP2:
            case Opcodes.DUP2_X1:
            case Opcodes.DUP2_X2:
            case Opcodes.SWAP:
            case Opcodes.IADD:
            case Opcodes.LADD:
            case Opcodes.FADD:
            case Opcodes.DADD:
            case Opcodes.ISUB:
            case Opcodes.LSUB:
            case Opcodes.FSUB:
            case Opcodes.DSUB:
            case Opcodes.IMUL:
            case Opcodes.LMUL:
            case Opcodes.FMUL:
            case Opcodes.DMUL:
            case Opcodes.IDIV:
            case Opcodes.LDIV:
            case Opcodes.FDIV:
            case Opcodes.DDIV:
            case Opcodes.IREM:
            case Opcodes.LREM:
            case Opcodes.FREM:
            case Opcodes.DREM:
            case Opcodes.INEG:
            case Opcodes.LNEG:
            case Opcodes.FNEG:
            case Opcodes.DNEG:
            case Opcodes.ISHL:
            case Opcodes.LSHL:
            case Opcodes.ISHR:
            case Opcodes.LSHR:
            case Opcodes.IUSHR:
            case Opcodes.LUSHR:
            case Opcodes.IAND:
            case Opcodes.LAND:
            case Opcodes.IOR:
            case Opcodes.LOR:
            case Opcodes.IXOR:
            case Opcodes.LXOR:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.IINC:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1],
                                                   byteCode[i+2] });
                iMod = 2;//i += 2;
                break;
            case Opcodes.I2L:
            case Opcodes.I2F:
            case Opcodes.I2D:
            case Opcodes.L2I:
            case Opcodes.L2F:
            case Opcodes.L2D:
            case Opcodes.F2I:
            case Opcodes.F2L:
            case Opcodes.F2D:
            case Opcodes.D2I:
            case Opcodes.D2L:
            case Opcodes.D2F:
            case Opcodes.I2B:
            case Opcodes.I2C:
            case Opcodes.I2S:
            case Opcodes.LCMP:
            case Opcodes.FCMPL:
            case Opcodes.FCMPG:
            case Opcodes.DCMPL:
            case Opcodes.DCMPG:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.IFEQ:
            case Opcodes.IFNE:
            case Opcodes.IFLT:
            case Opcodes.IFGE:
            case Opcodes.IFGT:
            case Opcodes.IFLE:
            case Opcodes.IF_ICMPEQ:
            case Opcodes.IF_ICMPNE:
            case Opcodes.IF_ICMPLT:
            case Opcodes.IF_ICMPGE:
            case Opcodes.IF_ICMPGT:
            case Opcodes.IF_ICMPLE:
            case Opcodes.IF_ACMPEQ:
            case Opcodes.IF_ACMPNE:
            case Opcodes.GOTO:
            case Opcodes.JSR:
                branchesFound = true;
                ins = new BranchInstruction(new byte[] { byteCode[i],
                                                         byteCode[i+1],
                                                         byteCode[i+2]});
                iMod = 2;//i += 2;
                break;
            case Opcodes.RET:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1]});
                iMod = 1;//i += 1;
                break;
            case Opcodes.TABLESWITCH:
                branchesFound = true;
                int tspCount = 3 - (i % 4);
               
                byte l1 = byteCode[i + tspCount + 5];
                byte l2 = byteCode[i + tspCount + 6];
                byte l3 = byteCode[i + tspCount + 7];
                byte l4 = byteCode[i + tspCount + 8];

                int low = (((int)l1) << 24) | (((int)l2) << 16) |
                    (((int)l3) << 8) | l4;

                byte h1 = byteCode[i + tspCount + 9];
                byte h2 = byteCode[i + tspCount + 10];
                byte h3 = byteCode[i + tspCount + 11];
                byte h4 = byteCode[i + tspCount + 12];

                int high = (((int)h1) << 24) | (((int)h2) << 16) |
                    (((int)h3) << 8) | h4;

                int size = high - low + 1;
                int bSize = size * 4; // Size of offset table in bytes

                byte[] tsBytes = new byte[13 + tspCount + bSize];
                for (int k = 0; k < tsBytes.length; k++) {
                    tsBytes[k] = byteCode[i + k];
                }

                iMod = tsBytes.length -1;//i += tsBytes.length -1;
                ins = new SwitchInstruction(tsBytes, tspCount, size);

                break;
            case Opcodes.LOOKUPSWITCH:
                branchesFound = true;
                int pCount = 3 - (i % 4);
                // count padding
                // NOTE: Following is a bug
               
                byte np1 = byteCode[i + pCount + 5];
                byte np2 = byteCode[i + pCount + 6];
                byte np3 = byteCode[i + pCount + 7];
                byte np4 = byteCode[i + pCount + 8];

                int nPairs = (np1 << 24) & 0xff000000 | (np2 << 16) & 0xff0000|
                    (np3 << 8) & 0xff00 | (np4 & 0xff);

                int lbSize = nPairs * 4 * 2; // Size of offset table in bytes

                byte[] lsBytes = new byte[9 + pCount + lbSize ];

                for (int k = 0; k < lsBytes.length; k++) {
                    lsBytes[k] = byteCode[i + k];
                }

                iMod = lsBytes.length -1;//i += lsBytes.length -1;
                ins = new SwitchInstruction(lsBytes, pCount, nPairs);
                break;
            case Opcodes.IRETURN:
            case Opcodes.LRETURN:
            case Opcodes.FRETURN:
            case Opcodes.DRETURN:
            case Opcodes.ARETURN:
            case Opcodes.RETURN:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.GETSTATIC:
            case Opcodes.PUTSTATIC:
            case Opcodes.GETFIELD:
            case Opcodes.PUTFIELD:
                ins = new FieldAccess(new byte[] { byteCode[i],
                                                   byteCode[i+1],
                                                   byteCode[i+2]}, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.INVOKEVIRTUAL:
            case Opcodes.INVOKESPECIAL:
            case Opcodes.INVOKESTATIC:
                // BUG: what is the stack consumption
                // cp.getMethodDescriptor(....);
                ins = new Invocation(new byte[] { byteCode[i],
                                                  byteCode[i+1],
                                                  byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.INVOKEINTERFACE:
                byte count = byteCode[i+3];
                ins = new Invocation(new byte[] { byteCode[i],
                                                  byteCode[i+1],
                                                  byteCode[i+2],
                                                  count,
                                                  byteCode[i+4]}, cp);
                iMod = 4;//i += 4;
                break;
            case Opcodes.XXXUNUSEDXXX:
                new Instruction(new byte[] { byteCode[i]});
                break;
            case Opcodes.NEW:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1],
                                                     byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.NEWARRAY:
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1] });
                iMod = 1; //i += 1;
                break;
            case Opcodes.ANEWARRAY:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1],
                                                     byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.ARRAYLENGTH:
                ins = new Instruction(new byte[] { byteCode[i] } );
                break;
            case Opcodes.ATHROW:
                ins = new Instruction(new byte[] { byteCode[i] } );
                break;
            case Opcodes.CHECKCAST:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1],
                                                     byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.INSTANCEOF:
                ins = new CPInstruction(new byte[] { byteCode[i],
                                                     byteCode[i+1],
                                                     byteCode[i+2] }, cp);
                iMod = 2;//i += 2;
                break;
            case Opcodes.MONITORENTER:
            case Opcodes.MONITOREXIT:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            case Opcodes.WIDE:
                if (byteCode[i + 1] == Opcodes.IINC) {
                    // Format 2:
                    ins = new Instruction(new byte[] { byteCode[i],
                                                       byteCode[i+1],
                                                       byteCode[i+2],
                                                       byteCode[i+3],
                                                       byteCode[i+4],
                                                       byteCode[i+5] });
                    iMod = 5;//i += 5;
                }
                else {
                    // Format 1:
                    ins = new Instruction(new byte[] { byteCode[i],
                                                       byteCode[i+1],
                                                       byteCode[i+2],
                                                       byteCode[i+3] });
                    iMod = 3;//i += 3;
                }
                break;
            case Opcodes.MULTIANEWARRAY:
                byte dim = byteCode[i+4];
                ins = new Instruction(new byte[] { byteCode[i],
                                                   byteCode[i+1],
                                                   byteCode[i+2],
                                                   byteCode[i+3],
                                                   dim }/*, dim*/);
                iMod = 4;//i += 4;
                break;
            case Opcodes.IFNULL:
            case Opcodes.IFNONNULL:
                branchesFound = true;
                ins = new BranchInstruction(new byte[] { byteCode[i],
                                                         byteCode[i+1],
                                                         byteCode[i+2] });
                iMod = 2;//i += 2;
                break;
            case Opcodes.GOTO_W:
                branchesFound = true;
                ins = new BranchInstruction(new byte[] { byteCode[i],
                                                         byteCode[i+1],
                                                         byteCode[i+2],
                                                         byteCode[i+3],
                                                         byteCode[i+4] });
                iMod = 4;//i += 4;
                break;
            case Opcodes.JSR_W:
                branchesFound = true;
                ins = new BranchInstruction(new byte[] { byteCode[i],
                                                         byteCode[i+1],
                                                         byteCode[i+2],
                                                         byteCode[i+3],
                                                         byteCode[i+4] });
                iMod = 4;//i += 4;
                break;
            case Opcodes.BREAKPOINT:
            case Opcodes.IMPDEP1:
            case Opcodes.IMPDEP2:
                ins = new Instruction(new byte[] { byteCode[i] });
                break;
            }

            ins.setOffset((short)i);
            i += iMod;

            list.add(ins);
        }

        // Now we have created raw Instructions.
        // If we have created any instruction in branch family,
        // resolve their target instructions.
        if (branchesFound) {
            // find branch targets
            for (int i = 0; i < list.size(); i++) {
                Instruction ins = (Instruction)list.get(i);
                if (ins instanceof BranchInstruction) {
                    // Simple branch

                    BranchInstruction bi = (BranchInstruction)ins;
                    int offset = bi.getTargetOffset();

                    Instruction target = null;
                    //target = findTarget(list, i, offset);
                    //target = findTarget(list, 0, (bi.getOffset() + offset));
                    target = findTarget(list, (bi.getOffset() + offset));
        if (target != null) {
      bi.setTarget(target);
        }
        else {
      System.out.println("Error locating branch target for instruction at " + i + ": " + bi);
        }
                }
                else if (ins instanceof SwitchInstruction) {
                    // complex branch

                    SwitchInstruction si = (SwitchInstruction)ins;
                    int dOffset = si.getDefaultOffset();

                    // default target:
                    Instruction target = null;
                    target = findTarget(list, i, dOffset);
                    si.setDefault(target);

                    // targets:
                    int[] tOffsets = si.getTargetOffsets();

                    Instruction[] targets = new Instruction[tOffsets.length];
                    for (int j = 0; j < targets.length; j++) {
                        targets[j] = findTarget(list, i, tOffsets[j]);
                    }
                    si.setTargets(targets);
                }
            }
        }


        return list;
    }

    /**
     * Finds a jump target
     */
    private Instruction findTarget(List list, int offset) {
        int idx = 0;
        int currentOffset = 0;
        while (currentOffset != offset) {
      if (idx == list.size()) {
    return null;
      }

            Instruction ins = (Instruction)list.get(idx);
            currentOffset += ins.length();
            idx++;
        }

        return (Instruction)list.get(idx);
    }

    /**
     * Finds a jump target
     */
    private Instruction findTarget(List list, int idx, int offset) {
        int offs = offset;
        int dir = 1;
        if (offset < 0) {
            offs = -offset;
            dir = -1;
        }

        int i = 0;

        while(i < offs) {
            Instruction ins = (Instruction)list.get(idx);
            i += ins.length();
            idx += dir;
        }

        // Replace 'target' instruction with TargetInstruction
        Instruction target = (Instruction)list.get(idx);
        TargetInstruction ti = new TargetInstruction(target);
        list.set(idx, ti);

        return ti;
    }
}
TOP

Related Classes of alt.jiapi.reflect.InstructionParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.