-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
wasmtime: Make table lazy-init configurable #8531
wasmtime: Make table lazy-init configurable #8531
Conversation
Subscribe to Label Action
This issue or pull request has been labeled: "wasmtime:api", "wasmtime:config", "winch"
Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
Label Messager: wasmtime:configIt looks like you are changing Wasmtime's configuration options. Make sure to
To modify this label's message, edit the To add new label messages or remove existing label messages, edit the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of adding this, good idea!
Some other bits I might recommend:
- Mind adding a CLI flag under
-O
for this as well? - For testing it might also be good enough to "just" hook this up to fuzzing
- Want to add a
disas
test or two with this flag?
@@ -701,29 +726,60 @@ impl Table { | |||
self.element_type().matches(val) | |||
} | |||
|
|||
fn funcrefs(&self) -> &[TaggedFuncRef] { | |||
fn funcrefs(&self) -> (&[TaggedFuncRef], bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about perhaps returning enum Funcrefs<'a> { Tagged(&'a [TaggedFuncRef]), Untagged(&'a [*mut VMFuncRef]) }
here? That feels a bit more "type safe" if a bit wordier and reflects how this is a boolean decision at runtime as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this idea, but while testing it out, I found so many more things I want to change about how the lazy-tagging invariants are maintained in these modules that I don't think I want to change any of them in this PR. 😅 A few:
- Getting a table reference should return enough information that the caller can initialize any elements it needs to, instead of passing in a range of indexes to init.
Table::get
and table copies should take&mut src
and init the elements they need in-place; the caller always has a mutable pointer.- Therefore, there's no need for
funcrefs()
, onlyfuncrefs_mut()
. StaticFuncTable
should maybe put the current size in thedata
slice and the capacity in a separate field; it's currently the other way around.funcrefs_mut()
is shorter and easier to reason about if it first getselements.as_mut_slice()
/unsafe { data.as_mut() }
depending on whether the table is static or dynamic, and then afterwards does the unsafeslice::from_raw_parts_mut
. I mixed up*mut [T]
with*mut [*mut [T]]
at one point and was afraid the.cast()
would just silently "fix" it for me- I'm imagining something resembling
MaybeUninit
as an interface for tracking at the type level whether it's okay to read a range of the table
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That all sounds great to me yeah, and seems fine to leave this as-is returning a bool in the meantime
TableStyle::CallerChecksSignature { lazy_init: true } => { | ||
self.emit_lazy_init_funcref(table_index) | ||
} | ||
_ => unimplemented!("Support for eager table init"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this remains (which I think is fine) mind adding a check in Config::validate
that returns an error if winch is enabled but lazy init is disabled?
Lazy initialization of tables has trade-offs that we haven't explored in a while. Making it configurable makes it easier to test the effects of these trade-offs on a variety of WebAssembly programs, and allows embedders to decide whether the trade-offs are worth-while for their use cases.
19c4249
to
06c9a6c
Compare
I think I've addressed all of your suggestions, Alex; thank you for them! I'm trying to coax the fuzzer to discover an artificial bug I added in the non-lazy-init configuration just to make sure it can, and it's been running for a while without finding it. So maybe you (or whoever reviews this) can double-check if I did something wrong in the fuzzer configuration? |
Okay, I've learned that the But I'm still not sure why |
Nevermind, So I think this is ready to land. |
Subscribe to Label Actioncc @fitzgen
This issue or pull request has been labeled: "fuzzing"
Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
We should really add a top-down generation mode to |
Lazy initialization of tables has trade-offs that we haven't explored in a while. Making it configurable makes it easier to test the effects of these trade-offs on a variety of WebAssembly programs, and allows embedders to decide whether the trade-offs are worth-while for their use cases.
TODO:
-O
groupConfig::validate
that when Winch is enabled so is lazy-initdisas
tests with lazy init disabledI've tested this by temporarily setting the flag to disable lazy-init by default (in
crates/environ/src/tunables.rs
) and verifying that the test suite still passes, except for a bunch of Winch tests (as expected), as well as the amusing case ofcode_too_large::code_too_large_without_panic
, which fails because disabling lazy-init deletes enough code that the code is no longer too large.With lazy-init disabled, the
disas
tests show that this shaves off six or seven CLIF instructions and a cold block percall_indirect
ortable_get
. Thetyped-funcrefs.wat
test becomes branch-free, with two loads and an indirect call percall_indirect
, making it equivalent to the version that uses globals instead of tables.cc: @cfallin