Stream: git-wasmtime

Topic: wasmtime / issue #8160 Wasmtime: avoid table lazy-init ru...


view this post on Zulip Wasmtime GitHub notifications bot (Mar 17 2024 at 20:23):

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

view this post on Zulip Wasmtime GitHub notifications bot (Mar 18 2024 at 14:54):

alexcrichton commented on issue #8160:

I like this idea! Some implementation points I can think of off the top of my head:

view this post on Zulip Wasmtime GitHub notifications bot (Mar 19 2024 at 21:08):

fitzgen commented on issue #8160:

See also https://github.com/bytecodealliance/wasmtime/issues/8002#issuecomment-2008139279

view this post on Zulip Wasmtime GitHub notifications bot (Mar 20 2024 at 05:18):

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.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 20 2024 at 21:09):

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.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 25 2024 at 20:51):

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