binaryen icon indicating copy to clipboard operation
binaryen copied to clipboard

GUFA mishandles escaping functions

Open vouillon opened this issue 1 year ago • 2 comments

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.

vouillon avatar Jun 05 '23 12:06 vouillon

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.

kripken avatar Jun 05 '23 18:06 kripken

This makes sense, indeed. Thanks for the clarification!

vouillon avatar Jun 06 '23 12:06 vouillon