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