/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.bytecode;
import java.util.Comparator;
import java.util.TreeMap;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.vm.JvmType;
import org.jnode.vm.classmgr.VmByteCode;
import org.jnode.vm.classmgr.VmConstClass;
import org.jnode.vm.classmgr.VmConstFieldRef;
import org.jnode.vm.classmgr.VmConstIMethodRef;
import org.jnode.vm.classmgr.VmConstMethodRef;
import org.jnode.vm.classmgr.VmConstString;
import org.jnode.vm.classmgr.VmInterpretedExceptionHandler;
import org.jnode.vm.classmgr.VmMethod;
/**
* Bytecode visitor, used to determine the start addresses of basic blocks.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
* @author Madhu Siddalingaiah
*/
public class BasicBlockFinder extends BytecodeVisitorSupport implements BytecodeFlags {
private static final boolean debug = false;
private final TreeMap<Integer, BasicBlock> blocks = new TreeMap<Integer, BasicBlock>();
private byte[] opcodeFlags;
private boolean nextIsStartOfBB;
private boolean nextFollowsTypeStack;
private int curAddress;
private final TypeStack tstack = new TypeStack();
private BasicBlock current;
private VmMethod method;
/**
* Create all determined basic blocks
*
* @return the basic blocks.
*/
public BasicBlock[] createBasicBlocks() {
// Create the array
final BasicBlock[] list = blocks.values().toArray(new BasicBlock[blocks.size()]);
// Set the EndPC's and flags
final byte[] opcodeFlags = this.opcodeFlags;
final int len = opcodeFlags.length;
int bbIndex = 0;
for (int i = 0; i < len; i++) {
if (isStartOfBB(i)) {
final int start = i;
// Find the end of the BB
i++;
while ((i < len) && (!isStartOfBB(i))) {
i++;
}
// the BB
final BasicBlock bb = list[bbIndex++];
if (bb.getStartPC() != start) {
throw new AssertionError("bb.getStartPC() != start");
}
bb.setEndPC(i);
bb.setStartOfExceptionHandler(isStartOfException(start));
i--;
}
}
if (bbIndex != list.length) {
throw new AssertionError("bbIndex != list.length");
}
return list;
}
/**
* Get the per-opcode bytecode flags.
*
* @return byte[]
*/
public final byte[] getOpcodeFlags() {
return opcodeFlags;
}
/**
* @param method
* @see org.jnode.vm.bytecode.BytecodeVisitor#startMethod(org.jnode.vm.classmgr.VmMethod)
*/
public void startMethod(VmMethod method) {
this.method = method;
final VmByteCode bc = method.getBytecode();
final int length = bc.getLength();
opcodeFlags = new byte[length];
// The first instruction is always the start of a BB.
startBB(0, true, tstack);
// The exception handler also start a basic block
final TypeStack ehTStack = new TypeStack();
ehTStack.push(JvmType.REFERENCE);
for (int i = 0; i < bc.getNoExceptionHandlers(); i++) {
VmInterpretedExceptionHandler eh = bc.getExceptionHandler(i);
startTryBlock(eh.getStartPC());
startTryBlockEnd(eh.getEndPC());
startException(eh.getHandlerPC(), ehTStack);
}
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifeq(int)
*/
public void visit_ifeq(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifne(int)
*/
public void visit_ifne(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iflt(int)
*/
public void visit_iflt(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifge(int)
*/
public void visit_ifge(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifgt(int)
*/
public void visit_ifgt(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifle(int)
*/
public void visit_ifle(int address) {
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpeq(int)
*/
public void visit_if_icmpeq(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpne(int)
*/
public void visit_if_icmpne(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmplt(int)
*/
public void visit_if_icmplt(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpge(int)
*/
public void visit_if_icmpge(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmpgt(int)
*/
public void visit_if_icmpgt(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_icmple(int)
*/
public void visit_if_icmple(int address) {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_acmpeq(int)
*/
public void visit_if_acmpeq(int address) {
tstack.pop(JvmType.REFERENCE);
tstack.pop(JvmType.REFERENCE);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_if_acmpne(int)
*/
public void visit_if_acmpne(int address) {
tstack.pop(JvmType.REFERENCE);
tstack.pop(JvmType.REFERENCE);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_goto(int)
*/
public void visit_goto(int address) {
// No change
addBranch(address, false);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_jsr(int)
*/
public void visit_jsr(int address) {
tstack.push(JvmType.RETURN_ADDRESS);
addBranch(address, false);
condYieldPoint(address);
tstack.pop();
}
/**
* @param defValue
* @param lowValue
* @param highValue
* @param addresses
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_tableswitch(int, int, int, int[])
*/
public void visit_tableswitch(int defValue, int lowValue, int highValue, int[] addresses) {
tstack.pop(JvmType.INT);
for (int address : addresses) {
addBranch(address, true);
condYieldPoint(address);
}
addBranch(defValue, false);
condYieldPoint(defValue);
}
/**
* @param defValue
* @param matchValues
* @param addresses
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lookupswitch(int, int[], int[])
*/
public void visit_lookupswitch(int defValue, int[] matchValues, int[] addresses) {
tstack.pop(JvmType.INT);
for (int address : addresses) {
addBranch(address, true);
condYieldPoint(address);
}
addBranch(defValue, false);
condYieldPoint(defValue);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifnull(int)
*/
public void visit_ifnull(int address) {
tstack.pop(JvmType.REFERENCE);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ifnonnull(int)
*/
public void visit_ifnonnull(int address) {
tstack.pop(JvmType.REFERENCE);
addBranch(address, true);
condYieldPoint(address);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_athrow()
*/
public void visit_athrow() {
tstack.pop(JvmType.REFERENCE);
endBB(false);
// Reference is actually pushed on the stack, but that is handled
// by the startException blocks.
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_areturn()
*/
public void visit_areturn() {
tstack.pop(JvmType.REFERENCE);
endBB(false);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dreturn()
*/
public void visit_dreturn() {
tstack.pop(JvmType.DOUBLE);
endBB(false);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_freturn()
*/
public void visit_freturn() {
tstack.pop(JvmType.FLOAT);
endBB(false);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ireturn()
*/
public void visit_ireturn() {
if (debug) {
BootLogInstance.get().debug("ireturn at " + curAddress + "; " + tstack);
}
tstack.pop(JvmType.INT);
endBB(false);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lreturn()
*/
public void visit_lreturn() {
tstack.pop(JvmType.LONG);
endBB(false);
}
/**
* @param index
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ret(int)
*/
public void visit_ret(int index) {
// No change
endBB(false);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_return()
*/
public void visit_return() {
// No change
endBB(false);
}
/**
* Add branching information (to the given target) to the basic blocks information.
*
* @param target
*/
private final void addBranch(int target, boolean conditional) {
startBB(target, true, this.tstack);
endBB(conditional);
}
/**
* Mark the end of a basic block
*/
private final void endBB(boolean nextFollowsTypeStack) {
this.nextIsStartOfBB = true;
this.nextFollowsTypeStack = nextFollowsTypeStack;
}
/**
* @param address
* @see org.jnode.vm.bytecode.BytecodeVisitor#startInstruction(int)
*/
public void startInstruction(int address) {
if (debug) {
BootLogInstance.get().debug("#" + address + '\t' + tstack);
}
curAddress = address;
super.startInstruction(address);
opcodeFlags[address] |= F_START_OF_INSTRUCTION;
if (nextIsStartOfBB) {
if (debug) BootLogInstance.get().debug("\tnextIsStartOfBB\t" + nextFollowsTypeStack);
startBB(address, nextFollowsTypeStack, this.tstack);
nextIsStartOfBB = false;
nextFollowsTypeStack = true;
}
if (isStartOfBB(address)) {
this.current = blocks.get(address);
if (debug) BootLogInstance.get().debug("\tcurrent\t" + current);
final TypeStack bbTStack = current.getStartStack();
if (bbTStack != null) {
if (debug) BootLogInstance.get().debug("\tcopyFrom\t" + bbTStack);
this.tstack.copyFrom(bbTStack);
} else if (!nextFollowsTypeStack) {
if (debug) BootLogInstance.get().debug("\tclear");
this.tstack.clear();
} else {
if (debug) BootLogInstance.get().debug("\tsetStartStack");
current.setStartStack(tstack);
}
}
if (debug) {
BootLogInstance.get().debug("#" + address + '\t' + tstack);
}
}
/**
* Mark the start of a basic block
*
* @param address
*/
private final void startBB(int address, boolean setTypeStack, TypeStack tstack) {
if ((opcodeFlags[address] & F_START_OF_BASICBLOCK) == 0) {
opcodeFlags[address] |= F_START_OF_BASICBLOCK;
final BasicBlock bb = new BasicBlock(address);
blocks.put(address, bb);
if (setTypeStack) {
bb.addEntryBlock(current);
bb.setStartStack(new TypeStack(tstack));
}
} else if (setTypeStack) {
// Verify stack
final BasicBlock bb = blocks.get(address);
final TypeStack bbTStack = bb.getStartStack();
if (bbTStack == null) {
bb.setStartStack(tstack);
} else if (!tstack.equals(bbTStack)) {
if (debug) {
BootLogInstance.get().warn("TypeStack is different in " + method + ';' + tstack + " vs. " +
bbTStack + " in " + bb + " at address " + this.curAddress);
}
//throw new VerifyError("TypeStack is different; " + tstack + " vs. " + bbTStack + " in " + bb);
}
// Add entry block
bb.addEntryBlock(current);
}
}
private final boolean isStartOfBB(int address) {
return ((opcodeFlags[address] & F_START_OF_BASICBLOCK) != 0);
}
private final boolean isStartOfException(int address) {
return ((opcodeFlags[address] & F_START_OF_EXCEPTIONHANDLER) != 0);
}
/**
* Mark the start of a exception handler
*
* @param address
*/
private final void startException(int address, TypeStack tstack) {
opcodeFlags[address] |= F_START_OF_EXCEPTIONHANDLER;
//System.out.println("startException: " + tstack);
startBB(address, true, tstack);
}
/**
* Mark the start of a try-catch block
*
* @param address
*/
private final void startTryBlock(int address) {
opcodeFlags[address] |= F_START_OF_TRYBLOCK;
//startBB(address, false, null);
}
/**
* Mark the end of a try-catch block
*
* @param address
*/
private final void startTryBlockEnd(int address) {
opcodeFlags[address] |= F_START_OF_TRYBLOCKEND;
//startBB(address, false, null);
}
/**
* Mark a conditional yieldpoint.
*/
private final void condYieldPoint(int target) {
if (target < curAddress) {
opcodeFlags[curAddress] |= F_YIELDPOINT;
}
}
/**
* Compare basic blocks on their start PC.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
static class BasicBlockComparator implements Comparator {
static final BasicBlockComparator INSTANCE = new BasicBlockComparator();
/**
* @param o1
* @param o2
* @return int
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object o1, Object o2) {
final int sp1 = ((BasicBlock) o1).getStartPC();
final int sp2 = ((BasicBlock) o2).getStartPC();
return sp1 - sp2;
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aaload()
*/
public void visit_aaload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aastore()
*/
public void visit_aastore() {
tstack.pop(JvmType.REFERENCE);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aconst_null()
*/
public void visit_aconst_null() {
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_aload(int)
*/
public void visit_aload(int index) {
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_anewarray(org.jnode.vm.classmgr.VmConstClass)
*/
public void visit_anewarray(VmConstClass clazz) {
tstack.pop(JvmType.INT);
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_arraylength()
*/
public void visit_arraylength() {
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_astore(int)
*/
public void visit_astore(int index) {
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_baload()
*/
public void visit_baload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_bastore()
*/
public void visit_bastore() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_caload()
*/
public void visit_caload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_castore()
*/
public void visit_castore() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_checkcast(org.jnode.vm.classmgr.VmConstClass)
*/
public void visit_checkcast(VmConstClass clazz) {
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2f()
*/
public void visit_d2f() {
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2i()
*/
public void visit_d2i() {
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_d2l()
*/
public void visit_d2l() {
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dadd()
*/
public void visit_dadd() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_daload()
*/
public void visit_daload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dastore()
*/
public void visit_dastore() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dcmpg()
*/
public void visit_dcmpg() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dcmpl()
*/
public void visit_dcmpl() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dconst(double)
*/
public void visit_dconst(double value) {
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ddiv()
*/
public void visit_ddiv() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dload(int)
*/
public void visit_dload(int index) {
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dmul()
*/
public void visit_dmul() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dneg()
*/
public void visit_dneg() {
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_drem()
*/
public void visit_drem() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dstore(int)
*/
public void visit_dstore(int index) {
tstack.pop(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dsub()
*/
public void visit_dsub() {
tstack.pop(JvmType.DOUBLE);
tstack.pop(JvmType.DOUBLE);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup_x1()
*/
public void visit_dup_x1() {
final int tv1 = tstack.pop();
final int tv2 = tstack.pop();
tstack.push(tv1);
tstack.push(tv2);
tstack.push(tv1);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup_x2()
*/
public void visit_dup_x2() {
final int tv1 = tstack.pop();
final int tv2 = tstack.pop();
if (JvmType.getCategory(tv2) == 1) {
final int tv3 = tstack.pop();
tstack.push(tv1);
tstack.push(tv3);
tstack.push(tv2);
tstack.push(tv1);
} else {
tstack.push(tv1);
tstack.push(tv2);
tstack.push(tv1);
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup()
*/
public void visit_dup() {
final int tv1 = tstack.pop();
tstack.push(tv1);
tstack.push(tv1);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup2_x1()
*/
public void visit_dup2_x1() {
final int tv1 = tstack.pop();
final int tv2 = tstack.pop();
if (JvmType.getCategory(tv1) == 1) {
final int tv3 = tstack.pop();
tstack.push(tv2);
tstack.push(tv1);
tstack.push(tv3);
tstack.push(tv2);
tstack.push(tv1);
} else {
tstack.push(tv1);
tstack.push(tv2);
tstack.push(tv1);
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup2_x2()
*/
public void visit_dup2_x2() {
final int tv1 = tstack.pop();
final int tv2 = tstack.pop();
final int cat1 = JvmType.getCategory(tv1);
final int cat2 = JvmType.getCategory(tv2);
if ((cat1 == 2) && (cat2 == 2)) {
// Form 4
tstack.push(tv1);
tstack.push(tv2);
tstack.push(tv1);
} else {
final int tv3 = tstack.pop();
final int cat3 = JvmType.getCategory(tv3);
if ((cat1 == 1) && (cat2 == 1) && (cat3 == 3)) {
// Form 3
tstack.push(tv2);
tstack.push(tv1);
tstack.push(tv3);
tstack.push(tv2);
tstack.push(tv1);
} else if ((cat1 == 2) && (cat2 == 1) && (cat3 == 1)) {
// Form 2
tstack.push(tv1);
tstack.push(tv3);
tstack.push(tv2);
tstack.push(tv1);
} else {
// Form 4
final int tv4 = tstack.pop();
tstack.push(tv2);
tstack.push(tv1);
tstack.push(tv4);
tstack.push(tv3);
tstack.push(tv2);
tstack.push(tv1);
}
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_dup2()
*/
public void visit_dup2() {
final int tv1 = tstack.pop();
if (JvmType.getCategory(tv1) == 1) {
final int tv2 = tstack.pop();
tstack.push(tv2);
tstack.push(tv1);
tstack.push(tv2);
tstack.push(tv1);
} else {
tstack.push(tv1);
tstack.push(tv1);
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_f2d()
*/
public void visit_f2d() {
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_f2i()
*/
public void visit_f2i() {
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_f2l()
*/
public void visit_f2l() {
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fadd()
*/
public void visit_fadd() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_faload()
*/
public void visit_faload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fastore()
*/
public void visit_fastore() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fcmpg()
*/
public void visit_fcmpg() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fcmpl()
*/
public void visit_fcmpl() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fconst(float)
*/
public void visit_fconst(float value) {
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fdiv()
*/
public void visit_fdiv() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fload(int)
*/
public void visit_fload(int index) {
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fmul()
*/
public void visit_fmul() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fneg()
*/
public void visit_fneg() {
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_frem()
*/
public void visit_frem() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fstore(int)
*/
public void visit_fstore(int index) {
tstack.pop(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_fsub()
*/
public void visit_fsub() {
tstack.pop(JvmType.FLOAT);
tstack.pop(JvmType.FLOAT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_getfield(org.jnode.vm.classmgr.VmConstFieldRef)
*/
public void visit_getfield(VmConstFieldRef fieldRef) {
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.SignatureToType(fieldRef.getSignature()));
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_getstatic(org.jnode.vm.classmgr.VmConstFieldRef)
*/
public void visit_getstatic(VmConstFieldRef fieldRef) {
tstack.push(JvmType.SignatureToType(fieldRef.getSignature()));
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2b()
*/
public void visit_i2b() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2c()
*/
public void visit_i2c() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2d()
*/
public void visit_i2d() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2f()
*/
public void visit_i2f() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2l()
*/
public void visit_i2l() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_i2s()
*/
public void visit_i2s() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iadd()
*/
public void visit_iadd() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iaload()
*/
public void visit_iaload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iand()
*/
public void visit_iand() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iastore()
*/
public void visit_iastore() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iconst(int)
*/
public void visit_iconst(int value) {
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_idiv()
*/
public void visit_idiv() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iinc(int, int)
*/
public void visit_iinc(int index, int incValue) {
// No change
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iload(int)
*/
public void visit_iload(int index) {
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_imul()
*/
public void visit_imul() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ineg()
*/
public void visit_ineg() {
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_instanceof(org.jnode.vm.classmgr.VmConstClass)
*/
public void visit_instanceof(VmConstClass clazz) {
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
private final void popArguments(VmConstMethodRef methodRef) {
final int[] types = JvmType.getArgumentTypes(methodRef.getSignature());
for (int i = types.length - 1; i >= 0; i--) {
tstack.pop(types[i]);
}
}
private final void pushReturnValue(VmConstMethodRef methodRef) {
final int type = JvmType.getReturnType(methodRef.getSignature());
if (type != JvmType.VOID) {
tstack.push(type);
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokeinterface(org.jnode.vm.classmgr.VmConstIMethodRef, int)
*/
public void visit_invokeinterface(VmConstIMethodRef methodRef, int count) {
popArguments(methodRef);
tstack.pop(JvmType.REFERENCE);
pushReturnValue(methodRef);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokespecial(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokespecial(VmConstMethodRef methodRef) {
popArguments(methodRef);
tstack.pop(JvmType.REFERENCE);
pushReturnValue(methodRef);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokestatic(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokestatic(VmConstMethodRef methodRef) {
popArguments(methodRef);
pushReturnValue(methodRef);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_invokevirtual(org.jnode.vm.classmgr.VmConstMethodRef)
*/
public void visit_invokevirtual(VmConstMethodRef methodRef) {
popArguments(methodRef);
tstack.pop(JvmType.REFERENCE);
pushReturnValue(methodRef);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ior()
*/
public void visit_ior() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_irem()
*/
public void visit_irem() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ishl()
*/
public void visit_ishl() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ishr()
*/
public void visit_ishr() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_istore(int)
*/
public void visit_istore(int index) {
tstack.pop(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_isub()
*/
public void visit_isub() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_iushr()
*/
public void visit_iushr() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ixor()
*/
public void visit_ixor() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_l2d()
*/
public void visit_l2d() {
tstack.pop(JvmType.LONG);
tstack.push(JvmType.DOUBLE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_l2f()
*/
public void visit_l2f() {
tstack.pop(JvmType.LONG);
tstack.push(JvmType.FLOAT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_l2i()
*/
public void visit_l2i() {
tstack.pop(JvmType.LONG);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ladd()
*/
public void visit_ladd() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_laload()
*/
public void visit_laload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_land()
*/
public void visit_land() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lastore()
*/
public void visit_lastore() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lcmp()
*/
public void visit_lcmp() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lconst(long)
*/
public void visit_lconst(long value) {
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ldc(org.jnode.vm.classmgr.VmConstClass)
*/
public void visit_ldc(VmConstClass value) {
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ldc(org.jnode.vm.classmgr.VmConstString)
*/
public void visit_ldc(VmConstString value) {
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_ldiv()
*/
public void visit_ldiv() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lload(int)
*/
public void visit_lload(int index) {
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lmul()
*/
public void visit_lmul() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lneg()
*/
public void visit_lneg() {
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lor()
*/
public void visit_lor() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lrem()
*/
public void visit_lrem() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lshl()
*/
public void visit_lshl() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lshr()
*/
public void visit_lshr() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lstore(int)
*/
public void visit_lstore(int index) {
tstack.pop(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lsub()
*/
public void visit_lsub() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lushr()
*/
public void visit_lushr() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_lxor()
*/
public void visit_lxor() {
tstack.pop(JvmType.LONG);
tstack.pop(JvmType.LONG);
tstack.push(JvmType.LONG);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_monitorenter()
*/
public void visit_monitorenter() {
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_monitorexit()
*/
public void visit_monitorexit() {
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_multianewarray(org.jnode.vm.classmgr.VmConstClass, int)
*/
public void visit_multianewarray(VmConstClass clazz, int dimensions) {
for (int i = 0; i < dimensions; i++) {
tstack.pop(JvmType.INT);
}
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_new(org.jnode.vm.classmgr.VmConstClass)
*/
public void visit_new(VmConstClass clazz) {
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_newarray(int)
*/
public void visit_newarray(int type) {
tstack.pop(JvmType.INT);
tstack.push(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_nop()
*/
public void visit_nop() {
// No change
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_pop()
*/
public void visit_pop() {
tstack.pop();
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_pop2()
*/
public void visit_pop2() {
final int tv1 = tstack.pop();
if (JvmType.getCategory(tv1) == 1) {
tstack.pop();
}
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_putfield(org.jnode.vm.classmgr.VmConstFieldRef)
*/
public void visit_putfield(VmConstFieldRef fieldRef) {
tstack.pop(JvmType.SignatureToType(fieldRef.getSignature()));
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_putstatic(org.jnode.vm.classmgr.VmConstFieldRef)
*/
public void visit_putstatic(VmConstFieldRef fieldRef) {
tstack.pop(JvmType.SignatureToType(fieldRef.getSignature()));
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_saload()
*/
public void visit_saload() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
tstack.push(JvmType.INT);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_sastore()
*/
public void visit_sastore() {
tstack.pop(JvmType.INT);
tstack.pop(JvmType.INT);
tstack.pop(JvmType.REFERENCE);
}
/**
* @see org.jnode.vm.bytecode.BytecodeVisitor#visit_swap()
*/
public void visit_swap() {
final int tv1 = tstack.pop();
final int tv2 = tstack.pop();
tstack.push(tv1);
tstack.push(tv2);
}
}