001 package serp.bytecode;
002
003 import serp.bytecode.visitor.*;
004
005 /**
006 * An instruction comparing two stack values. Examples include
007 * <code>lcmp, fcmpl</code>, etc.
008 *
009 * @author Abe White
010 */
011 public class CmpInstruction extends TypedInstruction {
012 private static Class[][] _mappings = new Class[][] {
013 { int.class, long.class },
014 { byte.class, long.class },
015 { char.class, long.class },
016 { short.class, long.class },
017 { boolean.class, long.class },
018 { void.class, long.class },
019 { Object.class, long.class },
020 };
021
022 CmpInstruction(Code owner) {
023 super(owner);
024 }
025
026 CmpInstruction(Code owner, int opcode) {
027 super(owner, opcode);
028 }
029
030 public int getLogicalStackChange() {
031 switch (getOpcode()) {
032 case Constants.NOP:
033 return 0;
034 default:
035 return -1;
036 }
037 }
038
039 public int getStackChange() {
040 switch (getOpcode()) {
041 case Constants.LCMP:
042 case Constants.DCMPL:
043 case Constants.DCMPG:
044 return -3;
045 case Constants.NOP:
046 return 0;
047 default:
048 return -1;
049 }
050 }
051
052 public String getTypeName() {
053 switch (getOpcode()) {
054 case Constants.LCMP:
055 return long.class.getName();
056 case Constants.FCMPL:
057 case Constants.FCMPG:
058 return float.class.getName();
059 case Constants.DCMPL:
060 case Constants.DCMPG:
061 return double.class.getName();
062 default:
063 return null;
064 }
065 }
066
067 public TypedInstruction setType(String type) {
068 type = mapType(type, _mappings, true);
069 if (type == null)
070 return (TypedInstruction) setOpcode(Constants.NOP);
071
072 int opcode = getOpcode();
073 switch (type.charAt(0)) {
074 case 'l':
075 return (TypedInstruction) setOpcode(Constants.LCMP);
076 case 'f':
077 if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL))
078 return (TypedInstruction) setOpcode(Constants.FCMPL);
079 return (TypedInstruction) setOpcode(Constants.FCMPG);
080 case 'd':
081 if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL))
082 return (TypedInstruction) setOpcode(Constants.DCMPL);
083 return (TypedInstruction) setOpcode(Constants.DCMPG);
084 default:
085 throw new IllegalStateException();
086 }
087 }
088
089 /**
090 * Return the number that will be placed on the stack if this instruction
091 * is of type float or double and one of the operands is NaN. For
092 * FCMPG or DCMPG, this value will be 1; for FCMPL or DCMPL this value
093 * will be -1. For LCMP or if the type is unset, this value will be 0.
094 */
095 public int getNaNValue() {
096 switch (getOpcode()) {
097 case Constants.FCMPL:
098 case Constants.DCMPL:
099 return -1;
100 case Constants.FCMPG:
101 case Constants.DCMPG:
102 return 1;
103 default:
104 return 0;
105 }
106 }
107
108 /**
109 * Set the number that will be placed on the stack if this instruction
110 * is of type float or double and one of the operands is NaN. For
111 * FCMPG or DCMPG, this value should be 1; for FCMPL or DCMPL this value
112 * should be -1. For LCMP, this value should be 0.
113 *
114 * @return this instruction, for method chaining
115 */
116 public CmpInstruction setNaNValue(int nan) {
117 switch (getOpcode()) {
118 case Constants.FCMPL:
119 case Constants.FCMPG:
120 if (nan == 1)
121 setOpcode(Constants.FCMPG);
122 else if (nan == -1)
123 setOpcode(Constants.FCMPL);
124 else
125 throw new IllegalArgumentException("Invalid nan for type");
126 case Constants.DCMPL:
127 case Constants.DCMPG:
128 if (nan == 1)
129 setOpcode(Constants.DCMPG);
130 else if (nan == -1)
131 setOpcode(Constants.DCMPL);
132 else
133 throw new IllegalArgumentException("Invalid nan for type");
134 default:
135 if (nan != 0)
136 throw new IllegalArgumentException("Invalid nan for type");
137 }
138 return this;
139 }
140
141 public void acceptVisit(BCVisitor visit) {
142 visit.enterCmpInstruction(this);
143 visit.exitCmpInstruction(this);
144 }
145 }