Implement the remaining valid spec tests.

And lots of other miscellaneous changes. Rename InstanceWorld to
InstancePlus and reorganize its contents. This still isn't a great name,
but at least now it has a clear purpose.
This commit is contained in:
Dan Gohman
2018-12-11 17:12:33 -08:00
parent 6dd39dee6a
commit 3f24098edc
34 changed files with 1572 additions and 1262 deletions

View File

@@ -1,16 +1,18 @@
use cranelift_codegen::binemit::Reloc;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, Global, GlobalInit, Memory, Table, TableElementType};
use export::{Export, FunctionExport, Resolver};
use resolver::Resolver;
use std::ptr::write_unaligned;
use std::string::String;
use std::vec::Vec;
use wasmtime_environ::{
MemoryPlan, MemoryStyle, Module, Relocation, RelocationTarget, Relocations, TablePlan,
TableStyle,
};
use wasmtime_runtime::libcalls;
use wasmtime_runtime::{Imports, VMFunctionBody, VMGlobalImport, VMMemoryImport, VMTableImport};
use wasmtime_runtime::{
Export, Imports, VMFunctionBody, VMFunctionImport, VMGlobalImport, VMMemoryImport,
VMTableImport,
};
/// A link error, such as incompatible or unmatched imports/exports.
#[derive(Fail, Debug)]
@@ -28,7 +30,11 @@ pub fn link_module(
for (index, (ref module_name, ref field)) in module.imported_funcs.iter() {
match resolver.resolve(module_name, field) {
Some(export_value) => match export_value {
Export::Function(FunctionExport { address, signature }) => {
Export::Function {
address,
signature,
vmctx,
} => {
let import_signature = &module.signatures[module.functions[index]];
if signature != *import_signature {
// TODO: If the difference is in the calling convention,
@@ -39,7 +45,10 @@ pub fn link_module(
signature, import_signature)
));
}
function_imports.push(address);
function_imports.push(VMFunctionImport {
body: address,
vmctx,
});
}
Export::Table { .. } | Export::Memory { .. } | Export::Global { .. } => {
return Err(LinkError(format!(
@@ -104,12 +113,28 @@ pub fn link_module(
memory,
} => {
let import_memory = &module.memory_plans[index];
if is_memory_compatible(&memory, import_memory) {
if !is_memory_compatible(&memory, import_memory) {
return Err(LinkError(format!(
"{}/{}: exported memory incompatible with memory import",
module_name, field
)));
}
// Sanity-check: Ensure that the imported memory has at least
// guard-page protections the importing module expects it to have.
match (memory.style, &import_memory.style) {
(
MemoryStyle::Static { bound },
MemoryStyle::Static {
bound: import_bound,
},
) => {
assert!(bound >= *import_bound);
}
_ => (),
}
assert!(memory.offset_guard_size >= import_memory.offset_guard_size);
memory_imports.push(VMMemoryImport {
from: address,
vmctx,
@@ -161,17 +186,15 @@ pub fn link_module(
}
}
let imports = Imports::new(
// Apply relocations, now that we have virtual addresses for everything.
relocate(allocated_functions, relocations, &module);
Ok(Imports::new(
function_imports,
table_imports,
memory_imports,
global_imports,
);
// Apply relocations, now that we have virtual addresses for everything.
relocate(&imports, allocated_functions, relocations, &module);
Ok(imports)
))
}
fn is_global_compatible(exported: &Global, imported: &Global) -> bool {
@@ -193,14 +216,6 @@ fn is_global_compatible(exported: &Global, imported: &Global) -> bool {
exported_ty == imported_ty && imported_mutability == exported_mutability
}
fn is_table_style_compatible(exported_style: &TableStyle, imported_style: &TableStyle) -> bool {
match exported_style {
TableStyle::CallerChecksSignature => match imported_style {
TableStyle::CallerChecksSignature => true,
},
}
}
fn is_table_element_type_compatible(
exported_type: TableElementType,
imported_type: TableElementType,
@@ -225,7 +240,7 @@ fn is_table_compatible(exported: &TablePlan, imported: &TablePlan) -> bool {
minimum: exported_minimum,
maximum: exported_maximum,
},
style: exported_style,
style: _exported_style,
} = exported;
let TablePlan {
table:
@@ -234,30 +249,14 @@ fn is_table_compatible(exported: &TablePlan, imported: &TablePlan) -> bool {
minimum: imported_minimum,
maximum: imported_maximum,
},
style: imported_style,
style: _imported_style,
} = imported;
is_table_element_type_compatible(*exported_ty, *imported_ty)
&& imported_minimum >= exported_minimum
&& imported_maximum <= exported_maximum
&& is_table_style_compatible(imported_style, exported_style)
}
fn is_memory_style_compatible(exported_style: &MemoryStyle, imported_style: &MemoryStyle) -> bool {
match exported_style {
MemoryStyle::Dynamic => match imported_style {
MemoryStyle::Dynamic => true,
_ => false,
},
MemoryStyle::Static {
bound: imported_bound,
} => match imported_style {
MemoryStyle::Static {
bound: exported_bound,
} => exported_bound >= imported_bound,
_ => false,
},
}
&& imported_minimum <= exported_minimum
&& (imported_maximum.is_none()
|| (!exported_maximum.is_none()
&& imported_maximum.unwrap() >= exported_maximum.unwrap()))
}
fn is_memory_compatible(exported: &MemoryPlan, imported: &MemoryPlan) -> bool {
@@ -268,8 +267,8 @@ fn is_memory_compatible(exported: &MemoryPlan, imported: &MemoryPlan) -> bool {
maximum: exported_maximum,
shared: exported_shared,
},
style: exported_style,
offset_guard_size: exported_offset_guard_size,
style: _exported_style,
offset_guard_size: _exported_offset_guard_size,
} = exported;
let MemoryPlan {
memory:
@@ -278,20 +277,19 @@ fn is_memory_compatible(exported: &MemoryPlan, imported: &MemoryPlan) -> bool {
maximum: imported_maximum,
shared: imported_shared,
},
style: imported_style,
offset_guard_size: imported_offset_guard_size,
style: _imported_style,
offset_guard_size: _imported_offset_guard_size,
} = imported;
imported_minimum >= exported_minimum
&& imported_maximum <= exported_maximum
imported_minimum <= exported_minimum
&& (imported_maximum.is_none()
|| (!exported_maximum.is_none()
&& imported_maximum.unwrap() >= exported_maximum.unwrap()))
&& exported_shared == imported_shared
&& is_memory_style_compatible(exported_style, imported_style)
&& exported_offset_guard_size >= imported_offset_guard_size
}
/// Performs the relocations inside the function bytecode, provided the necessary metadata.
fn relocate(
imports: &Imports,
allocated_functions: &PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
relocations: PrimaryMap<DefinedFuncIndex, Vec<Relocation>>,
module: &Module,
@@ -305,7 +303,7 @@ fn relocate(
let fatptr: *const [VMFunctionBody] = allocated_functions[f];
fatptr as *const VMFunctionBody as usize
}
None => imports.functions[index] as usize,
None => panic!("direct call to import"),
},
RelocationTarget::Memory32Grow => wasmtime_memory32_grow as usize,
RelocationTarget::Memory32Size => wasmtime_memory32_size as usize,