-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Use relative call instructions between wasm functions
#3254
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
e81a090
9588aba
d0278f0
c2665bf
f0bbc6b
d475194
63c0e77
c1ab805
41e191a
0c47bde
97853e4
1323014
3039140
6f64ab4
cb119a6
a50ccfd
faff1d4
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 |
|---|---|---|
|
|
@@ -425,6 +425,34 @@ pub trait MachBackend { | |
| fn map_reg_to_dwarf(&self, _: Reg) -> Result<u16, RegisterMappingError> { | ||
| Err(RegisterMappingError::UnsupportedArchitecture) | ||
| } | ||
|
|
||
| /// Generates as "veneer" which is used when a relative call instruction | ||
|
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. Two thoughts on this new addition to the backend trait:
Contributor
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 function could be useful for cranelift-jit too. It also needs a version that loads the address from memory at a specific location like ELF PLT's. Currently it only has a x86_64 version for the latter function. |
||
| /// cannot reach to the destination. | ||
| /// | ||
| /// Cranelift compiles wasm modules on a per-function basis entirely | ||
| /// isolated from all other functions. Functions also, ideally, use relative | ||
| /// calls between them to avoid needing relocation fixups when a module is | ||
| /// loaded and also having statically more predictable calls. These jumps, | ||
| /// however, may not always be able to reach the destination depending on | ||
| /// the final layout of the executable. | ||
| /// | ||
| /// This function is used to generate an executable code sequence which can | ||
| /// be used to jump to an arbitrary pointer-sized immediate. This is | ||
| /// only used when functions are too far apart to call each other with | ||
| /// relative call instructions. | ||
| /// | ||
| /// The first return of this function is the machine code of the veneer, and | ||
| /// the second argument is the offset, within the veneer, where an 8-byte | ||
| /// immediate needs to be written of the target destination. The veneer, | ||
| /// when jumped to, will add the 8-byte immediate to the address of the | ||
| /// 8-byte immediate and jump to that location. This means that the veneer | ||
| /// will do a relative jump to the final location, and the relative jump | ||
| /// uses a pointer-sized immediate to make the jump. | ||
| fn generate_jump_veneer(&self) -> (Vec<u8>, usize); | ||
|
|
||
| /// Returns the maximal size of the veneer returned by | ||
| /// `generate_jump_veneer`. | ||
| fn max_jump_veneer_size(&self) -> usize; | ||
| } | ||
|
|
||
| /// Expected unwind info type. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,20 @@ use wasmtime_environ::{CompilerBuilder, Setting, SettingKind}; | |
| struct Builder { | ||
| flags: settings::Builder, | ||
| isa_flags: isa::Builder, | ||
| linkopts: LinkOptions, | ||
| } | ||
|
|
||
| #[derive(Clone, Default)] | ||
| pub struct LinkOptions { | ||
| /// A debug-only setting used to synthetically insert 0-byte padding between | ||
| /// compiled functions to simulate huge compiled artifacts and exercise | ||
| /// logic related to jump veneers. | ||
| pub padding_between_functions: usize, | ||
|
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. Do we still need this if we have the option below (force veneers) as well?
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. I'm going to leave this in for now because I think it's useful to exercise the veneers in real-world situations where they're actually needed. Otherwise I'd be worried that the logic for actually inserting veneers was only correct when the forcing was turned on. This way there's some exercising of the actual "ok yes we need that veneer" logic as well. (it's also relatively easy to support).
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. Makes sense! Would it make sense to use it only in tests with the aarch64 backend (could be instantiated explicitly, doesn't need to run on aarch64 host), where the threshold for inserting an island is much lower, so we don't have the overhead of 2GiB object files in tests on x86? |
||
|
|
||
| /// A debug-only setting used to force inter-function calls in a wasm module | ||
| /// to always go through "jump veneers" which are typically only generated | ||
| /// when functions are very far from each other. | ||
| pub force_jump_veneers: bool, | ||
| } | ||
|
|
||
| pub fn builder() -> Box<dyn CompilerBuilder> { | ||
|
|
@@ -32,6 +46,7 @@ pub fn builder() -> Box<dyn CompilerBuilder> { | |
| Box::new(Builder { | ||
| flags, | ||
| isa_flags: cranelift_native::builder().expect("host machine is not a supported target"), | ||
| linkopts: LinkOptions::default(), | ||
| }) | ||
| } | ||
|
|
||
|
|
@@ -50,6 +65,17 @@ impl CompilerBuilder for Builder { | |
| } | ||
|
|
||
| fn set(&mut self, name: &str, value: &str) -> Result<()> { | ||
| // Special wasmtime-cranelift-only settings first | ||
| if name == "wasmtime_linkopt_padding_between_functions" { | ||
| self.linkopts.padding_between_functions = value.parse()?; | ||
| return Ok(()); | ||
| } | ||
| if name == "wasmtime_linkopt_force_jump_veneer" { | ||
| self.linkopts.force_jump_veneers = value.parse()?; | ||
| return Ok(()); | ||
| } | ||
|
|
||
| // ... then forward this to Cranelift | ||
| if let Err(err) = self.flags.set(name, value) { | ||
| match err { | ||
| SetError::BadName(_) => { | ||
|
|
@@ -80,7 +106,7 @@ impl CompilerBuilder for Builder { | |
| .isa_flags | ||
| .clone() | ||
| .finish(settings::Flags::new(self.flags.clone())); | ||
| Box::new(crate::compiler::Compiler::new(isa)) | ||
| Box::new(crate::compiler::Compiler::new(isa, self.linkopts.clone())) | ||
| } | ||
|
|
||
| fn settings(&self) -> Vec<Setting> { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.