Validate modules while translating (#2059)
* Validate modules while translating This commit is a change to cranelift-wasm to validate each function body as it is translated. Additionally top-level module translation functions will perform module validation. This commit builds on changes in wasmparser to perform module validation interwtwined with parsing and translation. This will be necessary for future wasm features such as module linking where the type behind a function index, for example, can be far away in another module. Additionally this also brings a nice benefit where parsing the binary only happens once (instead of having an up-front serial validation step) and validation can happen in parallel for each function. Most of the changes in this commit are plumbing to make sure everything lines up right. The major functional change here is that module compilation should be faster by validating in parallel (or skipping function validation entirely in the case of a cache hit). Otherwise from a user-facing perspective nothing should be that different. This commit does mean that cranelift's translation now inherently validates the input wasm module. This means that the Spidermonkey integration of cranelift-wasm will also be validating the function as it's being translated with cranelift. The associated PR for wasmparser (bytecodealliance/wasmparser#62) provides the necessary tools to create a `FuncValidator` for Gecko, but this is something I'll want careful review for before landing! * Read function operators until EOF This way we can let the validator take care of any issues with mismatched `end` instructions and/or trailing operators/bytes.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
//! Helper functions and structures for the translation.
|
||||
use crate::environ::{TargetEnvironment, WasmResult, WasmType};
|
||||
use crate::state::ModuleTranslationState;
|
||||
use crate::wasm_unsupported;
|
||||
use core::convert::TryInto;
|
||||
use core::u32;
|
||||
@@ -10,7 +9,7 @@ use cranelift_codegen::ir::immediates::V128Imm;
|
||||
use cranelift_frontend::FunctionBuilder;
|
||||
#[cfg(feature = "enable-serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasmparser;
|
||||
use wasmparser::{FuncValidator, WasmFuncType, WasmModuleResources};
|
||||
|
||||
/// Index type of a function (imported or defined) inside the WebAssembly module.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
|
||||
@@ -194,38 +193,56 @@ pub fn tabletype_to_type<PE: TargetEnvironment + ?Sized>(
|
||||
}
|
||||
|
||||
/// Get the parameter and result types for the given Wasm blocktype.
|
||||
pub fn blocktype_params_results(
|
||||
module_translation_state: &ModuleTranslationState,
|
||||
pub fn blocktype_params_results<'a, T>(
|
||||
validator: &'a FuncValidator<T>,
|
||||
ty_or_ft: wasmparser::TypeOrFuncType,
|
||||
) -> WasmResult<(&[wasmparser::Type], &[wasmparser::Type])> {
|
||||
Ok(match ty_or_ft {
|
||||
wasmparser::TypeOrFuncType::Type(ty) => match ty {
|
||||
wasmparser::Type::I32 => (&[], &[wasmparser::Type::I32]),
|
||||
wasmparser::Type::I64 => (&[], &[wasmparser::Type::I64]),
|
||||
wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]),
|
||||
wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]),
|
||||
wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]),
|
||||
wasmparser::Type::ExternRef => (&[], &[wasmparser::Type::ExternRef]),
|
||||
wasmparser::Type::FuncRef => (&[], &[wasmparser::Type::FuncRef]),
|
||||
wasmparser::Type::EmptyBlockType => (&[], &[]),
|
||||
ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)),
|
||||
},
|
||||
wasmparser::TypeOrFuncType::FuncType(ty_index) => {
|
||||
let sig_idx = SignatureIndex::from_u32(ty_index);
|
||||
let (ref params, ref returns) = module_translation_state.wasm_types[sig_idx];
|
||||
(&*params, &*returns)
|
||||
) -> WasmResult<(
|
||||
impl ExactSizeIterator<Item = wasmparser::Type> + Clone + 'a,
|
||||
impl ExactSizeIterator<Item = wasmparser::Type> + Clone + 'a,
|
||||
)>
|
||||
where
|
||||
T: WasmModuleResources,
|
||||
{
|
||||
return Ok(match ty_or_ft {
|
||||
wasmparser::TypeOrFuncType::Type(ty) => {
|
||||
let (params, results): (&'static [wasmparser::Type], &'static [wasmparser::Type]) =
|
||||
match ty {
|
||||
wasmparser::Type::I32 => (&[], &[wasmparser::Type::I32]),
|
||||
wasmparser::Type::I64 => (&[], &[wasmparser::Type::I64]),
|
||||
wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]),
|
||||
wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]),
|
||||
wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]),
|
||||
wasmparser::Type::ExternRef => (&[], &[wasmparser::Type::ExternRef]),
|
||||
wasmparser::Type::FuncRef => (&[], &[wasmparser::Type::FuncRef]),
|
||||
wasmparser::Type::EmptyBlockType => (&[], &[]),
|
||||
ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)),
|
||||
};
|
||||
(
|
||||
itertools::Either::Left(params.iter().copied()),
|
||||
itertools::Either::Left(results.iter().copied()),
|
||||
)
|
||||
}
|
||||
})
|
||||
wasmparser::TypeOrFuncType::FuncType(ty_index) => {
|
||||
let ty = validator
|
||||
.resources()
|
||||
.func_type_at(ty_index)
|
||||
.expect("should be valid");
|
||||
(
|
||||
itertools::Either::Right(ty.inputs()),
|
||||
itertools::Either::Right(ty.outputs()),
|
||||
)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Create a `Block` with the given Wasm parameters.
|
||||
pub fn block_with_params<PE: TargetEnvironment + ?Sized>(
|
||||
builder: &mut FunctionBuilder,
|
||||
params: &[wasmparser::Type],
|
||||
params: impl IntoIterator<Item = wasmparser::Type>,
|
||||
environ: &PE,
|
||||
) -> WasmResult<ir::Block> {
|
||||
let block = builder.create_block();
|
||||
for ty in params.iter() {
|
||||
for ty in params {
|
||||
match ty {
|
||||
wasmparser::Type::I32 => {
|
||||
builder.append_block_param(block, ir::types::I32);
|
||||
@@ -240,7 +257,7 @@ pub fn block_with_params<PE: TargetEnvironment + ?Sized>(
|
||||
builder.append_block_param(block, ir::types::F64);
|
||||
}
|
||||
wasmparser::Type::ExternRef | wasmparser::Type::FuncRef => {
|
||||
builder.append_block_param(block, environ.reference_type((*ty).try_into()?));
|
||||
builder.append_block_param(block, environ.reference_type(ty.try_into()?));
|
||||
}
|
||||
wasmparser::Type::V128 => {
|
||||
builder.append_block_param(block, ir::types::I8X16);
|
||||
|
||||
Reference in New Issue
Block a user