View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at 
7    * 
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License.
15   */
16  
17  
18  package org.apache.jdo.impl.enhancer.classfile;
19  
20  
21  import java.io.PrintStream;
22  import java.util.Stack;
23  
24  /***
25   * Special instruction form for the opc_tableswitch instruction
26   */
27  public class InsnTableSwitch extends Insn {
28      /* The lowest value in the jump table */
29      private int lowOp;
30  
31      /* The default target for the switch */
32      private InsnTarget defaultOp;
33  
34      /* The targets for the switch - a switch value of lowOp dispatches
35       * to targetsOp[0], lowOp+1 dispatches to targetsOp[1], etc. */
36      private InsnTarget[] targetsOp;
37  
38      /* public accessors */
39  
40      public int nStackArgs() {
41          return 1;
42      }
43  
44      public int nStackResults() {
45          return 0;
46      }
47  
48      public String argTypes() {
49          return "I";
50      }
51  
52      public String resultTypes() {
53          return "";
54      }
55  
56      public boolean branches() {
57          return true;
58      }
59  
60      /***
61       * Mark possible branch targets
62       */
63      public void markTargets() {
64          defaultOp.setBranchTarget();
65          for (int i=0; i<targetsOp.length; i++)
66              targetsOp[i].setBranchTarget();
67      }
68  
69      /***
70       * Return the lowest case for the switch
71       */
72      public int lowCase() {
73          return lowOp;
74      }
75  
76      /***
77       * Return the defaultTarget for the switch
78       */
79      public InsnTarget defaultTarget() {
80          return defaultOp;
81      }
82  
83      /***
84       * Return the targets for the cases of the switch.
85       */
86      public InsnTarget[] switchTargets() {
87          return targetsOp;
88      }
89  
90      /***
91       * Constructor for opc_tableswitch
92       */
93      //@olsen: made public
94      public InsnTableSwitch(int lowOp, InsnTarget defaultOp, 
95                             InsnTarget[] targetsOp) {
96          this(lowOp, defaultOp, targetsOp, NO_OFFSET);
97      }
98  
99      /***
100      * Compares this instance with another for structural equality.
101      */
102     //@olsen: added method
103     public boolean isEqual(Stack msg, Object obj) {
104         if (!(obj instanceof InsnTableSwitch)) {
105             msg.push("obj/obj.getClass() = "
106                      + (obj == null ? null : obj.getClass()));
107             msg.push("this.getClass() = "
108                      + this.getClass());
109             return false;
110         }
111         InsnTableSwitch other = (InsnTableSwitch)obj;
112 
113         if (!super.isEqual(msg, other)) {
114             return false;
115         }
116 
117         if (this.lowOp != other.lowOp) {
118             msg.push(String.valueOf("lowOp = "
119                                     + other.lowOp));
120             msg.push(String.valueOf("lowOp = "
121                                     + this.lowOp));
122             return false;
123         }
124 
125         if (!this.defaultOp.isEqual(msg, other.defaultOp)) {
126             msg.push(String.valueOf("defaultOp = "
127                                     + other.defaultOp));
128             msg.push(String.valueOf("defaultOp = "
129                                     + this.defaultOp));
130             return false;
131         }
132 
133         if (this.targetsOp.length != other.targetsOp.length) {
134             msg.push("targetsOp.length "
135                      + String.valueOf(other.targetsOp.length));
136             msg.push("targetsOp.length "
137                      + String.valueOf(this.targetsOp.length));
138             return false;
139         }
140         for (int i = 0; i < targetsOp.length; i++) {
141             InsnTarget t1 = this.targetsOp[i];
142             InsnTarget t2 = other.targetsOp[i];
143             if (!t1.isEqual(msg, t2)) {
144                 msg.push("targetsOp[" + i + "] = " + String.valueOf(t2));
145                 msg.push("targetsOp[" + i + "] = " + String.valueOf(t1));
146                 return false;
147             }
148         }
149         return true;
150     }
151 
152     /* package local methods *//package-summary/html">class="comment"> package local methods *//package-summary.html">/* package local methods *//package-summary.html">class="comment"> package local methods */
153 
154     void print (PrintStream out, int indent) {
155         ClassPrint.spaces(out, indent);
156         out.println(offset() + "  opc_tableswitch  ");
157         for (int i=0; i<targetsOp.length; i++) {
158             int index = i + lowOp;
159             if (targetsOp[i].offset() != defaultOp.offset()) {
160                 ClassPrint.spaces(out, indent+2);
161                 out.println(index + " -> " + targetsOp[i].offset());
162             }
163         }
164         ClassPrint.spaces(out, indent+2);
165         out.println("default -> " + defaultOp.offset());
166     }
167 
168     int store(byte[] buf, int index) {
169         buf[index++] = (byte) opcode();
170         index = (index + 3) & ~3;
171         index = storeInt(buf, index, defaultOp.offset() - offset());
172         index = storeInt(buf, index, lowOp);
173         index = storeInt(buf, index, lowOp+targetsOp.length-1);
174         for (int i=0; i<targetsOp.length; i++)
175             index = storeInt(buf, index, targetsOp[i].offset() - offset());
176         return index;
177     }
178 
179     int size() {
180         /* account for the instruction, 0-3 bytes of pad, 3 ints */
181         int basic = ((offset() + 4) & ~3) - offset() + 12;
182         /* Add 4*number of offsets */
183         return basic + targetsOp.length*4;
184     }
185 
186 
187     InsnTableSwitch(int lowOp, InsnTarget defaultOp, 
188                     InsnTarget[] targetsOp, int offset) {
189         super(opc_tableswitch, offset);
190 
191         this.lowOp = lowOp;
192         this.defaultOp = defaultOp; 
193         this.targetsOp = targetsOp;
194 
195         if (defaultOp == null || targetsOp == null)
196             throw new InsnError ("attempt to create an opc_tableswitch" +
197                                  " with invalid operands");
198     }
199 
200     static InsnTableSwitch read (InsnReadEnv insnEnv, int myPC) {
201         /* eat up any padding */
202         int thisPC = myPC +1;
203         for (int pads = ((thisPC + 3) & ~3) - thisPC; pads > 0; pads--)
204             insnEnv.getByte();
205         InsnTarget defaultTarget = insnEnv.getTarget(insnEnv.getInt() + myPC);
206         int low = insnEnv.getInt();
207         int high = insnEnv.getInt();
208         InsnTarget[] offsets = new InsnTarget[high - low + 1];
209         for (int i=0; i<offsets.length; i++)
210             offsets[i] = insnEnv.getTarget(insnEnv.getInt() + myPC);
211         return new InsnTableSwitch(low, defaultTarget,   offsets, myPC);
212     }
213 }