View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.generic;
20  
21  import static org.junit.jupiter.api.Assertions.fail;
22  import static org.junit.jupiter.api.Assumptions.assumeFalse;
23  
24  import org.apache.bcel.classfile.Code;
25  import org.apache.bcel.classfile.JavaClass;
26  import org.apache.bcel.classfile.Method;
27  import org.apache.bcel.util.SyntheticRepository;
28  import org.apache.commons.lang3.JavaVersion;
29  import org.apache.commons.lang3.SystemUtils;
30  import org.junit.jupiter.params.ParameterizedTest;
31  import org.junit.jupiter.params.provider.ValueSource;
32  
33  final class EmptyVisitorTest {
34  
35      /*
36       * https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-6.html#jvms-6.2
37       */
38      private static final String RESERVED_OPCODE = "Reserved opcode";
39  
40      @ParameterizedTest
41      @ValueSource(strings = {
42      // @formatter:off
43          "java.math.BigInteger",                          // contains instructions [AALOAD, AASTORE, ACONST_NULL, ALOAD, ANEWARRAY, ARETURN, ARRAYLENGTH,
44                                                           //   ASTORE, ATHROW, BALOAD, BASTORE, BIPUSH, CALOAD, CHECKCAST, D2I, DADD, DALOAD, DASTORE, DCONST
45                                                           //   DDIV, DMUL, DRETURN, DSUB, DUP, DUP2, DUP_X2, FCONST, FRETURN, GETFIELD, GETSTATIC, GOTO, I2B,
46                                                           //   I2D, I2L, IADD, IALOAD, IAND, IASTORE, ICONST, IDIV, IFEQ, IFGE, IFGT, IFLE, IFLT, IFNE,
47                                                           //   IFNONNULL, IFNULL, IF_ACMPNE, IF_ICMPEQ, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ICMPLT, IF_ICMPNE,
48                                                           //   IINC, ILOAD, IMUL, INEG, INSTANCEOF, INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, IOR, IREM,
49                                                           //   IRETURN, ISHL, ISHR, ISTORE, ISUB, IUSHR, IXOR, L2D, L2F, L2I, LADD, LALOAD, LAND, LASTORE, LCMP,
50                                                           //   LCONST, LDC, LDC2_W, LDC_W, LDIV, LLOAD, LMUL, LNEG, LOOKUPSWITCH, LOR, LREM, LRETURN, LSHL, LSHR,
51                                                           //   LSTORE, LSUB, LUSHR, NEW, NEWARRAY, POP, PUTFIELD, PUTSTATIC, RETURN, SIPUSH]
52          "java.math.BigDecimal",                          // contains instructions [CASTORE, D2L, DLOAD, FALOAD, FASTORE, FDIV, FMUL, I2S, IF_ACMPEQ, LXOR,
53                                                           //   MONITORENTER, MONITOREXIT, TABLESWITCH]
54          "java.awt.Color",                                // contains instructions [D2F, DCMPG, DCMPL, F2D, F2I, FADD, FCMPG, FCMPL, FLOAD, FSTORE, FSUB, I2F,
55                                                           //   INVOKEDYNAMIC]
56          "java.util.Map",                                 // contains instruction INVOKEINTERFACE
57          "java.io.Bits",                                  // contains instruction I2C
58          "java.io.BufferedInputStream",                   // contains instruction DUP_X1
59          "java.io.StreamTokenizer",                       // contains instruction DNEG, DSTORE
60          "java.lang.Float",                               // contains instruction F2L
61          "java.lang.invoke.LambdaForm",                   // contains instruction MULTIANEWARRAY,
62          "java.nio.Bits",                                 // contains instruction POP2,
63          "java.nio.HeapShortBuffer",                      // contains instruction SALOAD, SASTORE
64          "Java8Example2",                                 // contains instruction FREM
65          "java.awt.GradientPaintContext",                 // contains instruction DREM
66          "java.util.concurrent.atomic.DoubleAccumulator", // contains instruction DUP2_X1
67          "java.util.Hashtable",                           // contains instruction FNEG
68          "javax.swing.text.html.CSS",                     // contains instruction DUP2_X2
69          "org.apache.bcel.generic.LargeJump",             // contains instruction GOTO_W
70          "org.apache.commons.lang.SerializationUtils"     // contains instruction JSR
71      // @formatter:on
72      })
73      void test(final String className) throws ClassNotFoundException {
74          // "java.io.Bits" is not in Java 21.
75          assumeFalse(SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_21) && className.equals("java.io.Bits"));
76          final JavaClass javaClass = SyntheticRepository.getInstance().loadClass(className);
77          for (final Method method : javaClass.getMethods()) {
78              final Code code = method.getCode();
79              if (code != null) {
80                  final InstructionList instructionList = new InstructionList(code.getCode());
81                  for (final InstructionHandle instructionHandle : instructionList) {
82                      instructionHandle.accept(new EmptyVisitor() {
83                          @Override
84                          public void visitBREAKPOINT(final BREAKPOINT obj) {
85                              fail(RESERVED_OPCODE);
86                          }
87  
88                          @Override
89                          public void visitIMPDEP1(final IMPDEP1 obj) {
90                              fail(RESERVED_OPCODE);
91                          }
92  
93                          @Override
94                          public void visitIMPDEP2(final IMPDEP2 obj) {
95                              fail(RESERVED_OPCODE);
96                          }
97                      });
98                  }
99              }
100         }
101     }
102 }