serp.bytecode.ConvertInstruction Maven / Gradle / Ivy
The newest version!
package serp.bytecode;
import java.util.*;
import serp.bytecode.visitor.*;
import serp.util.*;
/**
* A conversion opcode such as i2l, f2i
, etc.
* Changing the types of the instruction will automatically
* update the underlying opcode. Converting from one type to the same
* type will result in a nop
.
*
* @author Abe White
*/
public class ConvertInstruction extends TypedInstruction {
private static final Class[][] _mappings = new Class[][] {
{ boolean.class, int.class },
{ void.class, int.class },
{ Object.class, int.class },
};
private static final Class[][] _fromMappings = new Class[][] {
{ boolean.class, int.class },
{ void.class, int.class },
{ Object.class, int.class },
{ byte.class, int.class },
{ char.class, int.class },
{ short.class, int.class },
};
String _toType = null;
String _fromType = null;
ConvertInstruction(Code owner) {
super(owner);
}
ConvertInstruction(Code owner, int opcode) {
super(owner, opcode);
}
public int getLogicalStackChange() {
return 0;
}
public int getStackChange() {
switch (getOpcode()) {
case Constants.I2L:
case Constants.I2D:
case Constants.F2L:
case Constants.F2D:
return 1;
case Constants.L2I:
case Constants.L2F:
case Constants.D2I:
case Constants.D2F:
return -1;
default:
return 0;
}
}
public String getTypeName() {
switch (getOpcode()) {
case Constants.L2I:
case Constants.F2I:
case Constants.D2I:
return int.class.getName();
case Constants.I2L:
case Constants.F2L:
case Constants.D2L:
return long.class.getName();
case Constants.I2F:
case Constants.L2F:
case Constants.D2F:
return float.class.getName();
case Constants.I2D:
case Constants.L2D:
case Constants.F2D:
return double.class.getName();
case Constants.I2B:
return byte.class.getName();
case Constants.I2C:
return char.class.getName();
case Constants.I2S:
return short.class.getName();
default:
return _toType;
}
}
public TypedInstruction setType(String type) {
String toType = mapType(type, _mappings, true);
String fromType = getFromTypeName();
// if no valid opcode, remember current types in case they reset one
// to create a valid opcode
if (toType == null || fromType == null || toType.equals(fromType)) {
_toType = toType;
_fromType = fromType;
return (TypedInstruction) setOpcode(Constants.NOP);
}
// ok, valid conversion possible, forget saved types
_toType = null;
_fromType = null;
char to = toType.charAt(0);
char from = fromType.charAt(0);
switch (to) {
case 'i':
switch (from) {
case 'l':
return (TypedInstruction) setOpcode(Constants.L2I);
case 'f':
return (TypedInstruction) setOpcode(Constants.F2I);
case 'd':
return (TypedInstruction) setOpcode(Constants.D2I);
}
case 'l':
switch (from) {
case 'i':
return (TypedInstruction) setOpcode(Constants.I2L);
case 'f':
return (TypedInstruction) setOpcode(Constants.F2L);
case 'd':
return (TypedInstruction) setOpcode(Constants.D2L);
}
case 'f':
switch (from) {
case 'i':
return (TypedInstruction) setOpcode(Constants.I2F);
case 'l':
return (TypedInstruction) setOpcode(Constants.L2F);
case 'd':
return (TypedInstruction) setOpcode(Constants.D2F);
}
case 'd':
switch (from) {
case 'i':
return (TypedInstruction) setOpcode(Constants.I2D);
case 'l':
return (TypedInstruction) setOpcode(Constants.L2D);
case 'f':
return (TypedInstruction) setOpcode(Constants.F2D);
}
case 'b':
if (from == 'i')
return (TypedInstruction) setOpcode(Constants.I2B);
case 'C':
if (from == 'i')
return (TypedInstruction) setOpcode(Constants.I2C);
case 'S':
if (from == 'i')
return (TypedInstruction) setOpcode(Constants.I2S);
default:
throw new IllegalStateException();
}
}
/**
* Return the name of the type being converted from.
* If neither type has been set, this method will return null.
*/
public String getFromTypeName() {
switch (getOpcode()) {
case Constants.I2L:
case Constants.I2F:
case Constants.I2D:
case Constants.I2B:
case Constants.I2S:
case Constants.I2C:
return int.class.getName();
case Constants.L2I:
case Constants.L2F:
case Constants.L2D:
return long.class.getName();
case Constants.F2I:
case Constants.F2L:
case Constants.F2D:
return float.class.getName();
case Constants.D2I:
case Constants.D2L:
case Constants.D2F:
return double.class.getName();
default:
return _fromType;
}
}
/**
* Return the {@link Class} of the type being converted from.
* If neither type has been set, this method will return null.
*/
public Class getFromType() {
String type = getFromTypeName();
if (type == null)
return null;
return Strings.toClass(type, getClassLoader());
}
/**
* Return the bytecode of the type being converted from.
* If neither type has been set, this method will return null.
*/
public BCClass getFromTypeBC() {
String type = getFromTypeName();
if (type == null)
return null;
return getProject().loadClass(type, getClassLoader());
}
/**
* Set the type being converted from. Types that have no direct
* support will be converted accordingly.
*
* @return this instruction, for method chaining
*/
public ConvertInstruction setFromType(String type) {
String fromType = mapType(type, _fromMappings, true);
String toType = getTypeName();
// if no valid opcode, remember current types in case they reset one
// to create a valid opcode
if ((toType == null) || (fromType == null) || toType.equals(fromType)) {
_toType = toType;
_fromType = fromType;
return (ConvertInstruction) setOpcode(Constants.NOP);
}
// ok, valid conversion possible, forget saved types
_toType = null;
_fromType = null;
char to = toType.charAt(0);
char from = fromType.charAt(0);
switch (from) {
case 'i':
switch (to) {
case 'l':
return (ConvertInstruction) setOpcode(Constants.I2L);
case 'f':
return (ConvertInstruction) setOpcode(Constants.I2F);
case 'd':
return (ConvertInstruction) setOpcode(Constants.I2D);
case 'b':
return (ConvertInstruction) setOpcode(Constants.I2B);
case 'c':
return (ConvertInstruction) setOpcode(Constants.I2C);
case 's':
return (ConvertInstruction) setOpcode(Constants.I2S);
}
case 'l':
switch (to) {
case 'i':
return (ConvertInstruction) setOpcode(Constants.L2I);
case 'f':
return (ConvertInstruction) setOpcode(Constants.L2F);
case 'd':
return (ConvertInstruction) setOpcode(Constants.L2D);
}
case 'f':
switch (to) {
case 'i':
return (ConvertInstruction) setOpcode(Constants.F2I);
case 'l':
return (ConvertInstruction) setOpcode(Constants.F2L);
case 'd':
return (ConvertInstruction) setOpcode(Constants.F2D);
}
case 'd':
switch (to) {
case 'i':
return (ConvertInstruction) setOpcode(Constants.D2I);
case 'l':
return (ConvertInstruction) setOpcode(Constants.D2L);
case 'f':
return (ConvertInstruction) setOpcode(Constants.D2F);
}
default:
throw new IllegalStateException();
}
}
/**
* Set the type being converted from. Types that have no direct
* support will be converted accordingly.
*
* @return this instruction, for method chaining
*/
public ConvertInstruction setFromType(Class type) {
if (type == null)
return setFromType((String) null);
return setFromType(type.getName());
}
/**
* Set the type being converted from. Types that have no direct
* support will be converted accordingly.
*
* @return this instruction, for method chaining
*/
public ConvertInstruction setFromType(BCClass type) {
if (type == null)
return setFromType((String) null);
return setFromType(type.getName());
}
/**
* ConvertInstructions are equal if the types they convert between are
* either equal or unset.
*/
public boolean equalsInstruction(Instruction other) {
if (other == this)
return true;
if (!(other instanceof ConvertInstruction))
return false;
ConvertInstruction ins = (ConvertInstruction) other;
if (getOpcode() != Constants.NOP && getOpcode() == ins.getOpcode())
return true;
String type = getTypeName();
String otherType = ins.getTypeName();
if (!(type == null || otherType == null || type.equals(otherType)))
return false;
type = getFromTypeName();
otherType = ins.getFromTypeName();
return type == null || otherType == null || type.equals(otherType);
}
public void acceptVisit(BCVisitor visit) {
visit.enterConvertInstruction(this);
visit.exitConvertInstruction(this);
}
void read(Instruction orig) {
super.read(orig);
ConvertInstruction ins = (ConvertInstruction) orig;
_toType = ins._toType;
_fromType = ins._fromType;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy