cfallin opened issue #8160:
From this comment: it would be great to have an optimization such that
if a table's default funcref is null, don't do lazy-init, and make the 0 bit-pattern mean null rather than non-initialized-pointer-to-anyfunc.
This comes from a circumstance where we know we'll initialize a table slot manually before calling it (not doing so is a program error that should lead to a trap), possibly because we already have a branch for the case where it is null at the program-logic level (e.g. fallback IC). We still must trap on null somehow but #8159 can do that implicitly by detecting a segfault in a load from a
NULL
anyfunc pointer. The above optimization then means that we do not need the lengthy lazy-init-check sequence on loads from such tables, and we can do so without requiring any initialization at instantiation time either.cc @alexcrichton @jameysharp
alexcrichton commented on issue #8160:
I like this idea! Some implementation points I can think of off the top of my head:
- This would only be applicable when there are no
elem
segments with non-null entries for a table.- We'd need to store runtime state for each table to know whether it contains tagged functions or non-tagged functions.
- In the
Module
's type information we'd need to store this in aTablePlan
as well so the table access codegen could take it into account as well as runtime instantiation
fitzgen commented on issue #8160:
See also https://github.com/bytecodealliance/wasmtime/issues/8002#issuecomment-2008139279
jameysharp commented on issue #8160:
An additional requirement, I think, is that we can only do this for tables which are not exported. If another module imports a table, it has no way of knowing at compile time whether this optimization applies.
I think this technique is still broadly applicable in spite of that though.
Nick pointed out that we could build a static page full of pointers which are null except the low bit is set, and CoW-map that page repeatedly as the initial table contents, if we know that the table is initially all null. That would be compatible with codegen that can't optimize away the lazy-init check, which would make it safe to export such tables.
He also pointed out that we could use the same trick to swap the meaning of our sentinel values: a
(void*)1
would then mean "uninitialized", but we could still instantiate quickly without writing a bunch of bytes into a bunch of new pages. Then we'd be able to avoid setting and clearing the lazy-init flag on every table access. When we can prove the initial values are all null, we'd map zero-filled pages instead.We discussed many more ideas, but I'll leave it at that for now.
alexcrichton commented on issue #8160:
We talked some more in the Cranelift meeting this morning again about this and I wanted to summarize our thinking here as well.
The main realization we had was that we can address the concern of "now there's two kinds of null pointers" by, well, not having two kinds of null pointers. For example initialization of of an all-null table where the null pointer is
(void*) 1
would be a bulk-initialization using that value (a memset-but-with-usize-value-things). Either that or an mmap'd memfd or page or something to use VM tricks. More-or-less we realized that we could implement the optimization in this issue, fast initialization of all-null tables, and then in codegen we can omit all lazy init checks since everything is statically known to be initialized.
cfallin commented on issue #8160:
As a quick data-point to drop here: in a very hacky (work-in-progress) dev branch of SpiderMonkey + weval with traditional funcptr ICs with signature checks simply removed (unsafe!), I measured the impact of the lazy-init table scheme on runtime directly and came up with ~8% -- fairly significant and makes the optimizations discussed here worthwhile, IMHO. (I'm going to "speculatively live in the glorious future" with this branch of wasmtime for all my experiments, which also removes table bounds-checks and stack limit checks, and hope that we can productionize all of this at some point!)
Last updated: Dec 23 2024 at 12:05 UTC