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 }