use libc; use stack::Stack; use std::simd::u64x2; use std::mem::{zeroed, size_of, transmute}; use std::raw; use fn_box::FnBox; pub struct Context { regs: Registers, stack: Stack } #[repr(C)] #[allow(dead_code)] struct Registers { rbx: u64, rsp: u64, rbp: u64, rdi: u64, r12: u64, r13: u64, r14: u64, r15: u64, ip: u64, xmm0: u64x2, xmm1: u64x2, xmm2: u64x2, xmm3: u64x2, xmm4: u64x2, xmm5: u64x2, } impl Registers { fn zeroed() -> Registers { unsafe { zeroed() } } } extern "C" { fn lwut_bootstrap(); fn lwut_swapcontext(save: *mut Registers, restore: *mut Registers); fn lwut_get_sp_limit() -> *const u8; fn lwut_set_sp_limit(limit: *const u8); fn lwut_abort() -> !; } pub type BoxedFn = Box + Send + 'static>; pub type StartFn = fn(data: *mut T, f: BoxedFn) -> !; impl Context { pub fn new(init: StartFn, data: *mut T, f: BoxedFn) -> Context { let stack = Stack::new(4 << 20); let sp = stack.top() as *mut uint; let sp = align_down_mut(sp, 16); let sp = offset_mut(sp, -1); unsafe { *sp = 0; } let f: raw::TraitObject = unsafe { transmute(f) }; Context { regs: Registers { rbp: 0, rsp: sp as libc::uintptr_t, ip: lwut_bootstrap as libc::uintptr_t, r12: lwut_init:: as libc::uintptr_t, rdi: init as libc::uintptr_t, r13: data as libc::uintptr_t, r14: f.data as libc::uintptr_t, r15: f.vtable as libc::uintptr_t, // r8: …, // r9: …, .. Registers::zeroed() }, stack: stack } } } unsafe extern "C" fn lwut_init(start: StartFn, data: *mut T, f_data: *mut (), f_vtable: *mut ()) -> ! { let f: BoxedFn = transmute(raw::TraitObject { data: f_data, vtable: f_vtable }); start(data, f) } impl Context { pub unsafe fn native() -> Context { Context { regs: Registers { ip: lwut_abort as libc::uintptr_t, .. Registers::zeroed() }, stack: Stack::native(lwut_get_sp_limit()) } } #[inline(always)] pub unsafe fn swap(out_context: &mut Context, in_context: &mut Context) { lwut_set_sp_limit(in_context.stack.limit()); lwut_swapcontext(&mut out_context.regs, &mut in_context.regs); } } #[inline] fn align_down_mut(sp: *mut T, n: uint) -> *mut T { let sp = (sp as uint) & !(n - 1); sp as *mut T } // ptr::offset_mmut is positive ints only #[inline] pub fn offset_mut(ptr: *mut T, count: int) -> *mut T { (ptr as int + count * (size_of::() as int)) as *mut T }