Fix Wasm translator to handle loop parameters on br_table default target.

Similar to an earlier issue for ordinary branches (fixed in PR #1833),
the cranelift-wasm crate did not previously correctly translate a
br_table instruction's default-target branch when the branch target was
a loop with loop parameters. The mistranslated CLIF resulted in a
validation error. This one-line fix simply fills in the correct
parameter count, generating a jump instruction with the appropriate
parameters from the stack.

This issue was found by :decoder in the SpiderMonkey embedding of
Cranelift, in https://bugzilla.mozilla.org/show_bug.cgi?id=1657062. The
test case is from that bug report.
This commit is contained in:
Chris Fallin
2020-08-04 16:44:22 -07:00
parent 3d2e0e55f2
commit 6ad0b04f05
2 changed files with 641 additions and 1 deletions

View File

@@ -395,7 +395,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let i = state.control_stack.len() - 1 - (min_depth as usize);
let min_depth_frame = &state.control_stack[i];
if min_depth_frame.is_loop() {
0
min_depth_frame.num_param_values()
} else {
min_depth_frame.num_return_values()
}

View File

@@ -0,0 +1,640 @@
;; From https://bugzilla.mozilla.org/show_bug.cgi?id=1657062.
;;
;; This just tests that Cranelift can compile this function; it previously
;; triggered a validator error on the CLIF that is generated by the wasm crate.
(module
(type (;0;) (func (param i32 i32 i32) (result i32)))
(func $main (type 0) (param i32 i32 i32) (result i32)
local.get 1
i32.const 6150
local.get 2
i32.const -63
br_if 0 (;@0;)
loop (param i32 i32 i32) (result i32) ;; label = @1
i32.const -59
local.get 1
i32.const -49
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
br_if 0 (;@1;)
i32.const 0
i32.ge_u
i32.const 0
i32.const 0
br_if 0 (;@1;)
i32.const 0
i32.const 27
select
i32.const 24
select
local.get 0
i32.const 27
i32.const 32
br_if 0 (;@1;)
i32.const 32
br_if 0 (;@1;)
i32.const 452672
i32.const 32
br_if 1 (;@0;)
i32.const -23
i32.div_s
local.get 1
if ;; label = @2
nop
i32.const -52
if ;; label = @3
nop
i32.const -52
local.tee 1
br_table 1 (;@2;) 0 (;@3;)
end
local.get 2
br_table 0 (;@2;) 0 (;@2;)
end
local.get 1
nop
i32.const -23
i32.div_s
nop
i32.const -25
i32.popcnt
select
select
i32.const 139
select
drop
i32.const -8051
nop
drop
i32.const 27
i32.const -63
local.get 1
i32.const 1
i32.const -63
i32.const 2
i32.const -6145
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
select
local.get 1
i32.const -7937
i32.const 2
i32.const 0
i32.ge_u
i32.eqz
i32.const -49
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
i32.const 32
call $main
i32.const -1
i32.rem_s
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const -49
i32.const 0
i32.const 0
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
call $main
i32.const -1
i32.rem_s
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 3
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
br_if 0 (;@1;)
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
nop
i32.const -59
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.const 32
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
br_if 0 (;@1;)
i32.const 4
i32.rem_s
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.const -19
nop
nop
i32.const -23
i32.div_s
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -63
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.div_s
local.get 1
i32.const 1
i32.const -63
i32.const 2
i32.const 1
drop
i32.const -63
i32.const 27
select
i32.const 27
select
local.tee 0
i32.const 27
i32.const 32
br_if 0 (;@1;)
i32.const 32
br_if 0 (;@1;)
i32.const 452672
i32.const 32
br_if 1 (;@0;)
i32.const -23
i32.div_s
local.get 1
if ;; label = @2
nop
i32.const -52
if ;; label = @3
nop
i32.const -52
local.tee 1
br_table 1 (;@2;) 0 (;@3;)
end
local.get 2
br_table 0 (;@2;) 0 (;@2;)
end
local.get 1
nop
i32.const -23
i32.div_s
nop
i32.const -25
i32.popcnt
select
select
i32.const 139
select
drop
i32.const -64
i32.ge_u
br_if 0 (;@1;)
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
nop
i32.const -59
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.const 32
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
br_if 0 (;@1;)
i32.const 4
i32.rem_s
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.const -19
nop
nop
i32.const -23
i32.div_s
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -63
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.div_s
local.get 1
i32.const 1
i32.const -63
i32.const 2
i32.const 1
drop
nop
i32.const -49
br_if 0 (;@1;)
local.set 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
br_if 0 (;@1;)
i32.const 0
i32.ge_u
i32.const 0
i32.const 0
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
call $main
i32.const -1
i32.rem_s
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
br_if 0 (;@1;)
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
nop
i32.const -59
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.const 32
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
br_if 0 (;@1;)
i32.const 4
i32.rem_s
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -63
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.div_s
local.get 1
i32.const 1
i32.const -63
i32.const 2
i32.const 1
drop
i32.const -63
i32.const 27
select
i32.const 27
select
local.tee 0
i32.const 27
i32.const 32
br_if 0 (;@1;)
i32.const 32
br_if 0 (;@1;)
i32.const 452672
i32.const 32
br_if 1 (;@0;)
i32.const -23
i32.div_s
local.get 1
if ;; label = @2
nop
i32.const -52
if ;; label = @3
nop
i32.const -52
local.tee 1
br_table 1 (;@2;) 0 (;@3;)
end
local.get 2
br_table 0 (;@2;) 0 (;@2;)
end
local.get 1
nop
i32.const -23
i32.div_s
nop
i32.const -25
i32.popcnt
select
select
i32.const 139
select
drop
i32.const -64
i32.ge_u
br_if 0 (;@1;)
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
nop
i32.const -59
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.const 32
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
br_if 0 (;@1;)
i32.const 4
i32.rem_s
i32.const 2
i32.const 0
br_table 0 (;@1;)
unreachable
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.const -19
nop
nop
i32.const -23
i32.div_s
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -63
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.div_s
local.get 1
i32.const 1
i32.const -63
i32.const 2
i32.const 1
drop
nop
i32.const -49
br_if 0 (;@1;)
local.set 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
br_if 0 (;@1;)
i32.const 0
i32.ge_u
i32.const 0
i32.const 0
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 32
call $main
i32.const -1
i32.rem_s
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
br_if 0 (;@1;)
select
br_if 0 (;@1;)
i32.const 0
local.get 1
select
i32.const 2
i32.const 0
i32.ge_u
br_if 0 (;@1;)
i32.const -64
i32.ge_u
i32.const 2
i32.const 0
i32.const 2
i32.const 0
i32.ge_u
i32.ge_u
br_if 0 (;@1;)
i32.const 0
i32.ge_u
nop
i32.const -59
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.eqz
i32.const 32
select
br_if 0 (;@1;)
i32.const 0
i32.const 2
i32.const 0
i32.const 2
i32.const -63
i32.const 27
i32.const -63
i32.eqz
i32.eqz
br 0 (;@1;)
end
unreachable
i32.div_s
unreachable
i32.rem_s
i32.div_s
return
br_if 0 (;@0;)
i32.const 0
i32.extend8_s
unreachable
unreachable
unreachable
unreachable
i32.ctz
unreachable
i32.ge_u
unreachable
unreachable
i32.popcnt
unreachable
unreachable
i32.popcnt)
(export "main" (func $main)))