View Javadoc

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