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 }