15 * distributed under the License is distributed on an "AS IS" BASIS, |
15 * distributed under the License is distributed on an "AS IS" BASIS, |
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 * See the License for the specific language governing permissions and |
17 * See the License for the specific language governing permissions and |
18 * limitations under the License. |
18 * limitations under the License. |
19 */ |
19 */ |
20 |
|
21 package com.sun.org.apache.bcel.internal.generic; |
20 package com.sun.org.apache.bcel.internal.generic; |
22 |
21 |
23 |
22 import java.io.DataOutputStream; |
24 import com.sun.org.apache.bcel.internal.Constants; |
23 import java.io.IOException; |
|
24 |
|
25 import com.sun.org.apache.bcel.internal.Const; |
25 import com.sun.org.apache.bcel.internal.classfile.ConstantPool; |
26 import com.sun.org.apache.bcel.internal.classfile.ConstantPool; |
26 import java.io.*; |
|
27 import com.sun.org.apache.bcel.internal.util.ByteSequence; |
27 import com.sun.org.apache.bcel.internal.util.ByteSequence; |
28 |
28 |
29 /** |
29 /** |
30 * Abstract super class for all Java byte codes. |
30 * Abstract super class for all Java byte codes. |
31 * |
31 * |
32 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> |
32 * @version $Id: Instruction.java 1750029 2016-06-23 22:14:38Z sebb $ |
33 */ |
33 */ |
34 public abstract class Instruction implements Cloneable, Serializable { |
34 public abstract class Instruction implements Cloneable { |
35 protected short length = 1; // Length of instruction in bytes |
35 |
36 protected short opcode = -1; // Opcode number |
36 private short length = 1; // Length of instruction in bytes |
37 |
37 private short opcode = -1; // Opcode number |
38 private static InstructionComparator cmp = InstructionComparator.DEFAULT; |
38 |
39 |
39 private static InstructionComparator cmp = InstructionComparator.DEFAULT; |
40 /** |
40 |
41 * Empty constructor needed for the Class.newInstance() statement in |
41 /** |
42 * Instruction.readInstruction(). Not to be used otherwise. |
42 * Empty constructor needed for the Class.newInstance() statement in |
43 */ |
43 * Instruction.readInstruction(). Not to be used otherwise. |
44 Instruction() {} |
44 */ |
45 |
45 Instruction() { |
46 public Instruction(short opcode, short length) { |
46 } |
47 this.length = length; |
47 |
48 this.opcode = opcode; |
48 public Instruction(final short opcode, final short length) { |
49 } |
49 this.length = length; |
50 |
50 this.opcode = opcode; |
51 /** |
51 } |
52 * Dump instruction as byte code to stream out. |
52 |
53 * @param out Output stream |
53 /** |
54 */ |
54 * Dump instruction as byte code to stream out. |
55 public void dump(DataOutputStream out) throws IOException { |
55 * |
56 out.writeByte(opcode); // Common for all instructions |
56 * @param out Output stream |
57 } |
57 */ |
58 |
58 public void dump(final DataOutputStream out) throws IOException { |
59 /** @return name of instruction, i.e., opcode name |
59 out.writeByte(opcode); // Common for all instructions |
60 */ |
60 } |
61 public String getName() { |
61 |
62 return Constants.OPCODE_NAMES[opcode]; |
62 /** |
63 } |
63 * @return name of instruction, i.e., opcode name |
64 |
64 */ |
65 /** |
65 public String getName() { |
66 * Long output format: |
66 return Const.getOpcodeName(opcode); |
67 * |
67 } |
68 * <name of opcode> "["<opcode number>"]" |
68 |
69 * "("<length of instruction>")" |
69 /** |
70 * |
70 * Long output format: |
71 * @param verbose long/short format switch |
71 * |
72 * @return mnemonic for instruction |
72 * <name of opcode> "["<opcode number>"]" "("<length of |
73 */ |
73 * instruction>")" |
74 public String toString(boolean verbose) { |
74 * |
75 if(verbose) |
75 * @param verbose long/short format switch |
76 return getName() + "[" + opcode + "](" + length + ")"; |
76 * @return mnemonic for instruction |
77 else |
77 */ |
78 return getName(); |
78 public String toString(final boolean verbose) { |
79 } |
79 if (verbose) { |
80 |
80 return getName() + "[" + opcode + "](" + length + ")"; |
81 /** |
81 } |
82 * @return mnemonic for instruction in verbose format |
82 return getName(); |
83 */ |
83 } |
84 public String toString() { |
84 |
85 return toString(true); |
85 /** |
86 } |
86 * @return mnemonic for instruction in verbose format |
87 |
87 */ |
88 /** |
88 @Override |
89 * @return mnemonic for instruction with sumbolic references resolved |
89 public String toString() { |
90 */ |
90 return toString(true); |
91 public String toString(ConstantPool cp) { |
91 } |
92 return toString(false); |
92 |
93 } |
93 /** |
94 |
94 * @return mnemonic for instruction with sumbolic references resolved |
95 /** |
95 */ |
96 * Use with caution, since `BranchInstruction's have a `target' reference which |
96 public String toString(final ConstantPool cp) { |
97 * is not copied correctly (only basic types are). This also applies for |
97 return toString(false); |
98 * `Select' instructions with their multiple branch targets. |
98 } |
99 * |
99 |
100 * @see BranchInstruction |
100 /** |
101 * @return (shallow) copy of an instruction |
101 * Use with caution, since `BranchInstruction's have a `target' reference |
102 */ |
102 * which is not copied correctly (only basic types are). This also applies |
103 public Instruction copy() { |
103 * for `Select' instructions with their multiple branch targets. |
104 Instruction i = null; |
104 * |
105 |
105 * @see BranchInstruction |
106 // "Constant" instruction, no need to duplicate |
106 * @return (shallow) copy of an instruction |
107 if(InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null) |
107 */ |
108 i = this; |
108 public Instruction copy() { |
109 else { |
109 Instruction i = null; |
110 try { |
110 // "Constant" instruction, no need to duplicate |
111 i = (Instruction)clone(); |
111 if (InstructionConst.getInstruction(this.getOpcode()) != null) { |
112 } catch(CloneNotSupportedException e) { |
112 i = this; |
113 System.err.println(e); |
113 } else { |
114 } |
114 try { |
115 } |
115 i = (Instruction) clone(); |
116 |
116 } catch (final CloneNotSupportedException e) { |
117 return i; |
117 System.err.println(e); |
118 } |
118 } |
119 |
119 } |
120 /** |
120 return i; |
121 * Read needed data (e.g. index) from file. |
121 } |
122 * |
122 |
123 * @param bytes byte sequence to read from |
123 /** |
124 * @param wide "wide" instruction flag |
124 * Read needed data (e.g. index) from file. |
125 */ |
125 * |
126 protected void initFromFile(ByteSequence bytes, boolean wide) |
126 * @param bytes byte sequence to read from |
127 throws IOException |
127 * @param wide "wide" instruction flag |
128 {} |
128 * @throws IOException may be thrown if the implementation needs to read |
129 |
129 * data from the file |
130 /** |
130 */ |
131 * Read an instruction from (byte code) input stream and return the |
131 protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { |
132 * appropiate object. |
132 } |
133 * |
133 |
134 * @param file file to read from |
134 /** |
135 * @return instruction object being read |
135 * Read an instruction from (byte code) input stream and return the |
136 */ |
136 * appropiate object. |
137 public static final Instruction readInstruction(ByteSequence bytes) |
137 * <p> |
138 throws IOException |
138 * If the Instruction is defined in {@link InstructionConst}, then the |
139 { |
139 * singleton instance is returned. |
140 boolean wide = false; |
140 * |
141 short opcode = (short)bytes.readUnsignedByte(); |
141 * @param bytes input stream bytes |
142 Instruction obj = null; |
142 * @return instruction object being read |
143 |
143 * @see InstructionConst#getInstruction(int) |
144 if(opcode == Constants.WIDE) { // Read next opcode after wide byte |
144 */ |
145 wide = true; |
145 // @since 6.0 no longer final |
146 opcode = (short)bytes.readUnsignedByte(); |
146 public static Instruction readInstruction(final ByteSequence bytes) throws IOException { |
147 } |
147 boolean wide = false; |
148 |
148 short opcode = (short) bytes.readUnsignedByte(); |
149 if(InstructionConstants.INSTRUCTIONS[opcode] != null) |
149 Instruction obj = null; |
150 return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available |
150 if (opcode == Const.WIDE) { // Read next opcode after wide byte |
151 |
151 wide = true; |
152 /* Find appropiate class, instantiate an (empty) instruction object |
152 opcode = (short) bytes.readUnsignedByte(); |
153 * and initialize it by hand. |
153 } |
154 */ |
154 final Instruction instruction = InstructionConst.getInstruction(opcode); |
155 Class clazz; |
155 if (instruction != null) { |
156 |
156 return instruction; // Used predefined immutable object, if available |
157 try { |
157 } |
158 clazz = Class.forName(className(opcode)); |
158 |
159 } catch (ClassNotFoundException cnfe){ |
159 switch (opcode) { |
160 // If a class by that name does not exist, the opcode is illegal. |
160 case Const.BIPUSH: |
161 // Note that IMPDEP1, IMPDEP2, BREAKPOINT are also illegal in a sense. |
161 obj = new BIPUSH(); |
162 throw new ClassGenException("Illegal opcode detected."); |
162 break; |
163 } |
163 case Const.SIPUSH: |
164 |
164 obj = new SIPUSH(); |
165 try { |
165 break; |
166 obj = (Instruction)clazz.getConstructor().newInstance(); |
166 case Const.LDC: |
167 |
167 obj = new LDC(); |
168 if(wide && !((obj instanceof LocalVariableInstruction) || |
168 break; |
169 (obj instanceof IINC) || |
169 case Const.LDC_W: |
170 (obj instanceof RET))) |
170 obj = new LDC_W(); |
171 throw new Exception("Illegal opcode after wide: " + opcode); |
171 break; |
172 |
172 case Const.LDC2_W: |
173 obj.setOpcode(opcode); |
173 obj = new LDC2_W(); |
174 obj.initFromFile(bytes, wide); // Do further initializations, if any |
174 break; |
175 // Byte code offset set in InstructionList |
175 case Const.ILOAD: |
176 } catch(Exception e) { throw new ClassGenException(e.toString()); } |
176 obj = new ILOAD(); |
177 |
177 break; |
178 return obj; |
178 case Const.LLOAD: |
179 } |
179 obj = new LLOAD(); |
180 |
180 break; |
181 private static final String className(short opcode) { |
181 case Const.FLOAD: |
182 String name = Constants.OPCODE_NAMES[opcode].toUpperCase(); |
182 obj = new FLOAD(); |
183 |
183 break; |
184 /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like |
184 case Const.DLOAD: |
185 * are not implemented (directly). |
185 obj = new DLOAD(); |
186 */ |
186 break; |
187 try { |
187 case Const.ALOAD: |
188 int len = name.length(); |
188 obj = new ALOAD(); |
189 char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1); |
189 break; |
190 |
190 case Const.ILOAD_0: |
191 if((ch1 == '_') && (ch2 >= '0') && (ch2 <= '5')) |
191 obj = new ILOAD(0); |
192 name = name.substring(0, len - 2); |
192 break; |
193 |
193 case Const.ILOAD_1: |
194 if(name.equals("ICONST_M1")) // Special case |
194 obj = new ILOAD(1); |
195 name = "ICONST"; |
195 break; |
196 } catch(StringIndexOutOfBoundsException e) { System.err.println(e); } |
196 case Const.ILOAD_2: |
197 |
197 obj = new ILOAD(2); |
198 return "com.sun.org.apache.bcel.internal.generic." + name; |
198 break; |
199 } |
199 case Const.ILOAD_3: |
200 |
200 obj = new ILOAD(3); |
201 /** |
201 break; |
202 * This method also gives right results for instructions whose |
202 case Const.LLOAD_0: |
203 * effect on the stack depends on the constant pool entry they |
203 obj = new LLOAD(0); |
204 * reference. |
204 break; |
205 * @return Number of words consumed from stack by this instruction, |
205 case Const.LLOAD_1: |
206 * or Constants.UNPREDICTABLE, if this can not be computed statically |
206 obj = new LLOAD(1); |
207 */ |
207 break; |
208 public int consumeStack(ConstantPoolGen cpg) { |
208 case Const.LLOAD_2: |
209 return Constants.CONSUME_STACK[opcode]; |
209 obj = new LLOAD(2); |
210 } |
210 break; |
211 |
211 case Const.LLOAD_3: |
212 /** |
212 obj = new LLOAD(3); |
213 * This method also gives right results for instructions whose |
213 break; |
214 * effect on the stack depends on the constant pool entry they |
214 case Const.FLOAD_0: |
215 * reference. |
215 obj = new FLOAD(0); |
216 * @return Number of words produced onto stack by this instruction, |
216 break; |
217 * or Constants.UNPREDICTABLE, if this can not be computed statically |
217 case Const.FLOAD_1: |
218 */ |
218 obj = new FLOAD(1); |
219 public int produceStack(ConstantPoolGen cpg) { |
219 break; |
220 return Constants.PRODUCE_STACK[opcode]; |
220 case Const.FLOAD_2: |
221 } |
221 obj = new FLOAD(2); |
222 |
222 break; |
223 /** |
223 case Const.FLOAD_3: |
224 * @return this instructions opcode |
224 obj = new FLOAD(3); |
225 */ |
225 break; |
226 public short getOpcode() { return opcode; } |
226 case Const.DLOAD_0: |
227 |
227 obj = new DLOAD(0); |
228 /** |
228 break; |
229 * @return length (in bytes) of instruction |
229 case Const.DLOAD_1: |
230 */ |
230 obj = new DLOAD(1); |
231 public int getLength() { return length; } |
231 break; |
232 |
232 case Const.DLOAD_2: |
233 /** |
233 obj = new DLOAD(2); |
234 * Needed in readInstruction. |
234 break; |
235 */ |
235 case Const.DLOAD_3: |
236 private void setOpcode(short opcode) { this.opcode = opcode; } |
236 obj = new DLOAD(3); |
237 |
237 break; |
238 /** Some instructions may be reused, so don't do anything by default. |
238 case Const.ALOAD_0: |
239 */ |
239 obj = new ALOAD(0); |
240 void dispose() {} |
240 break; |
241 |
241 case Const.ALOAD_1: |
242 /** |
242 obj = new ALOAD(1); |
243 * Call corresponding visitor method(s). The order is: |
243 break; |
244 * Call visitor methods of implemented interfaces first, then |
244 case Const.ALOAD_2: |
245 * call methods according to the class hierarchy in descending order, |
245 obj = new ALOAD(2); |
246 * i.e., the most specific visitXXX() call comes last. |
246 break; |
247 * |
247 case Const.ALOAD_3: |
248 * @param v Visitor object |
248 obj = new ALOAD(3); |
249 */ |
249 break; |
250 public abstract void accept(Visitor v); |
250 case Const.ISTORE: |
251 |
251 obj = new ISTORE(); |
252 /** Get Comparator object used in the equals() method to determine |
252 break; |
253 * equality of instructions. |
253 case Const.LSTORE: |
254 * |
254 obj = new LSTORE(); |
255 * @return currently used comparator for equals() |
255 break; |
256 */ |
256 case Const.FSTORE: |
257 public static InstructionComparator getComparator() { return cmp; } |
257 obj = new FSTORE(); |
258 |
258 break; |
259 /** Set comparator to be used for equals(). |
259 case Const.DSTORE: |
260 */ |
260 obj = new DSTORE(); |
261 public static void setComparator(InstructionComparator c) { cmp = c; } |
261 break; |
262 |
262 case Const.ASTORE: |
263 /** Check for equality, delegated to comparator |
263 obj = new ASTORE(); |
264 * @return true if that is an Instruction and has the same opcode |
264 break; |
265 */ |
265 case Const.ISTORE_0: |
266 public boolean equals(Object that) { |
266 obj = new ISTORE(0); |
267 return (that instanceof Instruction)? |
267 break; |
268 cmp.equals(this, (Instruction)that) : false; |
268 case Const.ISTORE_1: |
269 } |
269 obj = new ISTORE(1); |
|
270 break; |
|
271 case Const.ISTORE_2: |
|
272 obj = new ISTORE(2); |
|
273 break; |
|
274 case Const.ISTORE_3: |
|
275 obj = new ISTORE(3); |
|
276 break; |
|
277 case Const.LSTORE_0: |
|
278 obj = new LSTORE(0); |
|
279 break; |
|
280 case Const.LSTORE_1: |
|
281 obj = new LSTORE(1); |
|
282 break; |
|
283 case Const.LSTORE_2: |
|
284 obj = new LSTORE(2); |
|
285 break; |
|
286 case Const.LSTORE_3: |
|
287 obj = new LSTORE(3); |
|
288 break; |
|
289 case Const.FSTORE_0: |
|
290 obj = new FSTORE(0); |
|
291 break; |
|
292 case Const.FSTORE_1: |
|
293 obj = new FSTORE(1); |
|
294 break; |
|
295 case Const.FSTORE_2: |
|
296 obj = new FSTORE(2); |
|
297 break; |
|
298 case Const.FSTORE_3: |
|
299 obj = new FSTORE(3); |
|
300 break; |
|
301 case Const.DSTORE_0: |
|
302 obj = new DSTORE(0); |
|
303 break; |
|
304 case Const.DSTORE_1: |
|
305 obj = new DSTORE(1); |
|
306 break; |
|
307 case Const.DSTORE_2: |
|
308 obj = new DSTORE(2); |
|
309 break; |
|
310 case Const.DSTORE_3: |
|
311 obj = new DSTORE(3); |
|
312 break; |
|
313 case Const.ASTORE_0: |
|
314 obj = new ASTORE(0); |
|
315 break; |
|
316 case Const.ASTORE_1: |
|
317 obj = new ASTORE(1); |
|
318 break; |
|
319 case Const.ASTORE_2: |
|
320 obj = new ASTORE(2); |
|
321 break; |
|
322 case Const.ASTORE_3: |
|
323 obj = new ASTORE(3); |
|
324 break; |
|
325 case Const.IINC: |
|
326 obj = new IINC(); |
|
327 break; |
|
328 case Const.IFEQ: |
|
329 obj = new IFEQ(); |
|
330 break; |
|
331 case Const.IFNE: |
|
332 obj = new IFNE(); |
|
333 break; |
|
334 case Const.IFLT: |
|
335 obj = new IFLT(); |
|
336 break; |
|
337 case Const.IFGE: |
|
338 obj = new IFGE(); |
|
339 break; |
|
340 case Const.IFGT: |
|
341 obj = new IFGT(); |
|
342 break; |
|
343 case Const.IFLE: |
|
344 obj = new IFLE(); |
|
345 break; |
|
346 case Const.IF_ICMPEQ: |
|
347 obj = new IF_ICMPEQ(); |
|
348 break; |
|
349 case Const.IF_ICMPNE: |
|
350 obj = new IF_ICMPNE(); |
|
351 break; |
|
352 case Const.IF_ICMPLT: |
|
353 obj = new IF_ICMPLT(); |
|
354 break; |
|
355 case Const.IF_ICMPGE: |
|
356 obj = new IF_ICMPGE(); |
|
357 break; |
|
358 case Const.IF_ICMPGT: |
|
359 obj = new IF_ICMPGT(); |
|
360 break; |
|
361 case Const.IF_ICMPLE: |
|
362 obj = new IF_ICMPLE(); |
|
363 break; |
|
364 case Const.IF_ACMPEQ: |
|
365 obj = new IF_ACMPEQ(); |
|
366 break; |
|
367 case Const.IF_ACMPNE: |
|
368 obj = new IF_ACMPNE(); |
|
369 break; |
|
370 case Const.GOTO: |
|
371 obj = new GOTO(); |
|
372 break; |
|
373 case Const.JSR: |
|
374 obj = new JSR(); |
|
375 break; |
|
376 case Const.RET: |
|
377 obj = new RET(); |
|
378 break; |
|
379 case Const.TABLESWITCH: |
|
380 obj = new TABLESWITCH(); |
|
381 break; |
|
382 case Const.LOOKUPSWITCH: |
|
383 obj = new LOOKUPSWITCH(); |
|
384 break; |
|
385 case Const.GETSTATIC: |
|
386 obj = new GETSTATIC(); |
|
387 break; |
|
388 case Const.PUTSTATIC: |
|
389 obj = new PUTSTATIC(); |
|
390 break; |
|
391 case Const.GETFIELD: |
|
392 obj = new GETFIELD(); |
|
393 break; |
|
394 case Const.PUTFIELD: |
|
395 obj = new PUTFIELD(); |
|
396 break; |
|
397 case Const.INVOKEVIRTUAL: |
|
398 obj = new INVOKEVIRTUAL(); |
|
399 break; |
|
400 case Const.INVOKESPECIAL: |
|
401 obj = new INVOKESPECIAL(); |
|
402 break; |
|
403 case Const.INVOKESTATIC: |
|
404 obj = new INVOKESTATIC(); |
|
405 break; |
|
406 case Const.INVOKEINTERFACE: |
|
407 obj = new INVOKEINTERFACE(); |
|
408 break; |
|
409 case Const.INVOKEDYNAMIC: |
|
410 obj = new INVOKEDYNAMIC(); |
|
411 break; |
|
412 case Const.NEW: |
|
413 obj = new NEW(); |
|
414 break; |
|
415 case Const.NEWARRAY: |
|
416 obj = new NEWARRAY(); |
|
417 break; |
|
418 case Const.ANEWARRAY: |
|
419 obj = new ANEWARRAY(); |
|
420 break; |
|
421 case Const.CHECKCAST: |
|
422 obj = new CHECKCAST(); |
|
423 break; |
|
424 case Const.INSTANCEOF: |
|
425 obj = new INSTANCEOF(); |
|
426 break; |
|
427 case Const.MULTIANEWARRAY: |
|
428 obj = new MULTIANEWARRAY(); |
|
429 break; |
|
430 case Const.IFNULL: |
|
431 obj = new IFNULL(); |
|
432 break; |
|
433 case Const.IFNONNULL: |
|
434 obj = new IFNONNULL(); |
|
435 break; |
|
436 case Const.GOTO_W: |
|
437 obj = new GOTO_W(); |
|
438 break; |
|
439 case Const.JSR_W: |
|
440 obj = new JSR_W(); |
|
441 break; |
|
442 case Const.BREAKPOINT: |
|
443 obj = new BREAKPOINT(); |
|
444 break; |
|
445 case Const.IMPDEP1: |
|
446 obj = new IMPDEP1(); |
|
447 break; |
|
448 case Const.IMPDEP2: |
|
449 obj = new IMPDEP2(); |
|
450 break; |
|
451 default: |
|
452 throw new ClassGenException("Illegal opcode detected: " + opcode); |
|
453 |
|
454 } |
|
455 |
|
456 if (wide |
|
457 && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) || (obj instanceof RET))) { |
|
458 throw new ClassGenException("Illegal opcode after wide: " + opcode); |
|
459 } |
|
460 obj.setOpcode(opcode); |
|
461 obj.initFromFile(bytes, wide); // Do further initializations, if any |
|
462 return obj; |
|
463 } |
|
464 |
|
465 /** |
|
466 * This method also gives right results for instructions whose effect on the |
|
467 * stack depends on the constant pool entry they reference. |
|
468 * |
|
469 * @return Number of words consumed from stack by this instruction, or |
|
470 * Constants.UNPREDICTABLE, if this can not be computed statically |
|
471 */ |
|
472 public int consumeStack(final ConstantPoolGen cpg) { |
|
473 return Const.getConsumeStack(opcode); |
|
474 } |
|
475 |
|
476 /** |
|
477 * This method also gives right results for instructions whose effect on the |
|
478 * stack depends on the constant pool entry they reference. |
|
479 * |
|
480 * @return Number of words produced onto stack by this instruction, or |
|
481 * Constants.UNPREDICTABLE, if this can not be computed statically |
|
482 */ |
|
483 public int produceStack(final ConstantPoolGen cpg) { |
|
484 return Const.getProduceStack(opcode); |
|
485 } |
|
486 |
|
487 /** |
|
488 * @return this instructions opcode |
|
489 */ |
|
490 public short getOpcode() { |
|
491 return opcode; |
|
492 } |
|
493 |
|
494 /** |
|
495 * @return length (in bytes) of instruction |
|
496 */ |
|
497 public int getLength() { |
|
498 return length; |
|
499 } |
|
500 |
|
501 /** |
|
502 * Needed in readInstruction and subclasses in this package |
|
503 */ |
|
504 final void setOpcode(final short opcode) { |
|
505 this.opcode = opcode; |
|
506 } |
|
507 |
|
508 /** |
|
509 * Needed in readInstruction and subclasses in this package |
|
510 * |
|
511 * @since 6.0 |
|
512 */ |
|
513 final void setLength(final int length) { |
|
514 this.length = (short) length; // TODO check range? |
|
515 } |
|
516 |
|
517 /** |
|
518 * Some instructions may be reused, so don't do anything by default. |
|
519 */ |
|
520 void dispose() { |
|
521 } |
|
522 |
|
523 /** |
|
524 * Call corresponding visitor method(s). The order is: Call visitor methods |
|
525 * of implemented interfaces first, then call methods according to the class |
|
526 * hierarchy in descending order, i.e., the most specific visitXXX() call |
|
527 * comes last. |
|
528 * |
|
529 * @param v Visitor object |
|
530 */ |
|
531 public abstract void accept(Visitor v); |
|
532 |
|
533 /** |
|
534 * Get Comparator object used in the equals() method to determine equality |
|
535 * of instructions. |
|
536 * |
|
537 * @return currently used comparator for equals() |
|
538 * @deprecated (6.0) use the built in comparator, or wrap this class in |
|
539 * another object that implements these methods |
|
540 */ |
|
541 @Deprecated |
|
542 public static InstructionComparator getComparator() { |
|
543 return cmp; |
|
544 } |
|
545 |
|
546 /** |
|
547 * Set comparator to be used for equals(). |
|
548 * |
|
549 * @deprecated (6.0) use the built in comparator, or wrap this class in |
|
550 * another object that implements these methods |
|
551 */ |
|
552 @Deprecated |
|
553 public static void setComparator(final InstructionComparator c) { |
|
554 cmp = c; |
|
555 } |
|
556 |
|
557 /** |
|
558 * Check for equality, delegated to comparator |
|
559 * |
|
560 * @return true if that is an Instruction and has the same opcode |
|
561 */ |
|
562 @Override |
|
563 public boolean equals(final Object that) { |
|
564 return (that instanceof Instruction) ? cmp.equals(this, (Instruction) that) : false; |
|
565 } |
|
566 |
|
567 /** |
|
568 * calculate the hashCode of this object |
|
569 * |
|
570 * @return the hashCode |
|
571 * @since 6.0 |
|
572 */ |
|
573 @Override |
|
574 public int hashCode() { |
|
575 return opcode; |
|
576 } |
|
577 |
|
578 /** |
|
579 * Check if the value can fit in a byte (signed) |
|
580 * |
|
581 * @param value the value to check |
|
582 * @return true if the value is in range |
|
583 * @since 6.0 |
|
584 */ |
|
585 public static boolean isValidByte(final int value) { |
|
586 return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE; |
|
587 } |
|
588 |
|
589 /** |
|
590 * Check if the value can fit in a short (signed) |
|
591 * |
|
592 * @param value the value to check |
|
593 * @return true if the value is in range |
|
594 * @since 6.0 |
|
595 */ |
|
596 public static boolean isValidShort(final int value) { |
|
597 return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; |
|
598 } |
270 } |
599 } |