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 }