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 }