serp.bytecode.StackInstruction Maven / Gradle / Ivy
package serp.bytecode;
import serp.bytecode.lowlevel.*;
import serp.bytecode.visitor.*;
/**
* Represents an instruction that manipulates the stack of the current
* frame. Using the {@link #setType} methods is a hint about the type being
* manipulated that might cause this instruction to use the wide version
* of the opcode it represents (if manipulating a long or double). This
* saves the developer from having to decide at compile time whether to
* use pop
or pop2
, etc.
*
* @author Abe White
*/
public class StackInstruction extends TypedInstruction {
StackInstruction(Code owner, int opcode) {
super(owner, opcode);
}
public int getStackChange() {
switch (getOpcode()) {
case Constants.POP:
return -1;
case Constants.POP2:
return -2;
case Constants.DUP:
case Constants.DUPX1:
case Constants.DUPX2:
return 1;
case Constants.DUP2:
case Constants.DUP2X1:
case Constants.DUP2X2:
return 2;
default:
return 0;
}
}
/**
* This method will always return null; use {@link #isWide} to determine
* if this is pop2, dup2, etc.
*/
public String getTypeName() {
return null;
}
public TypedInstruction setType(String type) {
type = getProject().getNameCache().getExternalForm(type, false);
return setWide(long.class.getName().equals(type)
|| double.class.getName().equals(type));
}
/**
* Return whether to use the wide form of the current opcode for
* operations on longs or doubles.
*/
public boolean isWide() {
switch (getOpcode()) {
case Constants.POP2:
case Constants.DUP2:
case Constants.DUP2X1:
case Constants.DUP2X2:
return true;
default:
return false;
}
}
/**
* Set whether to use the wide form of the current opcode for operations
* on longs or doubles.
*
* @return this instruction, for method chaining
*/
public StackInstruction setWide(boolean wide) {
switch (getOpcode()) {
case Constants.POP:
if (wide)
setOpcode(Constants.POP2);
break;
case Constants.POP2:
if (!wide)
setOpcode(Constants.POP);
break;
case Constants.DUP:
if (wide)
setOpcode(Constants.DUP2);
break;
case Constants.DUP2:
if (!wide)
setOpcode(Constants.DUP);
break;
case Constants.DUPX1:
if (wide)
setOpcode(Constants.DUP2X1);
break;
case Constants.DUP2X1:
if (!wide)
setOpcode(Constants.DUPX1);
break;
case Constants.DUPX2:
if (wide)
setOpcode(Constants.DUP2X2);
break;
case Constants.DUP2X2:
if (!wide)
setOpcode(Constants.DUPX2);
break;
}
return this;
}
public void acceptVisit(BCVisitor visit) {
visit.enterStackInstruction(this);
visit.exitStackInstruction(this);
}
}