简体   繁体   中英

How to get the values on operand stack which the JVM instruction operates on with Javassist?

Javassist Provides the CodeIterator for editing a code attribute, which can be used to transverse all the instructions in the method.

For a JVM instruction, it always follows the specification : mnemonic operand1 operand2 ... Different from binary assembly, the stack-based JVM instructions takes value on the operand stack. Take the ifge as an example. The instruction has the following format if<cond> branchbyte1 branchbyte2 ifge succeeds if and only if value on stack ≥ 0, the branchbyte1 and branchbyte2 are the targets of the jump.

My question is, can I get the value on the operand stack using Javassist?

The answer is the javassist.bytecode.analysis module. According the JVM specification, frame is used to store data and partial results. Each frame has its own array of local variables, its own operand stack, and a reference to the run-time const pool.

In javassist.bytecode.analysis.FramePrinter , the funciton print shows how to print for each frame at each instruction.

/**
 * Prints the instructions and the frame states of the given method.
 */
public void print(CtMethod method) {
    stream.println("\n" + getMethodString(method));
    MethodInfo info = method.getMethodInfo2();
    ConstPool pool = info.getConstPool();
    CodeAttribute code = info.getCodeAttribute();
    if (code == null)
        return;

    Frame[] frames;
    try {
        frames = (new Analyzer()).analyze(method.getDeclaringClass(), info);
    } catch (BadBytecode e) {
        throw new RuntimeException(e);
    }

    int spacing = String.valueOf(code.getCodeLength()).length();

    CodeIterator iterator = code.iterator();
    while (iterator.hasNext()) {
        int pos;
        try {
            pos = iterator.next();
        } catch (BadBytecode e) {
            throw new RuntimeException(e);
        }

        stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool));

        addSpacing(spacing + 3);
        Frame frame = frames[pos];
        if (frame == null) {
            stream.println("--DEAD CODE--");
            continue;
        }
        printStack(frame);

        addSpacing(spacing + 3);
        printLocals(frame);
    }

}

From this code, we can see:

The frames can be acquired by frames = (new Analyzer()).analyze(method.getDeclaringClass(), info);

NOTE, this only return the type information of the stack item, but it doesn't give variable names.

As for the values each instruction uses, we should treat it differently according to the specification of the instruction.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM