• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
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 package com.android.dx.cf.code;
18 
19 import com.android.dx.cf.iface.ParseException;
20 import com.android.dx.rop.cst.Constant;
21 import com.android.dx.rop.cst.ConstantPool;
22 import com.android.dx.rop.cst.CstDouble;
23 import com.android.dx.rop.cst.CstFloat;
24 import com.android.dx.rop.cst.CstInteger;
25 import com.android.dx.rop.cst.CstKnownNull;
26 import com.android.dx.rop.cst.CstLiteralBits;
27 import com.android.dx.rop.cst.CstLong;
28 import com.android.dx.rop.cst.CstType;
29 import com.android.dx.rop.type.Type;
30 import com.android.dx.util.Bits;
31 import com.android.dx.util.ByteArray;
32 import com.android.dx.util.Hex;
33 import java.util.ArrayList;
34 
35 /**
36  * Bytecode array, which is part of a standard {@code Code} attribute.
37  */
38 public final class BytecodeArray {
39     /** convenient no-op implementation of {@link Visitor} */
40     public static final Visitor EMPTY_VISITOR = new BaseVisitor();
41 
42     /** {@code non-null;} underlying bytes */
43     private final ByteArray bytes;
44 
45     /**
46      * {@code non-null;} constant pool to use when resolving constant
47      * pool indices
48      */
49     private final ConstantPool pool;
50 
51     /**
52      * Constructs an instance.
53      *
54      * @param bytes {@code non-null;} underlying bytes
55      * @param pool {@code non-null;} constant pool to use when
56      * resolving constant pool indices
57      */
BytecodeArray(ByteArray bytes, ConstantPool pool)58     public BytecodeArray(ByteArray bytes, ConstantPool pool) {
59         if (bytes == null) {
60             throw new NullPointerException("bytes == null");
61         }
62 
63         if (pool == null) {
64             throw new NullPointerException("pool == null");
65         }
66 
67         this.bytes = bytes;
68         this.pool = pool;
69     }
70 
71     /**
72      * Gets the underlying byte array.
73      *
74      * @return {@code non-null;} the byte array
75      */
getBytes()76     public ByteArray getBytes() {
77         return bytes;
78     }
79 
80     /**
81      * Gets the size of the bytecode array, per se.
82      *
83      * @return {@code >= 0;} the length of the bytecode array
84      */
size()85     public int size() {
86         return bytes.size();
87     }
88 
89     /**
90      * Gets the total length of this structure in bytes, when included in
91      * a {@code Code} attribute. The returned value includes the
92      * array size plus four bytes for {@code code_length}.
93      *
94      * @return {@code >= 4;} the total length, in bytes
95      */
byteLength()96     public int byteLength() {
97         return 4 + bytes.size();
98     }
99 
100     /**
101      * Parses each instruction in the array, in order.
102      *
103      * @param visitor {@code null-ok;} visitor to call back to for
104      * each instruction
105      */
forEach(Visitor visitor)106     public void forEach(Visitor visitor) {
107         int sz = bytes.size();
108         int at = 0;
109 
110         while (at < sz) {
111             /*
112              * Don't record the previous offset here, so that we get to see the
113              * raw code that initializes the array
114              */
115             at += parseInstruction(at, visitor);
116         }
117     }
118 
119     /**
120      * Finds the offset to each instruction in the bytecode array. The
121      * result is a bit set with the offset of each opcode-per-se flipped on.
122      *
123      * @see Bits
124      * @return {@code non-null;} appropriately constructed bit set
125      */
getInstructionOffsets()126     public int[] getInstructionOffsets() {
127         int sz = bytes.size();
128         int[] result = Bits.makeBitSet(sz);
129         int at = 0;
130 
131         while (at < sz) {
132             Bits.set(result, at, true);
133             int length = parseInstruction(at, null);
134             at += length;
135         }
136 
137         return result;
138     }
139 
140     /**
141      * Processes the given "work set" by repeatedly finding the lowest bit
142      * in the set, clearing it, and parsing and visiting the instruction at
143      * the indicated offset (that is, the bit index), repeating until the
144      * work set is empty. It is expected that the visitor will regularly
145      * set new bits in the work set during the process.
146      *
147      * @param workSet {@code non-null;} the work set to process
148      * @param visitor {@code non-null;} visitor to call back to for
149      * each instruction
150      */
processWorkSet(int[] workSet, Visitor visitor)151     public void processWorkSet(int[] workSet, Visitor visitor) {
152         if (visitor == null) {
153             throw new NullPointerException("visitor == null");
154         }
155 
156         for (;;) {
157             int offset = Bits.findFirst(workSet, 0);
158             if (offset < 0) {
159                 break;
160             }
161             Bits.clear(workSet, offset);
162             parseInstruction(offset, visitor);
163             visitor.setPreviousOffset(offset);
164         }
165     }
166 
167     /**
168      * Parses the instruction at the indicated offset. Indicate the
169      * result by calling the visitor if supplied and by returning the
170      * number of bytes consumed by the instruction.
171      *
172      * <p>In order to simplify further processing, the opcodes passed
173      * to the visitor are canonicalized, altering the opcode to a more
174      * universal one and making formerly implicit arguments
175      * explicit. In particular:</p>
176      *
177      * <ul>
178      * <li>The opcodes to push literal constants of primitive types all become
179      *   {@code ldc}.
180      *   E.g., {@code fconst_0}, {@code sipush}, and
181      *   {@code lconst_0} qualify for this treatment.</li>
182      * <li>{@code aconst_null} becomes {@code ldc} of a
183      *   "known null."</li>
184      * <li>Shorthand local variable accessors become the corresponding
185      *   longhand. E.g. {@code aload_2} becomes {@code aload}.</li>
186      * <li>{@code goto_w} and {@code jsr_w} become {@code goto}
187      *   and {@code jsr} (respectively).</li>
188      * <li>{@code ldc_w} becomes {@code ldc}.</li>
189      * <li>{@code tableswitch} becomes {@code lookupswitch}.
190      * <li>Arithmetic, array, and value-returning ops are collapsed
191      *   to the {@code int} variant opcode, with the {@code type}
192      *   argument set to indicate the actual type. E.g.,
193      *   {@code fadd} becomes {@code iadd}, but
194      *   {@code type} is passed as {@code Type.FLOAT} in that
195      *   case. Similarly, {@code areturn} becomes
196      *   {@code ireturn}. (However, {@code return} remains
197      *   unchanged.</li>
198      * <li>Local variable access ops are collapsed to the {@code int}
199      *   variant opcode, with the {@code type} argument set to indicate
200      *   the actual type. E.g., {@code aload} becomes {@code iload},
201      *   but {@code type} is passed as {@code Type.OBJECT} in
202      *   that case.</li>
203      * <li>Numeric conversion ops ({@code i2l}, etc.) are left alone
204      *   to avoid too much confustion, but their {@code type} is
205      *   the pushed type. E.g., {@code i2b} gets type
206      *   {@code Type.INT}, and {@code f2d} gets type
207      *   {@code Type.DOUBLE}. Other unaltered opcodes also get
208      *   their pushed type. E.g., {@code arraylength} gets type
209      *   {@code Type.INT}.</li>
210      * </ul>
211      *
212      * @param offset {@code >= 0, < bytes.size();} offset to the start of the
213      * instruction
214      * @param visitor {@code null-ok;} visitor to call back to
215      * @return the length of the instruction, in bytes
216      */
parseInstruction(int offset, Visitor visitor)217     public int parseInstruction(int offset, Visitor visitor) {
218         if (visitor == null) {
219             visitor = EMPTY_VISITOR;
220         }
221 
222         try {
223             int opcode = bytes.getUnsignedByte(offset);
224             int info = ByteOps.opInfo(opcode);
225             int fmt = info & ByteOps.FMT_MASK;
226 
227             switch (opcode) {
228                 case ByteOps.NOP: {
229                     visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
230                     return 1;
231                 }
232                 case ByteOps.ACONST_NULL: {
233                     visitor.visitConstant(ByteOps.LDC, offset, 1,
234                                           CstKnownNull.THE_ONE, 0);
235                     return 1;
236                 }
237                 case ByteOps.ICONST_M1: {
238                     visitor.visitConstant(ByteOps.LDC, offset, 1,
239                                           CstInteger.VALUE_M1, -1);
240                     return 1;
241                 }
242                 case ByteOps.ICONST_0: {
243                     visitor.visitConstant(ByteOps.LDC, offset, 1,
244                                           CstInteger.VALUE_0, 0);
245                     return 1;
246                 }
247                 case ByteOps.ICONST_1: {
248                     visitor.visitConstant(ByteOps.LDC, offset, 1,
249                                           CstInteger.VALUE_1, 1);
250                     return 1;
251                 }
252                 case ByteOps.ICONST_2: {
253                     visitor.visitConstant(ByteOps.LDC, offset, 1,
254                                           CstInteger.VALUE_2, 2);
255                     return 1;
256                 }
257                 case ByteOps.ICONST_3: {
258                     visitor.visitConstant(ByteOps.LDC, offset, 1,
259                                           CstInteger.VALUE_3, 3);
260                     return 1;
261                 }
262                 case ByteOps.ICONST_4: {
263                     visitor.visitConstant(ByteOps.LDC, offset, 1,
264                                           CstInteger.VALUE_4, 4);
265                     return 1;
266                 }
267                 case ByteOps.ICONST_5:  {
268                     visitor.visitConstant(ByteOps.LDC, offset, 1,
269                                           CstInteger.VALUE_5, 5);
270                     return 1;
271                 }
272                 case ByteOps.LCONST_0: {
273                     visitor.visitConstant(ByteOps.LDC, offset, 1,
274                                           CstLong.VALUE_0, 0);
275                     return 1;
276                 }
277                 case ByteOps.LCONST_1: {
278                     visitor.visitConstant(ByteOps.LDC, offset, 1,
279                                           CstLong.VALUE_1, 0);
280                     return 1;
281                 }
282                 case ByteOps.FCONST_0: {
283                     visitor.visitConstant(ByteOps.LDC, offset, 1,
284                                           CstFloat.VALUE_0, 0);
285                     return 1;
286                 }
287                 case ByteOps.FCONST_1: {
288                     visitor.visitConstant(ByteOps.LDC, offset, 1,
289                                           CstFloat.VALUE_1, 0);
290                     return 1;
291                 }
292                 case ByteOps.FCONST_2:  {
293                     visitor.visitConstant(ByteOps.LDC, offset, 1,
294                                           CstFloat.VALUE_2, 0);
295                     return 1;
296                 }
297                 case ByteOps.DCONST_0: {
298                     visitor.visitConstant(ByteOps.LDC, offset, 1,
299                                           CstDouble.VALUE_0, 0);
300                     return 1;
301                 }
302                 case ByteOps.DCONST_1: {
303                     visitor.visitConstant(ByteOps.LDC, offset, 1,
304                                           CstDouble.VALUE_1, 0);
305                     return 1;
306                 }
307                 case ByteOps.BIPUSH: {
308                     int value = bytes.getByte(offset + 1);
309                     visitor.visitConstant(ByteOps.LDC, offset, 2,
310                                           CstInteger.make(value), value);
311                     return 2;
312                 }
313                 case ByteOps.SIPUSH: {
314                     int value = bytes.getShort(offset + 1);
315                     visitor.visitConstant(ByteOps.LDC, offset, 3,
316                                           CstInteger.make(value), value);
317                     return 3;
318                 }
319                 case ByteOps.LDC: {
320                     int idx = bytes.getUnsignedByte(offset + 1);
321                     Constant cst = pool.get(idx);
322                     int value = (cst instanceof CstInteger) ?
323                         ((CstInteger) cst).getValue() : 0;
324                     visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value);
325                     return 2;
326                 }
327                 case ByteOps.LDC_W: {
328                     int idx = bytes.getUnsignedShort(offset + 1);
329                     Constant cst = pool.get(idx);
330                     int value = (cst instanceof CstInteger) ?
331                         ((CstInteger) cst).getValue() : 0;
332                     visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value);
333                     return 3;
334                 }
335                 case ByteOps.LDC2_W: {
336                     int idx = bytes.getUnsignedShort(offset + 1);
337                     Constant cst = pool.get(idx);
338                     visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0);
339                     return 3;
340                 }
341                 case ByteOps.ILOAD: {
342                     int idx = bytes.getUnsignedByte(offset + 1);
343                     visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
344                                        Type.INT, 0);
345                     return 2;
346                 }
347                 case ByteOps.LLOAD: {
348                     int idx = bytes.getUnsignedByte(offset + 1);
349                     visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
350                                        Type.LONG, 0);
351                     return 2;
352                 }
353                 case ByteOps.FLOAD: {
354                     int idx = bytes.getUnsignedByte(offset + 1);
355                     visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
356                                        Type.FLOAT, 0);
357                     return 2;
358                 }
359                 case ByteOps.DLOAD: {
360                     int idx = bytes.getUnsignedByte(offset + 1);
361                     visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
362                                        Type.DOUBLE, 0);
363                     return 2;
364                 }
365                 case ByteOps.ALOAD: {
366                     int idx = bytes.getUnsignedByte(offset + 1);
367                     visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx,
368                                        Type.OBJECT, 0);
369                     return 2;
370                 }
371                 case ByteOps.ILOAD_0:
372                 case ByteOps.ILOAD_1:
373                 case ByteOps.ILOAD_2:
374                 case ByteOps.ILOAD_3: {
375                     int idx = opcode - ByteOps.ILOAD_0;
376                     visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
377                                        Type.INT, 0);
378                     return 1;
379                 }
380                 case ByteOps.LLOAD_0:
381                 case ByteOps.LLOAD_1:
382                 case ByteOps.LLOAD_2:
383                 case ByteOps.LLOAD_3: {
384                     int idx = opcode - ByteOps.LLOAD_0;
385                     visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
386                                        Type.LONG, 0);
387                     return 1;
388                 }
389                 case ByteOps.FLOAD_0:
390                 case ByteOps.FLOAD_1:
391                 case ByteOps.FLOAD_2:
392                 case ByteOps.FLOAD_3: {
393                     int idx = opcode - ByteOps.FLOAD_0;
394                     visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
395                                        Type.FLOAT, 0);
396                     return 1;
397                 }
398                 case ByteOps.DLOAD_0:
399                 case ByteOps.DLOAD_1:
400                 case ByteOps.DLOAD_2:
401                 case ByteOps.DLOAD_3: {
402                     int idx = opcode - ByteOps.DLOAD_0;
403                     visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
404                                        Type.DOUBLE, 0);
405                     return 1;
406                 }
407                 case ByteOps.ALOAD_0:
408                 case ByteOps.ALOAD_1:
409                 case ByteOps.ALOAD_2:
410                 case ByteOps.ALOAD_3: {
411                     int idx = opcode - ByteOps.ALOAD_0;
412                     visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx,
413                                        Type.OBJECT, 0);
414                     return 1;
415                 }
416                 case ByteOps.IALOAD: {
417                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT);
418                     return 1;
419                 }
420                 case ByteOps.LALOAD: {
421                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG);
422                     return 1;
423                 }
424                 case ByteOps.FALOAD: {
425                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
426                                         Type.FLOAT);
427                     return 1;
428                 }
429                 case ByteOps.DALOAD: {
430                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
431                                         Type.DOUBLE);
432                     return 1;
433                 }
434                 case ByteOps.AALOAD: {
435                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
436                                         Type.OBJECT);
437                     return 1;
438                 }
439                 case ByteOps.BALOAD: {
440                     /*
441                      * Note: This is a load from either a byte[] or a
442                      * boolean[].
443                      */
444                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE);
445                     return 1;
446                 }
447                 case ByteOps.CALOAD: {
448                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR);
449                     return 1;
450                 }
451                 case ByteOps.SALOAD: {
452                     visitor.visitNoArgs(ByteOps.IALOAD, offset, 1,
453                                         Type.SHORT);
454                     return 1;
455                 }
456                 case ByteOps.ISTORE: {
457                     int idx = bytes.getUnsignedByte(offset + 1);
458                     visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
459                                        Type.INT, 0);
460                     return 2;
461                 }
462                 case ByteOps.LSTORE: {
463                     int idx = bytes.getUnsignedByte(offset + 1);
464                     visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
465                                        Type.LONG, 0);
466                     return 2;
467                 }
468                 case ByteOps.FSTORE: {
469                     int idx = bytes.getUnsignedByte(offset + 1);
470                     visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
471                                        Type.FLOAT, 0);
472                     return 2;
473                 }
474                 case ByteOps.DSTORE: {
475                     int idx = bytes.getUnsignedByte(offset + 1);
476                     visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
477                                        Type.DOUBLE, 0);
478                     return 2;
479                 }
480                 case ByteOps.ASTORE: {
481                     int idx = bytes.getUnsignedByte(offset + 1);
482                     visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx,
483                                        Type.OBJECT, 0);
484                     return 2;
485                 }
486                 case ByteOps.ISTORE_0:
487                 case ByteOps.ISTORE_1:
488                 case ByteOps.ISTORE_2:
489                 case ByteOps.ISTORE_3: {
490                     int idx = opcode - ByteOps.ISTORE_0;
491                     visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
492                                        Type.INT, 0);
493                     return 1;
494                 }
495                 case ByteOps.LSTORE_0:
496                 case ByteOps.LSTORE_1:
497                 case ByteOps.LSTORE_2:
498                 case ByteOps.LSTORE_3: {
499                     int idx = opcode - ByteOps.LSTORE_0;
500                     visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
501                                        Type.LONG, 0);
502                     return 1;
503                 }
504                 case ByteOps.FSTORE_0:
505                 case ByteOps.FSTORE_1:
506                 case ByteOps.FSTORE_2:
507                 case ByteOps.FSTORE_3: {
508                     int idx = opcode - ByteOps.FSTORE_0;
509                     visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
510                                        Type.FLOAT, 0);
511                     return 1;
512                 }
513                 case ByteOps.DSTORE_0:
514                 case ByteOps.DSTORE_1:
515                 case ByteOps.DSTORE_2:
516                 case ByteOps.DSTORE_3: {
517                     int idx = opcode - ByteOps.DSTORE_0;
518                     visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
519                                        Type.DOUBLE, 0);
520                     return 1;
521                 }
522                 case ByteOps.ASTORE_0:
523                 case ByteOps.ASTORE_1:
524                 case ByteOps.ASTORE_2:
525                 case ByteOps.ASTORE_3: {
526                     int idx = opcode - ByteOps.ASTORE_0;
527                     visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx,
528                                        Type.OBJECT, 0);
529                     return 1;
530                 }
531                 case ByteOps.IASTORE: {
532                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT);
533                     return 1;
534                 }
535                 case ByteOps.LASTORE: {
536                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
537                                         Type.LONG);
538                     return 1;
539                 }
540                 case ByteOps.FASTORE: {
541                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
542                                         Type.FLOAT);
543                     return 1;
544                 }
545                 case ByteOps.DASTORE: {
546                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
547                                         Type.DOUBLE);
548                     return 1;
549                 }
550                 case ByteOps.AASTORE: {
551                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
552                                         Type.OBJECT);
553                     return 1;
554                 }
555                 case ByteOps.BASTORE: {
556                     /*
557                      * Note: This is a load from either a byte[] or a
558                      * boolean[].
559                      */
560                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
561                                         Type.BYTE);
562                     return 1;
563                 }
564                 case ByteOps.CASTORE: {
565                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
566                                         Type.CHAR);
567                     return 1;
568                 }
569                 case ByteOps.SASTORE: {
570                     visitor.visitNoArgs(ByteOps.IASTORE, offset, 1,
571                                         Type.SHORT);
572                     return 1;
573                 }
574                 case ByteOps.POP:
575                 case ByteOps.POP2:
576                 case ByteOps.DUP:
577                 case ByteOps.DUP_X1:
578                 case ByteOps.DUP_X2:
579                 case ByteOps.DUP2:
580                 case ByteOps.DUP2_X1:
581                 case ByteOps.DUP2_X2:
582                 case ByteOps.SWAP: {
583                     visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
584                     return 1;
585                 }
586                 case ByteOps.IADD:
587                 case ByteOps.ISUB:
588                 case ByteOps.IMUL:
589                 case ByteOps.IDIV:
590                 case ByteOps.IREM:
591                 case ByteOps.INEG:
592                 case ByteOps.ISHL:
593                 case ByteOps.ISHR:
594                 case ByteOps.IUSHR:
595                 case ByteOps.IAND:
596                 case ByteOps.IOR:
597                 case ByteOps.IXOR: {
598                     visitor.visitNoArgs(opcode, offset, 1, Type.INT);
599                     return 1;
600                 }
601                 case ByteOps.LADD:
602                 case ByteOps.LSUB:
603                 case ByteOps.LMUL:
604                 case ByteOps.LDIV:
605                 case ByteOps.LREM:
606                 case ByteOps.LNEG:
607                 case ByteOps.LSHL:
608                 case ByteOps.LSHR:
609                 case ByteOps.LUSHR:
610                 case ByteOps.LAND:
611                 case ByteOps.LOR:
612                 case ByteOps.LXOR: {
613                     /*
614                      * It's "opcode - 1" because, conveniently enough, all
615                      * these long ops are one past the int variants.
616                      */
617                     visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG);
618                     return 1;
619                 }
620                 case ByteOps.FADD:
621                 case ByteOps.FSUB:
622                 case ByteOps.FMUL:
623                 case ByteOps.FDIV:
624                 case ByteOps.FREM:
625                 case ByteOps.FNEG: {
626                     /*
627                      * It's "opcode - 2" because, conveniently enough, all
628                      * these float ops are two past the int variants.
629                      */
630                     visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT);
631                     return 1;
632                 }
633                 case ByteOps.DADD:
634                 case ByteOps.DSUB:
635                 case ByteOps.DMUL:
636                 case ByteOps.DDIV:
637                 case ByteOps.DREM:
638                 case ByteOps.DNEG: {
639                     /*
640                      * It's "opcode - 3" because, conveniently enough, all
641                      * these double ops are three past the int variants.
642                      */
643                     visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE);
644                     return 1;
645                 }
646                 case ByteOps.IINC: {
647                     int idx = bytes.getUnsignedByte(offset + 1);
648                     int value = bytes.getByte(offset + 2);
649                     visitor.visitLocal(opcode, offset, 3, idx,
650                                        Type.INT, value);
651                     return 3;
652                 }
653                 case ByteOps.I2L:
654                 case ByteOps.F2L:
655                 case ByteOps.D2L: {
656                     visitor.visitNoArgs(opcode, offset, 1, Type.LONG);
657                     return 1;
658                 }
659                 case ByteOps.I2F:
660                 case ByteOps.L2F:
661                 case ByteOps.D2F: {
662                     visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT);
663                     return 1;
664                 }
665                 case ByteOps.I2D:
666                 case ByteOps.L2D:
667                 case ByteOps.F2D: {
668                     visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE);
669                     return 1;
670                 }
671                 case ByteOps.L2I:
672                 case ByteOps.F2I:
673                 case ByteOps.D2I:
674                 case ByteOps.I2B:
675                 case ByteOps.I2C:
676                 case ByteOps.I2S:
677                 case ByteOps.LCMP:
678                 case ByteOps.FCMPL:
679                 case ByteOps.FCMPG:
680                 case ByteOps.DCMPL:
681                 case ByteOps.DCMPG:
682                 case ByteOps.ARRAYLENGTH: {
683                     visitor.visitNoArgs(opcode, offset, 1, Type.INT);
684                     return 1;
685                 }
686                 case ByteOps.IFEQ:
687                 case ByteOps.IFNE:
688                 case ByteOps.IFLT:
689                 case ByteOps.IFGE:
690                 case ByteOps.IFGT:
691                 case ByteOps.IFLE:
692                 case ByteOps.IF_ICMPEQ:
693                 case ByteOps.IF_ICMPNE:
694                 case ByteOps.IF_ICMPLT:
695                 case ByteOps.IF_ICMPGE:
696                 case ByteOps.IF_ICMPGT:
697                 case ByteOps.IF_ICMPLE:
698                 case ByteOps.IF_ACMPEQ:
699                 case ByteOps.IF_ACMPNE:
700                 case ByteOps.GOTO:
701                 case ByteOps.JSR:
702                 case ByteOps.IFNULL:
703                 case ByteOps.IFNONNULL: {
704                     int target = offset + bytes.getShort(offset + 1);
705                     visitor.visitBranch(opcode, offset, 3, target);
706                     return 3;
707                 }
708                 case ByteOps.RET: {
709                     int idx = bytes.getUnsignedByte(offset + 1);
710                     visitor.visitLocal(opcode, offset, 2, idx,
711                                        Type.RETURN_ADDRESS, 0);
712                     return 2;
713                 }
714                 case ByteOps.TABLESWITCH: {
715                     return parseTableswitch(offset, visitor);
716                 }
717                 case ByteOps.LOOKUPSWITCH: {
718                     return parseLookupswitch(offset, visitor);
719                 }
720                 case ByteOps.IRETURN: {
721                     visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT);
722                     return 1;
723                 }
724                 case ByteOps.LRETURN: {
725                     visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
726                                         Type.LONG);
727                     return 1;
728                 }
729                 case ByteOps.FRETURN: {
730                     visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
731                                         Type.FLOAT);
732                     return 1;
733                 }
734                 case ByteOps.DRETURN: {
735                     visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
736                                         Type.DOUBLE);
737                     return 1;
738                 }
739                 case ByteOps.ARETURN: {
740                     visitor.visitNoArgs(ByteOps.IRETURN, offset, 1,
741                                         Type.OBJECT);
742                     return 1;
743                 }
744                 case ByteOps.RETURN:
745                 case ByteOps.ATHROW:
746                 case ByteOps.MONITORENTER:
747                 case ByteOps.MONITOREXIT: {
748                     visitor.visitNoArgs(opcode, offset, 1, Type.VOID);
749                     return 1;
750                 }
751                 case ByteOps.GETSTATIC:
752                 case ByteOps.PUTSTATIC:
753                 case ByteOps.GETFIELD:
754                 case ByteOps.PUTFIELD:
755                 case ByteOps.INVOKEVIRTUAL:
756                 case ByteOps.INVOKESPECIAL:
757                 case ByteOps.INVOKESTATIC:
758                 case ByteOps.NEW:
759                 case ByteOps.ANEWARRAY:
760                 case ByteOps.CHECKCAST:
761                 case ByteOps.INSTANCEOF: {
762                     int idx = bytes.getUnsignedShort(offset + 1);
763                     Constant cst = pool.get(idx);
764                     visitor.visitConstant(opcode, offset, 3, cst, 0);
765                     return 3;
766                 }
767                 case ByteOps.INVOKEINTERFACE: {
768                     int idx = bytes.getUnsignedShort(offset + 1);
769                     int count = bytes.getUnsignedByte(offset + 3);
770                     int expectZero = bytes.getUnsignedByte(offset + 4);
771                     Constant cst = pool.get(idx);
772                     visitor.visitConstant(opcode, offset, 5, cst,
773                                           count | (expectZero << 8));
774                     return 5;
775                 }
776                 case ByteOps.INVOKEDYNAMIC: {
777                   throw new ParseException("invokedynamic not supported");
778                 }
779                 case ByteOps.NEWARRAY: {
780                     return parseNewarray(offset, visitor);
781                 }
782                 case ByteOps.WIDE: {
783                     return parseWide(offset, visitor);
784                 }
785                 case ByteOps.MULTIANEWARRAY: {
786                     int idx = bytes.getUnsignedShort(offset + 1);
787                     int dimensions = bytes.getUnsignedByte(offset + 3);
788                     Constant cst = pool.get(idx);
789                     visitor.visitConstant(opcode, offset, 4, cst, dimensions);
790                     return 4;
791                 }
792                 case ByteOps.GOTO_W:
793                 case ByteOps.JSR_W: {
794                     int target = offset + bytes.getInt(offset + 1);
795                     int newop =
796                         (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO :
797                         ByteOps.JSR;
798                     visitor.visitBranch(newop, offset, 5, target);
799                     return 5;
800                 }
801                 default: {
802                     visitor.visitInvalid(opcode, offset, 1);
803                     return 1;
804                 }
805             }
806         } catch (SimException ex) {
807             ex.addContext("...at bytecode offset " + Hex.u4(offset));
808             throw ex;
809         } catch (RuntimeException ex) {
810             SimException se = new SimException(ex);
811             se.addContext("...at bytecode offset " + Hex.u4(offset));
812             throw se;
813         }
814     }
815 
816     /**
817      * Helper to deal with {@code tableswitch}.
818      *
819      * @param offset the offset to the {@code tableswitch} opcode itself
820      * @param visitor {@code non-null;} visitor to use
821      * @return instruction length, in bytes
822      */
parseTableswitch(int offset, Visitor visitor)823     private int parseTableswitch(int offset, Visitor visitor) {
824         int at = (offset + 4) & ~3; // "at" skips the padding.
825 
826         // Collect the padding.
827         int padding = 0;
828         for (int i = offset + 1; i < at; i++) {
829             padding = (padding << 8) | bytes.getUnsignedByte(i);
830         }
831 
832         int defaultTarget = offset + bytes.getInt(at);
833         int low = bytes.getInt(at + 4);
834         int high = bytes.getInt(at + 8);
835         int count = high - low + 1;
836         at += 12;
837 
838         if (low > high) {
839             throw new SimException("low / high inversion");
840         }
841 
842         SwitchList cases = new SwitchList(count);
843         for (int i = 0; i < count; i++) {
844             int target = offset + bytes.getInt(at);
845             at += 4;
846             cases.add(low + i, target);
847         }
848         cases.setDefaultTarget(defaultTarget);
849         cases.removeSuperfluousDefaults();
850         cases.setImmutable();
851 
852         int length = at - offset;
853         visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
854                             padding);
855 
856         return length;
857     }
858 
859     /**
860      * Helper to deal with {@code lookupswitch}.
861      *
862      * @param offset the offset to the {@code lookupswitch} opcode itself
863      * @param visitor {@code non-null;} visitor to use
864      * @return instruction length, in bytes
865      */
parseLookupswitch(int offset, Visitor visitor)866     private int parseLookupswitch(int offset, Visitor visitor) {
867         int at = (offset + 4) & ~3; // "at" skips the padding.
868 
869         // Collect the padding.
870         int padding = 0;
871         for (int i = offset + 1; i < at; i++) {
872             padding = (padding << 8) | bytes.getUnsignedByte(i);
873         }
874 
875         int defaultTarget = offset + bytes.getInt(at);
876         int npairs = bytes.getInt(at + 4);
877         at += 8;
878 
879         SwitchList cases = new SwitchList(npairs);
880         for (int i = 0; i < npairs; i++) {
881             int match = bytes.getInt(at);
882             int target = offset + bytes.getInt(at + 4);
883             at += 8;
884             cases.add(match, target);
885         }
886         cases.setDefaultTarget(defaultTarget);
887         cases.removeSuperfluousDefaults();
888         cases.setImmutable();
889 
890         int length = at - offset;
891         visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
892                             padding);
893 
894         return length;
895     }
896 
897     /**
898      * Helper to deal with {@code newarray}.
899      *
900      * @param offset the offset to the {@code newarray} opcode itself
901      * @param visitor {@code non-null;} visitor to use
902      * @return instruction length, in bytes
903      */
parseNewarray(int offset, Visitor visitor)904     private int parseNewarray(int offset, Visitor visitor) {
905         int value = bytes.getUnsignedByte(offset + 1);
906         CstType type;
907         switch (value) {
908             case ByteOps.NEWARRAY_BOOLEAN: {
909                 type = CstType.BOOLEAN_ARRAY;
910                 break;
911             }
912             case ByteOps.NEWARRAY_CHAR: {
913                 type = CstType.CHAR_ARRAY;
914                 break;
915             }
916             case ByteOps.NEWARRAY_DOUBLE: {
917                 type = CstType.DOUBLE_ARRAY;
918                 break;
919             }
920             case ByteOps.NEWARRAY_FLOAT: {
921                 type = CstType.FLOAT_ARRAY;
922                 break;
923             }
924             case ByteOps.NEWARRAY_BYTE: {
925                 type = CstType.BYTE_ARRAY;
926                 break;
927             }
928             case ByteOps.NEWARRAY_SHORT: {
929                 type = CstType.SHORT_ARRAY;
930                 break;
931             }
932             case ByteOps.NEWARRAY_INT: {
933                 type = CstType.INT_ARRAY;
934                 break;
935             }
936             case ByteOps.NEWARRAY_LONG: {
937                 type = CstType.LONG_ARRAY;
938                 break;
939             }
940             default: {
941                 throw new SimException("bad newarray code " +
942                         Hex.u1(value));
943             }
944         }
945 
946         // Revisit the previous bytecode to find out the length of the array
947         int previousOffset = visitor.getPreviousOffset();
948         ConstantParserVisitor constantVisitor = new ConstantParserVisitor();
949         int arrayLength = 0;
950 
951         /*
952          * For visitors that don't record the previous offset, -1 will be
953          * seen here
954          */
955         if (previousOffset >= 0) {
956             parseInstruction(previousOffset, constantVisitor);
957             if (constantVisitor.cst instanceof CstInteger &&
958                     constantVisitor.length + previousOffset == offset) {
959                 arrayLength = constantVisitor.value;
960 
961             }
962         }
963 
964         /*
965          * Try to match the array initialization idiom. For example, if the
966          * subsequent code is initializing an int array, we are expecting the
967          * following pattern repeatedly:
968          *  dup
969          *  push index
970          *  push value
971          *  *astore
972          *
973          * where the index value will be incrimented sequentially from 0 up.
974          */
975         int nInit = 0;
976         int curOffset = offset+2;
977         int lastOffset = curOffset;
978         ArrayList<Constant> initVals = new ArrayList<Constant>();
979 
980         if (arrayLength != 0) {
981             while (true) {
982                 boolean punt = false;
983 
984                 // First, check if the next bytecode is dup.
985                 int nextByte = bytes.getUnsignedByte(curOffset++);
986                 if (nextByte != ByteOps.DUP)
987                     break;
988 
989                 /*
990                  * Next, check if the expected array index is pushed to
991                  * the stack.
992                  */
993                 parseInstruction(curOffset, constantVisitor);
994                 if (constantVisitor.length == 0 ||
995                         !(constantVisitor.cst instanceof CstInteger) ||
996                         constantVisitor.value != nInit)
997                     break;
998 
999                 // Next, fetch the init value and record it.
1000                 curOffset += constantVisitor.length;
1001 
1002                 /*
1003                  * Next, find out what kind of constant is pushed onto
1004                  * the stack.
1005                  */
1006                 parseInstruction(curOffset, constantVisitor);
1007                 if (constantVisitor.length == 0 ||
1008                         !(constantVisitor.cst instanceof CstLiteralBits))
1009                     break;
1010 
1011                 curOffset += constantVisitor.length;
1012                 initVals.add(constantVisitor.cst);
1013 
1014                 nextByte = bytes.getUnsignedByte(curOffset++);
1015                 // Now, check if the value is stored to the array properly.
1016                 switch (value) {
1017                     case ByteOps.NEWARRAY_BYTE:
1018                     case ByteOps.NEWARRAY_BOOLEAN: {
1019                         if (nextByte != ByteOps.BASTORE) {
1020                             punt = true;
1021                         }
1022                         break;
1023                     }
1024                     case ByteOps.NEWARRAY_CHAR: {
1025                         if (nextByte != ByteOps.CASTORE) {
1026                             punt = true;
1027                         }
1028                         break;
1029                     }
1030                     case ByteOps.NEWARRAY_DOUBLE: {
1031                         if (nextByte != ByteOps.DASTORE) {
1032                             punt = true;
1033                         }
1034                         break;
1035                     }
1036                     case ByteOps.NEWARRAY_FLOAT: {
1037                         if (nextByte != ByteOps.FASTORE) {
1038                             punt = true;
1039                         }
1040                         break;
1041                     }
1042                     case ByteOps.NEWARRAY_SHORT: {
1043                         if (nextByte != ByteOps.SASTORE) {
1044                             punt = true;
1045                         }
1046                         break;
1047                     }
1048                     case ByteOps.NEWARRAY_INT: {
1049                         if (nextByte != ByteOps.IASTORE) {
1050                             punt = true;
1051                         }
1052                         break;
1053                     }
1054                     case ByteOps.NEWARRAY_LONG: {
1055                         if (nextByte != ByteOps.LASTORE) {
1056                             punt = true;
1057                         }
1058                         break;
1059                     }
1060                     default:
1061                         punt = true;
1062                         break;
1063                 }
1064                 if (punt) {
1065                     break;
1066                 }
1067                 lastOffset = curOffset;
1068                 nInit++;
1069             }
1070         }
1071 
1072         /*
1073          * For singleton arrays it is still more economical to
1074          * generate the aput.
1075          */
1076         if (nInit < 2 || nInit != arrayLength) {
1077             visitor.visitNewarray(offset, 2, type, null);
1078             return 2;
1079         } else {
1080             visitor.visitNewarray(offset, lastOffset - offset, type, initVals);
1081             return lastOffset - offset;
1082         }
1083      }
1084 
1085 
1086     /**
1087      * Helper to deal with {@code wide}.
1088      *
1089      * @param offset the offset to the {@code wide} opcode itself
1090      * @param visitor {@code non-null;} visitor to use
1091      * @return instruction length, in bytes
1092      */
parseWide(int offset, Visitor visitor)1093     private int parseWide(int offset, Visitor visitor) {
1094         int opcode = bytes.getUnsignedByte(offset + 1);
1095         int idx = bytes.getUnsignedShort(offset + 2);
1096         switch (opcode) {
1097             case ByteOps.ILOAD: {
1098                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1099                                    Type.INT, 0);
1100                 return 4;
1101             }
1102             case ByteOps.LLOAD: {
1103                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1104                                    Type.LONG, 0);
1105                 return 4;
1106             }
1107             case ByteOps.FLOAD: {
1108                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1109                                    Type.FLOAT, 0);
1110                 return 4;
1111             }
1112             case ByteOps.DLOAD: {
1113                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1114                                    Type.DOUBLE, 0);
1115                 return 4;
1116             }
1117             case ByteOps.ALOAD: {
1118                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1119                                    Type.OBJECT, 0);
1120                 return 4;
1121             }
1122             case ByteOps.ISTORE: {
1123                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1124                                    Type.INT, 0);
1125                 return 4;
1126             }
1127             case ByteOps.LSTORE: {
1128                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1129                                    Type.LONG, 0);
1130                 return 4;
1131             }
1132             case ByteOps.FSTORE: {
1133                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1134                                    Type.FLOAT, 0);
1135                 return 4;
1136             }
1137             case ByteOps.DSTORE: {
1138                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1139                                    Type.DOUBLE, 0);
1140                 return 4;
1141             }
1142             case ByteOps.ASTORE: {
1143                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1144                                    Type.OBJECT, 0);
1145                 return 4;
1146             }
1147             case ByteOps.RET: {
1148                 visitor.visitLocal(opcode, offset, 4, idx,
1149                                    Type.RETURN_ADDRESS, 0);
1150                 return 4;
1151             }
1152             case ByteOps.IINC: {
1153                 int value = bytes.getShort(offset + 4);
1154                 visitor.visitLocal(opcode, offset, 6, idx,
1155                                    Type.INT, value);
1156                 return 6;
1157             }
1158             default: {
1159                 visitor.visitInvalid(ByteOps.WIDE, offset, 1);
1160                 return 1;
1161             }
1162         }
1163     }
1164 
1165     /**
1166      * Instruction visitor interface.
1167      */
1168     public interface Visitor {
1169         /**
1170          * Visits an invalid instruction.
1171          *
1172          * @param opcode the opcode
1173          * @param offset offset to the instruction
1174          * @param length length of the instruction, in bytes
1175          */
visitInvalid(int opcode, int offset, int length)1176         public void visitInvalid(int opcode, int offset, int length);
1177 
1178         /**
1179          * Visits an instruction which has no inline arguments
1180          * (implicit or explicit).
1181          *
1182          * @param opcode the opcode
1183          * @param offset offset to the instruction
1184          * @param length length of the instruction, in bytes
1185          * @param type {@code non-null;} type the instruction operates on
1186          */
visitNoArgs(int opcode, int offset, int length, Type type)1187         public void visitNoArgs(int opcode, int offset, int length,
1188                 Type type);
1189 
1190         /**
1191          * Visits an instruction which has a local variable index argument.
1192          *
1193          * @param opcode the opcode
1194          * @param offset offset to the instruction
1195          * @param length length of the instruction, in bytes
1196          * @param idx the local variable index
1197          * @param type {@code non-null;} the type of the accessed value
1198          * @param value additional literal integer argument, if salient (i.e.,
1199          * for {@code iinc})
1200          */
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1201         public void visitLocal(int opcode, int offset, int length,
1202                 int idx, Type type, int value);
1203 
1204         /**
1205          * Visits an instruction which has a (possibly synthetic)
1206          * constant argument, and possibly also an
1207          * additional literal integer argument. In the case of
1208          * {@code multianewarray}, the argument is the count of
1209          * dimensions. In the case of {@code invokeinterface},
1210          * the argument is the parameter count or'ed with the
1211          * should-be-zero value left-shifted by 8. In the case of entries
1212          * of type {@code int}, the {@code value} field always
1213          * holds the raw value (for convenience of clients).
1214          *
1215          * <p><b>Note:</b> In order to avoid giving it a barely-useful
1216          * visitor all its own, {@code newarray} also uses this
1217          * form, passing {@code value} as the array type code and
1218          * {@code cst} as a {@link CstType} instance
1219          * corresponding to the array type.</p>
1220          *
1221          * @param opcode the opcode
1222          * @param offset offset to the instruction
1223          * @param length length of the instruction, in bytes
1224          * @param cst {@code non-null;} the constant
1225          * @param value additional literal integer argument, if salient
1226          * (ignore if not)
1227          */
visitConstant(int opcode, int offset, int length, Constant cst, int value)1228         public void visitConstant(int opcode, int offset, int length,
1229                 Constant cst, int value);
1230 
1231         /**
1232          * Visits an instruction which has a branch target argument.
1233          *
1234          * @param opcode the opcode
1235          * @param offset offset to the instruction
1236          * @param length length of the instruction, in bytes
1237          * @param target the absolute (not relative) branch target
1238          */
visitBranch(int opcode, int offset, int length, int target)1239         public void visitBranch(int opcode, int offset, int length,
1240                 int target);
1241 
1242         /**
1243          * Visits a switch instruction.
1244          *
1245          * @param opcode the opcode
1246          * @param offset offset to the instruction
1247          * @param length length of the instruction, in bytes
1248          * @param cases {@code non-null;} list of (value, target)
1249          * pairs, plus the default target
1250          * @param padding the bytes found in the padding area (if any),
1251          * packed
1252          */
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1253         public void visitSwitch(int opcode, int offset, int length,
1254                 SwitchList cases, int padding);
1255 
1256         /**
1257          * Visits a newarray instruction.
1258          *
1259          * @param offset   offset to the instruction
1260          * @param length   length of the instruction, in bytes
1261          * @param type {@code non-null;} the type of the array
1262          * @param initVals {@code non-null;} list of bytecode offsets
1263          * for init values
1264          */
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1265         public void visitNewarray(int offset, int length, CstType type,
1266                 ArrayList<Constant> initVals);
1267 
1268         /**
1269          * Set previous bytecode offset
1270          * @param offset    offset of the previous fully parsed bytecode
1271          */
setPreviousOffset(int offset)1272         public void setPreviousOffset(int offset);
1273 
1274         /**
1275          * Get previous bytecode offset
1276          * @return return the recored offset of the previous bytecode
1277          */
getPreviousOffset()1278         public int getPreviousOffset();
1279     }
1280 
1281     /**
1282      * Base implementation of {@link Visitor}, which has empty method
1283      * bodies for all methods.
1284      */
1285     public static class BaseVisitor implements Visitor {
1286 
1287         /** offset of the previously parsed bytecode */
1288         private int previousOffset;
1289 
BaseVisitor()1290         BaseVisitor() {
1291             previousOffset = -1;
1292         }
1293 
1294         /** {@inheritDoc} */
visitInvalid(int opcode, int offset, int length)1295         public void visitInvalid(int opcode, int offset, int length) {
1296             // This space intentionally left blank.
1297         }
1298 
1299         /** {@inheritDoc} */
visitNoArgs(int opcode, int offset, int length, Type type)1300         public void visitNoArgs(int opcode, int offset, int length,
1301                 Type type) {
1302             // This space intentionally left blank.
1303         }
1304 
1305         /** {@inheritDoc} */
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1306         public void visitLocal(int opcode, int offset, int length,
1307                 int idx, Type type, int value) {
1308             // This space intentionally left blank.
1309         }
1310 
1311         /** {@inheritDoc} */
visitConstant(int opcode, int offset, int length, Constant cst, int value)1312         public void visitConstant(int opcode, int offset, int length,
1313                 Constant cst, int value) {
1314             // This space intentionally left blank.
1315         }
1316 
1317         /** {@inheritDoc} */
visitBranch(int opcode, int offset, int length, int target)1318         public void visitBranch(int opcode, int offset, int length,
1319                 int target) {
1320             // This space intentionally left blank.
1321         }
1322 
1323         /** {@inheritDoc} */
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1324         public void visitSwitch(int opcode, int offset, int length,
1325                 SwitchList cases, int padding) {
1326             // This space intentionally left blank.
1327         }
1328 
1329         /** {@inheritDoc} */
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initValues)1330         public void visitNewarray(int offset, int length, CstType type,
1331                 ArrayList<Constant> initValues) {
1332             // This space intentionally left blank.
1333         }
1334 
1335         /** {@inheritDoc} */
setPreviousOffset(int offset)1336         public void setPreviousOffset(int offset) {
1337             previousOffset = offset;
1338         }
1339 
1340         /** {@inheritDoc} */
getPreviousOffset()1341         public int getPreviousOffset() {
1342             return previousOffset;
1343         }
1344     }
1345 
1346     /**
1347      * Implementation of {@link Visitor}, which just pays attention
1348      * to constant values.
1349      */
1350     class ConstantParserVisitor extends BaseVisitor {
1351         Constant cst;
1352         int length;
1353         int value;
1354 
1355         /** Empty constructor */
ConstantParserVisitor()1356         ConstantParserVisitor() {
1357         }
1358 
clear()1359         private void clear() {
1360             length = 0;
1361         }
1362 
1363         /** {@inheritDoc} */
1364         @Override
visitInvalid(int opcode, int offset, int length)1365         public void visitInvalid(int opcode, int offset, int length) {
1366             clear();
1367         }
1368 
1369         /** {@inheritDoc} */
1370         @Override
visitNoArgs(int opcode, int offset, int length, Type type)1371         public void visitNoArgs(int opcode, int offset, int length,
1372                 Type type) {
1373             clear();
1374         }
1375 
1376         /** {@inheritDoc} */
1377         @Override
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1378         public void visitLocal(int opcode, int offset, int length,
1379                 int idx, Type type, int value) {
1380             clear();
1381         }
1382 
1383         /** {@inheritDoc} */
1384         @Override
visitConstant(int opcode, int offset, int length, Constant cst, int value)1385         public void visitConstant(int opcode, int offset, int length,
1386                 Constant cst, int value) {
1387             this.cst = cst;
1388             this.length = length;
1389             this.value = value;
1390         }
1391 
1392         /** {@inheritDoc} */
1393         @Override
visitBranch(int opcode, int offset, int length, int target)1394         public void visitBranch(int opcode, int offset, int length,
1395                 int target) {
1396             clear();
1397         }
1398 
1399         /** {@inheritDoc} */
1400         @Override
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1401         public void visitSwitch(int opcode, int offset, int length,
1402                 SwitchList cases, int padding) {
1403             clear();
1404         }
1405 
1406         /** {@inheritDoc} */
1407         @Override
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1408         public void visitNewarray(int offset, int length, CstType type,
1409                 ArrayList<Constant> initVals) {
1410             clear();
1411         }
1412 
1413         /** {@inheritDoc} */
1414         @Override
setPreviousOffset(int offset)1415         public void setPreviousOffset(int offset) {
1416             // Intentionally left empty
1417         }
1418 
1419         /** {@inheritDoc} */
1420         @Override
getPreviousOffset()1421         public int getPreviousOffset() {
1422             // Intentionally left empty
1423             return -1;
1424         }
1425     }
1426 }
1427