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

Allow use of pinned heap registers #512

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions benchmarks/lucet-benchmarks/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ fn context_init(c: &mut Criterion) {

c.bench_function("context_init", move |b| {
b.iter(|| {
ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
ContextHandle::create_and_init(&mut *stack, f as usize, &[], std::ptr::null_mut())
.unwrap();
})
});
}
Expand All @@ -22,7 +23,13 @@ fn context_swap_return(c: &mut Criterion) {
b.iter_batched(
|| {
let mut stack = vec![0u64; 1024].into_boxed_slice();
let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
let child = ContextHandle::create_and_init(
&mut *stack,
f as usize,
&[],
std::ptr::null_mut(),
)
.unwrap();
(stack, child)
},
|(stack, mut child)| unsafe {
Expand All @@ -44,8 +51,13 @@ fn context_init_swap_return(c: &mut Criterion) {
|| vec![0u64; 1024].into_boxed_slice(),
|mut stack| {
let mut parent = ContextHandle::new();
let mut child =
ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
let mut child = ContextHandle::create_and_init(
&mut *stack,
f as usize,
&[],
std::ptr::null_mut(),
)
.unwrap();
unsafe { Context::swap(&mut parent, &mut child) };
stack
},
Expand Down Expand Up @@ -332,8 +344,13 @@ fn context_init_swap_return_many_args(c: &mut Criterion) {
|| vec![0u64; 1024].into_boxed_slice(),
|mut stack| {
let mut parent = ContextHandle::new();
let mut child =
ContextHandle::create_and_init(&mut *stack, f as usize, &args).unwrap();
let mut child = ContextHandle::create_and_init(
&mut *stack,
f as usize,
&args,
std::ptr::null_mut(),
)
.unwrap();
unsafe { Context::swap(&mut parent, &mut child) };
stack
},
Expand Down
4 changes: 4 additions & 0 deletions lucet-module/src/module_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ pub struct ModuleFeatures {
pub lzcnt: bool,
pub popcnt: bool,
pub instruction_count: bool,
pub pinned_heap: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How's it sound to make this an Option<HeapPinStyle>? Then None means "no pinning", and HeapPinStyle can be written like

#[repr(u8)]
enum HeapPinStyle {
    PinR15 = 1
}

that we can extend if need be in the future?

I mostly want to avoid a cranelift RegUnit, even in u16 form in lucet-module - the stability of those numbers isn't guaranteed, so we could misinterpret an old module, or an old runtime could misinterpret a new module.

pub pinned_heap_register: u16,
_hidden: (),
}

Expand All @@ -75,6 +77,8 @@ impl ModuleFeatures {
lzcnt: false,
popcnt: false,
instruction_count: false,
pinned_heap: false,
pinned_heap_register: 0,
_hidden: (),
}
}
Expand Down
2 changes: 2 additions & 0 deletions lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ macro_rules! alloc_tests {
inst.alloc_mut().stack_u64_mut(),
heap_touching_child as usize,
&[Val::CPtr(heap_ptr)],
heap_ptr,
)
.expect("context init succeeds");
Context::swap(&mut parent, &mut child);
Expand Down Expand Up @@ -705,6 +706,7 @@ macro_rules! alloc_tests {
inst.alloc_mut().stack_u64_mut(),
stack_pattern_child as usize,
&[Val::CPtr(heap_ptr)],
heap_ptr,
)
.expect("context init succeeds");
Context::swap(&mut parent, &mut child);
Expand Down
13 changes: 12 additions & 1 deletion lucet-runtime/lucet-runtime-internals/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@ impl ContextHandle {
stack: &mut [u64],
fptr: usize,
args: &[Val],
heap: *mut core::ffi::c_void,
) -> Result<ContextHandle, Error> {
let mut child = ContextHandle::new();
Context::init(stack, &mut child, fptr, args)?;
Context::init(stack, &mut child, fptr, args, heap)?;
Ok(child)
}
}
Expand Down Expand Up @@ -303,6 +304,7 @@ impl Context {
/// &mut child,
/// entrypoint as usize,
/// &[Val::U64(120), Val::F32(3.14)],
/// std::ptr::null_mut(),
/// );
/// assert!(res.is_ok());
/// ```
Expand All @@ -326,6 +328,7 @@ impl Context {
/// &mut child,
/// entrypoint as usize,
/// &[Val::U64(120), Val::F32(3.14)],
/// std::ptr::null_mut(),
/// );
/// assert!(res.is_ok());
/// ```
Expand Down Expand Up @@ -367,6 +370,7 @@ impl Context {
child: &mut Context,
fptr: usize,
args: &[Val],
heap: *mut core::ffi::c_void,
) -> Result<(), Error> {
Context::init_with_callback(
stack,
Expand All @@ -375,6 +379,7 @@ impl Context {
ptr::null_mut(),
fptr,
args,
heap,
)
}

Expand All @@ -393,6 +398,7 @@ impl Context {
callback_data: *mut Instance,
fptr: usize,
args: &[Val],
heap: *mut core::ffi::c_void,
) -> Result<(), Error> {
if !stack_is_aligned(stack) {
return Err(Error::UnalignedStack);
Expand Down Expand Up @@ -475,6 +481,10 @@ impl Context {
// even at the entrypoint of the guest.
child.gpr.rbp = child as *const Context as u64;

// Heap pinning: r15 is not used to pass any parameters on Windows/POSIX abis, we simply set this to be the value of the heap always.
// This value will be used only when the lucet module loaded is compiled requiring use of the pinned heap register.
child.gpr.r15 = heap as u64;

Ok(())
}

Expand Down Expand Up @@ -547,6 +557,7 @@ impl Context {
/// &mut child,
/// entrypoint as usize,
/// &[],
/// std::ptr::null_mut(),
/// ).unwrap();
///
/// unsafe { Context::swap(&mut parent, &mut child); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ macro_rules! init_and_swap {
&mut *$stack,
$fn as usize,
&[$( $args ),*],
std::ptr::null_mut(),
).unwrap()));

child_regs = child;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ fn init_rejects_unaligned() {
let mut stack_unaligned = unsafe { slice::from_raw_parts_mut(ptr, len) };

// now we have the unaligned stack, let's make sure it blows up right
let res = ContextHandle::create_and_init(&mut stack_unaligned, dummy as usize, &[]);
let res = ContextHandle::create_and_init(
&mut stack_unaligned,
dummy as usize,
&[],
std::ptr::null_mut(),
);

if let Err(Error::UnalignedStack) = res {
assert!(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ macro_rules! init_and_swap {
&mut *$stack,
$fn as usize,
&[$( $args ),*],
std::ptr::null_mut(),
).unwrap();
CHILD = Some(child);

Expand Down
4 changes: 3 additions & 1 deletion lucet-runtime/lucet-runtime-internals/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,8 @@ impl Instance {

self.entrypoint = Some(func);

let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)];
let heap = self.alloc.slot().heap;
let mut args_with_vmctx = vec![Val::from(heap)];
args_with_vmctx.extend_from_slice(args);

let self_ptr = self as *mut _;
Expand All @@ -984,6 +985,7 @@ impl Instance {
self_ptr,
func.ptr.as_usize(),
&args_with_vmctx,
heap,
)?;

self.install_activator();
Expand Down
3 changes: 2 additions & 1 deletion lucetc/lucetc/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ pub fn run(opts: &Options) -> Result<(), Error> {
.with_bindings(bindings)
.with_opt_level(opts.opt_level)
.with_cpu_features(opts.cpu_features.clone())
.with_target(opts.target.clone());
.with_target(opts.target.clone())
.with_pinned_heap(opts.pinned_heap);

if let Some(validator) = validator.take() {
c.validator(validator);
Expand Down
9 changes: 9 additions & 0 deletions lucetc/lucetc/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub struct Options {
pub pk_path: Option<PathBuf>,
pub sk_path: Option<PathBuf>,
pub count_instructions: bool,
pub pinned_heap: bool,
pub error_style: ErrorStyle,
pub target: Triple,
}
Expand Down Expand Up @@ -211,6 +212,7 @@ impl Options {
let sk_path = m.value_of("sk_path").map(PathBuf::from);
let pk_path = m.value_of("pk_path").map(PathBuf::from);
let count_instructions = m.is_present("count_instructions");
let pinned_heap = m.is_present("pinned_heap");

let error_style = match m.value_of("error_style") {
None => ErrorStyle::default(),
Expand Down Expand Up @@ -239,6 +241,7 @@ impl Options {
sk_path,
pk_path,
count_instructions,
pinned_heap,
error_style,
target,
})
Expand Down Expand Up @@ -452,6 +455,12 @@ SSE3 but not AVX:
.takes_value(false)
.help("Instrument the produced binary to count the number of wasm operations the translated program executes")
)
.arg(
Arg::with_name("pinned_heap")
.long("--pinned-heap-reg")
.takes_value(false)
.help("This feature is not stable - it may be removed in the future! Pin a register to use as this module's heap base. Typically improves performance.")
)
.arg(
Arg::with_name("error_style")
.long("error-style")
Expand Down
36 changes: 35 additions & 1 deletion lucetc/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::traps::{translate_trapcode, trap_sym_for_func};
use byteorder::{LittleEndian, WriteBytesExt};
use cranelift_codegen::{
binemit, ir,
isa::RegUnit,
isa::TargetIsa,
settings::{self, Configurable},
Context as ClifContext,
Expand Down Expand Up @@ -63,6 +64,7 @@ pub struct CompilerBuilder {
heap_settings: HeapSettings,
count_instructions: bool,
canonicalize_nans: bool,
pinned_heap: bool,
validator: Option<Validator>,
}

Expand All @@ -75,6 +77,7 @@ impl CompilerBuilder {
heap_settings: HeapSettings::default(),
count_instructions: false,
canonicalize_nans: false,
pinned_heap: false,
validator: None,
}
}
Expand Down Expand Up @@ -145,6 +148,15 @@ impl CompilerBuilder {
self
}

pub fn pinned_heap(&mut self, pinned_heap: bool) {
self.pinned_heap = pinned_heap;
}

pub fn with_pinned_heap(mut self, pinned_heap: bool) -> Self {
self.pinned_heap(pinned_heap);
self
}

pub fn validator(&mut self, validator: Option<Validator>) {
self.validator = validator;
}
Expand All @@ -169,6 +181,7 @@ impl CompilerBuilder {
self.count_instructions,
&self.validator,
self.canonicalize_nans,
self.pinned_heap,
)
}
}
Expand All @@ -182,6 +195,8 @@ pub struct Compiler<'a> {
count_instructions: bool,
module_translation_state: ModuleTranslationState,
canonicalize_nans: bool,
pinned_heap: bool,
pinned_heap_register: RegUnit,
}

impl<'a> Compiler<'a> {
Expand All @@ -195,8 +210,15 @@ impl<'a> Compiler<'a> {
count_instructions: bool,
validator: &Option<Validator>,
canonicalize_nans: bool,
pinned_heap: bool,
) -> Result<Self, Error> {
let isa = Self::target_isa(target.clone(), opt_level, &cpu_features, canonicalize_nans)?;
let isa = Self::target_isa(
target.clone(),
opt_level,
&cpu_features,
canonicalize_nans,
pinned_heap,
)?;

let frontend_config = isa.frontend_config();
let mut module_info = ModuleInfo::new(frontend_config.clone());
Expand Down Expand Up @@ -228,6 +250,8 @@ impl<'a> Compiler<'a> {
_ => (cranelift_module::default_libcall_names())(libcall),
});

let pinned_heap_register = isa.register_info().parse_regunit("r15").unwrap();

let mut builder = ObjectBuilder::new(isa, "lucet_guest".to_owned(), libcalls);
builder.function_alignment(16);
let mut clif_module: ClifModule<ObjectBackend> = ClifModule::new(builder);
Expand All @@ -250,6 +274,8 @@ impl<'a> Compiler<'a> {
module_translation_state,
target,
canonicalize_nans,
pinned_heap,
pinned_heap_register,
})
}

Expand All @@ -260,6 +286,8 @@ impl<'a> Compiler<'a> {
pub fn module_features(&self) -> ModuleFeatures {
let mut mf: ModuleFeatures = (&self.cpu_features).into();
mf.instruction_count = self.count_instructions;
mf.pinned_heap = self.pinned_heap;
mf.pinned_heap_register = self.pinned_heap_register;
mf
}

Expand Down Expand Up @@ -475,6 +503,7 @@ impl<'a> Compiler<'a> {
self.opt_level,
&self.cpu_features,
self.canonicalize_nans,
self.pinned_heap,
)?,
))
}
Expand All @@ -484,6 +513,7 @@ impl<'a> Compiler<'a> {
opt_level: OptLevel,
cpu_features: &CpuFeatures,
canonicalize_nans: bool,
pinned_heap: bool,
) -> Result<Box<dyn TargetIsa>, Error> {
let mut flags_builder = settings::builder();
let isa_builder = cpu_features.isa_builder(target)?;
Expand All @@ -493,6 +523,10 @@ impl<'a> Compiler<'a> {
if canonicalize_nans {
flags_builder.enable("enable_nan_canonicalization").unwrap();
}
if pinned_heap {
flags_builder.enable("enable_pinned_reg").unwrap();
flags_builder.enable("use_pinned_reg_as_heap_base").unwrap();
}
Ok(isa_builder.finish(settings::Flags::new(flags_builder)))
}
}
Expand Down
Loading