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.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-13 11:35:33 -07:00
parent ef27c3daf0
commit eb42a2547e
3 changed files with 44 additions and 1 deletions

View File

@@ -76,6 +76,13 @@ impl Signature {
pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'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<usize> {
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(()),
}
}

View File

@@ -135,6 +135,16 @@ impl Function {
pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'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<ir::Value> {
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.

View File

@@ -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()`