Skip to content

Commit

Permalink
Add comments for trampoline_x64.
Browse files Browse the repository at this point in the history
  • Loading branch information
losfair committed Jun 4, 2019
1 parent f4df568 commit 66dcec9
Showing 1 changed file with 36 additions and 11 deletions.
47 changes: 36 additions & 11 deletions lib/runtime-core/src/trampoline_x64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@
//! Variadic functions are not supported because `rax` is used by the trampoline code.
use crate::loader::CodeMemory;
use std::{mem, slice};

lazy_static! {
/// Reads the context pointer from `mm0`.
///
/// This function generates code at runtime since `asm!` macro is not yet stable.
static ref GET_CONTEXT: extern "C" fn () -> *const CallContext = {
static CODE: &'static [u8] = &[
0x48, 0x0f, 0x7e, 0xc0, // movq %mm0, %rax
Expand All @@ -18,33 +22,39 @@ lazy_static! {
mem[..CODE.len()].copy_from_slice(CODE);
mem.make_executable();
let ptr = mem.as_ptr();
::std::mem::forget(mem);
mem::forget(mem);
unsafe {
::std::mem::transmute(ptr)
mem::transmute(ptr)
}
};
}

/// An opaque type for pointers to a callable memory location.
pub enum CallTarget {}

/// An opaque type for context pointers.
pub enum CallContext {}

/// An opaque type for generated trampolines' call entries.
pub enum Trampoline {}

/// Trampoline Buffer Builder.
pub struct TrampolineBufferBuilder {
code: Vec<u8>,
offsets: Vec<usize>,
}

/// Trampoline Buffer.
pub struct TrampolineBuffer {
code: CodeMemory,
offsets: Vec<usize>,
}

fn value_to_bytes<T: Copy>(ptr: &T) -> &[u8] {
unsafe {
::std::slice::from_raw_parts(ptr as *const T as *const u8, ::std::mem::size_of::<T>())
}
unsafe { slice::from_raw_parts(ptr as *const T as *const u8, mem::size_of::<T>()) }
}

/// Calls `GET_CONTEXT` and returns the current context.
pub fn get_context() -> *const CallContext {
GET_CONTEXT()
}
Expand All @@ -57,6 +67,13 @@ impl TrampolineBufferBuilder {
}
}

/// Adds a context trampoline.
///
/// This generates a transparent trampoline function that forwards any call to `target` with
/// unmodified params/returns. When called from the trampoline, `target` will have access to
/// the `context` specified here through `get_context()`.
///
/// Note that since `rax` is overwritten internally, variadic functions are not supported as `target`.
pub fn add_context_trampoline(
&mut self,
target: *const CallTarget,
Expand All @@ -81,6 +98,13 @@ impl TrampolineBufferBuilder {
idx
}

/// Adds a callinfo trampoline.
///
/// This generates a trampoline function that collects `num_params` parameters into an array
/// and passes the array into `target` as the second argument when called. The first argument
/// of `target` is the `context` specified here.
///
/// Note that non-integer parameters/variadic functions are not supported.
pub fn add_callinfo_trampoline(
&mut self,
target: unsafe extern "C" fn(*const CallContext, *const u64) -> u64,
Expand Down Expand Up @@ -151,6 +175,7 @@ impl TrampolineBufferBuilder {
idx
}

/// Consumes the builder and builds the trampoline buffer.
pub fn build(self) -> TrampolineBuffer {
get_context(); // ensure lazy initialization is completed

Expand All @@ -165,6 +190,7 @@ impl TrampolineBufferBuilder {
}

impl TrampolineBuffer {
/// Returns the trampoline pointer at index `idx`.
pub fn get_trampoline(&self, idx: usize) -> *const Trampoline {
&self.code[self.offsets[idx]] as *const u8 as *const Trampoline
}
Expand All @@ -190,8 +216,7 @@ mod tests {
);
let buf = builder.build();
let t = buf.get_trampoline(idx);
let ret =
unsafe { ::std::mem::transmute::<_, extern "C" fn(i32, f32) -> f32>(t)(1, 2.0) as i32 };
let ret = unsafe { mem::transmute::<_, extern "C" fn(i32, f32) -> f32>(t)(1, 2.0) as i32 };
assert_eq!(ret, 6);
}
#[test]
Expand All @@ -201,7 +226,7 @@ mod tests {
}
unsafe extern "C" fn do_add(ctx: *const CallContext, args: *const u64) -> u64 {
let ctx = &*(ctx as *const TestContext);
let args: &[u64] = ::std::slice::from_raw_parts(args, 8);
let args: &[u64] = slice::from_raw_parts(args, 8);
(args.iter().map(|x| *x as i32).fold(0, |a, b| a + b) + ctx.value) as u64
}
let mut builder = TrampolineBufferBuilder::new();
Expand All @@ -211,9 +236,9 @@ mod tests {
let buf = builder.build();
let t = buf.get_trampoline(idx);
let ret = unsafe {
::std::mem::transmute::<_, extern "C" fn(i32, i32, i32, i32, i32, i32, i32, i32) -> i32>(
t,
)(1, 2, 3, 4, 5, 6, 7, 8) as i32
mem::transmute::<_, extern "C" fn(i32, i32, i32, i32, i32, i32, i32, i32) -> i32>(t)(
1, 2, 3, 4, 5, 6, 7, 8,
) as i32
};
assert_eq!(ret, 136);
}
Expand Down

0 comments on commit 66dcec9

Please sign in to comment.