Inline the copying collector's bump allocation in Wasm code#13323
Conversation
Subscribe to Label Actioncc @fitzgen DetailsThis issue or pull request has been labeled: "wasmtime:api", "wasmtime:ref-types"Thus the following users have been cc'd because of the following labels:
To subscribe or unsubscribe from this label, edit the |
| unsafe fn vmctx_gc_heap_data(&self) -> NonNull<u8> { | ||
| // The copying collector doesn't currently have vmctx GC heap | ||
| // data. Return a dangling pointer. | ||
| NonNull::dangling() | ||
| let ptr: *const VMCopyingHeapData = &self.vmctx_data; | ||
| NonNull::new(ptr as *mut u8).unwrap() | ||
| } |
There was a problem hiding this comment.
This is preexisting I think for other collectors, but there's 2 primary ways that this method is UB according to Miri:
- This is deriving a pointer from
&selfwhich is later mutated through in compiled code. That's UB in Rust because by deriving the pointer from&selfyou're saying that the contents can't be mutated. This is a playground example showing the UB (top right, Tools -> Miri). The fix for this specific issue is to change this method to&mut selfand then have the implementation beNonNull::from(&mut self.vmctx_data).cast() - The second problem is that this struture is stored inline with the
CopyingHeap, which means that re-acquiring a mutable pointer toCopyingHeapwill actually invalidate the previous pointer returned by this method. This is a playground example of the UB here.
Fixing the latter one is not going to be super easy. I can think a few possible ways:
- Every time we return back to wasm re-acquire the pointer and put it back in the
VMContext. Probably too slow to work. - Place the VM data behind an indirection (e.g.
Box<VMCopyingHeapData>here). The goal is that by using&mut CopyingHeapit doesn't auto-invaildate the vmctx data structures. This alone is not enough, however. Another added fix necessary would be to create the raw pointer at creation ofCopyingHeap, and thenCopyingHeapitself only accesses the data through that pointer. The end result is sort of like this and models what we do withvm::Instanceand its siblingVMContextstorage data that comes after it.
I haven't double-checked, but I believe this would all plague the drc/null collectors as well. If you'd like I think it'd be reasonable to fix them all in a subsequent PR.
In terms of detecting all of this, in theory Miri should be able to capture everything here. I think that may mean we're not running much GC-compiled wasms through Miri, which might be a good addition to have? For miri coverage copying this line is probably the easiest. Along those lines rustup run nightly ./ci/miri-wast.sh ./tests/spec_testsuite/struct.wast locally shows a Miri violation which may be related to this, but it's always sort of hard to tell where exactly the miri error comes from due to the mix of pulley and lack of strict provenance...
There was a problem hiding this comment.
Will handle this in a follow up.
There was a problem hiding this comment.
Oh, another possible fix is like Store::data_mut where provenance of some Miri-safe pointer is used but the address is used like usual, meaning that the actual machine code doesn't change. This will still require an indirection, however, I think.
|
FWIW this is a 2% reduction in instructions retired on |
With 200 iterations: |
alexcrichton
left a comment
There was a problem hiding this comment.
Any idea what's going on with the splay benchmark? Is it not actually allocating that much? Or is something else so massively dominating that allocation isn't factoring in?
It has a few constants that control the size of the splay tree to create, the number of splay tree mutations to perform once its created, and one other thing that I forget. When porting it to Wasm, I replaced those constants with configurable parameters read from Also, it is written in an "idiomatic" style with lots of little functions, and we don't do any inlining by default. That could probably change things drastically for it. |
e862afd to
61bf89c
Compare

No description provided.