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

Commit dfdd17c

Browse files
committed
Allow use of pinned heap registers
1 parent e95a1bf commit dfdd17c

File tree

13 files changed

+111
-14
lines changed

13 files changed

+111
-14
lines changed

benchmarks/lucet-benchmarks/src/context.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ fn context_init(c: &mut Criterion) {
99

1010
c.bench_function("context_init", move |b| {
1111
b.iter(|| {
12-
ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
12+
ContextHandle::create_and_init(&mut *stack, f as usize, &[], std::ptr::null_mut())
13+
.unwrap();
1314
})
1415
});
1516
}
@@ -22,7 +23,13 @@ fn context_swap_return(c: &mut Criterion) {
2223
b.iter_batched(
2324
|| {
2425
let mut stack = vec![0u64; 1024].into_boxed_slice();
25-
let child = ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
26+
let child = ContextHandle::create_and_init(
27+
&mut *stack,
28+
f as usize,
29+
&[],
30+
std::ptr::null_mut(),
31+
)
32+
.unwrap();
2633
(stack, child)
2734
},
2835
|(stack, mut child)| unsafe {
@@ -44,8 +51,13 @@ fn context_init_swap_return(c: &mut Criterion) {
4451
|| vec![0u64; 1024].into_boxed_slice(),
4552
|mut stack| {
4653
let mut parent = ContextHandle::new();
47-
let mut child =
48-
ContextHandle::create_and_init(&mut *stack, f as usize, &[]).unwrap();
54+
let mut child = ContextHandle::create_and_init(
55+
&mut *stack,
56+
f as usize,
57+
&[],
58+
std::ptr::null_mut(),
59+
)
60+
.unwrap();
4961
unsafe { Context::swap(&mut parent, &mut child) };
5062
stack
5163
},
@@ -332,8 +344,13 @@ fn context_init_swap_return_many_args(c: &mut Criterion) {
332344
|| vec![0u64; 1024].into_boxed_slice(),
333345
|mut stack| {
334346
let mut parent = ContextHandle::new();
335-
let mut child =
336-
ContextHandle::create_and_init(&mut *stack, f as usize, &args).unwrap();
347+
let mut child = ContextHandle::create_and_init(
348+
&mut *stack,
349+
f as usize,
350+
&args,
351+
std::ptr::null_mut(),
352+
)
353+
.unwrap();
337354
unsafe { Context::swap(&mut parent, &mut child) };
338355
stack
339356
},

lucet-module/src/module_data.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ pub struct ModuleFeatures {
5959
pub lzcnt: bool,
6060
pub popcnt: bool,
6161
pub instruction_count: bool,
62+
pub pinned_heap: bool,
63+
pub pinned_heap_register: u16,
6264
_hidden: (),
6365
}
6466

@@ -75,6 +77,8 @@ impl ModuleFeatures {
7577
lzcnt: false,
7678
popcnt: false,
7779
instruction_count: false,
80+
pinned_heap: false,
81+
pinned_heap_register: 0,
7882
_hidden: (),
7983
}
8084
}

lucet-runtime/lucet-runtime-internals/src/alloc/tests.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ macro_rules! alloc_tests {
656656
inst.alloc_mut().stack_u64_mut(),
657657
heap_touching_child as usize,
658658
&[Val::CPtr(heap_ptr)],
659+
heap_ptr,
659660
)
660661
.expect("context init succeeds");
661662
Context::swap(&mut parent, &mut child);
@@ -705,6 +706,7 @@ macro_rules! alloc_tests {
705706
inst.alloc_mut().stack_u64_mut(),
706707
stack_pattern_child as usize,
707708
&[Val::CPtr(heap_ptr)],
709+
heap_ptr,
708710
)
709711
.expect("context init succeeds");
710712
Context::swap(&mut parent, &mut child);

lucet-runtime/lucet-runtime-internals/src/context/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,10 @@ impl ContextHandle {
208208
stack: &mut [u64],
209209
fptr: usize,
210210
args: &[Val],
211+
heap: *mut core::ffi::c_void,
211212
) -> Result<ContextHandle, Error> {
212213
let mut child = ContextHandle::new();
213-
Context::init(stack, &mut child, fptr, args)?;
214+
Context::init(stack, &mut child, fptr, args, heap)?;
214215
Ok(child)
215216
}
216217
}
@@ -303,6 +304,7 @@ impl Context {
303304
/// &mut child,
304305
/// entrypoint as usize,
305306
/// &[Val::U64(120), Val::F32(3.14)],
307+
/// std::ptr::null_mut(),
306308
/// );
307309
/// assert!(res.is_ok());
308310
/// ```
@@ -326,6 +328,7 @@ impl Context {
326328
/// &mut child,
327329
/// entrypoint as usize,
328330
/// &[Val::U64(120), Val::F32(3.14)],
331+
/// std::ptr::null_mut(),
329332
/// );
330333
/// assert!(res.is_ok());
331334
/// ```
@@ -367,6 +370,7 @@ impl Context {
367370
child: &mut Context,
368371
fptr: usize,
369372
args: &[Val],
373+
heap: *mut core::ffi::c_void,
370374
) -> Result<(), Error> {
371375
Context::init_with_callback(
372376
stack,
@@ -375,6 +379,7 @@ impl Context {
375379
ptr::null_mut(),
376380
fptr,
377381
args,
382+
heap,
378383
)
379384
}
380385

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

484+
// 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.
485+
// This value will be used only when the lucet module loaded is compiled requiring use of the pinned heap register.
486+
child.gpr.r15 = heap as u64;
487+
478488
Ok(())
479489
}
480490

@@ -547,6 +557,7 @@ impl Context {
547557
/// &mut child,
548558
/// entrypoint as usize,
549559
/// &[],
560+
/// std::ptr::null_mut(),
550561
/// ).unwrap();
551562
///
552563
/// unsafe { Context::swap(&mut parent, &mut child); }

lucet-runtime/lucet-runtime-internals/src/context/tests/c_child.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ macro_rules! init_and_swap {
5555
&mut *$stack,
5656
$fn as usize,
5757
&[$( $args ),*],
58+
std::ptr::null_mut(),
5859
).unwrap()));
5960

6061
child_regs = child;

lucet-runtime/lucet-runtime-internals/src/context/tests/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ fn init_rejects_unaligned() {
3131
let mut stack_unaligned = unsafe { slice::from_raw_parts_mut(ptr, len) };
3232

3333
// now we have the unaligned stack, let's make sure it blows up right
34-
let res = ContextHandle::create_and_init(&mut stack_unaligned, dummy as usize, &[]);
34+
let res = ContextHandle::create_and_init(
35+
&mut stack_unaligned,
36+
dummy as usize,
37+
&[],
38+
std::ptr::null_mut(),
39+
);
3540

3641
if let Err(Error::UnalignedStack) = res {
3742
assert!(true);

lucet-runtime/lucet-runtime-internals/src/context/tests/rust_child.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ macro_rules! init_and_swap {
5151
&mut *$stack,
5252
$fn as usize,
5353
&[$( $args ),*],
54+
std::ptr::null_mut(),
5455
).unwrap();
5556
CHILD = Some(child);
5657

lucet-runtime/lucet-runtime-internals/src/instance.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,8 @@ impl Instance {
973973

974974
self.entrypoint = Some(func);
975975

976-
let mut args_with_vmctx = vec![Val::from(self.alloc.slot().heap)];
976+
let heap = self.alloc.slot().heap;
977+
let mut args_with_vmctx = vec![Val::from(heap)];
977978
args_with_vmctx.extend_from_slice(args);
978979

979980
let self_ptr = self as *mut _;
@@ -984,6 +985,7 @@ impl Instance {
984985
self_ptr,
985986
func.ptr.as_usize(),
986987
&args_with_vmctx,
988+
heap,
987989
)?;
988990

989991
self.install_activator();

lucetc/lucetc/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ pub fn run(opts: &Options) -> Result<(), Error> {
100100
.with_bindings(bindings)
101101
.with_opt_level(opts.opt_level)
102102
.with_cpu_features(opts.cpu_features.clone())
103-
.with_target(opts.target.clone());
103+
.with_target(opts.target.clone())
104+
.with_pinned_heap(opts.pinned_heap);
104105

105106
if let Some(validator) = validator.take() {
106107
c.validator(validator);

lucetc/lucetc/options.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ pub struct Options {
120120
pub pk_path: Option<PathBuf>,
121121
pub sk_path: Option<PathBuf>,
122122
pub count_instructions: bool,
123+
pub pinned_heap: bool,
123124
pub error_style: ErrorStyle,
124125
pub target: Triple,
125126
}
@@ -211,6 +212,7 @@ impl Options {
211212
let sk_path = m.value_of("sk_path").map(PathBuf::from);
212213
let pk_path = m.value_of("pk_path").map(PathBuf::from);
213214
let count_instructions = m.is_present("count_instructions");
215+
let pinned_heap = m.is_present("pinned_heap");
214216

215217
let error_style = match m.value_of("error_style") {
216218
None => ErrorStyle::default(),
@@ -239,6 +241,7 @@ impl Options {
239241
sk_path,
240242
pk_path,
241243
count_instructions,
244+
pinned_heap,
242245
error_style,
243246
target,
244247
})
@@ -452,6 +455,12 @@ SSE3 but not AVX:
452455
.takes_value(false)
453456
.help("Instrument the produced binary to count the number of wasm operations the translated program executes")
454457
)
458+
.arg(
459+
Arg::with_name("pinned_heap")
460+
.long("--pinned-heap-reg")
461+
.takes_value(false)
462+
.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.")
463+
)
455464
.arg(
456465
Arg::with_name("error_style")
457466
.long("error-style")

lucetc/src/compiler.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::traps::{translate_trapcode, trap_sym_for_func};
1414
use byteorder::{LittleEndian, WriteBytesExt};
1515
use cranelift_codegen::{
1616
binemit, ir,
17+
isa::RegUnit,
1718
isa::TargetIsa,
1819
settings::{self, Configurable},
1920
Context as ClifContext,
@@ -63,6 +64,7 @@ pub struct CompilerBuilder {
6364
heap_settings: HeapSettings,
6465
count_instructions: bool,
6566
canonicalize_nans: bool,
67+
pinned_heap: bool,
6668
validator: Option<Validator>,
6769
}
6870

@@ -75,6 +77,7 @@ impl CompilerBuilder {
7577
heap_settings: HeapSettings::default(),
7678
count_instructions: false,
7779
canonicalize_nans: false,
80+
pinned_heap: false,
7881
validator: None,
7982
}
8083
}
@@ -145,6 +148,15 @@ impl CompilerBuilder {
145148
self
146149
}
147150

151+
pub fn pinned_heap(&mut self, pinned_heap: bool) {
152+
self.pinned_heap = pinned_heap;
153+
}
154+
155+
pub fn with_pinned_heap(mut self, pinned_heap: bool) -> Self {
156+
self.pinned_heap(pinned_heap);
157+
self
158+
}
159+
148160
pub fn validator(&mut self, validator: Option<Validator>) {
149161
self.validator = validator;
150162
}
@@ -169,6 +181,7 @@ impl CompilerBuilder {
169181
self.count_instructions,
170182
&self.validator,
171183
self.canonicalize_nans,
184+
self.pinned_heap,
172185
)
173186
}
174187
}
@@ -182,6 +195,8 @@ pub struct Compiler<'a> {
182195
count_instructions: bool,
183196
module_translation_state: ModuleTranslationState,
184197
canonicalize_nans: bool,
198+
pinned_heap: bool,
199+
pinned_heap_register: RegUnit,
185200
}
186201

187202
impl<'a> Compiler<'a> {
@@ -195,8 +210,15 @@ impl<'a> Compiler<'a> {
195210
count_instructions: bool,
196211
validator: &Option<Validator>,
197212
canonicalize_nans: bool,
213+
pinned_heap: bool,
198214
) -> Result<Self, Error> {
199-
let isa = Self::target_isa(target.clone(), opt_level, &cpu_features, canonicalize_nans)?;
215+
let isa = Self::target_isa(
216+
target.clone(),
217+
opt_level,
218+
&cpu_features,
219+
canonicalize_nans,
220+
pinned_heap,
221+
)?;
200222

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

253+
let pinned_heap_register = isa.register_info().parse_regunit("r15").unwrap();
254+
231255
let mut builder = ObjectBuilder::new(isa, "lucet_guest".to_owned(), libcalls);
232256
builder.function_alignment(16);
233257
let mut clif_module: ClifModule<ObjectBackend> = ClifModule::new(builder);
@@ -250,6 +274,8 @@ impl<'a> Compiler<'a> {
250274
module_translation_state,
251275
target,
252276
canonicalize_nans,
277+
pinned_heap,
278+
pinned_heap_register,
253279
})
254280
}
255281

@@ -260,6 +286,8 @@ impl<'a> Compiler<'a> {
260286
pub fn module_features(&self) -> ModuleFeatures {
261287
let mut mf: ModuleFeatures = (&self.cpu_features).into();
262288
mf.instruction_count = self.count_instructions;
289+
mf.pinned_heap = self.pinned_heap;
290+
mf.pinned_heap_register = self.pinned_heap_register;
263291
mf
264292
}
265293

@@ -475,6 +503,7 @@ impl<'a> Compiler<'a> {
475503
self.opt_level,
476504
&self.cpu_features,
477505
self.canonicalize_nans,
506+
self.pinned_heap,
478507
)?,
479508
))
480509
}
@@ -484,6 +513,7 @@ impl<'a> Compiler<'a> {
484513
opt_level: OptLevel,
485514
cpu_features: &CpuFeatures,
486515
canonicalize_nans: bool,
516+
pinned_heap: bool,
487517
) -> Result<Box<dyn TargetIsa>, Error> {
488518
let mut flags_builder = settings::builder();
489519
let isa_builder = cpu_features.isa_builder(target)?;
@@ -493,6 +523,10 @@ impl<'a> Compiler<'a> {
493523
if canonicalize_nans {
494524
flags_builder.enable("enable_nan_canonicalization").unwrap();
495525
}
526+
if pinned_heap {
527+
flags_builder.enable("enable_pinned_reg").unwrap();
528+
flags_builder.enable("use_pinned_reg_as_heap_base").unwrap();
529+
}
496530
Ok(isa_builder.finish(settings::Flags::new(flags_builder)))
497531
}
498532
}

0 commit comments

Comments
 (0)