Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Commit

Permalink
Revised instruction-count bounding with fewer checks and loads/stores.
Browse files Browse the repository at this point in the history
This PR revises the simple instruction-count binding work, which
initially loaded and stored the instruction-count field from memory on
every basic block and emitted an extra conditional branch and yielding
block after every basic block, with two optimizations:

1. The instruction count is kept in a local variable (which the register
   allocator will ideally keep in a register unless spills are
   necessary), and this count is saved back to the field in memory only
   when necessary, e.g., before calls and returns.

2. The checks and conditional branches are inserted only in places where
   necessary to ensure bounded time between checks, at the cost of
   slightly more overrun/approximation in the bound: specifically,
   before calls and returns (to avoid unbounded runtime due to
   recursion) and at loop backedges.

This PR also includes a ridealong fix while updating the wasmtime
submodule having to do with module-linking work.
  • Loading branch information
cfallin committed Nov 25, 2020
1 parent edf0d15 commit cc3ce00
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 54 deletions.
16 changes: 12 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions lucet-runtime/lucet-runtime-internals/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ impl Instance {

self.resumed_val = Some(Box::new(val) as Box<dyn Any + 'static>);

self.set_instruction_bound_delta(max_insn_count.unwrap_or(0));
self.set_instruction_bound_delta(max_insn_count);
self.swap_and_return(async_context)
}

Expand All @@ -611,7 +611,7 @@ impl Instance {
"can only call resume_bounded() on an instance that hit an instruction bound",
));
}
self.set_instruction_bound_delta(max_insn_count);
self.set_instruction_bound_delta(Some(max_insn_count));
self.swap_and_return(true)
}

Expand Down Expand Up @@ -958,11 +958,12 @@ impl Instance {
/// value is *crossed*, but not if execution *begins* with the value exceeded. Hence `delta`
/// must be greater than zero for this to set up the instance state to trigger a yield.
#[inline]
pub fn set_instruction_bound_delta(&mut self, delta: u64) {
pub fn set_instruction_bound_delta(&mut self, delta: Option<u64>) {
let implicits = self.get_instance_implicits_mut();
let sum = implicits.instruction_count_adj + implicits.instruction_count_bound;
let delta = delta.unwrap_or(i64::MAX as u64);
let delta = i64::try_from(delta).expect("delta too large");
implicits.instruction_count_bound = sum + delta;
implicits.instruction_count_bound = sum.wrapping_add(delta);
implicits.instruction_count_adj = -delta;
}

Expand Down Expand Up @@ -1140,7 +1141,7 @@ impl Instance {
let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)];
args_with_vmctx.extend_from_slice(args);

self.set_instruction_bound_delta(inst_count_bound.unwrap_or(0));
self.set_instruction_bound_delta(inst_count_bound);

let self_ptr = self as *mut _;
Context::init_with_callback(
Expand Down
37 changes: 34 additions & 3 deletions lucetc/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,22 @@ impl<'a> Compiler<'a> {
self.decls.get_module_data(self.module_features())
}

fn get_local_count(body: &FunctionBody, name: &str) -> Result<u32, Error> {
let error_mapper = |e| Error::FunctionTranslation {
symbol: name.to_string(),
source: Box::new(Error::from(e)),
};
Ok(body
.get_locals_reader()
.map_err(|source| error_mapper(source))?
.into_iter()
.map(|result| result.map_err(|source| error_mapper(source)))
.collect::<Result<Vec<(u32, _)>, Error>>()?
.into_iter()
.map(|(count, _ty)| count)
.sum())
}

pub fn object_file(self) -> Result<ObjectFile, Error> {
let mut function_manifest_ctx = ClifDataContext::new();
let mut function_manifest_bytes = Cursor::new(Vec::new());
Expand All @@ -273,7 +289,15 @@ impl<'a> Compiler<'a> {
let func = decls
.get_func(unique_func_ix)
.expect("decl exists for func body");
let mut func_info = FuncInfo::new(&decls, &codegen_context, count_instructions);
let arg_count = func.signature.params.len() as u32;
let local_count = Self::get_local_count(&func_body, func.name.symbol())?;
let mut func_info = FuncInfo::new(
&decls,
&codegen_context,
count_instructions,
arg_count,
local_count,
);
let mut clif_context = ClifContext::new();
clif_context.func.name = func.name.as_externalname();
clif_context.func.signature = func.signature.clone();
Expand Down Expand Up @@ -450,8 +474,15 @@ impl<'a> Compiler<'a> {
.decls
.get_func(unique_func_ix)
.expect("decl exists for func body");
let mut func_info =
FuncInfo::new(&self.decls, &self.codegen_context, self.count_instructions);
let arg_count = func.signature.params.len() as u32;
let local_count = Self::get_local_count(&body, func.name.symbol())?;
let mut func_info = FuncInfo::new(
&self.decls,
&self.codegen_context,
self.count_instructions,
arg_count,
local_count,
);
let mut clif_context = ClifContext::new();
clif_context.func.name = func.name.as_externalname();
clif_context.func.signature = func.signature.clone();
Expand Down
3 changes: 3 additions & 0 deletions lucetc/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::types::SignatureError;
use crate::validate::Error as ValidationError;
use cranelift_module::ModuleError as ClifModuleError;
use cranelift_wasm::wasmparser::BinaryReaderError as ClifWasmReaderError;
use cranelift_wasm::WasmError as ClifWasmError;
use lucet_module::error::Error as LucetModuleError;
use object;
Expand All @@ -27,6 +28,8 @@ pub enum Error {
MissingWasmPreamble,
#[error("Wasm validation: {0}")]
WasmValidation(#[from] wasmparser::BinaryReaderError),
#[error("Wasm validation: {0}")]
ClifWasmValidation(#[from] ClifWasmReaderError),
#[error("Wat input: {0}")]
WatInput(#[from] wabt::Error),
#[error("Object artifact: {1}. {0:?}")]
Expand Down
Loading

0 comments on commit cc3ce00

Please sign in to comment.