Improve infrastructure.

Do more encapsulation of raw pointers, use more PrimaryMaps instead of
Vecs, add a table.rs for managing table storage.
This commit is contained in:
Dan Gohman
2018-12-03 03:20:15 -08:00
parent fe1643733b
commit bd69768e0d
14 changed files with 360 additions and 253 deletions

View File

@@ -1,14 +1,19 @@
//! This file declares `VMContext` and several related structs which contain
//! fields that JIT code accesses directly.
use std::ptr::{size_of, align_of};
use cranelift_entity::EntityRef;
use cranelift_wasm::{GlobalIndex, MemoryIndex, TableIndex};
use instance::Instance;
use std::mem::size_of;
use std::slice;
/// The main fields a JIT needs to access to utilize a WebAssembly linear,
/// memory, namely the start address and the size in bytes.
#[repr(C, packed)]
#[derive(Debug)]
#[repr(C)]
pub struct VMMemory {
pub base: *mut u8,
pub current_length: usize,
base: *mut u8,
current_length: usize,
// If more elements are added here, remember to add offset_of tests below!
}
@@ -18,14 +23,24 @@ mod test {
#[test]
fn check_vmmemory_offsets() {
let offsets = VMOffsets::new(size_of<*mut u8>());
assert_eq!(size_of<VMMemory>(), offsets.size_of_vmmemory());
let offsets = VMOffsets::new(size_of::<*mut u8>());
assert_eq!(size_of::<VMMemory>(), offsets.size_of_vmmemory());
assert_eq!(offset_of!(VMMemory, base), offsets.vmmemory_base());
assert_eq!(offset_of!(VMMemory, current_length), offsets.vmmemory_current_length());
assert_eq!(
offset_of!(VMMemory, current_length),
offsets.vmmemory_current_length()
);
}
}
impl VMMemory {
pub fn new(base: *mut u8, current_length: usize) -> Self {
Self {
base,
current_length,
}
}
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.base, self.current_length) }
}
@@ -47,38 +62,50 @@ impl VMMemory {
}
}
#[repr(C, packed, align(8))]
/// The storage for a WebAssembly global.
///
/// TODO: Pack the globals more densely, rather than using the same size
/// for every type.
#[derive(Debug, Clone)]
#[repr(C, align(8))]
pub struct VMGlobal {
pub storage: [u8; 8],
storage: [u8; 8],
// If more elements are added here, remember to add offset_of tests below!
}
/// The storage for a WebAssembly global.
#[cfg(test)]
mod test {
use std::mem::align_of;
use wasmtime_environ::VMOffsets;
#[test]
fn check_vmglobal_alignment() {
assert!(align_of<VMGlobal>() <= align_of<i32>());
assert!(align_of<VMGlobal>() >= align_of<i64>());
assert!(align_of<VMGlobal>() >= align_of<f32>());
assert!(align_of<VMGlobal>() >= align_of<f64>());
assert!(align_of::<VMGlobal>() <= align_of::<i32>());
assert!(align_of::<VMGlobal>() >= align_of::<i64>());
assert!(align_of::<VMGlobal>() >= align_of::<f32>());
assert!(align_of::<VMGlobal>() >= align_of::<f64>());
}
#[test]
fn check_vmglobal_offsets() {
let offsets = VMOffsets::new(size_of<*mut u8>());
assert_eq!(size_of<VMGlobal>(), offsets.size_of_vmglobal());
let offsets = VMOffsets::new(size_of::<*mut u8>());
assert_eq!(size_of::<VMGlobal>(), offsets.size_of_vmglobal());
}
}
impl Default for VMGlobal {
fn default() -> Self {
VMGlobal { storage: [0; 8] }
}
}
#[derive(Debug)]
/// The main fields a JIT needs to access to utilize a WebAssembly table,
/// namely the start address and the number of elements.
#[repr(C, packed)]
pub struct VMTableStorage {
pub base: *mut u8,
pub current_elements: usize,
#[repr(C)]
pub struct VMTable {
base: *mut u8,
current_elements: usize,
// If more elements are added here, remember to add offset_of tests below!
}
@@ -88,20 +115,30 @@ mod test {
#[test]
fn check_vmtable_offsets() {
let offsets = VMOffsets::new(size_of<*mut u8>());
assert_eq!(size_of<VMTableStorage>(), offsets.size_of_vmtable());
assert_eq!(offset_of!(VMTableStorage, base), offsets.vmtable_base());
assert_eq!(offset_of!(VMTableStorage, current_elements), offsets.vmtable_current_elements());
let offsets = VMOffsets::new(size_of::<*mut u8>());
assert_eq!(size_of::<VMTable>(), offsets.size_of_vmtable());
assert_eq!(offset_of!(VMTable, base), offsets.vmtable_base());
assert_eq!(
offset_of!(VMTable, current_elements),
offsets.vmtable_current_elements()
);
}
}
impl VMTableStorage {
impl VMTable {
pub fn new(base: *mut u8, current_elements: usize) -> Self {
Self {
base,
current_elements,
}
}
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.base, self.current_length) }
unsafe { slice::from_raw_parts(self.base, self.current_elements) }
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.base, self.current_length) }
unsafe { slice::from_raw_parts_mut(self.base, self.current_elements) }
}
pub fn as_ptr(&self) -> *const u8 {
@@ -113,26 +150,24 @@ impl VMTableStorage {
}
pub fn len(&self) -> usize {
self.current_length
self.current_elements
}
}
/// The VM "context", which is pointed to by the `vmctx` arg in Cranelift.
/// This has pointers to the globals, memories, tables, and other runtime
/// state associated with the current instance.
#[repr(C, packed)]
#[derive(Debug)]
#[repr(C)]
pub struct VMContext {
/// A pointer to an array of `VMMemory` instances, indexed by
/// WebAssembly memory index.
pub memories: *mut VMMemory,
memories: *mut VMMemory,
/// A pointer to an array of globals.
pub globals: *mut u8,
/// A pointer to an array of `VMTableStorage` instances, indexed by
globals: *mut VMGlobal,
/// A pointer to an array of `VMTable` instances, indexed by
/// WebAssembly table index.
pub tables: *mut VMTableStorage,
/// A pointer to extra runtime state that isn't directly accessed
/// from JIT code.
pub instance: *mut u8,
tables: *mut VMTable,
// If more elements are added here, remember to add offset_of tests below!
}
@@ -142,41 +177,63 @@ mod test {
#[test]
fn check_vmctx_offsets() {
let offsets = VMOffsets::new(size_of<*mut u8>());
assert_eq!(size_of<VMContext>(), offsets.size_of_vmctx());
assert_eq!(offset_of!(VMContext, globals), offsets.vmctx_globals());
let offsets = VMOffsets::new(size_of::<*mut u8>());
assert_eq!(size_of::<VMContext>(), offsets.size_of_vmctx());
assert_eq!(offset_of!(VMContext, memories), offsets.vmctx_memories());
assert_eq!(offset_of!(VMContext, globals), offsets.vmctx_globals());
assert_eq!(offset_of!(VMContext, tables), offsets.vmctx_tables());
assert_eq!(offset_of!(VMContext, instance), offsets.vmctx_instance());
}
}
impl VMContext {
unsafe pub fn global_storage(&mut self, index: usize) -> *mut u8 {
globals.add(index * global_size)
/// Create a new `VMContext` instance.
pub fn new(memories: *mut VMMemory, globals: *mut VMGlobal, tables: *mut VMTable) -> Self {
Self {
memories,
globals,
tables,
}
}
unsafe pub fn global_i32(&mut self, index: usize) -> &mut i32 {
self.global_storage(index) as &mut i32
/// Return the base pointer of the globals array.
pub unsafe fn global_storage(&mut self, index: GlobalIndex) -> *mut VMGlobal {
self.globals.add(index.index() * size_of::<VMGlobal>())
}
unsafe pub fn global_i64(&mut self, index: usize) -> &mut i64 {
self.global_storage(index) as &mut i64
/// Return a mutable reference to global `index` which has type i32.
pub unsafe fn global_i32(&mut self, index: GlobalIndex) -> &mut i32 {
&mut *(self.global_storage(index) as *mut i32)
}
unsafe pub fn global_f32(&mut self, index: usize) -> &mut f32 {
self.global_storage(index) as &mut f32
/// Return a mutable reference to global `index` which has type i64.
pub unsafe fn global_i64(&mut self, index: GlobalIndex) -> &mut i64 {
&mut *(self.global_storage(index) as *mut i64)
}
unsafe pub fn global_f64(&mut self, index: usize) -> &mut f64 {
self.global_storage(index) as &mut f64
/// Return a mutable reference to global `index` which has type f32.
pub unsafe fn global_f32(&mut self, index: GlobalIndex) -> &mut f32 {
&mut *(self.global_storage(index) as *mut f32)
}
unsafe pub fn memory(&mut self, index: usize) -> &mut VMMemory {
memories.add(index) as &mut VMMemory
/// Return a mutable reference to global `index` which has type f64.
pub unsafe fn global_f64(&mut self, index: GlobalIndex) -> &mut f64 {
&mut *(self.global_storage(index) as *mut f64)
}
unsafe pub fn table(&mut self, index: usize) -> &mut VMTableStorage {
tables.add(index) as &mut VMTableStorage
/// Return a mutable reference to linear memory `index`.
pub unsafe fn memory(&mut self, index: MemoryIndex) -> &mut VMMemory {
&mut *self.memories.add(index.index())
}
/// Return a mutable reference to table `index`.
pub unsafe fn table(&mut self, index: TableIndex) -> &mut VMTable {
&mut *self.tables.add(index.index())
}
/// Return a mutable reference to the associated `Instance`.
pub unsafe fn instance(&mut self) -> &mut Instance {
&mut *((self as *mut VMContext as *mut u8).offset(-Instance::vmctx_offset())
as *mut Instance)
}
}