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  import java.io.PrintStream;
21  import java.util.Stack;
22  
23  /***
24   * Special instruction form for the opc_lookupswitch instruction
25   */
26  public class InsnLookupSwitch extends Insn {
27      /* The target for the default case */
28      private InsnTarget defaultOp;
29  
30      /* The int constants against which to perform the lookup */
31      private int[] matchesOp;
32  
33      /* The branch targets for the cases corresponding to the entries in
34       * the matchesOp array */
35      private InsnTarget[] targetsOp;
36  
37      /* public accessors */
38  
39      public int nStackArgs() {
40          return 1;
41      }
42  
43      public int nStackResults() {
44          return 0;
45      }
46  
47      /***
48       * What are the types of the stack operands ?
49       */
50      public String argTypes() {
51          return "I";
52      }
53  
54      /***
55       * What are the types of the stack results?
56       */
57      public String resultTypes() {
58          return "";
59      }
60  
61      public boolean branches() {
62          return true;
63      }
64  
65      /***
66       * Mark possible branch targets
67       */
68      public void markTargets() {
69          defaultOp.setBranchTarget();
70          for (int i=0; i<targetsOp.length; i++)
71              targetsOp[i].setBranchTarget();
72      }
73  
74  
75      /***
76       * Return the defaultTarget for the switch
77       */
78      public InsnTarget defaultTarget() {
79          return defaultOp;
80      }
81  
82      /***
83       * Return the case values of the switch.
84       */
85      public int[] switchCases() {
86          return matchesOp;
87      }
88  
89      /***
90       * Return the targets for the cases of the switch.
91       */
92      public InsnTarget[] switchTargets() {
93          return targetsOp;
94      }
95  
96      /***
97       * Constructor for opc_lookupswitch
98       */
99      public InsnLookupSwitch(InsnTarget defaultOp, int[] matchesOp,
100                             InsnTarget[] targetsOp) {
101         this(defaultOp, matchesOp, targetsOp, NO_OFFSET);
102     }
103 
104     /***
105      * Compares this instance with another for structural equality.
106      */
107     //@olsen: added method
108     public boolean isEqual(Stack msg, Object obj) {
109         if (!(obj instanceof InsnLookupSwitch)) {
110             msg.push("obj/obj.getClass() = "
111                      + (obj == null ? null : obj.getClass()));
112             msg.push("this.getClass() = "
113                      + this.getClass());
114             return false;
115         }
116         InsnLookupSwitch other = (InsnLookupSwitch)obj;
117 
118         if (!super.isEqual(msg, other)) {
119             return false;
120         }
121 
122         if (!this.defaultOp.isEqual(msg, other.defaultOp)) {
123             msg.push(String.valueOf("defaultOp = "
124                                     + other.defaultOp));
125             msg.push(String.valueOf("defaultOp = "
126                                     + this.defaultOp));
127             return false;
128         }
129 
130         if (this.matchesOp.length != other.matchesOp.length) {
131             msg.push("matchesOp.length "
132                      + String.valueOf(other.matchesOp.length));
133             msg.push("matchesOp.length "
134                      + String.valueOf(this.matchesOp.length));
135             return false;
136         }
137         for (int i = 0; i < matchesOp.length; i++) {
138             int m1 = this.matchesOp[i];
139             int m2 = other.matchesOp[i];
140             if (m1 != m2) {
141                 msg.push("matchesOp[" + i + "] = " + String.valueOf(m2));
142                 msg.push("matchesOp[" + i + "] = " + String.valueOf(m1));
143                 return false;
144             }
145         }
146 
147         if (this.targetsOp.length != other.targetsOp.length) {
148             msg.push("targetsOp.length "
149                      + String.valueOf(other.targetsOp.length));
150             msg.push("targetsOp.length "
151                      + String.valueOf(this.targetsOp.length));
152             return false;
153         }
154         for (int i = 0; i < targetsOp.length; i++) {
155             InsnTarget t1 = this.targetsOp[i];
156             InsnTarget t2 = other.targetsOp[i];
157             if (!t1.isEqual(msg, t2)) {
158                 msg.push("targetsOp[" + i + "] = " + String.valueOf(t2));
159                 msg.push("targetsOp[" + i + "] = " + String.valueOf(t1));
160                 return false;
161             }
162         }
163         return true;
164     }
165 
166     /* 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 */
167 
168     InsnLookupSwitch(InsnTarget defaultOp, int[] matchesOp,
169                      InsnTarget[] targetsOp, int offset) {
170         super(opc_lookupswitch, offset);
171 
172         this.defaultOp = defaultOp; 
173         this.matchesOp = matchesOp;
174         this.targetsOp = targetsOp;
175 
176         if (defaultOp == null || targetsOp == null || matchesOp == null ||
177             targetsOp.length != matchesOp.length)
178             throw new InsnError ("attempt to create an opc_lookupswitch" +
179                                  " with invalid operands");
180     }
181 
182     void print(PrintStream out, int indent) {
183         ClassPrint.spaces(out, indent);
184         out.println(offset() + "  opc_lookupswitch  ");
185         for (int i=0; i<matchesOp.length; i++) {
186             ClassPrint.spaces(out, indent+2);
187             out.println(matchesOp[i] + " -> " + targetsOp[i].offset());
188         }
189         ClassPrint.spaces(out, indent+2);
190         out.println("default -> " + defaultOp.offset());
191     }
192 
193     int store(byte[] buf, int index) {
194         buf[index++] = (byte) opcode();
195         index = (index + 3) & ~3;
196         index = storeInt(buf, index, defaultOp.offset() - offset());
197         index = storeInt(buf, index, targetsOp.length);
198         for (int i=0; i<targetsOp.length; i++) {
199             index = storeInt(buf, index, matchesOp[i]);
200             index = storeInt(buf, index, targetsOp[i].offset() - offset());
201         }
202         return index;
203     }
204 
205     int size() {
206         /* account for the instruction, 0-3 bytes of pad, 2 ints */
207         int basic = ((offset() + 4) & ~3) - offset() + 8;
208         /* Add 8*number of offsets */
209         return basic + targetsOp.length*8;
210     }
211 
212     static InsnLookupSwitch read (InsnReadEnv insnEnv, int myPC) {
213         /* eat up any padding */
214         int thisPC = myPC +1;
215         for (int pads = ((thisPC + 3) & ~3) - thisPC; pads > 0; pads--)
216             insnEnv.getByte();
217         InsnTarget defaultTarget = insnEnv.getTarget(insnEnv.getInt() + myPC);
218         int npairs = insnEnv.getInt();
219         int matches[] = new int[npairs];
220         InsnTarget[] offsets = new InsnTarget[npairs];
221         for (int i=0; i<npairs; i++) {
222             matches[i] = insnEnv.getInt();
223             offsets[i] = insnEnv.getTarget(insnEnv.getInt() + myPC);
224         }
225         return new InsnLookupSwitch(defaultTarget, matches, offsets, myPC);
226     }
227 }