alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (JCodeIterator.java)

This example Scala source code file (JCodeIterator.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

bytearray, error, error, iinc, iinc, jcode, jcodeiterator, jcodeiterator, jconstantpool, jmethodtype, jopcode, jopcode, low, unknown

The Scala JCodeIterator.java source code

/* FJBG -- Fast Java Bytecode Generator
 * Copyright 2002-2011 LAMP/EPFL
 * @author  Michel Schinz
 */

package ch.epfl.lamp.fjbg;

import ch.epfl.lamp.util.ByteArray;

/**
 * Iterator used to examine the contents of an instruction list.
 *
 * @author Michel Schinz, Thomas Friedli
 * @version 1.0
 */

public class JCodeIterator {
    protected final JCode code;
    protected final JConstantPool pool;
    protected final ByteArray codeArray;

    protected int pc;
    protected JOpcode opcode;

    /**
     * Creates a new code iterator with its instruction list
     * and its pc initialized to a given value.
     */
    public JCodeIterator(JCode code, int pc) {
        this.code = code;
        this.pool = code.getOwner().getOwner().getConstantPool();
        this.codeArray = code.codeArray;
        this.pc = pc;
        setOpcode();
    }

    public JCodeIterator(JCode code) {
        this(code, 0);
    }

    /**
     * Get the current program counter.
     * @return The current program counter.
     */
    public int getPC() { return pc; }

    /**
     * Searches the type of the instruction positionned at the
     * current address and updates the current instruction.
     */
    protected void setOpcode() {
        // TODO : check if the current pc is the beginning
        //        of an instruction
        opcode = isValid() ? JOpcode.OPCODES[codeArray.getU1(pc)] : null;
    }

    /**
     * Returns the opcode of the current instruction.
     * @return The opcode of the current instruction.
     */
    public JOpcode getOpcode() {
        return opcode;
    }

    /**
     * Updates the program counter to an given value.
     * @param pc The new value of the program counter.
     */
    public void moveTo(int pc) {
        this.pc = pc;
        setOpcode();
    }

    /**
     * Check the validity of the iterator.
     * @return true iff the iterator points to a valid address.
     */
    public boolean isValid() {
        return pc < codeArray.getSize();
    }

    /**
     * Updates the current instruction with the next one in the
     * sense of their position in the code.
     */
    public void moveToNext() {
        moveTo(pc + getInstructionSize());
    }

    /**
     * Updates the current instruction with a specific successor
     * of it.
     * @param succ The index of the wanted successor in the list of
     * the successors of the current instruction.
     */
    public void moveToSuccessor(int succ) {
        moveTo(getSuccessorPC(succ));
    }

    /**
     * Updates the current instruction with the one positionned
     * at a given index relatively to the actual program counter
     * @param offset The relative position of the instruction
     * compared with the position of the current one
     */
    public void moveRelatively(int offset) {
        moveTo(pc + offset);
    }

    /**
     * Returns the size in bytes of the current instruction.
     * @return The size in bytes of the current instruction.
     */
    public int getInstructionSize() {
        if (opcode.size != JOpcode.UNKNOWN) {
            return opcode.size;
        } else if (opcode == JOpcode.TABLESWITCH) {
            int lowOffset = 1 + pad4(pc + 1) + 4;
            int low = codeArray.getS4(pc + lowOffset);
            int high = codeArray.getS4(pc + lowOffset + 4);
            return lowOffset + 8 + 4 * (high - low + 1);
        } else if (opcode == JOpcode.LOOKUPSWITCH) {
            int npairsOffset = 1 + pad4(pc + 1) + 4;
            int npairs = codeArray.getS4(pc + npairsOffset);
            return npairsOffset + 4 + 8 * npairs;
        } else if (opcode == JOpcode.WIDE) {
            if (codeArray.getU1(pc + 1) == JOpcode.cIINC)
                return 6;
            else
                return 4;
        } else
            throw new Error("Unknown size for instruction " + opcode);
    }

    /**
     * Returns the number of successors of the current instruction.
     * @return The number of successors of the current instruction.
     */
    public int getSuccessorCount() {
        if (opcode.successorCount != JOpcode.UNKNOWN) {
            return opcode.successorCount;
        } else if (opcode == JOpcode.TABLESWITCH) {
            int lowPos = pc + 1 + pad4(pc + 1) + 4;
            return 1                           // default case
                + codeArray.getS4(lowPos + 4)  // value of HIGH field
                - codeArray.getS4(lowPos) + 1; // value of LOW field
        } else if (opcode == JOpcode.LOOKUPSWITCH) {
            int npairsPos = pc + 1 + pad4(pc + 1) + 4;
            return 1 + codeArray.getS4(npairsPos);
        } else
            throw new Error("Unknown successors for instruction " + opcode);
    }

    /**
     * Returns the address of the successor of the current instruction
     * given its index in the list of successors of the current
     * instruction.
     * @param index The index of the wanted successor in the list of
     * the successors of the current instruction.
     * @return The address of the specific successor.
     */
    public int getSuccessorPC(int index) {
        assert (index >= 0) && (index < getSuccessorCount()) : index;

        switch (opcode.jumpKind) {
        case JOpcode.JMP_NEXT:
            return pc + getInstructionSize();
        case JOpcode.JMP_ALWAYS_S2_OFFSET:
            return pc + codeArray.getS2(pc + 1);
        case JOpcode.JMP_ALWAYS_S4_OFFSET:
            return pc + codeArray.getS4(pc + 1);
        case JOpcode.JMP_MAYBE_S2_OFFSET:
            if (index == 0)
                return pc + getInstructionSize();
            else
                return pc + codeArray.getS2(pc + 1);
        case JOpcode.JMP_TABLE: {
            int defaultPos = pc + 1 + pad4(pc + 1);
            if (index == 0)
                return pc + codeArray.getS4(defaultPos);
            else
                return pc + codeArray.getS4(defaultPos + 3*4 + 4 * (index - 1));
        }
        case JOpcode.JMP_LOOKUP: {
            int defaultPos = pc + 1 + pad4(pc + 1);
            if (index == 0)
                return pc + codeArray.getS4(defaultPos);
            else
                return pc + codeArray.getS4(defaultPos + 2*4 + 4 + 8 * (index - 1));
        }
        default:
            throw new Error();
        }
    }

    /**
     * Returns the total size of data words put on the stack by the current
     * instruction.
     * @return The total size of data words put on the stack by the current
     * instruction.
     */
    public int getProducedDataSize() {
        if (opcode.getProducedDataTypes() == JOpcode.UNKNOWN_TYPE) {
            switch (opcode.code) {
            case JOpcode.cLDC: case JOpcode.cLDC_W: case JOpcode.cBALOAD:
                return 1;
            case JOpcode.cLDC2_W: case JOpcode.cDUP: case JOpcode.cSWAP:
                return 2;
            case JOpcode.cDUP_X1:
                return 3;
            case JOpcode.cDUP_X2: case JOpcode.cDUP2:
                return 4;
            case JOpcode.cDUP2_X1:
                return 5;
            case JOpcode.cDUP2_X2:
                return 6;
            case JOpcode.cGETSTATIC: case JOpcode.cGETFIELD: {
                JConstantPool.FieldOrMethodRefEntry entry =
                    (JConstantPool.FieldOrMethodRefEntry)
                    pool.lookupEntry(codeArray.getU2(pc + 1));
                return JType.parseSignature(entry.getSignature()).getSize();
            }
            case JOpcode.cWIDE : {
                int op = codeArray.getU1(pc + 1);
                if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD) {
                    JOpcode opcode2 = JOpcode.OPCODES[op];
                    return JType.getTotalSize(opcode2.getProducedDataTypes());
                } else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE)
                    return 0;
                else return 0; // (IINC)
            }
            default :
                throw new Error(opcode.toString());
            }
        } else
            return JType.getTotalSize(opcode.getProducedDataTypes());
    }

    /**
     * Returns the total size of data words taken from the stack by the current
     * instruction.
     * @return The total size of data words taken from the stack by the current
     * instruction.
     */
    public int getConsumedDataSize() {
        if (opcode.getConsumedDataTypes() != JOpcode.UNKNOWN_TYPE)
            return JType.getTotalSize(opcode.getConsumedDataTypes());
        else {
            switch (opcode.code) {
            case JOpcode.cPOP: case JOpcode.cDUP:
                return 1;
            case JOpcode.cPOP2: case JOpcode.cSWAP:
            case JOpcode.cDUP_X1: case JOpcode.cDUP2:
                return 2;
            case JOpcode.cDUP_X2: case JOpcode.cDUP2_X1:
                return 3;
            case JOpcode.cDUP2_X2:
                return 4;
            case JOpcode.cPUTSTATIC: case JOpcode.cPUTFIELD: {
                JConstantPool.FieldOrMethodRefEntry entry =
                    (JConstantPool.FieldOrMethodRefEntry)
                    pool.lookupEntry(codeArray.getU2(pc + 1));
                return JType.parseSignature(entry.getSignature()).getSize();
            }
            case JOpcode.cINVOKEVIRTUAL: case JOpcode.cINVOKESPECIAL:
            case JOpcode.cINVOKESTATIC:  case JOpcode.cINVOKEINTERFACE : {
                JConstantPool.FieldOrMethodRefEntry entry =
                    (JConstantPool.FieldOrMethodRefEntry)
                    pool.lookupEntry(codeArray.getU2(pc + 1));
                JMethodType tp = (JMethodType)
                    JType.parseSignature(entry.getSignature());
                return tp.getArgsSize()
                    + (opcode == JOpcode.INVOKESTATIC ? 0 : 1);
            }
            case JOpcode.cWIDE : {
                int op = codeArray.getU1(pc + 1);
                if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD)
                    return 0;
                else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE) {
                    JOpcode opcode2 = JOpcode.OPCODES[op];
                    return JType.getTotalSize(opcode2.getConsumedDataTypes());
                } else
                    return 0; // (IINC)
            }
            case JOpcode.cMULTIANEWARRAY :
                return codeArray.getU1(pc + 3);
            default:
                throw new Error(opcode.toString());
            }
        }
    }

    /**
     * Returns the number of data types put on the stack by the current
     * instruction.
     * @return The number of data types put on the stack by the current
     * instruction.
     */
    public int getProducedDataTypesNumber() {
        if (opcode.getProducedDataTypes() != JOpcode.UNKNOWN_TYPE)
            return opcode.getProducedDataTypes().length;
        else {
            switch (opcode.code) {
            case JOpcode.cLDC: case JOpcode.cLDC_W: case JOpcode.cLDC2_W:
            case JOpcode.cBALOAD: case JOpcode.cGETSTATIC:
            case JOpcode.cGETFIELD:
                return 1;
            case JOpcode.cDUP: case JOpcode.cSWAP:
                return 2;
            case JOpcode.cDUP_X1:
                return 3;
            case JOpcode.cWIDE: {
                int op = codeArray.getU1(pc + 1);
                if (op >= JOpcode.cILOAD && op <= JOpcode.cALOAD)
                    return 1;
                else if (op >= JOpcode.cISTORE && op <= JOpcode.cASTORE)
                    return 0;
                else
                    return 0; // (IINC)
            }
            default:
                throw new Error("JOpcode implementation error");
            }
        }
    }

    /**
     * Returns the number of data types taken from the stack by the current
     * instruction.
     * @return The number of data types taken from the stack by the current
     * instruction.
     */
