Merge branch 'master' into feat-runtime-core-clos-host-function

This commit is contained in:
Ivan Enderlin
2019-11-04 22:14:11 +01:00
9 changed files with 1171 additions and 214 deletions

View File

@ -11,12 +11,14 @@ use inkwell::{
use libc::c_char;
use std::{
any::Any,
cell::RefCell,
ffi::{c_void, CString},
fs::File,
io::Write,
mem,
ops::Deref,
ptr::{self, NonNull},
rc::Rc,
slice, str,
sync::{Arc, Once},
};
@ -169,14 +171,14 @@ pub struct LLVMBackend {
impl LLVMBackend {
pub fn new(
module: Module,
module: Rc<RefCell<Module>>,
_intrinsics: Intrinsics,
_stackmaps: &StackmapRegistry,
_module_info: &ModuleInfo,
target_machine: &TargetMachine,
) -> (Self, LLVMCache) {
let memory_buffer = target_machine
.write_to_memory_buffer(&module, FileType::Object)
.write_to_memory_buffer(&module.borrow_mut(), FileType::Object)
.unwrap();
let mem_buf_slice = memory_buffer.as_slice();

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,15 @@ use inkwell::{
BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType,
},
values::{
BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue, VectorValue,
BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue,
MetadataValue, PointerValue, VectorValue,
},
AddressSpace,
};
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::rc::Rc;
use wasmer_runtime_core::{
memory::MemoryType,
module::ModuleInfo,
@ -21,6 +24,7 @@ use wasmer_runtime_core::{
GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex,
TableIndex, Type,
},
units::Pages,
vm::{Ctx, INTERNALS_SIZE},
};
@ -559,11 +563,15 @@ pub enum MemoryCache {
Dynamic {
ptr_to_base_ptr: PointerValue,
ptr_to_bounds: PointerValue,
minimum: Pages,
maximum: Option<Pages>,
},
/// The memory is always in the same place.
Static {
base_ptr: PointerValue,
bounds: IntValue,
minimum: Pages,
maximum: Option<Pages>,
},
}
@ -653,7 +661,12 @@ impl<'a> CtxType<'a> {
ptr
}
pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache {
pub fn memory(
&mut self,
index: MemoryIndex,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
) -> MemoryCache {
let (cached_memories, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_memories,
self.info,
@ -662,34 +675,48 @@ impl<'a> CtxType<'a> {
);
*cached_memories.entry(index).or_insert_with(|| {
let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) {
LocalOrImport::Local(local_mem_index) => (
unsafe {
cache_builder.build_struct_gep(
ctx_ptr_value,
offset_to_index(Ctx::offset_memories()),
"memory_array_ptr_ptr",
)
},
local_mem_index.index() as u64,
info.memories[local_mem_index].memory_type(),
),
LocalOrImport::Import(import_mem_index) => (
unsafe {
cache_builder.build_struct_gep(
ctx_ptr_value,
offset_to_index(Ctx::offset_imported_memories()),
"memory_array_ptr_ptr",
)
},
import_mem_index.index() as u64,
info.imported_memories[import_mem_index].1.memory_type(),
),
};
let (memory_array_ptr_ptr, index, memory_type, minimum, maximum, field_name) =
match index.local_or_import(info) {
LocalOrImport::Local(local_mem_index) => (
unsafe {
cache_builder.build_struct_gep(
ctx_ptr_value,
offset_to_index(Ctx::offset_memories()),
"memory_array_ptr_ptr",
)
},
local_mem_index.index() as u64,
info.memories[local_mem_index].memory_type(),
info.memories[local_mem_index].minimum,
info.memories[local_mem_index].maximum,
"context_field_ptr_to_local_memory",
),
LocalOrImport::Import(import_mem_index) => (
unsafe {
cache_builder.build_struct_gep(
ctx_ptr_value,
offset_to_index(Ctx::offset_imported_memories()),
"memory_array_ptr_ptr",
)
},
import_mem_index.index() as u64,
info.imported_memories[import_mem_index].1.memory_type(),
info.imported_memories[import_mem_index].1.minimum,
info.imported_memories[import_mem_index].1.maximum,
"context_field_ptr_to_imported_memory",
),
};
let memory_array_ptr = cache_builder
.build_load(memory_array_ptr_ptr, "memory_array_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
field_name,
memory_array_ptr.as_instruction_value().unwrap(),
None,
);
let const_index = intrinsics.i32_ty.const_int(index, false);
let memory_ptr_ptr = unsafe {
cache_builder.build_in_bounds_gep(
@ -701,6 +728,13 @@ impl<'a> CtxType<'a> {
let memory_ptr = cache_builder
.build_load(memory_ptr_ptr, "memory_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"memory_ptr",
memory_ptr.as_instruction_value().unwrap(),
Some(index as u32),
);
let (ptr_to_base_ptr, ptr_to_bounds) = unsafe {
(
@ -713,15 +747,37 @@ impl<'a> CtxType<'a> {
MemoryType::Dynamic => MemoryCache::Dynamic {
ptr_to_base_ptr,
ptr_to_bounds,
minimum,
maximum,
},
MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static {
base_ptr: cache_builder
MemoryType::Static | MemoryType::SharedStatic => {
let base_ptr = cache_builder
.build_load(ptr_to_base_ptr, "base")
.into_pointer_value(),
bounds: cache_builder
.into_pointer_value();
let bounds = cache_builder
.build_load(ptr_to_bounds, "bounds")
.into_int_value(),
},
.into_int_value();
tbaa_label(
module.clone(),
intrinsics,
"static_memory_base",
base_ptr.as_instruction_value().unwrap(),
Some(index as u32),
);
tbaa_label(
module.clone(),
intrinsics,
"static_memory_bounds",
bounds.as_instruction_value().unwrap(),
Some(index as u32),
);
MemoryCache::Static {
base_ptr,
bounds,
minimum,
maximum,
}
}
}
})
}
@ -730,6 +786,7 @@ impl<'a> CtxType<'a> {
&mut self,
index: TableIndex,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
) -> (PointerValue, PointerValue) {
let (cached_tables, info, ctx_ptr_value, cache_builder) = (
&mut self.cached_tables,
@ -742,7 +799,7 @@ impl<'a> CtxType<'a> {
ptr_to_base_ptr,
ptr_to_bounds,
} = *cached_tables.entry(index).or_insert_with(|| {
let (table_array_ptr_ptr, index) = match index.local_or_import(info) {
let (table_array_ptr_ptr, index, field_name) = match index.local_or_import(info) {
LocalOrImport::Local(local_table_index) => (
unsafe {
cache_builder.build_struct_gep(
@ -752,6 +809,7 @@ impl<'a> CtxType<'a> {
)
},
local_table_index.index() as u64,
"context_field_ptr_to_local_table",
),
LocalOrImport::Import(import_table_index) => (
unsafe {
@ -762,12 +820,20 @@ impl<'a> CtxType<'a> {
)
},
import_table_index.index() as u64,
"context_field_ptr_to_import_table",
),
};
let table_array_ptr = cache_builder
.build_load(table_array_ptr_ptr, "table_array_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
field_name,
table_array_ptr.as_instruction_value().unwrap(),
None,
);
let const_index = intrinsics.i32_ty.const_int(index, false);
let table_ptr_ptr = unsafe {
cache_builder.build_in_bounds_gep(table_array_ptr, &[const_index], "table_ptr_ptr")
@ -775,6 +841,13 @@ impl<'a> CtxType<'a> {
let table_ptr = cache_builder
.build_load(table_ptr_ptr, "table_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"table_ptr",
table_array_ptr.as_instruction_value().unwrap(),
Some(index as u32),
);
let (ptr_to_base_ptr, ptr_to_bounds) = unsafe {
(
@ -796,15 +869,30 @@ impl<'a> CtxType<'a> {
&mut self,
index: TableIndex,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
builder: &Builder,
) -> (PointerValue, IntValue) {
let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics);
(
builder
.build_load(ptr_to_base_ptr, "base_ptr")
.into_pointer_value(),
builder.build_load(ptr_to_bounds, "bounds").into_int_value(),
)
let (ptr_to_base_ptr, ptr_to_bounds) =
self.table_prepare(index, intrinsics, module.clone());
let base_ptr = builder
.build_load(ptr_to_base_ptr, "base_ptr")
.into_pointer_value();
let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value();
tbaa_label(
module.clone(),
intrinsics,
"table_base_ptr",
base_ptr.as_instruction_value().unwrap(),
Some(index.index() as u32),
);
tbaa_label(
module.clone(),
intrinsics,
"table_bounds",
bounds.as_instruction_value().unwrap(),
Some(index.index() as u32),
);
(base_ptr, bounds)
}
pub fn local_func(
@ -812,6 +900,7 @@ impl<'a> CtxType<'a> {
index: LocalFuncIndex,
fn_ty: FunctionType,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
builder: &Builder,
) -> PointerValue {
let local_func_array_ptr_ptr = unsafe {
@ -824,6 +913,13 @@ impl<'a> CtxType<'a> {
let local_func_array_ptr = builder
.build_load(local_func_array_ptr_ptr, "local_func_array_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"context_field_ptr_to_local_funcs",
local_func_array_ptr.as_instruction_value().unwrap(),
None,
);
let local_func_ptr_ptr = unsafe {
builder.build_in_bounds_gep(
local_func_array_ptr,
@ -834,6 +930,13 @@ impl<'a> CtxType<'a> {
let local_func_ptr = builder
.build_load(local_func_ptr_ptr, "local_func_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"local_func_ptr",
local_func_ptr.as_instruction_value().unwrap(),
Some(index.index() as u32),
);
builder.build_pointer_cast(
local_func_ptr,
fn_ty.ptr_type(AddressSpace::Generic),
@ -875,7 +978,12 @@ impl<'a> CtxType<'a> {
})
}
pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache {
pub fn global_cache(
&mut self,
index: GlobalIndex,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
) -> GlobalCache {
let (cached_globals, ctx_ptr_value, info, cache_builder) = (
&mut self.cached_globals,
self.ctx_ptr_value,
@ -884,7 +992,7 @@ impl<'a> CtxType<'a> {
);
*cached_globals.entry(index).or_insert_with(|| {
let (globals_array_ptr_ptr, index, mutable, wasmer_ty) =
let (globals_array_ptr_ptr, index, mutable, wasmer_ty, field_name) =
match index.local_or_import(info) {
LocalOrImport::Local(local_global_index) => {
let desc = info.globals[local_global_index].desc;
@ -899,6 +1007,7 @@ impl<'a> CtxType<'a> {
local_global_index.index() as u64,
desc.mutable,
desc.ty,
"context_field_ptr_to_local_globals",
)
}
LocalOrImport::Import(import_global_index) => {
@ -914,6 +1023,7 @@ impl<'a> CtxType<'a> {
import_global_index.index() as u64,
desc.mutable,
desc.ty,
"context_field_ptr_to_imported_globals",
)
}
};
@ -923,6 +1033,13 @@ impl<'a> CtxType<'a> {
let global_array_ptr = cache_builder
.build_load(globals_array_ptr_ptr, "global_array_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
field_name,
globals_array_ptr_ptr.as_instruction_value().unwrap(),
None,
);
let const_index = intrinsics.i32_ty.const_int(index, false);
let global_ptr_ptr = unsafe {
cache_builder.build_in_bounds_gep(
@ -934,6 +1051,13 @@ impl<'a> CtxType<'a> {
let global_ptr = cache_builder
.build_load(global_ptr_ptr, "global_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"global_ptr",
globals_array_ptr_ptr.as_instruction_value().unwrap(),
Some(index as u32),
);
let global_ptr_typed =
cache_builder.build_pointer_cast(global_ptr, llvm_ptr_ty, "global_ptr_typed");
@ -943,9 +1067,15 @@ impl<'a> CtxType<'a> {
ptr_to_value: global_ptr_typed,
}
} else {
GlobalCache::Const {
value: cache_builder.build_load(global_ptr_typed, "global_value"),
}
let value = cache_builder.build_load(global_ptr_typed, "global_value");
tbaa_label(
module.clone(),
intrinsics,
"global",
value.as_instruction_value().unwrap(),
Some(index as u32),
);
GlobalCache::Const { value }
}
})
}
@ -954,6 +1084,7 @@ impl<'a> CtxType<'a> {
&mut self,
index: ImportedFuncIndex,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
) -> (PointerValue, PointerValue) {
let (cached_imported_functions, ctx_ptr_value, cache_builder) = (
&mut self.cached_imported_functions,
@ -972,6 +1103,13 @@ impl<'a> CtxType<'a> {
let func_array_ptr = cache_builder
.build_load(func_array_ptr_ptr, "func_array_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"context_field_ptr_to_imported_funcs",
func_array_ptr.as_instruction_value().unwrap(),
None,
);
let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false);
let imported_func_ptr = unsafe {
cache_builder.build_in_bounds_gep(
@ -993,6 +1131,20 @@ impl<'a> CtxType<'a> {
let ctx_ptr = cache_builder
.build_load(ctx_ptr_ptr, "ctx_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"imported_func_ptr",
func_ptr.as_instruction_value().unwrap(),
Some(index.index() as u32),
);
tbaa_label(
module.clone(),
intrinsics,
"imported_func_ctx_ptr",
ctx_ptr.as_instruction_value().unwrap(),
Some(index.index() as u32),
);
ImportedFuncCache { func_ptr, ctx_ptr }
});
@ -1004,6 +1156,7 @@ impl<'a> CtxType<'a> {
&mut self,
index: usize,
intrinsics: &Intrinsics,
module: Rc<RefCell<Module>>,
builder: &Builder,
) -> PointerValue {
assert!(index < INTERNALS_SIZE);
@ -1018,6 +1171,13 @@ impl<'a> CtxType<'a> {
let local_internals_ptr = builder
.build_load(local_internals_ptr_ptr, "local_internals_ptr")
.into_pointer_value();
tbaa_label(
module.clone(),
intrinsics,
"context_field_ptr_to_internals",
local_internals_ptr_ptr.as_instruction_value().unwrap(),
None,
);
unsafe {
builder.build_in_bounds_gep(
local_internals_ptr,
@ -1027,3 +1187,83 @@ impl<'a> CtxType<'a> {
}
}
}
// Given an instruction that operates on memory, mark the access as not aliasing
// other memory accesses which have a different (label, index) pair.
pub fn tbaa_label(
module: Rc<RefCell<Module>>,
intrinsics: &Intrinsics,
label: &str,
instruction: InstructionValue,
index: Option<u32>,
) {
// To convey to LLVM that two pointers must be pointing to distinct memory,
// we use LLVM's Type Based Aliasing Analysis, or TBAA, to mark the memory
// operations as having different types whose pointers may not alias.
//
// See the LLVM documentation at
// https://llvm.org/docs/LangRef.html#tbaa-metadata
//
// LLVM TBAA supports many features, but we use it in a simple way, with
// only scalar types that are children of the root node. Every TBAA type we
// declare is NoAlias with the others. See NoAlias, PartialAlias,
// MayAlias and MustAlias in the LLVM documentation:
// https://llvm.org/docs/AliasAnalysis.html#must-may-and-no-alias-responses
let module = module.borrow_mut();
let context = module.get_context();
// `!wasmer_tbaa_root = {}`, the TBAA root node for wasmer.
let tbaa_root = module
.get_global_metadata("wasmer_tbaa_root")
.pop()
.unwrap_or_else(|| {
module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[]));
module.get_global_metadata("wasmer_tbaa_root")[0]
});
// Construct (or look up) the type descriptor, for example
// `!"local 0" = !{!"local 0", !wasmer_tbaa_root}`.
let label = if let Some(idx) = index {
format!("{}{}", label, idx)
} else {
label.to_string()
};
let type_label = context.metadata_string(label.as_str());
let type_tbaa = module
.get_global_metadata(label.as_str())
.pop()
.unwrap_or_else(|| {
module.add_global_metadata(
label.as_str(),
&MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]),
);
module.get_global_metadata(label.as_str())[0]
});
// Construct (or look up) the access tag, which is a struct of the form
// (base type, access type, offset).
//
// "If BaseTy is a scalar type, Offset must be 0 and BaseTy and AccessTy
// must be the same".
// -- https://llvm.org/docs/LangRef.html#tbaa-metadata
let label = label + "_memop";
let type_tbaa = module
.get_global_metadata(label.as_str())
.pop()
.unwrap_or_else(|| {
module.add_global_metadata(
label.as_str(),
&MetadataValue::create_node(&[
type_tbaa.into(),
type_tbaa.into(),
intrinsics.i64_zero.into(),
]),
);
module.get_global_metadata(label.as_str())[0]
});
// Attach the access tag to the instruction.
let tbaa_kind = context.get_kind_id("tbaa");
instruction.set_metadata(type_tbaa, tbaa_kind);
}