001 package serp.bytecode; 002 003 import java.io.*; 004 005 import serp.bytecode.visitor.*; 006 007 /** 008 * An instruction to store a value from a local variable onto the stack. 009 * 010 * @author Abe White 011 */ 012 public class StoreInstruction extends LocalVariableInstruction { 013 private static final Class[][] _mappings = new Class[][] { 014 { byte.class, int.class }, 015 { boolean.class, int.class }, 016 { char.class, int.class }, 017 { short.class, int.class }, 018 { void.class, int.class }, 019 }; 020 String _type = null; 021 022 StoreInstruction(Code owner) { 023 super(owner); 024 } 025 026 StoreInstruction(Code owner, int opcode) { 027 super(owner, opcode); 028 } 029 030 int getLength() { 031 switch (getOpcode()) { 032 case Constants.ISTORE: 033 case Constants.LSTORE: 034 case Constants.FSTORE: 035 case Constants.DSTORE: 036 case Constants.ASTORE: 037 return super.getLength() + 1; 038 default: 039 return super.getLength(); 040 } 041 } 042 043 public int getLogicalStackChange() { 044 switch (getOpcode()) { 045 case Constants.NOP: 046 return 0; 047 default: 048 return -1; 049 } 050 } 051 052 public int getStackChange() { 053 switch (getOpcode()) { 054 case Constants.LSTORE: 055 case Constants.LSTORE0: 056 case Constants.LSTORE1: 057 case Constants.LSTORE2: 058 case Constants.LSTORE3: 059 case Constants.DSTORE: 060 case Constants.DSTORE0: 061 case Constants.DSTORE1: 062 case Constants.DSTORE2: 063 case Constants.DSTORE3: 064 return -2; 065 case Constants.NOP: 066 return 0; 067 default: 068 return -1; 069 } 070 } 071 072 public String getTypeName() { 073 switch (getOpcode()) { 074 case Constants.ISTORE: 075 case Constants.ISTORE0: 076 case Constants.ISTORE1: 077 case Constants.ISTORE2: 078 case Constants.ISTORE3: 079 return int.class.getName(); 080 case Constants.LSTORE: 081 case Constants.LSTORE0: 082 case Constants.LSTORE1: 083 case Constants.LSTORE2: 084 case Constants.LSTORE3: 085 return long.class.getName(); 086 case Constants.FSTORE: 087 case Constants.FSTORE0: 088 case Constants.FSTORE1: 089 case Constants.FSTORE2: 090 case Constants.FSTORE3: 091 return float.class.getName(); 092 case Constants.DSTORE: 093 case Constants.DSTORE0: 094 case Constants.DSTORE1: 095 case Constants.DSTORE2: 096 case Constants.DSTORE3: 097 return double.class.getName(); 098 case Constants.ASTORE: 099 case Constants.ASTORE0: 100 case Constants.ASTORE1: 101 case Constants.ASTORE2: 102 case Constants.ASTORE3: 103 return Object.class.getName(); 104 default: 105 return _type; 106 } 107 } 108 109 public TypedInstruction setType(String type) { 110 type = mapType(type, _mappings, true); 111 int local = getLocal(); 112 int len = getLength(); 113 114 // if an invalid type or local, revert to nop 115 if ((type == null) || (local < 0)) { 116 _type = type; 117 setOpcode(Constants.NOP); 118 } else { 119 // valid opcode, unset saved type 120 _type = null; 121 switch (type.charAt(0)) { 122 case 'i': 123 setOpcode((local > 3) ? Constants.ISTORE 124 : (Constants.ISTORE0 + local)); 125 break; 126 case 'l': 127 setOpcode((local > 3) ? Constants.LSTORE 128 : (Constants.LSTORE0 + local)); 129 break; 130 case 'f': 131 setOpcode((local > 3) ? Constants.FSTORE 132 : (Constants.FSTORE0 + local)); 133 break; 134 case 'd': 135 setOpcode((local > 3) ? Constants.DSTORE 136 : (Constants.DSTORE0 + local)); 137 break; 138 default: 139 setOpcode((local > 3) ? Constants.ASTORE 140 : (Constants.ASTORE0 + local)); 141 break; 142 } 143 } 144 if (len != getLength()) 145 invalidateByteIndexes(); 146 return this; 147 } 148 149 /** 150 * StoreInstructions are equal if the type they reference the same 151 * type and locals index or if either is unset. 152 */ 153 public boolean equalsInstruction(Instruction other) { 154 if (other == this) 155 return true; 156 if (!super.equalsInstruction(other)) 157 return false; 158 159 String type = getTypeName(); 160 String otherType = ((StoreInstruction) other).getTypeName(); 161 return type == null || otherType == null || type.equals(otherType); 162 } 163 164 public void acceptVisit(BCVisitor visit) { 165 visit.enterStoreInstruction(this); 166 visit.exitStoreInstruction(this); 167 } 168 169 void read(Instruction orig) { 170 super.read(orig); 171 StoreInstruction ins = (StoreInstruction) orig; 172 _type = ins._type; 173 } 174 175 void read(DataInput in) throws IOException { 176 super.read(in); 177 switch (getOpcode()) { 178 case Constants.ISTORE: 179 case Constants.LSTORE: 180 case Constants.FSTORE: 181 case Constants.DSTORE: 182 case Constants.ASTORE: 183 setLocal(in.readUnsignedByte()); 184 break; 185 } 186 } 187 188 void write(DataOutput out) throws IOException { 189 super.write(out); 190 switch (getOpcode()) { 191 case Constants.ISTORE: 192 case Constants.LSTORE: 193 case Constants.FSTORE: 194 case Constants.DSTORE: 195 case Constants.ASTORE: 196 out.writeByte(getLocal()); 197 } 198 } 199 200 void calculateOpcode() { 201 // taken care of when setting type 202 setType(getTypeName()); 203 } 204 205 void calculateLocal() { 206 switch (getOpcode()) { 207 case Constants.ISTORE0: 208 case Constants.LSTORE0: 209 case Constants.FSTORE0: 210 case Constants.DSTORE0: 211 case Constants.ASTORE0: 212 setLocal(0); 213 break; 214 case Constants.ISTORE1: 215 case Constants.LSTORE1: 216 case Constants.FSTORE1: 217 case Constants.DSTORE1: 218 case Constants.ASTORE1: 219 setLocal(1); 220 break; 221 case Constants.ISTORE2: 222 case Constants.LSTORE2: 223 case Constants.FSTORE2: 224 case Constants.DSTORE2: 225 case Constants.ASTORE2: 226 setLocal(2); 227 break; 228 case Constants.ISTORE3: 229 case Constants.LSTORE3: 230 case Constants.FSTORE3: 231 case Constants.DSTORE3: 232 case Constants.ASTORE3: 233 setLocal(3); 234 break; 235 } 236 } 237 }