From c09508d09d48ef0d13d9ed135e5e796696ed3d29 Mon Sep 17 00:00:00 2001 From: Naveed Khan Date: Tue, 7 Jul 2026 11:59:41 +0530 Subject: [PATCH] Build TABLESWITCH from sorted arrays in SWITCH The TABLESWITCH branch filled the table from the caller's unsorted match/targets arrays instead of the sorted clones the LOOKUPSWITCH branch uses, so an unsorted match array produced a table with out-of-order case values and a low/high header that disagrees with the emitted offset count. --- .../java/org/apache/bcel/generic/SWITCH.java | 12 ++--- .../org/apache/bcel/generic/SWITCHTest.java | 49 +++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/apache/bcel/generic/SWITCHTest.java diff --git a/src/main/java/org/apache/bcel/generic/SWITCH.java b/src/main/java/org/apache/bcel/generic/SWITCH.java index 24d64b1fbc..389b1e5493 100644 --- a/src/main/java/org/apache/bcel/generic/SWITCH.java +++ b/src/main/java/org/apache/bcel/generic/SWITCH.java @@ -111,18 +111,18 @@ public SWITCH(final int[] match, final InstructionHandle[] targets, final Instru final int[] mVec = new int[maxSize]; final InstructionHandle[] tVec = new InstructionHandle[maxSize]; int count = 1; - mVec[0] = match[0]; - tVec[0] = targets[0]; + mVec[0] = matchClone[0]; + tVec[0] = targetsClone[0]; for (int i = 1; i < matchLength; i++) { - final int prev = match[i - 1]; - final int gap = match[i] - prev; + final int prev = matchClone[i - 1]; + final int gap = matchClone[i] - prev; for (int j = 1; j < gap; j++) { mVec[count] = prev + j; tVec[count] = target; count++; } - mVec[count] = match[i]; - tVec[count] = targets[i]; + mVec[count] = matchClone[i]; + tVec[count] = targetsClone[i]; count++; } instruction = new TABLESWITCH(Arrays.copyOf(mVec, count), Arrays.copyOf(tVec, count), target); diff --git a/src/test/java/org/apache/bcel/generic/SWITCHTest.java b/src/test/java/org/apache/bcel/generic/SWITCHTest.java new file mode 100644 index 0000000000..a741dfc5f5 --- /dev/null +++ b/src/test/java/org/apache/bcel/generic/SWITCHTest.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.bcel.generic; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import org.junit.jupiter.api.Test; + +class SWITCHTest { + + /** + * {@link SWITCH} documents that the key array is sorted internally while the caller's arrays are left unaltered, + * so an unsorted match array whose sorted form is gap-free must produce a TABLESWITCH whose case values are + * ascending and paired with their targets. Filling the table from the unsorted originals instead yields + * out-of-order match values padded with the default target. + */ + @Test + void testUnsortedMatchBuildsSortedTableSwitch() { + final InstructionList il = new InstructionList(); + final InstructionHandle defaultTarget = il.append(InstructionConst.NOP); + final InstructionHandle target1 = il.append(InstructionConst.NOP); + final InstructionHandle target2 = il.append(InstructionConst.NOP); + final InstructionHandle target3 = il.append(InstructionConst.NOP); + // Sorted form {1, 2, 3} is gap-free, so a TABLESWITCH is generated. + final int[] match = {2, 1, 3}; + final InstructionHandle[] targets = {target2, target1, target3}; + final Select select = (Select) new SWITCH(match, targets, defaultTarget).getInstruction(); + assertInstanceOf(TABLESWITCH.class, select); + assertArrayEquals(new int[] {1, 2, 3}, select.getMatchs()); + assertArrayEquals(new InstructionHandle[] {target1, target2, target3}, select.getTargets()); + } +}