Hi all! I'm playing with typed funcrefs to see about using them for efficient indirection (ICs); specifically I want globals that are mutable typed non-nullable funcrefs.
I've hit some perplexing behavior that I can't square with anything I see in the proposal doc; specifically, a ref.func
instruction yields an "undeclared function reference" error when validated by wasm-tools if the func it refers to is not also used in an init expression for a global or in a table element segment.
This validates:
(module
(type $ic (func (param i32 i32 i32 i32) (result i32)))
(global $ic1 (mut (ref $ic)) (ref.func $icfunc1))
(global $ic2 (mut (ref $ic)) (ref.func $icfunc2))
(func $icfunc1 (param i32 i32 i32 i32) (result i32)
local.get 0)
(func $icfunc2 (param i32 i32 i32 i32) (result i32)
local.get 1)
(func (export "setup")
ref.func $icfunc2
global.set $ic1))
but this does not:
(module
(type $ic (func (param i32 i32 i32 i32) (result i32)))
(global $ic1 (mut (ref $ic)) (ref.func $icfunc1))
(func $icfunc1 (param i32 i32 i32 i32) (result i32)
local.get 0)
(func $icfunc2 (param i32 i32 i32 i32) (result i32)
local.get 1)
(func (export "setup")
ref.func $icfunc2
global.set $ic1))
which looks like weird action-at-a-distance to me (removing global $ic2
affects validation of a function that doesn't mention it at all). Any thoughts @fitzgen (he/him) / @Alex Crichton / anyone else?
(validating with latest main
of wasm-tools
, using wasm-tools validate -f all file.wat
)
Any function that isn’t exported needs to be in an (elem declare …) element for you to ref.func it
Ah yeah this is expected behavior (albeit with a bad error message), this came about with the reference-types proposal
IIRC the intention was to enable runtimes to, before the code section has arrived, be able to enumerate functions which could "escape" through globals/tables/etc
ah, great, I had missed that; thanks!
Chris Fallin has marked this topic as resolved.
Thanks for working on this @Chris Fallin. I naively tried to use typed funcrefs in componentize-py
before realizing they weren't implemented yet. I look forward to revisiting that.
yup, I had a realization that they are exactly what I want for "just call a native function pointer with no checks plzkthx" performance
thanks folks (fitzgen I think?) for implementing them :-)
Should I take that to mean typed funcrefs already work in recent versions of Wasmtime? If so, that's awesome.
I think that call_ref
should work yeah, but I'll also note that the perf isn't quite there yet. Right now call_ref
still does the fully general typecheck
I don't think we've implemented the optimization where the type information from validation flows directly into translation
that's what would enable completely skipping typechecks and such
my experiments last night showed a null check still (and there's a comment in visit_call_ref
about removing it by threading type info, yeah), but no typecheck?
oh I must be misremembering the instruction then, I thought call_ref
took a funcref
as opposed to a (ref $ty)
Does anyone happen to know if typed funcrefs work in Node and/or recent browsers (e.g. if I were to use them in componentize-py
and run the result with Jco)?
https://webassembly.org/features/
they're a prereq for GC, so according to that ^^ at least FF and Chrome, but not Safari I guess
it pretty much folded into the gc proposal, and browsers don't generally differentiate at this point
Last updated: Dec 23 2024 at 12:05 UTC