View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.visitor.*;
7   import serp.util.*;
8   
9   /***
10   * The <code>lookupswitch</code> instruction.
11   *
12   * @author Abe White
13   */
14  public class LookupSwitchInstruction extends JumpInstruction {
15      // case info
16      private List _matches = new LinkedList();
17      private List _cases = new LinkedList();
18  
19      LookupSwitchInstruction(Code owner) {
20          super(owner, Constants.LOOKUPSWITCH);
21      }
22  
23      int getLength() {
24          // don't call super.getLength(), cause JumpInstruction will return
25          // value assuming this is an 'if' or 'goto' instruction
26          int length = 1;
27  
28          // make the first byte of the 'default' a multiple of 4 from the
29          // start of the method
30          int byteIndex = getByteIndex() + 1;
31          for (; (byteIndex % 4) != 0; byteIndex++, length++);
32  
33          // default, npairs
34          length += 8;
35  
36          // pairs
37          length += (8 * _matches.size());
38          return length;
39      }
40  
41      public int getStackChange() {
42          return -1;
43      }
44  
45      /***
46       * Synonymous with {@link #getTarget}.
47       */
48      public Instruction getDefaultTarget() {
49          return getTarget();
50      }
51  
52      /***
53       * Synonymous with {@link #setTarget}.
54       */
55      public LookupSwitchInstruction setDefaultTarget(Instruction ins) {
56          return (LookupSwitchInstruction) setTarget(ins);
57      }
58  
59      /***
60       * Synonymous with {@link #getOffset}.
61       */
62      public int getDefaultOffset() {
63          return getOffset();
64      }
65  
66      /***
67       * Synonymous with {@link #setOffset}.
68       */
69      public LookupSwitchInstruction setDefaultOffset(int offset) {
70          setOffset(offset);
71          return this;
72      }
73  
74      /***
75       * Set the match-jumppt pairs for this switch.
76       *
77       * @return this instruction, for method chaining
78       */
79      public LookupSwitchInstruction setCases(int[] matches, 
80          Instruction[] targets) {
81          _matches.clear();
82          _cases.clear();
83          for (int i = 0; i < matches.length; i++)
84              _matches.add(Numbers.valueOf(matches[i]));
85          for (int i = 0; i < targets.length; i++) {
86              InstructionPtrStrategy next = new InstructionPtrStrategy(this);
87              next.setTargetInstruction(targets[i]);
88              _cases.add(next);
89          }
90          invalidateByteIndexes();
91          return this;
92      }
93  
94      public int[] getOffsets() {
95          int bi = getByteIndex();
96          int[] offsets = new int[_cases.size()];
97          for (int i = 0; i < offsets.length; i++)
98              offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
99                  - bi;
100         return offsets;
101     }
102 
103     /***
104      * Return the values of the case statements for this switch.
105      */
106     public int[] getMatches() {
107         int[] matches = new int[_matches.size()];
108         Iterator itr = _matches.iterator();
109         for (int i = 0; i < matches.length; i++)
110             matches[i] = ((Integer) itr.next()).intValue();
111         return matches;
112     }
113 
114     /***
115      * Return the targets of the case statements for this switch.
116      */
117     public Instruction[] getTargets() {
118         Instruction[] result = new Instruction[_cases.size()];
119         for (int i = 0; i < result.length; i++)
120             result[i] = ((InstructionPtrStrategy) _cases.get(i)).
121                 getTargetInstruction();
122         return result;
123     }
124 
125     /***
126      * Add a case to this switch.
127      *
128      * @return this instruction, for method chaining
129      */
130     public LookupSwitchInstruction addCase(int match, Instruction target) {
131         _matches.add(Numbers.valueOf(match));
132         _cases.add(new InstructionPtrStrategy(this, target));
133         invalidateByteIndexes();
134         return this;
135     }
136 
137     private Instruction findJumpPoint(int jumpByteIndex, List inss) {
138         Instruction ins;
139         for (Iterator itr = inss.iterator(); itr.hasNext();) {
140             ins = (Instruction) itr.next();
141             if (ins.getByteIndex() == jumpByteIndex)
142                 return ins;
143         }
144         return null;
145     }
146 
147     public void updateTargets() {
148         super.updateTargets();
149         for (Iterator itr = _cases.iterator(); itr.hasNext();)
150             ((InstructionPtrStrategy) itr.next()).updateTargets();
151     }
152 
153     public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
154         super.replaceTarget(oldTarget, newTarget);
155         for (Iterator itr = _cases.iterator(); itr.hasNext();)
156             ((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget,
157                 newTarget);
158     }
159 
160     public void acceptVisit(BCVisitor visit) {
161         visit.enterLookupSwitchInstruction(this);
162         visit.exitLookupSwitchInstruction(this);
163     }
164 
165     void read(Instruction orig) {
166         super.read(orig);
167 
168         LookupSwitchInstruction ins = (LookupSwitchInstruction) orig;
169         _matches = new LinkedList(ins._matches);
170         _cases.clear();
171         for (Iterator itr = ins._cases.iterator(); itr.hasNext();) {
172             InstructionPtrStrategy origPtr = (InstructionPtrStrategy)itr.next();
173             InstructionPtrStrategy newPtr = new InstructionPtrStrategy(this);
174             newPtr.setByteIndex(origPtr.getByteIndex());
175             _cases.add(newPtr);
176         }
177         invalidateByteIndexes();
178     }
179 
180     void read(DataInput in) throws IOException {
181         // don't call super
182         int bi = getByteIndex();
183         for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
184             in.readByte();
185 
186         setOffset(in.readInt());
187         _matches.clear();
188         _cases.clear();
189         for (int i = 0, pairCount = in.readInt(); i < pairCount; i++) {
190             _matches.add(Numbers.valueOf(in.readInt()));
191             InstructionPtrStrategy next = new InstructionPtrStrategy(this);
192             next.setByteIndex(bi + in.readInt());
193             _cases.add(next);
194         }
195     }
196 
197     void write(DataOutput out) throws IOException {
198         // don't call super
199         int bi = getByteIndex();
200         for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
201             out.writeByte(0);
202 
203         out.writeInt(getOffset());
204         out.writeInt(_matches.size());
205         for (int i = 0; i < _matches.size(); i++) {
206             out.writeInt(((Integer) _matches.get(i)).intValue());
207             out.writeInt(((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
208                 - bi);
209         }
210     }
211 }