• 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.rop.cst.Constant;
20 import com.android.dx.rop.cst.ConstantPool;
21 import com.android.dx.rop.cst.CstDouble;
22 import com.android.dx.rop.cst.CstFloat;
23 import com.android.dx.rop.cst.CstInteger;
24 import com.android.dx.rop.cst.CstInvokeDynamic;
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                     int idx = bytes.getUnsignedShort(offset + 1);
778                     // Skip to must-be-zero bytes at offsets 3 and 4
779                     CstInvokeDynamic cstInvokeDynamic = (CstInvokeDynamic) pool.get(idx);
780                     visitor.visitConstant(opcode, offset, 5, cstInvokeDynamic, 0);
781                     return 5;
782                 }
783                 case ByteOps.NEWARRAY: {
784                     return parseNewarray(offset, visitor);
785                 }
786                 case ByteOps.WIDE: {
787                     return parseWide(offset, visitor);
788                 }
789                 case ByteOps.MULTIANEWARRAY: {
790                     int idx = bytes.getUnsignedShort(offset + 1);
791                     int dimensions = bytes.getUnsignedByte(offset + 3);
792                     Constant cst = pool.get(idx);
793                     visitor.visitConstant(opcode, offset, 4, cst, dimensions);
794                     return 4;
795                 }
796                 case ByteOps.GOTO_W:
797                 case ByteOps.JSR_W: {
798                     int target = offset + bytes.getInt(offset + 1);
799                     int newop =
800                         (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO :
801                         ByteOps.JSR;
802                     visitor.visitBranch(newop, offset, 5, target);
803                     return 5;
804                 }
805                 default: {
806                     visitor.visitInvalid(opcode, offset, 1);
807                     return 1;
808                 }
809             }
810         } catch (SimException ex) {
811             ex.addContext("...at bytecode offset " + Hex.u4(offset));
812             throw ex;
813         } catch (RuntimeException ex) {
814             SimException se = new SimException(ex);
815             se.addContext("...at bytecode offset " + Hex.u4(offset));
816             throw se;
817         }
818     }
819 
820     /**
821      * Helper to deal with {@code tableswitch}.
822      *
823      * @param offset the offset to the {@code tableswitch} opcode itself
824      * @param visitor {@code non-null;} visitor to use
825      * @return instruction length, in bytes
826      */
parseTableswitch(int offset, Visitor visitor)827     private int parseTableswitch(int offset, Visitor visitor) {
828         int at = (offset + 4) & ~3; // "at" skips the padding.
829 
830         // Collect the padding.
831         int padding = 0;
832         for (int i = offset + 1; i < at; i++) {
833             padding = (padding << 8) | bytes.getUnsignedByte(i);
834         }
835 
836         int defaultTarget = offset + bytes.getInt(at);
837         int low = bytes.getInt(at + 4);
838         int high = bytes.getInt(at + 8);
839         int count = high - low + 1;
840         at += 12;
841 
842         if (low > high) {
843             throw new SimException("low / high inversion");
844         }
845 
846         SwitchList cases = new SwitchList(count);
847         for (int i = 0; i < count; i++) {
848             int target = offset + bytes.getInt(at);
849             at += 4;
850             cases.add(low + i, target);
851         }
852         cases.setDefaultTarget(defaultTarget);
853         cases.removeSuperfluousDefaults();
854         cases.setImmutable();
855 
856         int length = at - offset;
857         visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
858                             padding);
859 
860         return length;
861     }
862 
863     /**
864      * Helper to deal with {@code lookupswitch}.
865      *
866      * @param offset the offset to the {@code lookupswitch} opcode itself
867      * @param visitor {@code non-null;} visitor to use
868      * @return instruction length, in bytes
869      */
parseLookupswitch(int offset, Visitor visitor)870     private int parseLookupswitch(int offset, Visitor visitor) {
871         int at = (offset + 4) & ~3; // "at" skips the padding.
872 
873         // Collect the padding.
874         int padding = 0;
875         for (int i = offset + 1; i < at; i++) {
876             padding = (padding << 8) | bytes.getUnsignedByte(i);
877         }
878 
879         int defaultTarget = offset + bytes.getInt(at);
880         int npairs = bytes.getInt(at + 4);
881         at += 8;
882 
883         SwitchList cases = new SwitchList(npairs);
884         for (int i = 0; i < npairs; i++) {
885             int match = bytes.getInt(at);
886             int target = offset + bytes.getInt(at + 4);
887             at += 8;
888             cases.add(match, target);
889         }
890         cases.setDefaultTarget(defaultTarget);
891         cases.removeSuperfluousDefaults();
892         cases.setImmutable();
893 
894         int length = at - offset;
895         visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases,
896                             padding);
897 
898         return length;
899     }
900 
901     /**
902      * Helper to deal with {@code newarray}.
903      *
904      * @param offset the offset to the {@code newarray} opcode itself
905      * @param visitor {@code non-null;} visitor to use
906      * @return instruction length, in bytes
907      */
parseNewarray(int offset, Visitor visitor)908     private int parseNewarray(int offset, Visitor visitor) {
909         int value = bytes.getUnsignedByte(offset + 1);
910         CstType type;
911         switch (value) {
912             case ByteOps.NEWARRAY_BOOLEAN: {
913                 type = CstType.BOOLEAN_ARRAY;
914                 break;
915             }
916             case ByteOps.NEWARRAY_CHAR: {
917                 type = CstType.CHAR_ARRAY;
918                 break;
919             }
920             case ByteOps.NEWARRAY_DOUBLE: {
921                 type = CstType.DOUBLE_ARRAY;
922                 break;
923             }
924             case ByteOps.NEWARRAY_FLOAT: {
925                 type = CstType.FLOAT_ARRAY;
926                 break;
927             }
928             case ByteOps.NEWARRAY_BYTE: {
929                 type = CstType.BYTE_ARRAY;
930                 break;
931             }
932             case ByteOps.NEWARRAY_SHORT: {
933                 type = CstType.SHORT_ARRAY;
934                 break;
935             }
936             case ByteOps.NEWARRAY_INT: {
937                 type = CstType.INT_ARRAY;
938                 break;
939             }
940             case ByteOps.NEWARRAY_LONG: {
941                 type = CstType.LONG_ARRAY;
942                 break;
943             }
944             default: {
945                 throw new SimException("bad newarray code " +
946                         Hex.u1(value));
947             }
948         }
949 
950         // Revisit the previous bytecode to find out the length of the array
951         int previousOffset = visitor.getPreviousOffset();
952         ConstantParserVisitor constantVisitor = new ConstantParserVisitor();
953         int arrayLength = 0;
954 
955         /*
956          * For visitors that don't record the previous offset, -1 will be
957          * seen here
958          */
959         if (previousOffset >= 0) {
960             parseInstruction(previousOffset, constantVisitor);
961             if (constantVisitor.cst instanceof CstInteger &&
962                     constantVisitor.length + previousOffset == offset) {
963                 arrayLength = constantVisitor.value;
964 
965             }
966         }
967 
968         /*
969          * Try to match the array initialization idiom. For example, if the
970          * subsequent code is initializing an int array, we are expecting the
971          * following pattern repeatedly:
972          *  dup
973          *  push index
974          *  push value
975          *  *astore
976          *
977          * where the index value will be incrimented sequentially from 0 up.
978          */
979         int nInit = 0;
980         int curOffset = offset+2;
981         int lastOffset = curOffset;
982         ArrayList<Constant> initVals = new ArrayList<Constant>();
983 
984         if (arrayLength != 0) {
985             while (true) {
986                 boolean punt = false;
987 
988                 // First, check if the next bytecode is dup.
989                 int nextByte = bytes.getUnsignedByte(curOffset++);
990                 if (nextByte != ByteOps.DUP)
991                     break;
992 
993                 /*
994                  * Next, check if the expected array index is pushed to
995                  * the stack.
996                  */
997                 parseInstruction(curOffset, constantVisitor);
998                 if (constantVisitor.length == 0 ||
999                         !(constantVisitor.cst instanceof CstInteger) ||
1000                         constantVisitor.value != nInit)
1001                     break;
1002 
1003                 // Next, fetch the init value and record it.
1004                 curOffset += constantVisitor.length;
1005 
1006                 /*
1007                  * Next, find out what kind of constant is pushed onto
1008                  * the stack.
1009                  */
1010                 parseInstruction(curOffset, constantVisitor);
1011                 if (constantVisitor.length == 0 ||
1012                         !(constantVisitor.cst instanceof CstLiteralBits))
1013                     break;
1014 
1015                 curOffset += constantVisitor.length;
1016                 initVals.add(constantVisitor.cst);
1017 
1018                 nextByte = bytes.getUnsignedByte(curOffset++);
1019                 // Now, check if the value is stored to the array properly.
1020                 switch (value) {
1021                     case ByteOps.NEWARRAY_BYTE:
1022                     case ByteOps.NEWARRAY_BOOLEAN: {
1023                         if (nextByte != ByteOps.BASTORE) {
1024                             punt = true;
1025                         }
1026                         break;
1027                     }
1028                     case ByteOps.NEWARRAY_CHAR: {
1029                         if (nextByte != ByteOps.CASTORE) {
1030                             punt = true;
1031                         }
1032                         break;
1033                     }
1034                     case ByteOps.NEWARRAY_DOUBLE: {
1035                         if (nextByte != ByteOps.DASTORE) {
1036                             punt = true;
1037                         }
1038                         break;
1039                     }
1040                     case ByteOps.NEWARRAY_FLOAT: {
1041                         if (nextByte != ByteOps.FASTORE) {
1042                             punt = true;
1043                         }
1044                         break;
1045                     }
1046                     case ByteOps.NEWARRAY_SHORT: {
1047                         if (nextByte != ByteOps.SASTORE) {
1048                             punt = true;
1049                         }
1050                         break;
1051                     }
1052                     case ByteOps.NEWARRAY_INT: {
1053                         if (nextByte != ByteOps.IASTORE) {
1054                             punt = true;
1055                         }
1056                         break;
1057                     }
1058                     case ByteOps.NEWARRAY_LONG: {
1059                         if (nextByte != ByteOps.LASTORE) {
1060                             punt = true;
1061                         }
1062                         break;
1063                     }
1064                     default:
1065                         punt = true;
1066                         break;
1067                 }
1068                 if (punt) {
1069                     break;
1070                 }
1071                 lastOffset = curOffset;
1072                 nInit++;
1073             }
1074         }
1075 
1076         /*
1077          * For singleton arrays it is still more economical to
1078          * generate the aput.
1079          */
1080         if (nInit < 2 || nInit != arrayLength) {
1081             visitor.visitNewarray(offset, 2, type, null);
1082             return 2;
1083         } else {
1084             visitor.visitNewarray(offset, lastOffset - offset, type, initVals);
1085             return lastOffset - offset;
1086         }
1087      }
1088 
1089 
1090     /**
1091      * Helper to deal with {@code wide}.
1092      *
1093      * @param offset the offset to the {@code wide} opcode itself
1094      * @param visitor {@code non-null;} visitor to use
1095      * @return instruction length, in bytes
1096      */
parseWide(int offset, Visitor visitor)1097     private int parseWide(int offset, Visitor visitor) {
1098         int opcode = bytes.getUnsignedByte(offset + 1);
1099         int idx = bytes.getUnsignedShort(offset + 2);
1100         switch (opcode) {
1101             case ByteOps.ILOAD: {
1102                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1103                                    Type.INT, 0);
1104                 return 4;
1105             }
1106             case ByteOps.LLOAD: {
1107                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1108                                    Type.LONG, 0);
1109                 return 4;
1110             }
1111             case ByteOps.FLOAD: {
1112                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1113                                    Type.FLOAT, 0);
1114                 return 4;
1115             }
1116             case ByteOps.DLOAD: {
1117                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1118                                    Type.DOUBLE, 0);
1119                 return 4;
1120             }
1121             case ByteOps.ALOAD: {
1122                 visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx,
1123                                    Type.OBJECT, 0);
1124                 return 4;
1125             }
1126             case ByteOps.ISTORE: {
1127                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1128                                    Type.INT, 0);
1129                 return 4;
1130             }
1131             case ByteOps.LSTORE: {
1132                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1133                                    Type.LONG, 0);
1134                 return 4;
1135             }
1136             case ByteOps.FSTORE: {
1137                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1138                                    Type.FLOAT, 0);
1139                 return 4;
1140             }
1141             case ByteOps.DSTORE: {
1142                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1143                                    Type.DOUBLE, 0);
1144                 return 4;
1145             }
1146             case ByteOps.ASTORE: {
1147                 visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx,
1148                                    Type.OBJECT, 0);
1149                 return 4;
1150             }
1151             case ByteOps.RET: {
1152                 visitor.visitLocal(opcode, offset, 4, idx,
1153                                    Type.RETURN_ADDRESS, 0);
1154                 return 4;
1155             }
1156             case ByteOps.IINC: {
1157                 int value = bytes.getShort(offset + 4);
1158                 visitor.visitLocal(opcode, offset, 6, idx,
1159                                    Type.INT, value);
1160                 return 6;
1161             }
1162             default: {
1163                 visitor.visitInvalid(ByteOps.WIDE, offset, 1);
1164                 return 1;
1165             }
1166         }
1167     }
1168 
1169     /**
1170      * Instruction visitor interface.
1171      */
1172     public interface Visitor {
1173         /**
1174          * Visits an invalid instruction.
1175          *
1176          * @param opcode the opcode
1177          * @param offset offset to the instruction
1178          * @param length length of the instruction, in bytes
1179          */
visitInvalid(int opcode, int offset, int length)1180         public void visitInvalid(int opcode, int offset, int length);
1181 
1182         /**
1183          * Visits an instruction which has no inline arguments
1184          * (implicit or explicit).
1185          *
1186          * @param opcode the opcode
1187          * @param offset offset to the instruction
1188          * @param length length of the instruction, in bytes
1189          * @param type {@code non-null;} type the instruction operates on
1190          */
visitNoArgs(int opcode, int offset, int length, Type type)1191         public void visitNoArgs(int opcode, int offset, int length,
1192                 Type type);
1193 
1194         /**
1195          * Visits an instruction which has a local variable index argument.
1196          *
1197          * @param opcode the opcode
1198          * @param offset offset to the instruction
1199          * @param length length of the instruction, in bytes
1200          * @param idx the local variable index
1201          * @param type {@code non-null;} the type of the accessed value
1202          * @param value additional literal integer argument, if salient (i.e.,
1203          * for {@code iinc})
1204          */
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1205         public void visitLocal(int opcode, int offset, int length,
1206                 int idx, Type type, int value);
1207 
1208         /**
1209          * Visits an instruction which has a (possibly synthetic)
1210          * constant argument, and possibly also an
1211          * additional literal integer argument. In the case of
1212          * {@code multianewarray}, the argument is the count of
1213          * dimensions. In the case of {@code invokeinterface},
1214          * the argument is the parameter count or'ed with the
1215          * should-be-zero value left-shifted by 8. In the case of entries
1216          * of type {@code int}, the {@code value} field always
1217          * holds the raw value (for convenience of clients).
1218          *
1219          * <p><b>Note:</b> In order to avoid giving it a barely-useful
1220          * visitor all its own, {@code newarray} also uses this
1221          * form, passing {@code value} as the array type code and
1222          * {@code cst} as a {@link CstType} instance
1223          * corresponding to the array type.</p>
1224          *
1225          * @param opcode the opcode
1226          * @param offset offset to the instruction
1227          * @param length length of the instruction, in bytes
1228          * @param cst {@code non-null;} the constant
1229          * @param value additional literal integer argument, if salient
1230          * (ignore if not)
1231          */
visitConstant(int opcode, int offset, int length, Constant cst, int value)1232         public void visitConstant(int opcode, int offset, int length,
1233                 Constant cst, int value);
1234 
1235         /**
1236          * Visits an instruction which has a branch target argument.
1237          *
1238          * @param opcode the opcode
1239          * @param offset offset to the instruction
1240          * @param length length of the instruction, in bytes
1241          * @param target the absolute (not relative) branch target
1242          */
visitBranch(int opcode, int offset, int length, int target)1243         public void visitBranch(int opcode, int offset, int length,
1244                 int target);
1245 
1246         /**
1247          * Visits a switch instruction.
1248          *
1249          * @param opcode the opcode
1250          * @param offset offset to the instruction
1251          * @param length length of the instruction, in bytes
1252          * @param cases {@code non-null;} list of (value, target)
1253          * pairs, plus the default target
1254          * @param padding the bytes found in the padding area (if any),
1255          * packed
1256          */
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1257         public void visitSwitch(int opcode, int offset, int length,
1258                 SwitchList cases, int padding);
1259 
1260         /**
1261          * Visits a newarray instruction.
1262          *
1263          * @param offset   offset to the instruction
1264          * @param length   length of the instruction, in bytes
1265          * @param type {@code non-null;} the type of the array
1266          * @param initVals {@code non-null;} list of bytecode offsets
1267          * for init values
1268          */
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1269         public void visitNewarray(int offset, int length, CstType type,
1270                 ArrayList<Constant> initVals);
1271 
1272         /**
1273          * Set previous bytecode offset
1274          * @param offset    offset of the previous fully parsed bytecode
1275          */
setPreviousOffset(int offset)1276         public void setPreviousOffset(int offset);
1277 
1278         /**
1279          * Get previous bytecode offset
1280          * @return return the recored offset of the previous bytecode
1281          */
getPreviousOffset()1282         public int getPreviousOffset();
1283     }
1284 
1285     /**
1286      * Base implementation of {@link Visitor}, which has empty method
1287      * bodies for all methods.
1288      */
1289     public static class BaseVisitor implements Visitor {
1290 
1291         /** offset of the previously parsed bytecode */
1292         private int previousOffset;
1293 
BaseVisitor()1294         BaseVisitor() {
1295             previousOffset = -1;
1296         }
1297 
1298         /** {@inheritDoc} */
1299         @Override
visitInvalid(int opcode, int offset, int length)1300         public void visitInvalid(int opcode, int offset, int length) {
1301             // This space intentionally left blank.
1302         }
1303 
1304         /** {@inheritDoc} */
1305         @Override
visitNoArgs(int opcode, int offset, int length, Type type)1306         public void visitNoArgs(int opcode, int offset, int length,
1307                 Type type) {
1308             // This space intentionally left blank.
1309         }
1310 
1311         /** {@inheritDoc} */
1312         @Override
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1313         public void visitLocal(int opcode, int offset, int length,
1314                 int idx, Type type, int value) {
1315             // This space intentionally left blank.
1316         }
1317 
1318         /** {@inheritDoc} */
1319         @Override
visitConstant(int opcode, int offset, int length, Constant cst, int value)1320         public void visitConstant(int opcode, int offset, int length,
1321                 Constant cst, int value) {
1322             // This space intentionally left blank.
1323         }
1324 
1325         /** {@inheritDoc} */
1326         @Override
visitBranch(int opcode, int offset, int length, int target)1327         public void visitBranch(int opcode, int offset, int length,
1328                 int target) {
1329             // This space intentionally left blank.
1330         }
1331 
1332         /** {@inheritDoc} */
1333         @Override
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1334         public void visitSwitch(int opcode, int offset, int length,
1335                 SwitchList cases, int padding) {
1336             // This space intentionally left blank.
1337         }
1338 
1339         /** {@inheritDoc} */
1340         @Override
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initValues)1341         public void visitNewarray(int offset, int length, CstType type,
1342                 ArrayList<Constant> initValues) {
1343             // This space intentionally left blank.
1344         }
1345 
1346         /** {@inheritDoc} */
1347         @Override
setPreviousOffset(int offset)1348         public void setPreviousOffset(int offset) {
1349             previousOffset = offset;
1350         }
1351 
1352         /** {@inheritDoc} */
1353         @Override
getPreviousOffset()1354         public int getPreviousOffset() {
1355             return previousOffset;
1356         }
1357     }
1358 
1359     /**
1360      * Implementation of {@link Visitor}, which just pays attention
1361      * to constant values.
1362      */
1363     class ConstantParserVisitor extends BaseVisitor {
1364         Constant cst;
1365         int length;
1366         int value;
1367 
1368         /** Empty constructor */
ConstantParserVisitor()1369         ConstantParserVisitor() {
1370         }
1371 
clear()1372         private void clear() {
1373             length = 0;
1374         }
1375 
1376         /** {@inheritDoc} */
1377         @Override
visitInvalid(int opcode, int offset, int length)1378         public void visitInvalid(int opcode, int offset, int length) {
1379             clear();
1380         }
1381 
1382         /** {@inheritDoc} */
1383         @Override
visitNoArgs(int opcode, int offset, int length, Type type)1384         public void visitNoArgs(int opcode, int offset, int length,
1385                 Type type) {
1386             clear();
1387         }
1388 
1389         /** {@inheritDoc} */
1390         @Override
visitLocal(int opcode, int offset, int length, int idx, Type type, int value)1391         public void visitLocal(int opcode, int offset, int length,
1392                 int idx, Type type, int value) {
1393             clear();
1394         }
1395 
1396         /** {@inheritDoc} */
1397         @Override
visitConstant(int opcode, int offset, int length, Constant cst, int value)1398         public void visitConstant(int opcode, int offset, int length,
1399                 Constant cst, int value) {
1400             this.cst = cst;
1401             this.length = length;
1402             this.value = value;
1403         }
1404 
1405         /** {@inheritDoc} */
1406         @Override
visitBranch(int opcode, int offset, int length, int target)1407         public void visitBranch(int opcode, int offset, int length,
1408                 int target) {
1409             clear();
1410         }
1411 
1412         /** {@inheritDoc} */
1413         @Override
visitSwitch(int opcode, int offset, int length, SwitchList cases, int padding)1414         public void visitSwitch(int opcode, int offset, int length,
1415                 SwitchList cases, int padding) {
1416             clear();
1417         }
1418 
1419         /** {@inheritDoc} */
1420         @Override
visitNewarray(int offset, int length, CstType type, ArrayList<Constant> initVals)1421         public void visitNewarray(int offset, int length, CstType type,
1422                 ArrayList<Constant> initVals) {
1423             clear();
1424         }
1425 
1426         /** {@inheritDoc} */
1427         @Override
setPreviousOffset(int offset)1428         public void setPreviousOffset(int offset) {
1429             // Intentionally left empty
1430         }
1431 
1432         /** {@inheritDoc} */
1433         @Override
getPreviousOffset()1434         public int getPreviousOffset() {
1435             // Intentionally left empty
1436             return -1;
1437         }
1438     }
1439 }
1440