Skip to content

Commit e3de28b

Browse files
authored
Merge pull request jruby#8424 from headius/sort_switch_jumps
Sort the jump tables based on new values
2 parents 6f9df83 + d216986 commit e3de28b

File tree

2 files changed

+122
-39
lines changed

2 files changed

+122
-39
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);

spec/compiler/general_spec.rb

Lines changed: 95 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ def self.name; "interpreter"; end
2929
module PersistenceSpecUtils
3030
include CompilerSpecUtils
3131

32+
def initialize(*x, **y)
33+
super
34+
@persist_runtime = org.jruby.Ruby.newInstance
35+
end
36+
37+
attr_reader :persist_runtime
38+
3239
def run_in_method(src, filename = caller_locations[0].path, line = caller_locations[0].lineno)
3340
run( "def __temp; #{src}; end; __temp", filename, line)
3441
end
@@ -42,22 +49,34 @@ def self.name; "persistence"; end
4249
private
4350

4451
def encode_decode_run(src, filename, line)
45-
runtime = JRuby.runtime
46-
manager = runtime.getIRManager()
47-
48-
method = JRuby.compile_ir(src, filename, false, line - 1)
49-
50-
top_self = runtime.top_self
52+
# persist with separate runtime
53+
jruby_module = persist_runtime.eval_scriptlet("require 'jruby'; JRuby")
54+
persist_context = persist_runtime.current_context
55+
persist_src = persist_runtime.new_string(src)
56+
persist_filename = persist_runtime.new_string(src)
57+
persist_line = persist_runtime.new_fixnum(line - 1)
58+
method = org.jruby.ext.jruby.JRubyLibrary.compile_ir(
59+
persist_context,
60+
jruby_module,
61+
[persist_src,
62+
persist_filename,
63+
persist_runtime.false,
64+
persist_line].to_java(org.jruby.runtime.builtin.IRubyObject),
65+
org.jruby.runtime.Block::NULL_BLOCK)
5166

5267
# encode and decode
5368
baos = java.io.ByteArrayOutputStream.new
5469
writer = org.jruby.ir.persistence.IRWriterStream.new(baos)
5570
org.jruby.ir.persistence.IRWriter.persist(writer, method)
5671

72+
# interpret with test runtime
73+
runtime = JRuby.runtime
74+
manager = runtime.getIRManager()
75+
top_self = runtime.top_self
76+
5777
reader = org.jruby.ir.persistence.IRReaderStream.new(manager, baos.to_byte_array, filename.to_java)
5878
method = org.jruby.ir.persistence.IRReader.load(manager, reader)
5979

60-
# interpret
6180
interpreter = org.jruby.ir.interpreter.Interpreter.new
6281
interpreter.execute(runtime, method, top_self)
6382
end
@@ -591,42 +610,86 @@ def foo
591610

592611
it "handles optimized homogeneous case/when" do
593612
run('
594-
case "a"
595-
when "b"
596-
fail
597-
when "a"
598-
1
599-
else
600-
fail
613+
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"].map do |x|
614+
case x
615+
when "a"
616+
1
617+
when "b"
618+
2
619+
when "c"
620+
3
621+
when "d"
622+
4
623+
when "e"
624+
5
625+
when "f"
626+
6
627+
when "g"
628+
7
629+
when "h"
630+
8
631+
when "i"
632+
9
633+
when "j"
634+
10
635+
else
636+
fail
637+
end
601638
end
602639
') do |result|
603-
expect(result).to eq 1
640+
expect(result).to eq [1,2,3,4,5,6,7,8,9,10]
604641
end
605642

606643
run('
607-
case :a
608-
when :b
609-
fail
610-
when :a
611-
1
612-
else
613-
fail
614-
end
644+
[:zxcvbnmzxcvbnm, :qwertyuiopqwertyuiop, :asdfghjklasdfghjkl, :a, :z].map do |x|
645+
case x
646+
when :zxcvbnmzxcvbnm
647+
1
648+
when :qwertyuiopqwertyuiop
649+
2
650+
when :asdfghjklasdfghjkl
651+
3
652+
when :a
653+
4
654+
when :z
655+
5
656+
else
657+
fail
658+
end
659+
end
615660
') do |result|
616-
expect(result).to eq 1
661+
expect(result).to eq [1,2,3,4,5]
617662
end
618663

619664
run('
620-
case 1
621-
when 2
622-
fail
623-
when 1
624-
1
625-
else
626-
fail
665+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map do |x|
666+
case x
667+
when 1
668+
1
669+
when 2
670+
2
671+
when 3
672+
3
673+
when 4
674+
4
675+
when 5
676+
5
677+
when 6
678+
6
679+
when 7
680+
7
681+
when 8
682+
8
683+
when 9
684+
9
685+
when 10
686+
10
687+
else
688+
fail
689+
end
627690
end
628691
') do |result|
629-
expect(result).to eq 1
692+
expect(result).to eq [1,2,3,4,5,6,7,8,9,10]
630693
end
631694
end
632695

0 commit comments

Comments
 (0)