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

Commit 59ece79

Browse files
committed
Add wasm reference/pointers translation.
1 parent 01201b1 commit 59ece79

File tree

10 files changed

+84
-45
lines changed

10 files changed

+84
-45
lines changed

cranelift-wasm/src/code_translator.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
5050
environ: &mut FE,
5151
) -> WasmResult<()> {
5252
if !state.reachable {
53-
translate_unreachable_operator(wasm_types, &op, builder, state)?;
53+
translate_unreachable_operator(wasm_types, &op, builder, state, environ)?;
5454
return Ok(());
5555
}
5656

@@ -134,13 +134,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
134134
***********************************************************************************/
135135
Operator::Block { ty } => {
136136
let (params, results) = blocktype_params_results(wasm_types, *ty)?;
137-
let next = ebb_with_params(builder, results)?;
137+
let next = ebb_with_params(builder, results, environ)?;
138138
state.push_block(next, params.len(), results.len());
139139
}
140140
Operator::Loop { ty } => {
141141
let (params, results) = blocktype_params_results(wasm_types, *ty)?;
142-
let loop_body = ebb_with_params(builder, params)?;
143-
let next = ebb_with_params(builder, results)?;
142+
let loop_body = ebb_with_params(builder, params, environ)?;
143+
let next = ebb_with_params(builder, results, environ)?;
144144
builder.ins().jump(loop_body, state.peekn(params.len()));
145145
state.push_loop(loop_body, next, params.len(), results.len());
146146

@@ -163,16 +163,16 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
163163
// destination ebb following the whole `if...end`. If we do end
164164
// up discovering an `else`, then we will allocate an ebb for it
165165
// and go back and patch the jump.
166-
let destination = ebb_with_params(builder, results)?;
166+
let destination = ebb_with_params(builder, results, environ)?;
167167
let branch_inst = builder
168168
.ins()
169169
.brz(val, destination, state.peekn(params.len()));
170170
(destination, ElseData::NoElse { branch_inst })
171171
} else {
172172
// The `if` type signature is not valid without an `else` block,
173173
// so we eagerly allocate the `else` block here.
174-
let destination = ebb_with_params(builder, results)?;
175-
let else_block = ebb_with_params(builder, params)?;
174+
let destination = ebb_with_params(builder, results, environ)?;
175+
let else_block = ebb_with_params(builder, params, environ)?;
176176
builder
177177
.ins()
178178
.brz(val, else_block, state.peekn(params.len()));
@@ -215,7 +215,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
215215
*reachable_from_top = false;
216216

217217
let (params, _results) = blocktype_params_results(wasm_types, blocktype)?;
218-
let else_ebb = ebb_with_params(builder, params)?;
218+
let else_ebb = ebb_with_params(builder, params, environ)?;
219219
builder.ins().jump(destination, state.peekn(params.len()));
220220
state.popn(params.len());
221221

@@ -1193,11 +1193,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
11931193
/// Deals with a Wasm instruction located in an unreachable portion of the code. Most of them
11941194
/// are dropped but special ones like `End` or `Else` signal the potential end of the unreachable
11951195
/// portion so the translation state must be updated accordingly.
1196-
fn translate_unreachable_operator(
1196+
fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
11971197
wasm_types: &WasmTypesMap,
11981198
op: &Operator,
11991199
builder: &mut FunctionBuilder,
12001200
state: &mut TranslationState,
1201+
environ: &mut FE,
12011202
) -> WasmResult<()> {
12021203
match *op {
12031204
Operator::If { ty } => {
@@ -1233,7 +1234,7 @@ fn translate_unreachable_operator(
12331234
*reachable_from_top = false;
12341235

12351236
let (params, _results) = blocktype_params_results(wasm_types, blocktype)?;
1236-
let else_ebb = ebb_with_params(builder, params)?;
1237+
let else_ebb = ebb_with_params(builder, params, environ)?;
12371238

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

cranelift-wasm/src/environ/dummy.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
//! [Wasmtime]: https://github.com/CraneStation/wasmtime
77
88
use crate::environ::{
9-
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, WasmResult, WasmTypesMap,
9+
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmResult,
10+
WasmTypesMap,
1011
};
1112
use crate::func_translator::FuncTranslator;
1213
use crate::translation_utils::{
@@ -193,11 +194,13 @@ impl<'dummy_environment> DummyFuncEnvironment<'dummy_environment> {
193194
}
194195
}
195196

196-
impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
197+
impl<'dummy_environment> TargetEnvironment for DummyFuncEnvironment<'dummy_environment> {
197198
fn target_config(&self) -> TargetFrontendConfig {
198199
self.mod_info.config
199200
}
201+
}
200202

203+
impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environment> {
201204
fn return_mode(&self) -> ReturnMode {
202205
self.return_mode
203206
}
@@ -374,11 +377,13 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ
374377
}
375378
}
376379

377-
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
380+
impl TargetEnvironment for DummyEnvironment {
378381
fn target_config(&self) -> TargetFrontendConfig {
379382
self.info.config
380383
}
384+
}
381385

386+
impl<'data> ModuleEnvironment<'data> for DummyEnvironment {
382387
fn declare_signature(&mut self, sig: ir::Signature) -> WasmResult<()> {
383388
self.info.signatures.push(sig);
384389
Ok(())

cranelift-wasm/src/environ/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +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,
10-
WasmTypesMap,
9+
FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode, TargetEnvironment, WasmError,
10+
WasmResult, WasmTypesMap,
1111
};

cranelift-wasm/src/environ/spec.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,8 @@ impl WasmTypesMap {
122122
}
123123
}
124124

125-
/// Environment affecting the translation of a single WebAssembly function.
126-
///
127-
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
128-
/// IR. The function environment provides information about the WebAssembly module as well as the
129-
/// runtime environment.
130-
pub trait FuncEnvironment {
125+
/// Environment affecting the translation of a WebAssembly.
126+
pub trait TargetEnvironment {
131127
/// Get the information needed to produce Cranelift IR for the given target.
132128
fn target_config(&self) -> TargetFrontendConfig;
133129

@@ -143,13 +139,6 @@ pub trait FuncEnvironment {
143139
self.target_config().pointer_bytes()
144140
}
145141

146-
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
147-
/// of the function body, rather than `return` instructions as needed? This is used by VMs
148-
/// to append custom epilogues.
149-
fn return_mode(&self) -> ReturnMode {
150-
ReturnMode::NormalReturns
151-
}
152-
153142
/// Get the Cranelift reference type to use for native references.
154143
///
155144
/// This returns `R64` for 64-bit architectures and `R32` for 32-bit architectures.
@@ -160,6 +149,20 @@ pub trait FuncEnvironment {
160149
_ => panic!("unsupported pointer type"),
161150
}
162151
}
152+
}
153+
154+
/// Environment affecting the translation of a single WebAssembly function.
155+
///
156+
/// A `FuncEnvironment` trait object is required to translate a WebAssembly function to Cranelift
157+
/// IR. The function environment provides information about the WebAssembly module as well as the
158+
/// runtime environment.
159+
pub trait FuncEnvironment: TargetEnvironment {
160+
/// Should the code be structured to use a single `fallthrough_return` instruction at the end
161+
/// of the function body, rather than `return` instructions as needed? This is used by VMs
162+
/// to append custom epilogues.
163+
fn return_mode(&self) -> ReturnMode {
164+
ReturnMode::NormalReturns
165+
}
163166

164167
/// Set up the necessary preamble definitions in `func` to access the global variable
165168
/// identified by `index`.
@@ -320,10 +323,7 @@ pub trait FuncEnvironment {
320323
/// An object satisfying the `ModuleEnvironment` trait can be passed as argument to the
321324
/// [`translate_module`](fn.translate_module.html) function. These methods should not be called
322325
/// by the user, they are only for `cranelift-wasm` internal use.
323-
pub trait ModuleEnvironment<'data> {
324-
/// Get the information needed to produce Cranelift IR for the current target.
325-
fn target_config(&self) -> TargetFrontendConfig;
326-
326+
pub trait ModuleEnvironment<'data>: TargetEnvironment {
327327
/// Provides the number of signatures up front. By default this does nothing, but
328328
/// implementations can use this to preallocate memory if desired.
329329
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
@@ -187,6 +187,7 @@ fn declare_locals<FE: FuncEnvironment + ?Sized>(
187187
builder.ins().vconst(ir::types::I8X16, constant_handle)
188188
}
189189
AnyRef => builder.ins().null(environ.reference_type()),
190+
AnyFunc => builder.ins().null(environ.reference_type()),
190191
ty => return Err(wasm_unsupported!("unsupported local type {:?}", ty)),
191192
};
192193

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, WasmTypesMap,
61+
DummyEnvironment, FuncEnvironment, GlobalVariable, ModuleEnvironment, ReturnMode,
62+
TargetEnvironment, WasmError, WasmResult, WasmTypesMap,
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
@@ -43,14 +43,15 @@ pub fn parse_type_section(
4343
params,
4444
returns,
4545
} => {
46-
let mut sig = Signature::new(environ.target_config().default_call_conv);
46+
let mut sig =
47+
Signature::new(ModuleEnvironment::target_config(environ).default_call_conv);
4748
sig.params.extend(params.iter().map(|ty| {
48-
let cret_arg: ir::Type = type_to_type(*ty)
49+
let cret_arg: ir::Type = type_to_type(*ty, environ)
4950
.expect("only numeric types are supported in function signatures");
5051
AbiParam::new(cret_arg)
5152
}));
5253
sig.returns.extend(returns.iter().map(|ty| {
53-
let cret_arg: ir::Type = type_to_type(*ty)
54+
let cret_arg: ir::Type = type_to_type(*ty, environ)
5455
.expect("only numeric types are supported in function signatures");
5556
AbiParam::new(cret_arg)
5657
}));
@@ -105,7 +106,7 @@ pub fn parse_import_section<'data>(
105106
ImportSectionEntryType::Global(ref ty) => {
106107
environ.declare_global_import(
107108
Global {
108-
ty: type_to_type(ty.content_type).unwrap(),
109+
ty: type_to_type(ty.content_type, environ).unwrap(),
109110
mutability: ty.mutable,
110111
initializer: GlobalInit::Import,
111112
},
@@ -116,7 +117,7 @@ pub fn parse_import_section<'data>(
116117
ImportSectionEntryType::Table(ref tab) => {
117118
environ.declare_table_import(
118119
Table {
119-
ty: match tabletype_to_type(tab.element_type)? {
120+
ty: match tabletype_to_type(tab.element_type, environ)? {
120121
Some(t) => TableElementType::Val(t),
121122
None => TableElementType::Func,
122123
},
@@ -159,7 +160,7 @@ pub fn parse_table_section(
159160
for entry in tables {
160161
let table = entry?;
161162
environ.declare_table(Table {
162-
ty: match tabletype_to_type(table.element_type)? {
163+
ty: match tabletype_to_type(table.element_type, environ)? {
163164
Some(t) => TableElementType::Val(t),
164165
None => TableElementType::Func,
165166
},
@@ -214,6 +215,7 @@ pub fn parse_global_section(
214215
Operator::V128Const { value } => {
215216
GlobalInit::V128Const(V128Imm::from(value.bytes().to_vec().as_slice()))
216217
}
218+
Operator::RefNull => GlobalInit::RefNullConst,
217219
Operator::GetGlobal { global_index } => {
218220
GlobalInit::GetGlobal(GlobalIndex::from_u32(global_index))
219221
}
@@ -225,7 +227,7 @@ pub fn parse_global_section(
225227
}
226228
};
227229
let global = Global {
228-
ty: type_to_type(content_type).unwrap(),
230+
ty: type_to_type(content_type, environ).unwrap(),
229231
mutability: mutable,
230232
initializer,
231233
};

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, WasmTypesMap};
2+
use crate::environ::{TargetEnvironment, WasmResult, WasmTypesMap};
33
use crate::wasm_unsupported;
44
use core::u32;
55
use cranelift_codegen::entity::entity_impl;
@@ -82,6 +82,8 @@ pub enum GlobalInit {
8282
V128Const(V128Imm),
8383
/// A `get_global` of another global.
8484
GetGlobal(GlobalIndex),
85+
/// A `ref.null`.
86+
RefNullConst,
8587
///< The global is imported from, and thus initialized by, a different module.
8688
Import,
8789
}
@@ -118,26 +120,34 @@ pub struct Memory {
118120
}
119121

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

132138
/// Helper function translating wasmparser possible table types to Cranelift types when possible,
133139
/// or None for Func tables.
134-
pub fn tabletype_to_type(ty: wasmparser::Type) -> WasmResult<Option<ir::Type>> {
140+
pub fn tabletype_to_type<PE: TargetEnvironment + ?Sized>(
141+
ty: wasmparser::Type,
142+
environ: &PE,
143+
) -> WasmResult<Option<ir::Type>> {
135144
match ty {
136145
wasmparser::Type::I32 => Ok(Some(ir::types::I32)),
137146
wasmparser::Type::I64 => Ok(Some(ir::types::I64)),
138147
wasmparser::Type::F32 => Ok(Some(ir::types::F32)),
139148
wasmparser::Type::F64 => Ok(Some(ir::types::F64)),
140149
wasmparser::Type::V128 => Ok(Some(ir::types::I8X16)),
150+
wasmparser::Type::AnyRef => Ok(Some(environ.reference_type())),
141151
wasmparser::Type::AnyFunc => Ok(None),
142152
ty => Err(wasm_unsupported!(
143153
"tabletype_to_type: table wasm type {:?}",
@@ -158,6 +168,8 @@ pub fn blocktype_params_results(
158168
wasmparser::Type::F32 => (&[], &[wasmparser::Type::F32]),
159169
wasmparser::Type::F64 => (&[], &[wasmparser::Type::F64]),
160170
wasmparser::Type::V128 => (&[], &[wasmparser::Type::V128]),
171+
wasmparser::Type::AnyRef => (&[], &[wasmparser::Type::AnyRef]),
172+
wasmparser::Type::AnyFunc => (&[], &[wasmparser::Type::AnyFunc]),
161173
wasmparser::Type::EmptyBlockType => (&[], &[]),
162174
ty => return Err(wasm_unsupported!("blocktype_params_results: type {:?}", ty)),
163175
},
@@ -170,9 +182,10 @@ pub fn blocktype_params_results(
170182
}
171183

172184
/// Create an `Ebb` with the given Wasm parameters.
173-
pub fn ebb_with_params(
185+
pub fn ebb_with_params<PE: TargetEnvironment + ?Sized>(
174186
builder: &mut FunctionBuilder,
175187
params: &[wasmparser::Type],
188+
environ: &PE,
176189
) -> WasmResult<ir::Ebb> {
177190
let ebb = builder.create_ebb();
178191
for ty in params.iter() {
@@ -189,6 +202,9 @@ pub fn ebb_with_params(
189202
wasmparser::Type::F64 => {
190203
builder.append_ebb_param(ebb, ir::types::F64);
191204
}
205+
wasmparser::Type::AnyRef | wasmparser::Type::AnyFunc => {
206+
builder.append_ebb_param(ebb, environ.reference_type());
207+
}
192208
wasmparser::Type::V128 => {
193209
builder.append_ebb_param(ebb, ir::types::I8X16);
194210
}

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)