Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit c4762e5

Browse files
authored
Add wasm reference/pointers translation. (#1073)
1 parent 78769a1 commit c4762e5

File tree

10 files changed

+85
-44
lines changed

10 files changed

+85
-44
lines changed

cranelift-wasm/src/code_translator.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
5555
environ: &mut FE,
5656
) -> WasmResult<()> {
5757
if !state.reachable {
58-
translate_unreachable_operator(module_translation_state, &op, builder, state)?;
58+
translate_unreachable_operator(module_translation_state, &op, builder, state, environ)?;
5959
return Ok(());
6060
}
6161

@@ -139,13 +139,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
139139
***********************************************************************************/
140140
Operator::Block { ty } => {
141141
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
142-
let next = ebb_with_params(builder, results)?;
142+
let next = ebb_with_params(builder, results, environ)?;
143143
state.push_block(next, params.len(), results.len());
144144
}
145145
Operator::Loop { ty } => {
146146
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
147-
let loop_body = ebb_with_params(builder, params)?;
148-
let next = ebb_with_params(builder, results)?;
147+
let loop_body = ebb_with_params(builder, params, environ)?;
148+
let next = ebb_with_params(builder, results, environ)?;
149149
builder.ins().jump(loop_body, state.peekn(params.len()));
150150
state.push_loop(loop_body, next, params.len(), results.len());
151151

@@ -168,16 +168,16 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
168168
// destination ebb following the whole `if...end`. If we do end
169169
// up discovering an `else`, then we will allocate an ebb for it
170170
// and go back and patch the jump.
171-
let destination = ebb_with_params(builder, results)?;
171+
let destination = ebb_with_params(builder, results, environ)?;
172172
let branch_inst = builder
173173
.ins()
174174
.brz(val, destination, state.peekn(params.len()));
175175
(destination, ElseData::NoElse { branch_inst })
176176
} else {
177177
// The `if` type signature is not valid without an `else` block,
178178
// so we eagerly allocate the `else` block here.
179-
let destination = ebb_with_params(builder, results)?;
180-
let else_block = ebb_with_params(builder, params)?;
179+
let destination = ebb_with_params(builder, results, environ)?;
180+
let else_block = ebb_with_params(builder, params, environ)?;
181181
builder
182182
.ins()
183183
.brz(val, else_block, state.peekn(params.len()));
@@ -229,7 +229,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
229229
let (params, _results) =
230230
blocktype_params_results(module_translation_state, blocktype)?;
231231
debug_assert_eq!(params.len(), num_return_values);
232-
let else_ebb = ebb_with_params(builder, params)?;
232+
let else_ebb = ebb_with_params(builder, params, environ)?;
233233
builder.ins().jump(destination, state.peekn(params.len()));
234234
state.popn(params.len());
235235

@@ -1352,11 +1352,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
13521352
/// Deals with a Wasm instruction located in an unreachable portion of the code. Most of them
13531353
/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
13541354
/// portion so the translation state must be updated accordingly.
1355-
fn translate_unreachable_operator(
1355+
fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
13561356
module_translation_state: &ModuleTranslationState,
13571357
op: &Operator,
13581358
builder: &mut FunctionBuilder,
13591359
state: &mut FuncTranslationState,
1360+
environ: &mut FE,
13601361
) -> WasmResult<()> {
13611362
debug_assert!(!state.reachable);
13621363
match *op {
@@ -1397,7 +1398,7 @@ fn translate_unreachable_operator(
13971398
ElseData::NoElse { branch_inst } => {
13981399
let (params, _results) =
13991400
blocktype_params_results(module_translation_state, blocktype)?;
1400-
let else_ebb = ebb_with_params(builder, params)?;
1401+
let else_ebb = ebb_with_params(builder, params, environ)?;
14011402

14021403
// We change the target of the branch instruction.
14031404
builder.change_jump_destination(branch_inst, else_ebb);

cranelift-wasm/src/environ/dummy.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
//! [wasmtime-environ]: https://crates.io/crates/wasmtime-environ
66
//! [Wasmtime]: https://github.com/bytecodealliance/wasmtime
77
8-
use crate::environ::{FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmResult};
8+
use crate::environ::{
9+
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmResult,
10+
};
911
use crate::func_translator::FuncTranslator;
1012
use crate::state::ModuleTranslationState;
1113
use crate::translation_utils::{
@@ -192,11 +194,13 @@ impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
192194
}
193195
}
194196

195-
impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
197+
impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
196198
fn target_config(&self) -> TargetFrontendConfig {
197199
self.mod_info.config
198200
}
201+
}
199202

203+
impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
200204
fn return_mode(&self) -> ReturnMode {
201205
self.return_mode
202206
}
@@ -454,11 +458,13 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
454458
}
455459
}
456460

457-
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
461+
impl TargetEnvironment for DummyEnvironment {
458462
fn target_config(&self) -> TargetFrontendConfig {
459463
self.info.config
460464
}
465+
}
461466

467+
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
462468
fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()> {
463469
self.info.signatures.push(sig);
464470
Ok(())

cranelift-wasm/src/environ/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ mod spec;
66

77
pub use crate::environ::dummy::DummyEnvironment;
88
pub use crate::environ::spec::{
9-
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError, WasmResult,
9+
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmError,
10+
WasmResult,
1011
};

cranelift-wasm/src/environ/spec.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,8 @@ pub enum ReturnMode {
103103
FallthroughReturn,
104104
}
105105

106-
/// Environment affecting the translation of a single WebAssembly function.
107-
///
108-
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
109-
/// IR. The function environment provides information about the WebAssembly module as well as the
110-
/// runtime environment.
111-
pub trait FuncEnvironment {
106+
/// Environment affecting the translation of a WebAssembly.
107+
pub trait TargetEnvironment {
112108
/// Get the information needed to produce Cranelift IR for the given target.
113109
fn target_config(&self) -> TargetFrontendConfig;
114110

@@ -124,13 +120,6 @@ pub trait FuncEnvironment {
124120
self.target_config().pointer_bytes()
125121
}
126122

127-
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
128-
/// of the function body, rather than `return` instructions as needed? This is used by VMs
129-
/// to append custom epilogues.
130-
fn return_mode(&self) -> ReturnMode {
131-
ReturnMode::NormalReturns
132-
}
133-
134123
/// Get the Cranelift reference type to use for native references.
135124
///
136125
/// This returns `R64` for 64-bit architectures and `R32` for 32-bit architectures.
@@ -141,6 +130,20 @@ pub trait FuncEnvironment {
141130
_ => panic!("unsupported pointer type"),
142131
}
143132
}
133+
}
134+
135+
/// Environment affecting the translation of a single WebAssembly function.
136+
///
137+
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
138+
/// IR. The function environment provides information about the WebAssembly module as well as the
139+
/// runtime environment.
140+
pub trait FuncEnvironment: TargetEnvironment {
141+
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
142+
/// of the function body, rather than `return` instructions as needed? This is used by VMs
143+
/// to append custom epilogues.
144+
fn return_mode(&self) -> ReturnMode {
145+
ReturnMode::NormalReturns
146+
}
144147

145148
/// Set up the necessary preamble definitions in `func` to access the global variable
146149
/// identified by `index`.
@@ -384,10 +387,7 @@ pub trait FuncEnvironment {
384387
/// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the
385388
/// [`translate_module`](fn.translate_module.html) function. These methods should not be called
386389
/// by the user, they are only for `cranelift-wasm` internal use.
387-
pub trait ModuleEnvironment<'data> {
388-
/// Get the information needed to produce Cranelift IR for the current target.
389-
fn target_config(&self) -> TargetFrontendConfig;
390-
390+
pub trait ModuleEnvironment<'data>: TargetEnvironment {
391391
/// Provides the number of signatures up front. By default this does nothing, but
392392
/// implementations can use this to preallocate memory if desired.
393393
fn reserve_signatures(&mut self, _num: u32) -> WasmResult<()> {

cranelift-wasm/src/func_translator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
193193
builder.ins().vconst(ir::types::I8X16, constant_handle)
194194
}
195195
AnyRef => builder.ins().null(environ.reference_type()),
196+
AnyFunc => builder.ins().null(environ.reference_type()),
196197
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
197198
};
198199

cranelift-wasm/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ mod state;
5858
mod translation_utils;
5959

6060
pub use crate::environ::{
61-
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmError,
62-
WasmResult,
61+
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
62+
TargetEnvironment, WasmError, WasmResult,
6363
};
6464
pub use crate::func_translator::FuncTranslator;
6565
pub use crate::module_translator::translate_module;

cranelift-wasm/src/sections_translator.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,15 @@ pub fn parse_type_section(
4444
params,
4545
returns,
4646
} => {
47-
let mut sig = Signature::new(environ.target_config().default_call_conv);
47+
let mut sig =
48+
Signature::new(ModuleEnvironment::target_config(environ).default_call_conv);
4849
sig.params.extend(params.iter().map(|ty| {
49-
let cret_arg: ir::Type = type_to_type(*ty)
50+
let cret_arg: ir::Type = type_to_type(*ty, environ)
5051
.expect("only numeric types are supported in function signatures");
5152
AbiParam::new(cret_arg)
5253
}));
5354
sig.returns.extend(returns.iter().map(|ty| {
54-
let cret_arg: ir::Type = type_to_type(*ty)
55+
let cret_arg: ir::Type = type_to_type(*ty, environ)
5556
.expect("only numeric types are supported in function signatures");
5657
AbiParam::new(cret_arg)
5758
}));
@@ -106,7 +107,7 @@ pub fn parse_import_section<'data>(
106107
ImportSectionEntryType::Global(ref ty) => {
107108
environ.declare_global_import(
108109
Global {
109-
ty: type_to_type(ty.content_type).unwrap(),
110+
ty: type_to_type(ty.content_type, environ).unwrap(),
110111
mutability: ty.mutable,
111112
initializer: GlobalInit::Import,
112113
},
@@ -117,7 +118,7 @@ pub fn parse_import_section<'data>(
117118
ImportSectionEntryType::Table(ref tab) => {
118119
environ.declare_table_import(
119120
Table {
120-
ty: match tabletype_to_type(tab.element_type)? {
121+
ty: match tabletype_to_type(tab.element_type, environ)? {
121122
Some(t) => TableElementType::Val(t),
122123
None => TableElementType::Func,
123124
},
@@ -160,7 +161,7 @@ pub fn parse_table_section(
160161
for entry in tables {
161162
let table = entry?;
162163
environ.declare_table(Table {
163-
ty: match tabletype_to_type(table.element_type)? {
164+
ty: match tabletype_to_type(table.element_type, environ)? {
164165
Some(t) => TableElementType::Val(t),
165166
None => TableElementType::Func,
166167
},
@@ -215,6 +216,7 @@ pub fn parse_global_section(
215216
Operator::V128Const { value } => {
216217
GlobalInit::V128Const(V128Imm::from(value.bytes().to_vec().as_slice()))
217218
}
219+
Operator::RefNull => GlobalInit::RefNullConst,
218220
Operator::GetGlobal { global_index } => {
219221
GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
220222
}
@@ -226,7 +228,7 @@ pub fn parse_global_section(
226228
}
227229
};
228230
let global = Global {
229-
ty: type_to_type(content_type).unwrap(),
231+
ty: type_to_type(content_type, environ).unwrap(),
230232
mutability: mutable,
231233
initializer,
232234
};

cranelift-wasm/src/translation_utils.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! Helper functions and structures for the translation.
2-
use crate::environ::WasmResult;
2+
use crate::environ::{TargetEnvironment, WasmResult};
33
use crate::state::ModuleTranslationState;
44
use crate::wasm_unsupported;
55
use core::u32;
@@ -83,6 +83,8 @@ pub enum GlobalInit {
8383
V128Const(V128Imm),
8484
/// A `get_global` of another global.
8585
GetGlobal(GlobalIndex),
86+
/// A `ref.null`.
87+
RefNullConst,
8688
///< The global is imported from, and thus initialized by, a different module.
8789
Import,
8890
}
@@ -119,26 +121,34 @@ pub struct Memory {
119121
}
120122

121123
/// Helper function translating wasmparser types to Cranelift types when possible.
122-
pub fn type_to_type(ty: wasmparser::Type) -> WasmResult<ir::Type> {
124+
pub fn type_to_type<PE: TargetEnvironment + ?Sized>(
125+
ty: wasmparser::Type,
126+
environ: &PE,
127+
) -> WasmResult<ir::Type> {
123128
match ty {
124129
wasmparser::Type::I32 => Ok(ir::types::I32),
125130
wasmparser::Type::I64 => Ok(ir::types::I64),
126131
wasmparser::Type::F32 => Ok(ir::types::F32),
127132
wasmparser::Type::F64 => Ok(ir::types::F64),
128133
wasmparser::Type::V128 => Ok(ir::types::I8X16),
134+
wasmparser::Type::AnyRef | wasmparser::Type::AnyFunc => Ok(environ.reference_type()),
129135
ty => Err(wasm_unsupported!("type_to_type: wasm type {:?}", ty)),
130136
}
131137
}
132138

133139
/// Helper function translating wasmparser possible table types to Cranelift types when possible,
134140
/// or None for Func tables.
135-
pub fn tabletype_to_type(ty: wasmparser::Type) -> WasmResult<Option<ir::Type>> {
141+
pub fn tabletype_to_type<PE: TargetEnvironment + ?Sized>(
142+
ty: wasmparser::Type,
143+
environ: &PE,
144+
) -> WasmResult<Option<ir::Type>> {
136145
match ty {
137146
wasmparser::Type::I32 => Ok(Some(ir::types::I32)),
138147
wasmparser::Type::I64 => Ok(Some(ir::types::I64)),
139148
wasmparser::Type::F32 => Ok(Some(ir::types::F32)),
140149
wasmparser::Type::F64 => Ok(Some(ir::types::F64)),
141150
wasmparser::Type::V128 => Ok(Some(ir::types::I8X16)),
151+
wasmparser::Type::AnyRef => Ok(Some(environ.reference_type())),
142152
wasmparser::Type::AnyFunc => Ok(None),
143153
ty => Err(wasm_unsupported!(
144154
"tabletype_to_type: table wasm type {:?}",
@@ -159,6 +169,8 @@ pub fn blocktype_params_results(
159169
wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]),
160170
wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]),
161171
wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]),
172+
wasmparser::Type::AnyRef => (&[], &[wasmparser::Type::AnyRef]),
173+
wasmparser::Type::AnyFunc => (&[], &[wasmparser::Type::AnyFunc]),
162174
wasmparser::Type::EmptyBlockType => (&[], &[]),
163175
ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)),
164176
},
@@ -171,9 +183,10 @@ pub fn blocktype_params_results(
171183
}
172184

173185
/// Create an `Ebb` with the given Wasm parameters.
174-
pub fn ebb_with_params(
186+
pub fn ebb_with_params<PE: TargetEnvironment + ?Sized>(
175187
builder: &mut FunctionBuilder,
176188
params: &[wasmparser::Type],
189+
environ: &PE,
177190
) -> WasmResult<ir::Ebb> {
178191
let ebb = builder.create_ebb();
179192
for ty in params.iter() {
@@ -190,6 +203,9 @@ pub fn ebb_with_params(
190203
wasmparser::Type::F64 => {
191204
builder.append_ebb_param(ebb, ir::types::F64);
192205
}
206+
wasmparser::Type::AnyRef | wasmparser::Type::AnyFunc => {
207+
builder.append_ebb_param(ebb, environ.reference_type());
208+
}
193209
wasmparser::Type::V128 => {
194210
builder.append_ebb_param(ebb, ir::types::I8X16);
195211
}

src/clif-util.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ fn add_enable_multi_value<'a>() -> clap::Arg<'a, 'a> {
119119
.help("Enable WASM's multi-value support")
120120
}
121121

122+
fn add_enable_reference_types_flag<'a>() -> clap::Arg<'a, 'a> {
123+
Arg::with_name("enable-reference-types")
124+
.long("enable-reference-types")
125+
.help("Enable WASM's reference types operations")
126+
}
127+
122128
fn add_just_decode_flag<'a>() -> clap::Arg<'a, 'a> {
123129
Arg::with_name("just-decode")
124130
.short("t")
@@ -163,6 +169,7 @@ fn add_wasm_or_compile<'a>(cmd: &str) -> clap::App<'a, 'a> {
163169
.arg(add_debug_flag())
164170
.arg(add_enable_simd_flag())
165171
.arg(add_enable_multi_value())
172+
.arg(add_enable_reference_types_flag())
166173
.arg(add_just_decode_flag())
167174
.arg(add_check_translation_flag())
168175
}
@@ -316,6 +323,7 @@ fn main() {
316323
rest_cmd.is_present("value-ranges"),
317324
rest_cmd.is_present("enable-simd"),
318325
rest_cmd.is_present("enable-multi-value"),
326+
rest_cmd.is_present("enable-reference-types"),
319327
)
320328
};
321329

0 commit comments

Comments
 (0)