binaryen
binaryen copied to clipboard
GUFA mishandles escaping functions
Consider the following module:
(module
(type $t (func (param i32) (result i32)))
(type $u (func (param (ref $t))))
(func $g (type $t) (param i32) (result i32) (local.get 0))
(import "env" "f" (func $f (param funcref)))
(func (export "passed_to_imported_function")
(call $f (ref.func $g)))
(func (export "returned_from_exported_function") (result funcref)
(ref.func $g))
(func (export "passed_to_unknown_function") (param $f (ref $u))
(call_ref $u (ref.func $g) (local.get $f)))
(global (export "exported_through_global") (mut funcref) (ref.func $g))
)
Function $g
can definitively be called from outside the module, in multiple ways. But when optimizing this module with the command wasm-opt --gufa -all -S -o - bug.wat
, the function's body is considered as unreachable:
(func $g (type $t) (param $0 i32) (result i32)
(unreachable)
)
I came upon this while trying to pass a Wasm function to JavaScript as a callback (something like function $passed_to_imported_function
above). But we have the same issue with the example in https://github.com/WebAssembly/binaryen/issues/5292.
GUFA atm assumes a closed world. I see we don't error without setting --closed-world
, which is a bug - sorry for the confusion.
That does mean we can't run GUFA on cases where you pass a wasm function to be called by JS. Perhaps in the future we can make it optimize only the things that don't "escape" the wasm module, but that is not a simple analysis, which is why we haven't done it yet.
This makes sense, indeed. Thanks for the clarification!