cranelift-wasm: Create ModuleTranslationState and polish API a little (#1111)
* cranelift-wasm: replace `WasmTypesMap` with `ModuleTranslationState`
The `ModuleTranslationState` contains information decoded from the Wasm module
that must be referenced during each Wasm function's translation.
This is only for data that is maintained by `cranelift-wasm` itself, as opposed
to being maintained by the embedder. Data that is maintained by the embedder is
represented with `ModuleEnvironment`.
A `ModuleTranslationState` is returned by `translate_module`, and can then be
used when translating functions from that module.
* cranelift-wasm: rename `TranslationState` to `FuncTranslationState`
To disambiguate a bit with the new `ModuleTranslationState`.
* cranelift-wasm: Reorganize the internal `state` module into submodules
One module for the `ModuleTranslationState` and another for the
`FuncTranslationState`.
* cranelift-wasm: replace `FuncTranslator` with methods on `ModuleTranslationState`
`FuncTranslator` was two methods that always took ownership of `self`, so it
didn't really make sense as an object as opposed to two different functions, or
in this case methods on the object that actually persists for a longer time.
I think this improves ergonomics nicely.
Before:
```rust
let module_translation = translate_module(...)?;
for body in func_bodies {
let mut translator = FuncTranslator::new();
translator.translate(body, ...)?;
}
```
After:
```rust
let module_translation = translate_module(...)?;
for body in func_bodies {
module_translation.translate_func(body, ...)?;
}
```
Note that this commit does not remove `FuncTranslator`. It still exists, but is
just a wrapper over the `ModuleTranslationState` methods, and it is marked
deprecated, so that downstream users get a heads up. This should make the
transition easier.
* Revert "cranelift-wasm: replace `FuncTranslator` with methods on `ModuleTranslationState`"
This reverts commit 075f9ae933bcaae39348b61287c8f78a4009340d.
This commit is contained in:
@@ -23,8 +23,8 @@
|
|||||||
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
||||||
//! argument.
|
//! argument.
|
||||||
use super::{hash_map, HashMap};
|
use super::{hash_map, HashMap};
|
||||||
use crate::environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmResult, WasmTypesMap};
|
use crate::environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmResult};
|
||||||
use crate::state::{ControlStackFrame, ElseData, TranslationState};
|
use crate::state::{ControlStackFrame, ElseData, FuncTranslationState, ModuleTranslationState};
|
||||||
use crate::translation_utils::{
|
use crate::translation_utils::{
|
||||||
blocktype_params_results, ebb_with_params, f32_translation, f64_translation,
|
blocktype_params_results, ebb_with_params, f32_translation, f64_translation,
|
||||||
};
|
};
|
||||||
@@ -43,14 +43,14 @@ use wasmparser::{MemoryImmediate, Operator};
|
|||||||
/// Translates wasm operators into Cranelift IR instructions. Returns `true` if it inserted
|
/// Translates wasm operators into Cranelift IR instructions. Returns `true` if it inserted
|
||||||
/// a return.
|
/// a return.
|
||||||
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
if !state.reachable {
|
if !state.reachable {
|
||||||
translate_unreachable_operator(wasm_types, &op, builder, state)?;
|
translate_unreachable_operator(module_translation_state, &op, builder, state)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,12 +133,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
* possible `Ebb`'s arguments values.
|
* possible `Ebb`'s arguments values.
|
||||||
***********************************************************************************/
|
***********************************************************************************/
|
||||||
Operator::Block { ty } => {
|
Operator::Block { ty } => {
|
||||||
let (params, results) = blocktype_params_results(wasm_types, *ty)?;
|
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||||
let next = ebb_with_params(builder, results)?;
|
let next = ebb_with_params(builder, results)?;
|
||||||
state.push_block(next, params.len(), results.len());
|
state.push_block(next, params.len(), results.len());
|
||||||
}
|
}
|
||||||
Operator::Loop { ty } => {
|
Operator::Loop { ty } => {
|
||||||
let (params, results) = blocktype_params_results(wasm_types, *ty)?;
|
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||||
let loop_body = ebb_with_params(builder, params)?;
|
let loop_body = ebb_with_params(builder, params)?;
|
||||||
let next = ebb_with_params(builder, results)?;
|
let next = ebb_with_params(builder, results)?;
|
||||||
builder.ins().jump(loop_body, state.peekn(params.len()));
|
builder.ins().jump(loop_body, state.peekn(params.len()));
|
||||||
@@ -155,7 +155,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
Operator::If { ty } => {
|
Operator::If { ty } => {
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
|
|
||||||
let (params, results) = blocktype_params_results(wasm_types, *ty)?;
|
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||||
let (destination, else_data) = if params == results {
|
let (destination, else_data) = if params == results {
|
||||||
// It is possible there is no `else` block, so we will only
|
// It is possible there is no `else` block, so we will only
|
||||||
// allocate an ebb for it if/when we find the `else`. For now,
|
// allocate an ebb for it if/when we find the `else`. For now,
|
||||||
@@ -214,7 +214,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
// The `if` has an `else`, so there's no branch to the end from the top.
|
// The `if` has an `else`, so there's no branch to the end from the top.
|
||||||
*reachable_from_top = false;
|
*reachable_from_top = false;
|
||||||
|
|
||||||
let (params, _results) = blocktype_params_results(wasm_types, blocktype)?;
|
let (params, _results) =
|
||||||
|
blocktype_params_results(module_translation_state, blocktype)?;
|
||||||
let else_ebb = ebb_with_params(builder, params)?;
|
let else_ebb = ebb_with_params(builder, params)?;
|
||||||
builder.ins().jump(destination, state.peekn(params.len()));
|
builder.ins().jump(destination, state.peekn(params.len()));
|
||||||
state.popn(params.len());
|
state.popn(params.len());
|
||||||
@@ -1206,10 +1207,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
|
/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
|
||||||
/// portion so the translation state must be updated accordingly.
|
/// portion so the translation state must be updated accordingly.
|
||||||
fn translate_unreachable_operator(
|
fn translate_unreachable_operator(
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
op: &Operator,
|
op: &Operator,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
match *op {
|
match *op {
|
||||||
Operator::If { ty } => {
|
Operator::If { ty } => {
|
||||||
@@ -1244,7 +1245,8 @@ fn translate_unreachable_operator(
|
|||||||
// branch from the top directly to the end.
|
// branch from the top directly to the end.
|
||||||
*reachable_from_top = false;
|
*reachable_from_top = false;
|
||||||
|
|
||||||
let (params, _results) = blocktype_params_results(wasm_types, blocktype)?;
|
let (params, _results) =
|
||||||
|
blocktype_params_results(module_translation_state, blocktype)?;
|
||||||
let else_ebb = ebb_with_params(builder, params)?;
|
let else_ebb = ebb_with_params(builder, params)?;
|
||||||
|
|
||||||
// We change the target of the branch instruction.
|
// We change the target of the branch instruction.
|
||||||
@@ -1371,7 +1373,7 @@ fn translate_load<FE: FuncEnvironment + ?Sized>(
|
|||||||
opcode: ir::Opcode,
|
opcode: ir::Opcode,
|
||||||
result_ty: Type,
|
result_ty: Type,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let addr32 = state.pop1();
|
let addr32 = state.pop1();
|
||||||
@@ -1394,7 +1396,7 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
|
|||||||
offset: u32,
|
offset: u32,
|
||||||
opcode: ir::Opcode,
|
opcode: ir::Opcode,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let (addr32, val) = state.pop2();
|
let (addr32, val) = state.pop2();
|
||||||
@@ -1411,13 +1413,13 @@ fn translate_store<FE: FuncEnvironment + ?Sized>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut TranslationState) {
|
fn translate_icmp(cc: IntCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
|
||||||
let (arg0, arg1) = state.pop2();
|
let (arg0, arg1) = state.pop2();
|
||||||
let val = builder.ins().icmp(cc, arg0, arg1);
|
let val = builder.ins().icmp(cc, arg0, arg1);
|
||||||
state.push1(builder.ins().bint(I32, val));
|
state.push1(builder.ins().bint(I32, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut TranslationState) {
|
fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut FuncTranslationState) {
|
||||||
let (arg0, arg1) = state.pop2();
|
let (arg0, arg1) = state.pop2();
|
||||||
let val = builder.ins().fcmp(cc, arg0, arg1);
|
let val = builder.ins().fcmp(cc, arg0, arg1);
|
||||||
state.push1(builder.ins().bint(I32, val));
|
state.push1(builder.ins().bint(I32, val));
|
||||||
@@ -1426,7 +1428,7 @@ fn translate_fcmp(cc: FloatCC, builder: &mut FunctionBuilder, state: &mut Transl
|
|||||||
fn translate_br_if(
|
fn translate_br_if(
|
||||||
relative_depth: u32,
|
relative_depth: u32,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
) {
|
) {
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
|
let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
|
||||||
@@ -1443,7 +1445,7 @@ fn translate_br_if(
|
|||||||
|
|
||||||
fn translate_br_if_args(
|
fn translate_br_if_args(
|
||||||
relative_depth: u32,
|
relative_depth: u32,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
) -> (ir::Ebb, &[ir::Value]) {
|
) -> (ir::Ebb, &[ir::Value]) {
|
||||||
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
||||||
let (return_count, br_destination) = {
|
let (return_count, br_destination) = {
|
||||||
|
|||||||
@@ -5,10 +5,9 @@
|
|||||||
//! [wasmtime-environ]: https://crates.io/crates/wasmtime-environ
|
//! [wasmtime-environ]: https://crates.io/crates/wasmtime-environ
|
||||||
//! [Wasmtime]: https://github.com/CraneStation/wasmtime
|
//! [Wasmtime]: https://github.com/CraneStation/wasmtime
|
||||||
|
|
||||||
use crate::environ::{
|
use crate::environ::{FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmResult};
|
||||||
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmResult, WasmTypesMap,
|
|
||||||
};
|
|
||||||
use crate::func_translator::FuncTranslator;
|
use crate::func_translator::FuncTranslator;
|
||||||
|
use crate::state::ModuleTranslationState;
|
||||||
use crate::translation_utils::{
|
use crate::translation_utils::{
|
||||||
DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
|
DefinedFuncIndex, FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table,
|
||||||
TableIndex,
|
TableIndex,
|
||||||
@@ -531,7 +530,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
|
|
||||||
fn define_function_body(
|
fn define_function_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
body_bytes: &'data [u8],
|
body_bytes: &'data [u8],
|
||||||
body_offset: usize,
|
body_offset: usize,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
@@ -546,7 +545,7 @@ impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
|
|||||||
func.collect_debug_info();
|
func.collect_debug_info();
|
||||||
}
|
}
|
||||||
self.trans.translate(
|
self.trans.translate(
|
||||||
wasm_types,
|
module_translation_state,
|
||||||
body_bytes,
|
body_bytes,
|
||||||
body_offset,
|
body_offset,
|
||||||
&mut func,
|
&mut func,
|
||||||
|
|||||||
@@ -7,5 +7,4 @@ mod spec;
|
|||||||
pub use crate::environ::dummy::DummyEnvironment;
|
pub use crate::environ::dummy::DummyEnvironment;
|
||||||
pub use crate::environ::spec::{
|
pub use crate::environ::spec::{
|
||||||
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError, WasmResult,
|
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError, WasmResult,
|
||||||
WasmTypesMap,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
//!
|
//!
|
||||||
//! [Wasmtime]: https://github.com/CraneStation/wasmtime
|
//! [Wasmtime]: https://github.com/CraneStation/wasmtime
|
||||||
|
|
||||||
use crate::state::TranslationState;
|
use crate::state::{FuncTranslationState, ModuleTranslationState};
|
||||||
use crate::translation_utils::{
|
use crate::translation_utils::{
|
||||||
FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
|
FuncIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
|
||||||
};
|
};
|
||||||
@@ -15,7 +15,6 @@ use cranelift_codegen::cursor::FuncCursor;
|
|||||||
use cranelift_codegen::ir::immediates::Offset32;
|
use cranelift_codegen::ir::immediates::Offset32;
|
||||||
use cranelift_codegen::ir::{self, InstBuilder};
|
use cranelift_codegen::ir::{self, InstBuilder};
|
||||||
use cranelift_codegen::isa::TargetFrontendConfig;
|
use cranelift_codegen::isa::TargetFrontendConfig;
|
||||||
use cranelift_entity::PrimaryMap;
|
|
||||||
use cranelift_frontend::FunctionBuilder;
|
use cranelift_frontend::FunctionBuilder;
|
||||||
use failure_derive::Fail;
|
use failure_derive::Fail;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
@@ -104,25 +103,6 @@ pub enum ReturnMode {
|
|||||||
FallthroughReturn,
|
FallthroughReturn,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A map containing a Wasm module's original, raw signatures.
|
|
||||||
///
|
|
||||||
/// This is used for translating multi-value Wasm blocks inside functions, which
|
|
||||||
/// are encoded to refer to their type signature via index.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WasmTypesMap {
|
|
||||||
pub(crate) inner:
|
|
||||||
PrimaryMap<SignatureIndex, (Box<[wasmparser::Type]>, Box<[wasmparser::Type]>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WasmTypesMap {
|
|
||||||
/// Creates a new type map.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: PrimaryMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Environment affecting the translation of a single WebAssembly function.
|
/// Environment affecting the translation of a single WebAssembly function.
|
||||||
///
|
///
|
||||||
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
|
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
|
||||||
@@ -301,7 +281,7 @@ pub trait FuncEnvironment {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_op: &Operator,
|
_op: &Operator,
|
||||||
_builder: &mut FunctionBuilder,
|
_builder: &mut FunctionBuilder,
|
||||||
_state: &TranslationState,
|
_state: &FuncTranslationState,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -312,7 +292,7 @@ pub trait FuncEnvironment {
|
|||||||
&mut self,
|
&mut self,
|
||||||
_op: &Operator,
|
_op: &Operator,
|
||||||
_builder: &mut FunctionBuilder,
|
_builder: &mut FunctionBuilder,
|
||||||
_state: &TranslationState,
|
_state: &FuncTranslationState,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -469,7 +449,7 @@ pub trait ModuleEnvironment<'data> {
|
|||||||
/// functions is already provided by `reserve_func_types`.
|
/// functions is already provided by `reserve_func_types`.
|
||||||
fn define_function_body(
|
fn define_function_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
body_bytes: &'data [u8],
|
body_bytes: &'data [u8],
|
||||||
body_offset: usize,
|
body_offset: usize,
|
||||||
) -> WasmResult<()>;
|
) -> WasmResult<()>;
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
//! WebAssembly module and the runtime environment.
|
//! WebAssembly module and the runtime environment.
|
||||||
|
|
||||||
use crate::code_translator::translate_operator;
|
use crate::code_translator::translate_operator;
|
||||||
use crate::environ::{FuncEnvironment, ReturnMode, WasmResult, WasmTypesMap};
|
use crate::environ::{FuncEnvironment, ReturnMode, WasmResult};
|
||||||
use crate::state::TranslationState;
|
use crate::state::{FuncTranslationState, ModuleTranslationState};
|
||||||
use crate::translation_utils::get_vmctx_value_label;
|
use crate::translation_utils::get_vmctx_value_label;
|
||||||
use crate::wasm_unsupported;
|
use crate::wasm_unsupported;
|
||||||
use cranelift_codegen::entity::EntityRef;
|
use cranelift_codegen::entity::EntityRef;
|
||||||
@@ -23,7 +23,7 @@ use wasmparser::{self, BinaryReader};
|
|||||||
/// functions which will reduce heap allocation traffic.
|
/// functions which will reduce heap allocation traffic.
|
||||||
pub struct FuncTranslator {
|
pub struct FuncTranslator {
|
||||||
func_ctx: FunctionBuilderContext,
|
func_ctx: FunctionBuilderContext,
|
||||||
state: TranslationState,
|
state: FuncTranslationState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FuncTranslator {
|
impl FuncTranslator {
|
||||||
@@ -31,7 +31,7 @@ impl FuncTranslator {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
func_ctx: FunctionBuilderContext::new(),
|
func_ctx: FunctionBuilderContext::new(),
|
||||||
state: TranslationState::new(),
|
state: FuncTranslationState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,14 +55,14 @@ impl FuncTranslator {
|
|||||||
///
|
///
|
||||||
pub fn translate<FE: FuncEnvironment + ?Sized>(
|
pub fn translate<FE: FuncEnvironment + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
code: &[u8],
|
code: &[u8],
|
||||||
code_offset: usize,
|
code_offset: usize,
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
self.translate_from_reader(
|
self.translate_from_reader(
|
||||||
wasm_types,
|
module_translation_state,
|
||||||
BinaryReader::new_with_offset(code, code_offset),
|
BinaryReader::new_with_offset(code, code_offset),
|
||||||
func,
|
func,
|
||||||
environ,
|
environ,
|
||||||
@@ -72,7 +72,7 @@ impl FuncTranslator {
|
|||||||
/// Translate a binary WebAssembly function from a `BinaryReader`.
|
/// Translate a binary WebAssembly function from a `BinaryReader`.
|
||||||
pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
|
pub fn translate_from_reader<FE: FuncEnvironment + ?Sized>(
|
||||||
&mut self,
|
&mut self,
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
mut reader: BinaryReader,
|
mut reader: BinaryReader,
|
||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
@@ -108,7 +108,13 @@ impl FuncTranslator {
|
|||||||
self.state.initialize(&builder.func.signature, exit_block);
|
self.state.initialize(&builder.func.signature, exit_block);
|
||||||
|
|
||||||
parse_local_decls(&mut reader, &mut builder, num_params, environ)?;
|
parse_local_decls(&mut reader, &mut builder, num_params, environ)?;
|
||||||
parse_function_body(wasm_types, reader, &mut builder, &mut self.state, environ)?;
|
parse_function_body(
|
||||||
|
module_translation_state,
|
||||||
|
reader,
|
||||||
|
&mut builder,
|
||||||
|
&mut self.state,
|
||||||
|
environ,
|
||||||
|
)?;
|
||||||
|
|
||||||
builder.finalize();
|
builder.finalize();
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -206,10 +212,10 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
|
|||||||
/// This assumes that the local variable declarations have already been parsed and function
|
/// This assumes that the local variable declarations have already been parsed and function
|
||||||
/// arguments and locals are declared in the builder.
|
/// arguments and locals are declared in the builder.
|
||||||
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
mut reader: BinaryReader,
|
mut reader: BinaryReader,
|
||||||
builder: &mut FunctionBuilder,
|
builder: &mut FunctionBuilder,
|
||||||
state: &mut TranslationState,
|
state: &mut FuncTranslationState,
|
||||||
environ: &mut FE,
|
environ: &mut FE,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
// The control stack is initialized with a single block representing the whole function.
|
// The control stack is initialized with a single block representing the whole function.
|
||||||
@@ -220,7 +226,7 @@ fn parse_function_body<FE: FuncEnvironment + ?Sized>(
|
|||||||
builder.set_srcloc(cur_srcloc(&reader));
|
builder.set_srcloc(cur_srcloc(&reader));
|
||||||
let op = reader.read_operator()?;
|
let op = reader.read_operator()?;
|
||||||
environ.before_translate_operator(&op, builder, state)?;
|
environ.before_translate_operator(&op, builder, state)?;
|
||||||
translate_operator(wasm_types, &op, builder, state, environ)?;
|
translate_operator(module_translation_state, &op, builder, state, environ)?;
|
||||||
environ.after_translate_operator(&op, builder, state)?;
|
environ.after_translate_operator(&op, builder, state)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +264,8 @@ fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{FuncTranslator, ReturnMode};
|
use super::{FuncTranslator, ReturnMode};
|
||||||
use crate::environ::{DummyEnvironment, WasmTypesMap};
|
use crate::environ::DummyEnvironment;
|
||||||
|
use crate::ModuleTranslationState;
|
||||||
use cranelift_codegen::ir::types::I32;
|
use cranelift_codegen::ir::types::I32;
|
||||||
use cranelift_codegen::{ir, isa, settings, Context};
|
use cranelift_codegen::{ir, isa, settings, Context};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
@@ -290,7 +297,7 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let wasm_types = WasmTypesMap::new();
|
let module_translation_state = ModuleTranslationState::new();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::ExternalName::testcase("small1");
|
ctx.func.name = ir::ExternalName::testcase("small1");
|
||||||
@@ -299,7 +306,7 @@ mod tests {
|
|||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(
|
.translate(
|
||||||
&wasm_types,
|
&module_translation_state,
|
||||||
&BODY,
|
&BODY,
|
||||||
0,
|
0,
|
||||||
&mut ctx.func,
|
&mut ctx.func,
|
||||||
@@ -337,7 +344,7 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let wasm_types = WasmTypesMap::new();
|
let module_translation_state = ModuleTranslationState::new();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::ExternalName::testcase("small2");
|
ctx.func.name = ir::ExternalName::testcase("small2");
|
||||||
@@ -346,7 +353,7 @@ mod tests {
|
|||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(
|
.translate(
|
||||||
&wasm_types,
|
&module_translation_state,
|
||||||
&BODY,
|
&BODY,
|
||||||
0,
|
0,
|
||||||
&mut ctx.func,
|
&mut ctx.func,
|
||||||
@@ -393,7 +400,7 @@ mod tests {
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
let wasm_types = WasmTypesMap::new();
|
let module_translation_state = ModuleTranslationState::new();
|
||||||
let mut ctx = Context::new();
|
let mut ctx = Context::new();
|
||||||
|
|
||||||
ctx.func.name = ir::ExternalName::testcase("infloop");
|
ctx.func.name = ir::ExternalName::testcase("infloop");
|
||||||
@@ -401,7 +408,7 @@ mod tests {
|
|||||||
|
|
||||||
trans
|
trans
|
||||||
.translate(
|
.translate(
|
||||||
&wasm_types,
|
&module_translation_state,
|
||||||
&BODY,
|
&BODY,
|
||||||
0,
|
0,
|
||||||
&mut ctx.func,
|
&mut ctx.func,
|
||||||
|
|||||||
@@ -59,11 +59,12 @@ mod translation_utils;
|
|||||||
|
|
||||||
pub use crate::environ::{
|
pub use crate::environ::{
|
||||||
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError,
|
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError,
|
||||||
WasmResult, WasmTypesMap,
|
WasmResult,
|
||||||
};
|
};
|
||||||
pub use crate::func_translator::FuncTranslator;
|
pub use crate::func_translator::FuncTranslator;
|
||||||
pub use crate::module_translator::translate_module;
|
pub use crate::module_translator::translate_module;
|
||||||
pub use crate::state::TranslationState;
|
pub use crate::state::func_state::FuncTranslationState;
|
||||||
|
pub use crate::state::module_state::ModuleTranslationState;
|
||||||
pub use crate::translation_utils::{
|
pub use crate::translation_utils::{
|
||||||
get_vmctx_value_label, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex,
|
get_vmctx_value_label, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex,
|
||||||
DefinedTableIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex,
|
DefinedTableIndex, FuncIndex, Global, GlobalIndex, GlobalInit, Memory, MemoryIndex,
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
//! Translation skeleton that traverses the whole WebAssembly module and call helper functions
|
||||||
//! to deal with each part of it.
|
//! to deal with each part of it.
|
||||||
use crate::environ::{ModuleEnvironment, WasmError, WasmResult, WasmTypesMap};
|
use crate::environ::{ModuleEnvironment, WasmError, WasmResult};
|
||||||
use crate::sections_translator::{
|
use crate::sections_translator::{
|
||||||
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
parse_code_section, parse_data_section, parse_element_section, parse_export_section,
|
||||||
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
parse_function_section, parse_global_section, parse_import_section, parse_memory_section,
|
||||||
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
parse_name_section, parse_start_section, parse_table_section, parse_type_section,
|
||||||
};
|
};
|
||||||
|
use crate::state::ModuleTranslationState;
|
||||||
use cranelift_codegen::timing;
|
use cranelift_codegen::timing;
|
||||||
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
||||||
|
|
||||||
@@ -14,16 +15,16 @@ use wasmparser::{CustomSectionContent, ModuleReader, SectionContent};
|
|||||||
pub fn translate_module<'data>(
|
pub fn translate_module<'data>(
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
environ: &mut dyn ModuleEnvironment<'data>,
|
environ: &mut dyn ModuleEnvironment<'data>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<ModuleTranslationState> {
|
||||||
let _tt = timing::wasm_translate_module();
|
let _tt = timing::wasm_translate_module();
|
||||||
let mut reader = ModuleReader::new(data)?;
|
let mut reader = ModuleReader::new(data)?;
|
||||||
let mut wasm_types = WasmTypesMap::new();
|
let mut module_translation_state = ModuleTranslationState::new();
|
||||||
|
|
||||||
while !reader.eof() {
|
while !reader.eof() {
|
||||||
let section = reader.read()?;
|
let section = reader.read()?;
|
||||||
match section.content()? {
|
match section.content()? {
|
||||||
SectionContent::Type(types) => {
|
SectionContent::Type(types) => {
|
||||||
parse_type_section(types, &mut wasm_types, environ)?;
|
parse_type_section(types, &mut module_translation_state, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Import(imports) => {
|
SectionContent::Import(imports) => {
|
||||||
@@ -59,7 +60,7 @@ pub fn translate_module<'data>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Code(code) => {
|
SectionContent::Code(code) => {
|
||||||
parse_code_section(code, &wasm_types, environ)?;
|
parse_code_section(code, &module_translation_state, environ)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectionContent::Data(data) => {
|
SectionContent::Data(data) => {
|
||||||
@@ -91,5 +92,5 @@ pub fn translate_module<'data>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(module_translation_state)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
//! The special case of the initialize expressions for table elements offsets or global variables
|
//! The special case of the initialize expressions for table elements offsets or global variables
|
||||||
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
//! is handled, according to the semantics of WebAssembly, to only specific expressions that are
|
||||||
//! interpreted on the fly.
|
//! interpreted on the fly.
|
||||||
use crate::environ::{ModuleEnvironment, WasmResult, WasmTypesMap};
|
use crate::environ::{ModuleEnvironment, WasmResult};
|
||||||
|
use crate::state::ModuleTranslationState;
|
||||||
use crate::translation_utils::{
|
use crate::translation_utils::{
|
||||||
tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
tabletype_to_type, type_to_type, FuncIndex, Global, GlobalIndex, GlobalInit, Memory,
|
||||||
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
MemoryIndex, SignatureIndex, Table, TableElementType, TableIndex,
|
||||||
@@ -29,11 +30,11 @@ use wasmparser::{
|
|||||||
/// Parses the Type section of the wasm module.
|
/// Parses the Type section of the wasm module.
|
||||||
pub fn parse_type_section(
|
pub fn parse_type_section(
|
||||||
types: TypeSectionReader,
|
types: TypeSectionReader,
|
||||||
wasm_types: &mut WasmTypesMap,
|
module_translation_state: &mut ModuleTranslationState,
|
||||||
environ: &mut dyn ModuleEnvironment,
|
environ: &mut dyn ModuleEnvironment,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
let count = types.get_count();
|
let count = types.get_count();
|
||||||
wasm_types.inner.reserve(count as usize);
|
module_translation_state.wasm_types.reserve(count as usize);
|
||||||
environ.reserve_signatures(count)?;
|
environ.reserve_signatures(count)?;
|
||||||
|
|
||||||
for entry in types {
|
for entry in types {
|
||||||
@@ -55,7 +56,7 @@ pub fn parse_type_section(
|
|||||||
AbiParam::new(cret_arg)
|
AbiParam::new(cret_arg)
|
||||||
}));
|
}));
|
||||||
environ.declare_signature(sig)?;
|
environ.declare_signature(sig)?;
|
||||||
wasm_types.inner.push((params, returns));
|
module_translation_state.wasm_types.push((params, returns));
|
||||||
}
|
}
|
||||||
ty => {
|
ty => {
|
||||||
return Err(wasm_unsupported!(
|
return Err(wasm_unsupported!(
|
||||||
@@ -327,14 +328,14 @@ pub fn parse_element_section<'data>(
|
|||||||
/// Parses the Code section of the wasm module.
|
/// Parses the Code section of the wasm module.
|
||||||
pub fn parse_code_section<'data>(
|
pub fn parse_code_section<'data>(
|
||||||
code: CodeSectionReader<'data>,
|
code: CodeSectionReader<'data>,
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
environ: &mut dyn ModuleEnvironment<'data>,
|
environ: &mut dyn ModuleEnvironment<'data>,
|
||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
for body in code {
|
for body in code {
|
||||||
let mut reader = body?.get_binary_reader();
|
let mut reader = body?.get_binary_reader();
|
||||||
let size = reader.bytes_remaining();
|
let size = reader.bytes_remaining();
|
||||||
let offset = reader.original_position();
|
let offset = reader.original_position();
|
||||||
environ.define_function_body(wasm_types, reader.read_bytes(size)?, offset)?;
|
environ.define_function_body(module_translation_state, reader.read_bytes(size)?, offset)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
//! WebAssembly function translation state.
|
//! WebAssembly module and function translation state.
|
||||||
//!
|
//!
|
||||||
//! The `TranslationState` struct defined in this module is used to keep track of the WebAssembly
|
//! The `ModuleTranslationState` struct defined in this module is used to keep track of data about
|
||||||
|
//! the whole WebAssembly module, such as the decoded type signatures.
|
||||||
|
//!
|
||||||
|
//! The `FuncTranslationState` struct defined in this module is used to keep track of the WebAssembly
|
||||||
//! value and control stacks during the translation of a single function.
|
//! value and control stacks during the translation of a single function.
|
||||||
|
|
||||||
use super::{HashMap, Occupied, Vacant};
|
|
||||||
use crate::environ::{FuncEnvironment, GlobalVariable, WasmResult};
|
use crate::environ::{FuncEnvironment, GlobalVariable, WasmResult};
|
||||||
use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
|
use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
|
||||||
|
use crate::{HashMap, Occupied, Vacant};
|
||||||
use cranelift_codegen::ir::{self, Ebb, Inst, Value};
|
use cranelift_codegen::ir::{self, Ebb, Inst, Value};
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@@ -159,12 +162,12 @@ impl ControlStackFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains information passed along during the translation and that records:
|
/// Contains information passed along during a function's translation and that records:
|
||||||
///
|
///
|
||||||
/// - The current value and control stacks.
|
/// - The current value and control stacks.
|
||||||
/// - The depth of the two unreachable control blocks stacks, that are manipulated when translating
|
/// - The depth of the two unreachable control blocks stacks, that are manipulated when translating
|
||||||
/// unreachable code;
|
/// unreachable code;
|
||||||
pub struct TranslationState {
|
pub struct FuncTranslationState {
|
||||||
/// A stack of values corresponding to the active values in the input wasm function at this
|
/// A stack of values corresponding to the active values in the input wasm function at this
|
||||||
/// point.
|
/// point.
|
||||||
pub(crate) stack: Vec<Value>,
|
pub(crate) stack: Vec<Value>,
|
||||||
@@ -195,7 +198,7 @@ pub struct TranslationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Public methods that are exposed to non-`cranelift_wasm` API consumers.
|
// Public methods that are exposed to non-`cranelift_wasm` API consumers.
|
||||||
impl TranslationState {
|
impl FuncTranslationState {
|
||||||
/// True if the current translation state expresses reachable code, false if it is unreachable.
|
/// True if the current translation state expresses reachable code, false if it is unreachable.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reachable(&self) -> bool {
|
pub fn reachable(&self) -> bool {
|
||||||
@@ -203,8 +206,8 @@ impl TranslationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TranslationState {
|
impl FuncTranslationState {
|
||||||
/// Construct a new, empty, `TranslationState`
|
/// Construct a new, empty, `FuncTranslationState`
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
@@ -386,7 +389,7 @@ impl TranslationState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Methods for handling entity references.
|
/// Methods for handling entity references.
|
||||||
impl TranslationState {
|
impl FuncTranslationState {
|
||||||
/// Get the `GlobalVariable` reference that should be used to access the global variable
|
/// Get the `GlobalVariable` reference that should be used to access the global variable
|
||||||
/// `index`. Create the reference if necessary.
|
/// `index`. Create the reference if necessary.
|
||||||
/// Also return the WebAssembly type of the global.
|
/// Also return the WebAssembly type of the global.
|
||||||
14
cranelift/wasm/src/state/mod.rs
Normal file
14
cranelift/wasm/src/state/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
//! WebAssembly module and function translation state.
|
||||||
|
//!
|
||||||
|
//! The `ModuleTranslationState` struct defined in this module is used to keep track of data about
|
||||||
|
//! the whole WebAssembly module, such as the decoded type signatures.
|
||||||
|
//!
|
||||||
|
//! The `FuncTranslationState` struct defined in this module is used to keep track of the WebAssembly
|
||||||
|
//! value and control stacks during the translation of a single function.
|
||||||
|
|
||||||
|
pub(crate) mod func_state;
|
||||||
|
pub(crate) mod module_state;
|
||||||
|
|
||||||
|
// Re-export for convenience.
|
||||||
|
pub(crate) use func_state::*;
|
||||||
|
pub(crate) use module_state::*;
|
||||||
27
cranelift/wasm/src/state/module_state.rs
Normal file
27
cranelift/wasm/src/state/module_state.rs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
use crate::translation_utils::SignatureIndex;
|
||||||
|
use cranelift_entity::PrimaryMap;
|
||||||
|
use std::boxed::Box;
|
||||||
|
|
||||||
|
/// Contains information decoded from the Wasm module that must be referenced
|
||||||
|
/// during each Wasm function's translation.
|
||||||
|
///
|
||||||
|
/// This is only for data that is maintained by `cranelift-wasm` itself, as
|
||||||
|
/// opposed to being maintained by the embedder. Data that is maintained by the
|
||||||
|
/// embedder is represented with `ModuleEnvironment`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ModuleTranslationState {
|
||||||
|
/// A map containing a Wasm module's original, raw signatures.
|
||||||
|
///
|
||||||
|
/// This is used for translating multi-value Wasm blocks inside functions,
|
||||||
|
/// which are encoded to refer to their type signature via index.
|
||||||
|
pub(crate) wasm_types:
|
||||||
|
PrimaryMap<SignatureIndex, (Box<[wasmparser::Type]>, Box<[wasmparser::Type]>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleTranslationState {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
ModuleTranslationState {
|
||||||
|
wasm_types: PrimaryMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
//! Helper functions and structures for the translation.
|
//! Helper functions and structures for the translation.
|
||||||
use crate::environ::{WasmResult, WasmTypesMap};
|
use crate::environ::WasmResult;
|
||||||
|
use crate::state::ModuleTranslationState;
|
||||||
use crate::wasm_unsupported;
|
use crate::wasm_unsupported;
|
||||||
use core::u32;
|
use core::u32;
|
||||||
use cranelift_codegen::entity::entity_impl;
|
use cranelift_codegen::entity::entity_impl;
|
||||||
@@ -148,7 +149,7 @@ pub fn tabletype_to_type(ty: wasmparser::Type) -> WasmResult<Option<ir::Type>> {
|
|||||||
|
|
||||||
/// Get the parameter and result types for the given Wasm blocktype.
|
/// Get the parameter and result types for the given Wasm blocktype.
|
||||||
pub fn blocktype_params_results(
|
pub fn blocktype_params_results(
|
||||||
wasm_types: &WasmTypesMap,
|
module_translation_state: &ModuleTranslationState,
|
||||||
ty_or_ft: wasmparser::TypeOrFuncType,
|
ty_or_ft: wasmparser::TypeOrFuncType,
|
||||||
) -> WasmResult<(&[wasmparser::Type], &[wasmparser::Type])> {
|
) -> WasmResult<(&[wasmparser::Type], &[wasmparser::Type])> {
|
||||||
Ok(match ty_or_ft {
|
Ok(match ty_or_ft {
|
||||||
@@ -163,7 +164,7 @@ pub fn blocktype_params_results(
|
|||||||
},
|
},
|
||||||
wasmparser::TypeOrFuncType::FuncType(ty_index) => {
|
wasmparser::TypeOrFuncType::FuncType(ty_index) => {
|
||||||
let sig_idx = SignatureIndex::from_u32(ty_index);
|
let sig_idx = SignatureIndex::from_u32(ty_index);
|
||||||
let (ref params, ref returns) = wasm_types.inner[sig_idx];
|
let (ref params, ref returns) = module_translation_state.wasm_types[sig_idx];
|
||||||
(&*params, &*returns)
|
(&*params, &*returns)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user