001 package serp.bytecode; 002 003 import serp.bytecode.visitor.*; 004 005 /** 006 * An instruction that has an argument of an index into the 007 * local variable table of the current frame. This includes most of the 008 * <code>load</code> and <code>store</code> instructions. 009 * 010 * <p>The local variable table size is fixed by the <code>maxLocals</code> 011 * property of the code block. Long and double types take up 2 local variable 012 * indexes.</p> 013 * 014 * <p>Parameter values to methods are loaded into the local variable table 015 * prior to the execution of the first instruction. The 0 index of the 016 * table is set to the instance of the class the method is being invoked on.</p> 017 * 018 * @author Abe White 019 */ 020 public abstract class LocalVariableInstruction extends TypedInstruction { 021 private int _index = -1; 022 023 LocalVariableInstruction(Code owner) { 024 super(owner); 025 } 026 027 LocalVariableInstruction(Code owner, int opcode) { 028 super(owner, opcode); 029 calculateLocal(); 030 } 031 032 public String getTypeName() { 033 return null; 034 } 035 036 public TypedInstruction setType(String type) { 037 throw new UnsupportedOperationException(); 038 } 039 040 /** 041 * Return the index of the local variable that this instruction operates on. 042 */ 043 public int getLocal() { 044 return _index; 045 } 046 047 /** 048 * Set the index of the local variable that this instruction operates on. 049 * 050 * @return this instruction, for method chaining 051 */ 052 public LocalVariableInstruction setLocal(int index) { 053 _index = index; 054 calculateOpcode(); 055 return this; 056 } 057 058 /** 059 * Return the parameter that this instruction operates on, or -1 if none. 060 */ 061 public int getParam() { 062 return getCode().getParamsIndex(getLocal()); 063 } 064 065 /** 066 * Set the method parameter that this instruction operates on. This 067 * will set both the local index and the type of the instruction based 068 * on the current method parameters. 069 */ 070 public LocalVariableInstruction setParam(int param) { 071 int local = getCode().getLocalsIndex(param); 072 if (local != -1) { 073 BCMethod method = getCode().getMethod(); 074 setType(method.getParamNames()[param]); 075 } 076 return setLocal(local); 077 } 078 079 /** 080 * Return the local variable object this instruction 081 * operates on, or null if none. 082 * 083 * @see LocalVariableTable#getLocalVariable(int) 084 */ 085 public LocalVariable getLocalVariable() { 086 LocalVariableTable table = getCode().getLocalVariableTable(false); 087 if (table == null) 088 return null; 089 return table.getLocalVariable(getLocal()); 090 } 091 092 /** 093 * Set the local variable object this instruction 094 * operates on. This method will set both the type and local index 095 * of this instruction from the given local variable. 096 * 097 * @return this instruction, for method chaining 098 */ 099 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 }