From eb42a2547eb9877e4ae020aef1d548c5408d0438 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 13 Sep 2017 11:35:33 -0700 Subject: [PATCH] Add helper routines for special-purpose arguments. - ArgumentType::special() creates a new special-purpose argument without assigning it to a register location. - Signature::special_arg_index() funds a unique special-purpose argument. - Function::special_arg() finds a special-purpose argument by value. Also add a new "sigid" argument purpose which will be used for runtime signature checks in WebAssembly indirect calls. --- lib/cretonne/src/ir/extfunc.rs | 26 +++++++++++++++++++++++++- lib/cretonne/src/ir/function.rs | 10 ++++++++++ lib/cretonne/src/legalizer/boundary.rs | 9 +++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/cretonne/src/ir/extfunc.rs b/lib/cretonne/src/ir/extfunc.rs index 353d49256e..5983182d87 100644 --- a/lib/cretonne/src/ir/extfunc.rs +++ b/lib/cretonne/src/ir/extfunc.rs @@ -76,6 +76,13 @@ impl Signature { pub fn display<'a, R: Into>>(&'a self, regs: R) -> DisplaySignature<'a> { DisplaySignature(self, regs.into()) } + + /// Find the index of a presumed unique special-purpose argument. + pub fn special_arg_index(&self, purpose: ArgumentPurpose) -> Option { + self.argument_types.iter().rposition( + |arg| arg.purpose == purpose, + ) + } } /// Wrapper type capable of displaying a `Signature` with correct register names. @@ -146,6 +153,16 @@ impl ArgumentType { } } + /// Create a special-purpose argument type that is not (yet) bound to a specific register. + pub fn special(vt: Type, purpose: ArgumentPurpose) -> ArgumentType { + ArgumentType { + value_type: vt, + extension: ArgumentExtension::None, + purpose, + location: Default::default(), + } + } + /// Create an argument type for a special-purpose register. pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> ArgumentType { ArgumentType { @@ -255,10 +272,16 @@ pub enum ArgumentPurpose { /// This is a pointer to a context struct containing details about the current sandbox. It is /// used as a base pointer for `vmctx` global variables. VMContext, + + /// A signature identifier. + /// + /// This is a special-purpose argument used to identify the calling convention expected by the + /// caller in an indirect call. The callee can verify that the expected signature ID matches. + SignatureId, } /// Text format names of the `ArgumentPurpose` variants. -static PURPOSE_NAMES: [&str; 6] = ["normal", "sret", "link", "fp", "csr", "vmctx"]; +static PURPOSE_NAMES: [&str; 7] = ["normal", "sret", "link", "fp", "csr", "vmctx", "sigid"]; impl fmt::Display for ArgumentPurpose { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -276,6 +299,7 @@ impl FromStr for ArgumentPurpose { "fp" => Ok(ArgumentPurpose::FramePointer), "csr" => Ok(ArgumentPurpose::CalleeSaved), "vmctx" => Ok(ArgumentPurpose::VMContext), + "sigid" => Ok(ArgumentPurpose::SignatureId), _ => Err(()), } } diff --git a/lib/cretonne/src/ir/function.rs b/lib/cretonne/src/ir/function.rs index 0c86ac66e0..f7ba244ae0 100644 --- a/lib/cretonne/src/ir/function.rs +++ b/lib/cretonne/src/ir/function.rs @@ -135,6 +135,16 @@ impl Function { pub fn display<'a, I: Into>>(&'a self, isa: I) -> DisplayFunction<'a> { DisplayFunction(self, isa.into()) } + + /// Find a presumed unique special-purpose function argument value. + /// + /// Returns the value of the last `purpose` argument, or `None` if no such argument exists. + pub fn special_arg(&self, purpose: ir::ArgumentPurpose) -> Option { + let entry = self.layout.entry_block().expect("Function is empty"); + self.signature.special_arg_index(purpose).map(|i| { + self.dfg.ebb_args(entry)[i] + }) + } } /// Wrapper type capable of displaying a `Function` with correct ISA annotations. diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/cretonne/src/legalizer/boundary.rs index a5442ba8be..2e16627efe 100644 --- a/lib/cretonne/src/legalizer/boundary.rs +++ b/lib/cretonne/src/legalizer/boundary.rs @@ -57,6 +57,7 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) { let mut has_sret = false; let mut has_link = false; let mut has_vmctx = false; + let mut has_sigid = false; // Insert position for argument conversion code. // We want to insert instructions before the first instruction in the entry block. @@ -91,6 +92,10 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) { assert!(!has_vmctx, "Multiple vmctx arguments found"); has_vmctx = true; } + ArgumentPurpose::SignatureId => { + assert!(!has_sigid, "Multiple sigid arguments found"); + has_sigid = true; + } _ => panic!("Unexpected special-purpose arg {}", abi_types[abi_arg]), } abi_arg += 1; @@ -145,6 +150,10 @@ fn legalize_entry_arguments(func: &mut Function, entry: Ebb) { assert!(!has_vmctx, "Multiple vmctx arguments found"); has_vmctx = true; } + ArgumentPurpose::SignatureId => { + assert!(!has_sigid, "Multiple sigid arguments found"); + has_sigid = true; + } } // Just create entry block values to match here. We will use them in `handle_return_abi()`