[llvm-bugs] [Bug 51702] New: wasm-ld __wasm_init_memory calls atomic.wait which will fail on the main thread or in (Audio)Worklets

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Sep 1 06:39:47 PDT 2021


https://bugs.llvm.org/show_bug.cgi?id=51702

            Bug ID: 51702
           Summary: wasm-ld __wasm_init_memory calls atomic.wait which
                    will fail on the main thread or in (Audio)Worklets
           Product: lld
           Version: unspecified
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: wasm
          Assignee: unassignedbugs at nondot.org
          Reporter: tibor.klajnscek at gmail.com
                CC: llvm-bugs at lists.llvm.org, sbc at chromium.org

When compiling with `sharedMemory` wasm-ld emits the __wasm_init_memory memory
function and runs it via the `start` section. The function is emitted in
"lld/wasm/Writer.cpp" -> Writer::createInitMemoryFunction()

The function is responsible for initializing the memory from the data segments
stored in the WASM. 

The first thread to enter will acquire the lock via atomic RMW, setting the
guard value from 0 to 1, then proceed to initialize the memory, then set it to
2 at the end.

Any other threads that enter will fail the RMW and attempt to `atomic.wait` on
the guard value with the expected value of 1. If it's already 2 the wait
doesn't block and the thread carries on as usual.

Now this works fine in regular WebWorkers, but we've hit a problem with the
current design when using WASM in AudioWorkletGlobalScope where atomics.wait is
not allowed to be called. The memory is already initialized on the main thread
so the wait will never block, but it still gets called and immediately traps.

Furthermore, this will also fail if the the WASM is initialized in a Worker
first, then instantiated on the main thread, where atomics.wait is not allowed
either. AFAICT this can never be the case when running with the current
Emscripten JS boilerplate, but it's easy enough to hit when working with the
compiled WASM manually.

I think the best solution is to replace the notify/wait pair with a simple spin
lock. It will work correctly in all contexts and the lock duration for the
memory init should be very short in any case so I think this makes sense.

Effectively, what I'm proposing is changing this:
>(if
> (i32.atomic.rmw.cmpxchg align=2 offset=0 (i32.const $__init_memory_flag) (i32.const 0) (i32.const 1))
> (then
>  (drop
>   (i32.atomic.wait align=2 offset=0 (i32.const $__init_memory_flag) (i32.const 1) (i32.const -1)
>   )
>  )
> )
> (else
>  ( ... initialize data segments ... )
>  (i32.atomic.store align=2 offset=0 (i32.const $__init_memory_flag) (i32.const 2)
>  )
>  (drop
>   (i32.atomic.notify align=2 offset=0 (i32.const $__init_memory_flag)(i32.const -1u)
>   )
>  )
> )
>)

To this:
>(if
> (i32.atomic.rmw.cmpxchg align=2 offset=0 (i32.const $__init_memory_flag) (i32.const 0) (i32.const 1)
> )
> (then
>  (loop
>   (br_if 1
>    (i32.eq
>     (i32.atomic.load  align=2 offset=0 (i32.const $__init_memory_flag))
>     (i32.const 2)
>    )
>   )
>  )
> )
> (else
>  ( ... initialize data segments ... )
>  (i32.atomic.store align=2 offset=0 (i32.const $__init_memory_flag) (i32.const 2)
>  )
> )
>)

I've made the change to the source code and I'll post a link to the patch for
review once I have it up.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210901/05aafc1e/attachment.html>


More information about the llvm-bugs mailing list