001 package serp.bytecode; 002 003 import java.io.*; 004 005 import serp.bytecode.visitor.*; 006 007 /** 008 * Loads a value from the locals table to the stack. 009 * 010 * @author Abe White 011 */ 012 public class LoadInstruction 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 LoadInstruction(Code owner) { 023 super(owner); 024 } 025 026 LoadInstruction(Code owner, int opcode) { 027 super(owner, opcode); 028 } 029 030 int getLength() { 031 switch (getOpcode()) { 032 case Constants.ILOAD: 033 case Constants.LLOAD: 034 case Constants.FLOAD: 035 case Constants.DLOAD: 036 case Constants.ALOAD: 037 return super.getLength() + 1; 038 default: 039 return super.getLength(); 040 } 041 } 042 043 public int getStackChange() { 044 switch (getOpcode()) { 045 case Constants.LLOAD: 046 case Constants.LLOAD0: 047 case Constants.LLOAD1: 048 case Constants.LLOAD2: 049 case Constants.LLOAD3: 050 case Constants.DLOAD: 051 case Constants.DLOAD0: 052 case Constants.DLOAD1: 053 case Constants.DLOAD2: 054 case Constants.DLOAD3: 055 return 2; 056 case Constants.NOP: 057 return 0; 058 default: 059 return 1; 060 } 061 } 062 063 public int getLogicalStackChange() { 064 switch (getOpcode()) { 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.ILOAD: 075 case Constants.ILOAD0: 076 case Constants.ILOAD1: 077 case Constants.ILOAD2: 078 case Constants.ILOAD3: 079 return int.class.getName(); 080 case Constants.LLOAD: 081 case Constants.LLOAD0: 082 case Constants.LLOAD1: 083 case Constants.LLOAD2: 084 case Constants.LLOAD3: 085 return long.class.getName(); 086 case Constants.FLOAD: 087 case Constants.FLOAD0: 088 case Constants.FLOAD1: 089 case Constants.FLOAD2: 090 case Constants.FLOAD3: 091 return float.class.getName(); 092 case Constants.DLOAD: 093 case Constants.DLOAD0: 094 case Constants.DLOAD1: 095 case Constants.DLOAD2: 096 case Constants.DLOAD3: 097 return double.class.getName(); 098 case Constants.ALOAD: 099 case Constants.ALOAD0: 100 case Constants.ALOAD1: 101 case Constants.ALOAD2: 102 case Constants.ALOAD3: 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.ILOAD 124 : (Constants.ILOAD0 + local)); 125 break; 126 case 'l': 127 setOpcode((local > 3) ? Constants.LLOAD 128 : (Constants.LLOAD0 + local)); 129 break; 130 case 'f': 131 setOpcode((local > 3) ? Constants.FLOAD 132 : (Constants.FLOAD0 + local)); 133 break; 134 case 'd': 135 setOpcode((local > 3) ? Constants.DLOAD 136 : (Constants.DLOAD0 + local)); 137 break; 138 default: 139 setOpcode((local > 3) ? Constants.ALOAD 140 : (Constants.ALOAD0 + local)); 141 } 142 } 143 if (len != getLength()) 144 invalidateByteIndexes(); 145 return this; 146 } 147 148 /** 149 * Equivalent to <code>setLocal (0).setType (Object.class)</code>; the 150 * <code>this</code> ptr is always passed in local variable 0. 151 * 152 * @return this instruction, for method chaining 153 */ 154 public LoadInstruction setThis() { 155 return (LoadInstruction) setLocal(0).setType(Object.class); 156 } 157 158 /** 159 * Equivalent to <code>getLocal () == 0 && getType () == 160 * Object.class</code>; the <code>this</code> ptr 161 * is always passed in local variable 0. 162 */ 163 public boolean isThis() { 164 return getLocal() == 0 && getType() == Object.class; 165 } 166 167 /** 168 * LoadInstructions are equal if the type they reference the same 169 * type and locals index or if either is unset. 170 */ 171 public boolean equalsInstruction(Instruction other) { 172 if (other == this) 173 return true; 174 if (!super.equalsInstruction(other)) 175 return false; 176 177 String type = getTypeName(); 178 String otherType = ((LoadInstruction) other).getTypeName(); 179 return type == null || otherType == null || type.equals(otherType); 180 } 181 182 public void acceptVisit(BCVisitor visit) { 183 visit.enterLoadInstruction(this); 184 visit.exitLoadInstruction(this); 185 } 186 187 void read(Instruction orig) { 188 super.read(orig); 189 LoadInstruction ins = (LoadInstruction) orig; 190 _type = ins._type; 191 } 192 193 void read(DataInput in) throws IOException { 194 super.read(in); 195 switch (getOpcode()) { 196 case Constants.ILOAD: 197 case Constants.LLOAD: 198 case Constants.FLOAD: 199 case Constants.DLOAD: 200 case Constants.ALOAD: 201 setLocal(in.readUnsignedByte()); 202 break; 203 } 204 } 205 206 void write(DataOutput out) throws IOException { 207 super.write(out); 208 switch (getOpcode()) { 209 case Constants.ILOAD: 210 case Constants.LLOAD: 211 case Constants.FLOAD: 212 case Constants.DLOAD: 213 case Constants.ALOAD: 214 out.writeByte(getLocal()); 215 } 216 } 217 218 void calculateOpcode() { 219 // taken care of when setting type 220 setType(getTypeName()); 221 } 222 223 void calculateLocal() { 224 switch (getOpcode()) { 225 case Constants.ILOAD0: 226 case Constants.LLOAD0: 227 case Constants.FLOAD0: 228 case Constants.DLOAD0: 229 case Constants.ALOAD0: 230 setLocal(0); 231 break; 232 case Constants.ILOAD1: 233 case Constants.LLOAD1: 234 case Constants.FLOAD1: 235 case Constants.DLOAD1: 236 case Constants.ALOAD1: 237 setLocal(1); 238 break; 239 case Constants.ILOAD2: 240 case Constants.LLOAD2: 241 case Constants.FLOAD2: 242 case Constants.DLOAD2: 243 case Constants.ALOAD2: 244 setLocal(2); 245 break; 246 case Constants.ILOAD3: 247 case Constants.LLOAD3: 248 case Constants.FLOAD3: 249 case Constants.DLOAD3: 250 case Constants.ALOAD3: 251 setLocal(3); 252 break; 253 } 254 } 255 }