Closed Bug 1735207 Opened 3 years ago Closed 3 years ago

Wasm bounds check elimination is ineffective

Categories

(Core :: JavaScript Engine: JIT, defect, P2)

defect

Tracking

()

RESOLVED FIXED
95 Branch
Tracking Status
firefox-esr78 --- unaffected
firefox-esr91 95+ fixed
firefox93 --- wontfix
firefox94 --- wontfix
firefox95 --- fixed

People

(Reporter: lth, Assigned: lth)

References

(Blocks 3 open bugs, Regression)

Details

(Keywords: regression)

Attachments

(1 file)

Consider a simple program:

var mod = new WebAssembly.Module(wasmTextToBinary(
`(module
   (memory 1)
   (func (param i32) (result i32)
     (i32.load (local.get 0))
     drop
     (i32.load (local.get 0))))`));
wasmDis(mod)

Run with --wasm-compiler=optimizing --spectre-mitigations=off --disable-wasm-huge-memory after commenting out the body of MacroAssembler::assertCanonicalInt32 (in order to get legible code). Output:

00000000  55                        push %rbp
00000001  48 8b ec                  mov %rsp, %rbp
00000004  41 83 fa 23               cmp $0x23, %r10d
00000008  0f 84 06 00 00 00         jz 0x0000000000000014
0000000E  0f 0b                     ud2
00000010  55                        push %rbp
00000011  48 8b ec                  mov %rsp, %rbp
00000014  49 8b 46 08               movq 0x08(%r14), %rax
00000018  8b cf                     mov %edi, %ecx
0000001A  48 3b c8                  cmp %rax, %rcx
0000001D  0f 82 02 00 00 00         jb 0x0000000000000025
00000023  0f 0b                     ud2
00000025  41 8b 0c 3f               movl (%r15,%rdi,1), %ecx
00000029  8b cf                     mov %edi, %ecx
0000002B  48 3b c8                  cmp %rax, %rcx
0000002E  0f 82 02 00 00 00         jb 0x0000000000000036
00000034  0f 0b                     ud2
00000036  41 8b 04 3f               movl (%r15,%rdi,1), %eax
0000003A  5d                        pop %rbp
0000003B  c3                        ret

This has both bounds checks intact, even though the second one is clearly redundant. The reason seems to be that the two addressing nodes in the MIR graphs, both representing "local 0", have different IDs and thus are not considered the same by BCE (non-constant case).

Poor BCE will hurt us big-time on 32-bit systems but also on 64-bit systems with Memory64. We should get at least simple cases right, which means constant indices and checks that are dominated by identical checks, as is this one. And we need to have test cases to check that BCE works.

Looks like WasmExtendU32Index node is not GVN-friendly. Easy fix.

I think this only affects 64-bit systems at present (memory64 may change that); as we rarely use explicit bounds checking on 64-bit the regression is not a huge problem in practice.

Elimination of bounds checks on constant indices below the heap minimum is also broken because WasmExtendU32Index(constant) is not folded, and so the constant-index case does not trigger.

The introduction of support for 4GB heaps with 64-bit bounds created this problem:

changeset:   640948:293371b99fca
user:        Lars T Hansen <lhansen@mozilla.com>
date:        Fri Mar 26 12:33:01 2021 +0000
summary:     Bug 1676441 - Bounds checking for 4GB heaps. r=rhunt
Keywords: regression
Regressed by: 1676441
Has Regression Range: --- → yes

WasmExtendU32Index and WasmWrapU32Index were not GVN-friendly and did
not perform constant folding. (The problem was introduced by the
support for 4GB heaps and 64-bit bounds, which created these nodes.)
As a consequence, these nodes impeded bounds check elimination, with
the effect that BCE on 64-bit systems did nothing. BCE on 32-bit
systems was likely unaffected by the bug, as the max heap size on
32-bit is 2GB.

Make these nodes GVN-friendly and add appropriate constant folding.

Add simple white-box test cases to test that the BCE works properly on
64-bit and 32-bit both.

Pushed by lhansen@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/399badd3e25b
Improve WasmExtendU32Index and WasmWrapU32Index. r=nbp

Set release status flags based on info from the regressing bug 1676441

The failure to match the generated code is caused by extra code inserted by --ion-check-range-analysis. This code is inserted into the function:

00000014  33 c0                     xor %eax, %eax
00000016  85 c0                     test %eax, %eax
00000018  0f 8d 01 00 00 00         jnl 0x000000000000001F
0000001E  cc                        int3
0000001F  85 c0                     test %eax, %eax
00000021  0f 8e 01 00 00 00         jle 0x0000000000000028
00000027  cc                        int3

This is just the integer zero + an AssertRange node that checks that it is in the range [0,0], I think. Not very helpful. Constant folding AssertRange nodes would have maybe gotten rid of most of this but might still leave us with the dead integer zero.

Hard to say where the zero comes from, to be honest. The test case is

var mod = new WebAssembly.Module(wasmTextToBinary(
`(module
   (memory 1)
   (func (result i32)
     (i32.load (i32.const 16))))`));
wasmDis(mod)
Flags: needinfo?(lhansen)

I'm skipping the test if ion.check-range-analysis is true though I'm still baffled as to why this problem does not affect the codegen tests in the simd subdirectory.

Pushed by lhansen@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/5051da6637dc
Improve WasmExtendU32Index and WasmWrapU32Index. r=nbp
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
Target Milestone: --- → 95 Branch

Comment on attachment 9245420 [details]
Bug 1735207 - Improve WasmExtendU32Index and WasmWrapU32Index. r?nbp

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: Wasm content on some 64-bit devices that are underprovisioned with virtual memory (mobile phones typically; virtualized environments sometimes) may execute more slowly because bounds check elimination was rendered inoperative by a previous patch. The present patch reenables the optimization.
  • User impact if declined: Somewhat (but not hugely) slower wasm execution in contexts mentioned above.
  • Fix Landed on Version: FF95
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): This is pretty well-understood code, and the fix is the obvious one and not complicated. That said, any change to the optimizer is a little risky.
  • String or UUID changes made by this patch:
Attachment #9245420 - Flags: approval-mozilla-esr91?
Regressions: 1735990

Comment on attachment 9245420 [details]
Bug 1735207 - Improve WasmExtendU32Index and WasmWrapU32Index. r?nbp

Approved for 91.4esr.

Attachment #9245420 - Flags: approval-mozilla-esr91? → approval-mozilla-esr91+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: