[wasm] Make FuncEnvironment functions fallible (fixes #752);

This commit is contained in:
Benjamin Bouvier
2019-04-29 11:27:13 +02:00
parent efdb7d86b3
commit 02e114cf3d
5 changed files with 131 additions and 91 deletions

View File

@@ -182,18 +182,26 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
self.mod_info.config
}
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable {
fn return_mode(&self) -> ReturnMode {
self.return_mode
}
fn make_global(
&mut self,
func: &mut ir::Function,
index: GlobalIndex,
) -> WasmResult<GlobalVariable> {
// Just create a dummy `vmctx` global.
let offset = cast::i32((index.index() * 8) + 8).unwrap().into();
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext {});
GlobalVariable::Memory {
Ok(GlobalVariable::Memory {
gv: vmctx,
offset,
ty: self.mod_info.globals[index].entity.ty,
}
})
}
fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> WasmResult<ir::Heap> {
// Create a static heap whose base address is stored at `vmctx+0`.
let addr = func.create_global_value(ir::GlobalValueData::VMContext);
let gv = func.create_global_value(ir::GlobalValueData::Load {
@@ -203,7 +211,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
readonly: true,
});
func.create_heap(ir::HeapData {
Ok(func.create_heap(ir::HeapData {
base: gv,
min_size: 0.into(),
offset_guard_size: 0x8000_0000.into(),
@@ -211,10 +219,10 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
bound: 0x1_0000_0000.into(),
},
index_type: I32,
})
}))
}
fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> ir::Table {
fn make_table(&mut self, func: &mut ir::Function, _index: TableIndex) -> WasmResult<ir::Table> {
// Create a table whose base address is stored at `vmctx+0`.
let vmctx = func.create_global_value(ir::GlobalValueData::VMContext);
let base_gv = func.create_global_value(ir::GlobalValueData::Load {
@@ -230,32 +238,40 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
readonly: true,
});
func.create_table(ir::TableData {
Ok(func.create_table(ir::TableData {
base_gv,
min_size: Uimm64::new(0),
bound_gv,
element_size: Uimm64::from(u64::from(self.pointer_bytes()) * 2),
index_type: I32,
})
}))
}
fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
fn make_indirect_sig(
&mut self,
func: &mut ir::Function,
index: SignatureIndex,
) -> WasmResult<ir::SigRef> {
// A real implementation would probably change the calling convention and add `vmctx` and
// signature index arguments.
func.import_signature(self.vmctx_sig(index))
Ok(func.import_signature(self.vmctx_sig(index)))
}
fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef {
fn make_direct_func(
&mut self,
func: &mut ir::Function,
index: FuncIndex,
) -> WasmResult<ir::FuncRef> {
let sigidx = self.mod_info.functions[index].entity;
// A real implementation would probably add a `vmctx` argument.
// And maybe attempt some signature de-duplication.
let signature = func.import_signature(self.vmctx_sig(sigidx));
let name = get_func_name(index);
func.import_function(ir::ExtFuncData {
Ok(func.import_function(ir::ExtFuncData {
name,
signature,
colocated: false,
})
}))
}
fn translate_call_indirect(
@@ -340,10 +356,6 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
) -> WasmResult<ir::Value> {
Ok(pos.ins().iconst(I32, -1))
}
fn return_mode(&self) -> ReturnMode {
self.return_mode
}
}
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {

View File

@@ -110,6 +110,13 @@ pub trait FuncEnvironment {
self.target_config().pointer_bytes()
}
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
/// of the function body, rather than `return` instructions as needed? This is used by VMs
/// to append custom epilogues.
fn return_mode(&self) -> ReturnMode {
ReturnMode::NormalReturns
}
/// Set up the necessary preamble definitions in `func` to access the global variable
/// identified by `index`.
///
@@ -117,19 +124,23 @@ pub trait FuncEnvironment {
///
/// Return the global variable reference that should be used to access the global and the
/// WebAssembly type of the global.
fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalVariable;
fn make_global(
&mut self,
func: &mut ir::Function,
index: GlobalIndex,
) -> WasmResult<GlobalVariable>;
/// Set up the necessary preamble definitions in `func` to access the linear memory identified
/// by `index`.
///
/// The index space covers both imported and locally declared memories.
fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> ir::Heap;
fn make_heap(&mut self, func: &mut ir::Function, index: MemoryIndex) -> WasmResult<ir::Heap>;
/// Set up the necessary preamble definitions in `func` to access the table identified
/// by `index`.
///
/// The index space covers both imported and locally declared tables.
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> ir::Table;
fn make_table(&mut self, func: &mut ir::Function, index: TableIndex) -> WasmResult<ir::Table>;
/// Set up a signature definition in the preamble of `func` that can be used for an indirect
/// call with signature `index`.
@@ -140,7 +151,11 @@ pub trait FuncEnvironment {
///
/// The signature will only be used for indirect calls, even if the module has direct function
/// calls with the same WebAssembly type.
fn make_indirect_sig(&mut self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef;
fn make_indirect_sig(
&mut self,
func: &mut ir::Function,
index: SignatureIndex,
) -> WasmResult<ir::SigRef>;
/// Set up an external function definition in the preamble of `func` that can be used to
/// directly call the function `index`.
@@ -153,7 +168,11 @@ pub trait FuncEnvironment {
///
/// The function's signature will only be used for direct calls, even if the module has
/// indirect calls with the same WebAssembly type.
fn make_direct_func(&mut self, func: &mut ir::Function, index: FuncIndex) -> ir::FuncRef;
fn make_direct_func(
&mut self,
func: &mut ir::Function,
index: FuncIndex,
) -> WasmResult<ir::FuncRef>;
/// Translate a `call_indirect` WebAssembly instruction at `pos`.
///
@@ -226,15 +245,9 @@ pub trait FuncEnvironment {
///
/// This can be used to insert explicit interrupt or safepoint checking at
/// the beginnings of loops.
fn translate_loop_header(&mut self, _pos: FuncCursor) {
fn translate_loop_header(&mut self, _pos: FuncCursor) -> WasmResult<()> {
// By default, don't emit anything.
}
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
/// of the function body, rather than `return` instructions as needed? This is used by VMs
/// to append custom epilogues.
fn return_mode(&self) -> ReturnMode {
ReturnMode::NormalReturns
Ok(())
}
}