-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Improve signature lookup happening during instantiation #2818
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,15 +43,6 @@ impl StoreFrameInfo { | |
| .map(|info| (info, module.has_unparsed_debuginfo())) | ||
| } | ||
|
|
||
| /// Returns whether the `pc` specified is contained within some module's | ||
| /// function. | ||
| pub fn contains_pc(&self, pc: usize) -> bool { | ||
| match self.module(pc) { | ||
| Some(module) => module.contains_pc(pc), | ||
| None => false, | ||
| } | ||
| } | ||
|
|
||
| /// Fetches trap information about a program counter in a backtrace. | ||
| pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> { | ||
| self.module(pc)?.lookup_trap_info(pc) | ||
|
|
@@ -79,10 +70,6 @@ impl StoreFrameInfo { | |
| // may be a valid PC value | ||
| let end = end - 1; | ||
|
|
||
| if self.contains_pc(start) { | ||
| return; | ||
| } | ||
|
|
||
|
Comment on lines
-82
to
-85
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly confused with what's going on over here.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was ensuring we don't register the same module more than once in the store, however, this could probably just be
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh wait, I just caught up to the changes below. Yeah, this shouldn't be necessary any more. |
||
| // Assert that this module's code doesn't collide with any other registered modules | ||
| if let Some((_, prev)) = self.ranges.range(end..).next() { | ||
| assert!(prev.start > end); | ||
|
|
@@ -191,12 +178,6 @@ impl ModuleFrameInfo { | |
| }) | ||
| } | ||
|
|
||
| /// Returns whether the `pc` specified is contained within some module's | ||
| /// function. | ||
| pub fn contains_pc(&self, pc: usize) -> bool { | ||
| self.func(pc).is_some() | ||
| } | ||
|
|
||
| /// Fetches trap information about a program counter in a backtrace. | ||
| pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> { | ||
| let (index, offset) = self.func(pc)?; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,11 @@ | ||
| //! Implement a registry of function signatures, for fast indirect call | ||
| //! signature checking. | ||
|
|
||
| use crate::Module; | ||
| use std::collections::{hash_map, HashMap}; | ||
| use std::convert::TryFrom; | ||
| use wasmtime_environ::wasm::WasmFuncType; | ||
| use wasmtime_environ::entity::PrimaryMap; | ||
| use wasmtime_environ::wasm::{SignatureIndex, WasmFuncType}; | ||
| use wasmtime_runtime::{VMSharedSignatureIndex, VMTrampoline}; | ||
|
|
||
| /// WebAssembly requires that the caller and callee signatures in an indirect | ||
|
|
@@ -33,12 +35,40 @@ struct Entry { | |
| } | ||
|
|
||
| impl SignatureRegistry { | ||
| /// Register a signature and return its unique index. | ||
| /// Registers all signatures within a module into this registry all at once. | ||
| /// | ||
| /// Note that `trampoline` can be `None` which indicates that an index is | ||
| /// desired for this signature but the trampoline for it is not compiled or | ||
| /// available. | ||
| /// This will also internally register trampolines compiled in the module. | ||
| pub fn register_module(&mut self, module: &Module) { | ||
| // Register a unique index for all types in this module, even if they | ||
| // don't have a trampoline. | ||
| let signatures = &module.types().wasm_signatures; | ||
| for ty in module.compiled_module().module().types.values() { | ||
| if let wasmtime_environ::ModuleType::Function(index) = ty { | ||
| self.register_one(&signatures[*index], None); | ||
| } | ||
| } | ||
|
|
||
| // Once we've got a shared index for all types used then also fill in | ||
| // any trampolines that the module has compiled as well. | ||
| for (index, trampoline) in module.compiled_module().trampolines() { | ||
| let shared = self.wasm2index[&signatures[*index]]; | ||
| let entry = &mut self.index_map[shared.bits() as usize]; | ||
| if entry.trampoline.is_none() { | ||
| entry.trampoline = Some(*trampoline); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Register a signature and return its unique index. | ||
| pub fn register( | ||
| &mut self, | ||
| wasm: &WasmFuncType, | ||
| trampoline: VMTrampoline, | ||
| ) -> VMSharedSignatureIndex { | ||
| self.register_one(wasm, Some(trampoline)) | ||
| } | ||
|
|
||
| fn register_one( | ||
| &mut self, | ||
| wasm: &WasmFuncType, | ||
| trampoline: Option<VMTrampoline>, | ||
|
|
@@ -80,6 +110,34 @@ impl SignatureRegistry { | |
| self.wasm2index.get(wasm).cloned() | ||
| } | ||
|
|
||
| /// Builds a lookup table for a module from the possible module's signature | ||
| /// indices to the shared signature index within this registry. | ||
| pub fn lookup_table( | ||
| &self, | ||
| module: &Module, | ||
| ) -> PrimaryMap<SignatureIndex, VMSharedSignatureIndex> { | ||
|
Comment on lines
+113
to
+118
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than returning the I suppose -- at that point, though -- we might as well move this out and cache it ✨ somewhere ✨ like you mention in the OP. I guess finding that somewhere is a bit hard because
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm good point! Given what we were discussing on chat though where this may soon move into a |
||
| // For module-linking using modules this builds up a map that is | ||
| // too large. This builds up a map for everything in `TypeTables` but | ||
| // that's all the types for all modules in a whole module linking graph, | ||
| // which our `module` may not be using. | ||
| // | ||
| // For all non-module-linking-using modules, though, this is not an | ||
| // issue. This is optimizing for the non-module-linking case right now | ||
| // and it seems like module linking will likely change to the point that | ||
| // this will no longer be an issue in the future. | ||
| let signatures = &module.types().wasm_signatures; | ||
| let mut map = PrimaryMap::with_capacity(signatures.len()); | ||
| for wasm in signatures.values() { | ||
| map.push( | ||
| self.wasm2index | ||
| .get(wasm) | ||
| .cloned() | ||
| .unwrap_or(VMSharedSignatureIndex::new(u32::MAX)), | ||
| ); | ||
| } | ||
| map | ||
| } | ||
|
|
||
| /// Looks up information known about a shared signature index. | ||
| /// | ||
| /// Note that for this operation to be semantically correct the `idx` must | ||
|
|
||
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.
Was this showing up in profiles? It seems unrelated to the rest of the changes in this PR and the early return seems like it is necessary to avoid tripping the
assert!(old.is_none())assertion at the end of this function.