View Javadoc

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 }