//     public int getConsumedDataTypesNumber() {
//         if (opcode.getConsumedDataTypes() == JOpcode.UNKNOWN_TYPE) {
//             switch (opcode.code) {
//             case 87 : return 1; // POP
//             case 88 : return 2; // POP2
//             case 89 : return 1; // DUP
//             case 90 : return 2; // DUP_X1
//             case 91 : // DUP_X2
//             case 92 : // DUP2
//             case 93 : // DUP2_X1
//             case 94 : // DUP2_X2
//                 throw new UnsupportedOperationException("Opcode " + opcode.name
//                                                         + " has a stack-dependant"
//                                                         + " data types consumption");
//             case 95 : return 2; // SWAP
//             case 179 : return 1; // PUTSTATIC
//             case 181 : return 1; // PUTFIELD
//             case 182 : // INVOKEVIRTUAL
//             case 183 : // INVOKESPECIAL
//             case 185 : // INVOKEINTERFACE
//                 s = epool.getClassMethodRef(codeArray.getU2(pc + 1)).split(" ")[3];
//                 return ((JMethodType)JType.parseSignature(s)).argTypes.length + 1;
//             case 184 : // INVOKESTATIC
//                 s = epool.getClassMethodRef(codeArray.getU2(pc + 1)).split(" ")[3];
//                 return ((JMethodType)JType.parseSignature(s)).argTypes.length;
//             case 196 : // WIDE
//                 int op = codeArray.getU1(pc + 1);
//                 if (op >= 21 && op <= 25) return 0; // (xLOAD)
//                 else if (op >= 54 && op <= 58) // (xSTORE)
//                     return JOpcode.OPCODES[op].getConsumedDataTypes().length;
//                 else return 0; // (IINC)
//             case 197 : return codeArray.getU1(pc + 3); // MULTIANEWARRAY
//             default : throw new Error("JOpcode implementation error");
//             }
//         } else return opcode.getConsumedDataTypes().length;
//     }


    // Return the number between 0 and 3 which, if added to the given
    // value, would yield a multiple of 4.
    protected int[] padding = { 0, 3, 2, 1 };
    protected int pad4(int value) {
        return padding[value % 4];
    }
}

Other Scala examples (source code examples)

Here is a short list of links related to this Scala JCodeIterator.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.