1 package serp.bytecode; 2 3 import serp.bytecode.visitor.*; 4 5 /*** 6 * An instruction that has an argument of an index into the 7 * local variable table of the current frame. This includes most of the 8 * <code>load</code> and <code>store</code> instructions. 9 * 10 * <p>The local variable table size is fixed by the <code>maxLocals</code> 11 * property of the code block. Long and double types take up 2 local variable 12 * indexes.</p> 13 * 14 * <p>Parameter values to methods are loaded into the local variable table 15 * prior to the execution of the first instruction. The 0 index of the 16 * table is set to the instance of the class the method is being invoked on.</p> 17 * 18 * @author Abe White 19 */ 20 public abstract class LocalVariableInstruction extends TypedInstruction { 21 private int _index = -1; 22 23 LocalVariableInstruction(Code owner) { 24 super(owner); 25 } 26 27 LocalVariableInstruction(Code owner, int opcode) { 28 super(owner, opcode); 29 calculateLocal(); 30 } 31 32 public String getTypeName() { 33 return null; 34 } 35 36 public TypedInstruction setType(String type) { 37 throw new UnsupportedOperationException(); 38 } 39 40 /*** 41 * Return the index of the local variable that this instruction operates on. 42 */ 43 public int getLocal() { 44 return _index; 45 } 46 47 /*** 48 * Set the index of the local variable that this instruction operates on. 49 * 50 * @return this instruction, for method chaining 51 */ 52 public LocalVariableInstruction setLocal(int index) { 53 _index = index; 54 calculateOpcode(); 55 return this; 56 } 57 58 /*** 59 * Return the parameter that this instruction operates on, or -1 if none. 60 */ 61 public int getParam() { 62 return getCode().getParamsIndex(getLocal()); 63 } 64 65 /*** 66 * Set the method parameter that this instruction operates on. This 67 * will set both the local index and the type of the instruction based 68 * on the current method parameters. 69 */ 70 public LocalVariableInstruction setParam(int param) { 71 int local = getCode().getLocalsIndex(param); 72 if (local != -1) { 73 BCMethod method = getCode().getMethod(); 74 setType(method.getParamNames()[param]); 75 } 76 return setLocal(local); 77 } 78 79 /*** 80 * Return the local variable object this instruction 81 * operates on, or null if none. 82 * 83 * @see LocalVariableTable#getLocalVariable(int) 84 */ 85 public LocalVariable getLocalVariable() { 86 LocalVariableTable table = getCode().getLocalVariableTable(false); 87 if (table == null) 88 return null; 89 return table.getLocalVariable(getLocal()); 90 } 91 92 /*** 93 * Set the local variable object this instruction 94 * operates on. This method will set both the type and local index 95 * of this instruction from the given local variable. 96 * 97 * @return this instruction, for method chaining 98 */ 99 public LocalVariableInstruction setLocalVariable(LocalVariable local) { 100 if (local == null) 101 return setLocal(-1); 102 String type = local.getTypeName(); 103 if (type != null) 104 setType(type); 105 return setLocal(local.getLocal()); 106 } 107 108 /*** 109 * Two local variable instructions are equal if the local index they 110 * reference is equal or if either index is 0/unset. 111 */ 112 public boolean equalsInstruction(Instruction other) { 113 if (this == other) 114 return true; 115 if (!getClass().equals(other.getClass())) 116 return false; 117 118 LocalVariableInstruction ins = (LocalVariableInstruction) other; 119 int index = getLocal(); 120 int insIndex = ins.getLocal(); 121 return index == -1 || insIndex == -1 || index == insIndex; 122 } 123 124 void read(Instruction orig) { 125 super.read(orig); 126 setLocal(((LocalVariableInstruction) orig).getLocal()); 127 } 128 129 /*** 130 * Subclasses with variable opcodes can use this method to be 131 * notified that information possibly affecting the opcode has been changed. 132 */ 133 void calculateOpcode() { 134 } 135 136 /*** 137 * Subclasses can use this method to calculate 138 * the locals index based on their opcode. 139 */ 140 void calculateLocal() { 141 } 142 }