Skip to content

Commit 0d92591

Browse files
committed
Sort the jump tables based on new values
When deserializing a BSwitch we recalculate the values for the switch based on the new runtime, which mostly means getting new Symbol IDs. This was fixed in jruby#8209. However we need to ensure that the jump table is sorted or the binary search for the switch will sometimes fail. This patch sorts the related tables based on the new switch values. Fixes jruby#8421
1 parent 6f9df83 commit 0d92591

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

core/src/main/java/org/jruby/ir/instructions/BSwitchInstr.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public BSwitchInstr(int[] jumps, Operand[] jumpOperands, Operand operand, Label
3636
super(Operation.B_SWITCH);
3737

3838
// We depend on the jump table being sorted, so ensure that's the case here
39-
assert jumpsAreSorted(jumps);
39+
assert jumpsAreSorted(jumps) : "jump table must be sorted";
4040

4141
// Switch cases must not have an empty "case" value (GH-6440)
4242
assert operand != null : "Switch cases must not have an empty \"case\" value";
@@ -108,17 +108,37 @@ public void encode(IRWriterEncoder e) {
108108
public static BSwitchInstr decode(IRReaderDecoder d) {
109109
try {
110110
Operand[] jumpOperands = d.decodeOperandArray();
111+
Operand operand = d.decodeOperand();
112+
Label rubyCase = d.decodeLabel();
113+
Label[] targets = d.decodeLabelArray();
114+
Label elseTarget = d.decodeLabel();
115+
Class<?> expectedClass = Class.forName(d.decodeString());
116+
111117
int[] jumps = new int[jumpOperands.length];
112118
for (int i = 0; i < jumps.length; i++) {
113-
Operand operand = jumpOperands[i];
114-
if (operand instanceof Symbol) {
115-
jumps[i] = ((Symbol) operand).getSymbol().getId();
116-
} else if (operand instanceof Fixnum) {
117-
jumps[i] = (int) ((Fixnum) operand).getValue();
119+
Operand jumpOperand = jumpOperands[i];
120+
if (jumpOperand instanceof Symbol) {
121+
jumps[i] = ((Symbol) jumpOperand).getSymbol().getId();
122+
} else if (jumpOperand instanceof Fixnum) {
123+
jumps[i] = (int) ((Fixnum) jumpOperand).getValue();
118124
}
119125
}
120126

121-
return new BSwitchInstr(jumps, jumpOperands, d.decodeOperand(), d.decodeLabel(), d.decodeLabelArray(), d.decodeLabel(), Class.forName(d.decodeString()));
127+
int[] sortedJumps = jumps.clone();
128+
Arrays.sort(sortedJumps);
129+
130+
Operand[] sortedJumpOperands = jumpOperands.clone();
131+
Label[] sortedTargets = targets.clone();
132+
133+
for (int i = 0; i < jumps.length; i++) {
134+
int oldJump = jumps[i];
135+
int newIndex = Arrays.binarySearch(sortedJumps, oldJump);
136+
137+
sortedJumpOperands[newIndex] = jumpOperands[i];
138+
sortedTargets[newIndex] = targets[i];
139+
}
140+
141+
return new BSwitchInstr(sortedJumps, sortedJumpOperands, operand, rubyCase, sortedTargets, elseTarget, expectedClass);
122142
} catch (Exception e) {
123143
// should never happen unless encode was corrupted
124144
Helpers.throwException(e);

0 commit comments

Comments
 (0)