Support for multi-value wasm (#399)

* deps: bump wasmparser to 0.39.2

This has a bug fix for multi-value Wasm validation that is required for getting
the spec tests passing.

https://github.com/yurydelendik/wasmparser.rs/pull/135

* Update cranelift to 0.46.1 to get multi-value Wasm support

The `cranelift_wasm` APIs had to change a little bit to maintain state necessary
when translating multi-value Wasm blocks. The `translate_module` function now
returns a `ModuleTranslationState` that is borrowed during each function's
translation.

* Enable multi-value proposal's spec tests

This enables all the Wasm multi-value proposal's spec tests other than the ones
that rely on functions having more return values than registers available on the
target. That is not supported by cranelift yet.

* wasmtime-interface-types: always use multi-value Wasm

And remove the return pointer hacks that work around the lack of multi-value.
This commit is contained in:
Nick Fitzgerald
2019-10-17 17:12:01 -07:00
committed by Dan Gohman
parent 9d54f84a32
commit 842faf5aa6
25 changed files with 177 additions and 172 deletions

View File

@@ -12,9 +12,9 @@ readme = "README.md"
edition = "2018"
[dependencies]
cranelift-codegen = { version = "0.44.0", features = ["enable-serde"] }
cranelift-entity = { version = "0.44.0", features = ["enable-serde"] }
cranelift-wasm = { version = "0.44.0", features = ["enable-serde"] }
cranelift-codegen = { version = "0.46.1", features = ["enable-serde"] }
cranelift-entity = { version = "0.46.1", features = ["enable-serde"] }
cranelift-wasm = { version = "0.46.1", features = ["enable-serde"] }
lightbeam = { path = "../lightbeam", optional = true }
failure = { version = "0.1.3", default-features = false }
failure_derive = { version = "0.1.3", default-features = false }
@@ -44,7 +44,7 @@ tempfile = "3"
target-lexicon = { version = "0.8.1", default-features = false }
pretty_env_logger = "0.3.0"
rand = { version = "0.7.0", features = ["small_rng"] }
cranelift-codegen = { version = "0.44.0", features = ["enable-serde", "all-arch"] }
cranelift-codegen = { version = "0.46.1", features = ["enable-serde", "all-arch"] }
filetime = "0.2.7"
[features]

View File

@@ -7,7 +7,7 @@ use crate::module_environ::FunctionBodyData;
use alloc::vec::Vec;
use cranelift_codegen::{binemit, ir, isa, CodegenError};
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, WasmError};
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError};
use serde::{Deserialize, Serialize};
use std::ops::Range;
@@ -164,6 +164,7 @@ pub trait Compiler {
/// Compile a parsed module with the given `TargetIsa`.
fn compile_module<'data, 'module>(
module: &'module module::Module,
module_translation: &ModuleTranslationState,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
generate_debug_info: bool,

View File

@@ -21,7 +21,7 @@ use cranelift_codegen::ir::ExternalName;
use cranelift_codegen::isa;
use cranelift_codegen::Context;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator};
use cranelift_wasm::{DefinedFuncIndex, FuncIndex, FuncTranslator, ModuleTranslationState};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
/// Implementation of a relocation sink that just saves all the information for later
@@ -177,6 +177,7 @@ impl crate::compilation::Compiler for Cranelift {
/// associated relocations.
fn compile_module<'data, 'module>(
module: &'module Module,
module_translation: &ModuleTranslationState,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
generate_debug_info: bool,
@@ -213,71 +214,74 @@ impl crate::compilation::Compiler for Cranelift {
.into_iter()
.collect::<Vec<(DefinedFuncIndex, &FunctionBodyData<'data>)>>()
.par_iter()
.map(|(i, input)| {
let func_index = module.func_index(*i);
let mut context = Context::new();
context.func.name = get_func_name(func_index);
context.func.signature =
module.signatures[module.functions[func_index]].clone();
if generate_debug_info {
context.func.collect_debug_info();
}
.map_init(
|| FuncTranslator::new(),
|func_translator, (i, input)| {
let func_index = module.func_index(*i);
let mut context = Context::new();
context.func.name = get_func_name(func_index);
context.func.signature =
module.signatures[module.functions[func_index]].clone();
if generate_debug_info {
context.func.collect_debug_info();
}
let mut trans = FuncTranslator::new();
trans
.translate(
input.data,
input.module_offset,
&mut context.func,
&mut FuncEnvironment::new(isa.frontend_config(), module),
)
.map_err(CompileError::Wasm)?;
func_translator
.translate(
module_translation,
input.data,
input.module_offset,
&mut context.func,
&mut FuncEnvironment::new(isa.frontend_config(), module),
)
.map_err(CompileError::Wasm)?;
let mut code_buf: Vec<u8> = Vec::new();
let mut reloc_sink = RelocSink::new(func_index);
let mut trap_sink = TrapSink::new();
let mut stackmap_sink = binemit::NullStackmapSink {};
context
.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut trap_sink,
&mut stackmap_sink,
)
.map_err(CompileError::Codegen)?;
let mut code_buf: Vec<u8> = Vec::new();
let mut reloc_sink = RelocSink::new(func_index);
let mut trap_sink = TrapSink::new();
let mut stackmap_sink = binemit::NullStackmapSink {};
context
.compile_and_emit(
isa,
&mut code_buf,
&mut reloc_sink,
&mut trap_sink,
&mut stackmap_sink,
)
.map_err(CompileError::Codegen)?;
let jt_offsets = context.func.jt_offsets.clone();
let jt_offsets = context.func.jt_offsets.clone();
let address_transform = if generate_debug_info {
let body_len = code_buf.len();
Some(get_function_address_map(&context, input, body_len, isa))
} else {
None
};
let address_transform = if generate_debug_info {
let body_len = code_buf.len();
Some(get_function_address_map(&context, input, body_len, isa))
} else {
None
};
let ranges = if generate_debug_info {
Some(
context
.build_value_labels_ranges(isa)
.map_err(CompileError::Codegen)?,
)
} else {
None
};
let ranges = if generate_debug_info {
Some(
context
.build_value_labels_ranges(isa)
.map_err(CompileError::Codegen)?,
)
} else {
None
};
let stack_slots = context.func.stack_slots.clone();
let stack_slots = context.func.stack_slots.clone();
Ok((
code_buf,
jt_offsets,
reloc_sink.func_relocs,
address_transform,
ranges,
stack_slots,
trap_sink.traps,
))
})
Ok((
code_buf,
jt_offsets,
reloc_sink.func_relocs,
address_transform,
ranges,
stack_slots,
trap_sink.traps,
))
},
)
.collect::<Result<Vec<_>, CompileError>>()?
.into_iter()
.for_each(

View File

@@ -20,6 +20,7 @@ impl crate::compilation::Compiler for Lightbeam {
/// associated relocations.
fn compile_module<'data, 'module>(
module: &'module Module,
module_translation: &ModuleTranslationState,
function_body_inputs: PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
// TODO

View File

@@ -11,7 +11,7 @@ use cranelift_codegen::isa::TargetFrontendConfig;
use cranelift_entity::PrimaryMap;
use cranelift_wasm::{
self, translate_module, DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex,
SignatureIndex, Table, TableIndex, WasmResult,
ModuleTranslationState, SignatureIndex, Table, TableIndex, WasmResult,
};
/// Contains function data: byte code and its offset in the module.
@@ -42,6 +42,9 @@ pub struct ModuleTranslation<'data> {
/// Tunable parameters.
pub tunables: Tunables,
/// The decoded Wasm types for the module.
pub module_translation: Option<ModuleTranslationState>,
}
impl<'data> ModuleTranslation<'data> {
@@ -67,6 +70,7 @@ impl<'data> ModuleEnvironment<'data> {
function_body_inputs: PrimaryMap::new(),
data_initializers: Vec::new(),
tunables,
module_translation: None,
},
}
}
@@ -78,8 +82,9 @@ impl<'data> ModuleEnvironment<'data> {
/// Translate a wasm module using this environment. This consumes the
/// `ModuleEnvironment` and produces a `ModuleTranslation`.
pub fn translate(mut self, data: &'data [u8]) -> WasmResult<ModuleTranslation<'data>> {
translate_module(data, &mut self)?;
assert!(self.result.module_translation.is_none());
let module_translation = translate_module(data, &mut self)?;
self.result.module_translation = Some(module_translation);
Ok(self.result)
}
}
@@ -320,6 +325,7 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
fn define_function_body(
&mut self,
_module_translation: &ModuleTranslationState,
body_bytes: &'data [u8],
body_offset: usize,
) -> WasmResult<()> {