View Javadoc

1   package serp.bytecode;
2   
3   import serp.bytecode.visitor.*;
4   
5   /***
6    * An instruction comparing two stack values. Examples include
7    * <code>lcmp, fcmpl</code>, etc.
8    *
9    * @author Abe White
10   */
11  public class CmpInstruction extends TypedInstruction {
12      private static Class[][] _mappings = new Class[][] {
13          { int.class, long.class },
14          { byte.class, long.class },
15          { char.class, long.class },
16          { short.class, long.class },
17          { boolean.class, long.class },
18          { void.class, long.class },
19          { Object.class, long.class },
20      };
21  
22      CmpInstruction(Code owner) {
23          super(owner);
24      }
25  
26      CmpInstruction(Code owner, int opcode) {
27          super(owner, opcode);
28      }
29  
30      public int getLogicalStackChange() {
31          switch (getOpcode()) {
32          case Constants.NOP:
33              return 0;
34          default:
35              return -1;
36          }
37      }
38  
39      public int getStackChange() {
40          switch (getOpcode()) {
41          case Constants.LCMP:
42          case Constants.DCMPL:
43          case Constants.DCMPG:
44              return -3;
45          case Constants.NOP:
46              return 0;
47          default:
48              return -1;
49          }
50      }
51  
52      public String getTypeName() {
53          switch (getOpcode()) {
54          case Constants.LCMP:
55              return long.class.getName();
56          case Constants.FCMPL:
57          case Constants.FCMPG:
58              return float.class.getName();
59          case Constants.DCMPL:
60          case Constants.DCMPG:
61              return double.class.getName();
62          default:
63              return null;
64          }
65      }
66  
67      public TypedInstruction setType(String type) {
68          type = mapType(type, _mappings, true);
69          if (type == null)
70              return (TypedInstruction) setOpcode(Constants.NOP);
71  
72          int opcode = getOpcode();
73          switch (type.charAt(0)) {
74          case 'l':
75              return (TypedInstruction) setOpcode(Constants.LCMP);
76          case 'f':
77              if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL))
78                  return (TypedInstruction) setOpcode(Constants.FCMPL);
79              return (TypedInstruction) setOpcode(Constants.FCMPG);
80          case 'd':
81              if ((opcode == Constants.FCMPL) || (opcode == Constants.DCMPL))
82                  return (TypedInstruction) setOpcode(Constants.DCMPL);
83              return (TypedInstruction) setOpcode(Constants.DCMPG);
84          default:
85              throw new IllegalStateException();
86          }
87      }
88  
89      /***
90       * Return the number that will be placed on the stack if this instruction
91       * is of type float or double and one of the operands is NaN. For
92       * FCMPG or DCMPG, this value will be 1; for FCMPL or DCMPL this value
93       * will be -1. For LCMP or if the type is unset, this value will be 0.
94       */
95      public int getNaNValue() {
96          switch (getOpcode()) {
97          case Constants.FCMPL:
98          case Constants.DCMPL:
99              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 }