Handle typed funcrefs.
This commit is contained in:
parent
fcbd32e6b4
commit
86be4c06e1
|
@ -909,6 +909,13 @@ impl<'a> WasmFuncBackend<'a> {
|
||||||
}
|
}
|
||||||
Operator::F32x4DemoteF64x2Zero => Some(wasm_encoder::Instruction::F32x4DemoteF64x2Zero),
|
Operator::F32x4DemoteF64x2Zero => Some(wasm_encoder::Instruction::F32x4DemoteF64x2Zero),
|
||||||
Operator::F64x2PromoteLowF32x4 => Some(wasm_encoder::Instruction::F64x2PromoteLowF32x4),
|
Operator::F64x2PromoteLowF32x4 => Some(wasm_encoder::Instruction::F64x2PromoteLowF32x4),
|
||||||
|
|
||||||
|
Operator::CallRef { sig_index } => {
|
||||||
|
Some(wasm_encoder::Instruction::CallRef(sig_index.index() as u32))
|
||||||
|
}
|
||||||
|
Operator::RefFunc { func_index } => {
|
||||||
|
Some(wasm_encoder::Instruction::RefFunc(func_index.index() as u32))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(inst) = inst {
|
if let Some(inst) = inst {
|
||||||
|
@ -955,7 +962,7 @@ pub fn compile(module: &Module<'_>) -> anyhow::Result<Vec<u8>> {
|
||||||
.func_elements
|
.func_elements
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|elts| elts.len() as u32)
|
.map(|elts| elts.len() as u32)
|
||||||
.unwrap_or(0),
|
.unwrap_or(table.initial),
|
||||||
maximum: table.max,
|
maximum: table.max,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1081,12 +1088,27 @@ pub fn compile(module: &Module<'_>) -> anyhow::Result<Vec<u8>> {
|
||||||
if let Some(elts) = &table_data.func_elements {
|
if let Some(elts) = &table_data.func_elements {
|
||||||
for (i, &elt) in elts.iter().enumerate() {
|
for (i, &elt) in elts.iter().enumerate() {
|
||||||
if elt.is_valid() {
|
if elt.is_valid() {
|
||||||
|
match table_data.ty {
|
||||||
|
Type::FuncRef => {
|
||||||
elem.active(
|
elem.active(
|
||||||
Some(table.index() as u32),
|
Some(table.index() as u32),
|
||||||
&wasm_encoder::ConstExpr::i32_const(i as i32),
|
&wasm_encoder::ConstExpr::i32_const(i as i32),
|
||||||
wasm_encoder::Elements::Functions(&[elt.index() as u32]),
|
wasm_encoder::Elements::Functions(&[elt.index() as u32]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Type::TypedFuncRef(..) => {
|
||||||
|
elem.active(
|
||||||
|
Some(table.index() as u32),
|
||||||
|
&wasm_encoder::ConstExpr::i32_const(i as i32),
|
||||||
|
wasm_encoder::Elements::Expressions(
|
||||||
|
table_data.ty.into(),
|
||||||
|
&[wasm_encoder::ConstExpr::ref_func(elt.index() as u32)],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,11 @@ fn handle_payload<'a>(
|
||||||
ImportKind::Global(global)
|
ImportKind::Global(global)
|
||||||
}
|
}
|
||||||
TypeRef::Table(ty) => {
|
TypeRef::Table(ty) => {
|
||||||
let table = module.frontend_add_table(ty.element_type.into(), None);
|
let table = module.frontend_add_table(
|
||||||
|
ty.element_type.into(),
|
||||||
|
ty.initial,
|
||||||
|
ty.maximum,
|
||||||
|
);
|
||||||
ImportKind::Table(table)
|
ImportKind::Table(table)
|
||||||
}
|
}
|
||||||
TypeRef::Memory(mem) => {
|
TypeRef::Memory(mem) => {
|
||||||
|
@ -174,7 +178,11 @@ fn handle_payload<'a>(
|
||||||
Payload::TableSection(reader) => {
|
Payload::TableSection(reader) => {
|
||||||
for table in reader {
|
for table in reader {
|
||||||
let table = table?;
|
let table = table?;
|
||||||
module.frontend_add_table(table.ty.element_type.into(), table.ty.maximum);
|
module.frontend_add_table(
|
||||||
|
table.ty.element_type.into(),
|
||||||
|
table.ty.initial,
|
||||||
|
table.ty.maximum,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Payload::FunctionSection(reader) => {
|
Payload::FunctionSection(reader) => {
|
||||||
|
@ -318,7 +326,7 @@ fn handle_payload<'a>(
|
||||||
} => {
|
} => {
|
||||||
let table = Table::from(table_index.unwrap_or(0));
|
let table = Table::from(table_index.unwrap_or(0));
|
||||||
let offset = parse_init_expr(&offset_expr)?.unwrap_or(0) as usize;
|
let offset = parse_init_expr(&offset_expr)?.unwrap_or(0) as usize;
|
||||||
match element.items {
|
let funcs = match element.items {
|
||||||
wasmparser::ElementItems::Functions(items) => {
|
wasmparser::ElementItems::Functions(items) => {
|
||||||
let mut funcs = vec![];
|
let mut funcs = vec![];
|
||||||
for item in items {
|
for item in items {
|
||||||
|
@ -326,11 +334,34 @@ fn handle_payload<'a>(
|
||||||
let func = Func::from(item);
|
let func = Func::from(item);
|
||||||
funcs.push(func);
|
funcs.push(func);
|
||||||
}
|
}
|
||||||
|
funcs
|
||||||
|
}
|
||||||
|
wasmparser::ElementItems::Expressions(_, const_exprs) => {
|
||||||
|
let mut funcs = vec![];
|
||||||
|
for const_expr in const_exprs {
|
||||||
|
let const_expr = const_expr?;
|
||||||
|
let mut func = None;
|
||||||
|
for op in const_expr.get_operators_reader() {
|
||||||
|
let op = op?;
|
||||||
|
match op {
|
||||||
|
wasmparser::Operator::End => {}
|
||||||
|
wasmparser::Operator::RefFunc { function_index } => {
|
||||||
|
func = Some(Func::from(function_index));
|
||||||
|
}
|
||||||
|
wasmparser::Operator::RefNull { .. } => {
|
||||||
|
func = Some(Func::invalid());
|
||||||
|
}
|
||||||
|
_ => panic!("Unsupported table-init op: {:?}", op),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
funcs.push(func.unwrap_or(Func::invalid()));
|
||||||
|
}
|
||||||
|
funcs
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let table_items =
|
let table_items = module.tables[table].func_elements.as_mut().unwrap();
|
||||||
module.tables[table].func_elements.as_mut().unwrap();
|
let new_size = offset.checked_add(funcs.len()).ok_or_else(|| {
|
||||||
let new_size =
|
|
||||||
offset.checked_add(funcs.len()).ok_or_else(|| {
|
|
||||||
FrontendError::TooLarge(format!(
|
FrontendError::TooLarge(format!(
|
||||||
"Overflowing element offset + length: {} + {}",
|
"Overflowing element offset + length: {} + {}",
|
||||||
offset,
|
offset,
|
||||||
|
@ -349,13 +380,6 @@ fn handle_payload<'a>(
|
||||||
}
|
}
|
||||||
table_items[offset..new_size].copy_from_slice(&funcs[..]);
|
table_items[offset..new_size].copy_from_slice(&funcs[..]);
|
||||||
}
|
}
|
||||||
wasmparser::ElementItems::Expressions(..) => {
|
|
||||||
bail!(FrontendError::UnsupportedFeature(
|
|
||||||
"Expression element items".into()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1394,7 +1418,9 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> {
|
||||||
| wasmparser::Operator::F64x2ConvertLowI32x4S
|
| wasmparser::Operator::F64x2ConvertLowI32x4S
|
||||||
| wasmparser::Operator::F64x2ConvertLowI32x4U
|
| wasmparser::Operator::F64x2ConvertLowI32x4U
|
||||||
| wasmparser::Operator::F32x4DemoteF64x2Zero
|
| wasmparser::Operator::F32x4DemoteF64x2Zero
|
||||||
| wasmparser::Operator::F64x2PromoteLowF32x4 => {
|
| wasmparser::Operator::F64x2PromoteLowF32x4
|
||||||
|
| wasmparser::Operator::CallRef { .. }
|
||||||
|
| wasmparser::Operator::RefFunc { .. } => {
|
||||||
self.emit(Operator::try_from(&op).unwrap(), loc)?
|
self.emit(Operator::try_from(&op).unwrap(), loc)?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ impl From<wasmparser::ValType> for Type {
|
||||||
}
|
}
|
||||||
impl From<wasmparser::RefType> for Type {
|
impl From<wasmparser::RefType> for Type {
|
||||||
fn from(ty: wasmparser::RefType) -> Self {
|
fn from(ty: wasmparser::RefType) -> Self {
|
||||||
assert!(ty.is_func_ref(), "only funcrefs are supported right now");
|
|
||||||
match ty.type_index() {
|
match ty.type_index() {
|
||||||
Some(idx) => {
|
Some(idx) => {
|
||||||
let nullable = ty.is_nullable();
|
let nullable = ty.is_nullable();
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub struct MemorySegment {
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct TableData {
|
pub struct TableData {
|
||||||
pub ty: Type,
|
pub ty: Type,
|
||||||
|
pub initial: u32,
|
||||||
pub max: Option<u32>,
|
pub max: Option<u32>,
|
||||||
pub func_elements: Option<Vec<Func>>,
|
pub func_elements: Option<Vec<Func>>,
|
||||||
}
|
}
|
||||||
|
@ -170,15 +171,12 @@ impl<'a> Module<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Module<'a> {
|
impl<'a> Module<'a> {
|
||||||
pub(crate) fn frontend_add_table(&mut self, ty: Type, max: Option<u32>) -> Table {
|
pub(crate) fn frontend_add_table(&mut self, ty: Type, initial: u32, max: Option<u32>) -> Table {
|
||||||
let func_elements = if ty == Type::FuncRef {
|
let func_elements = Some(vec![]);
|
||||||
Some(vec![])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
self.tables.push(TableData {
|
self.tables.push(TableData {
|
||||||
ty,
|
ty,
|
||||||
func_elements,
|
func_elements,
|
||||||
|
initial,
|
||||||
max,
|
max,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Metadata on operators.
|
//! Metadata on operators.
|
||||||
|
|
||||||
|
use crate::entity::EntityRef;
|
||||||
use crate::ir::{Module, Type, Value};
|
use crate::ir::{Module, Type, Value};
|
||||||
use crate::Operator;
|
use crate::Operator;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -475,6 +476,13 @@ pub fn op_inputs(
|
||||||
Operator::F64x2ConvertLowI32x4U => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F64x2ConvertLowI32x4U => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
Operator::F32x4DemoteF64x2Zero => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F32x4DemoteF64x2Zero => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
Operator::F64x2PromoteLowF32x4 => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F64x2PromoteLowF32x4 => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
|
|
||||||
|
Operator::CallRef { sig_index } => {
|
||||||
|
let mut params = module.signatures[*sig_index].params.to_vec();
|
||||||
|
params.push(Type::TypedFuncRef(true, sig_index.index() as u32));
|
||||||
|
Ok(params.into())
|
||||||
|
}
|
||||||
|
Operator::RefFunc { .. } => Ok(Cow::Borrowed(&[])),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -933,6 +941,14 @@ pub fn op_outputs(
|
||||||
Operator::F64x2ConvertLowI32x4U => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F64x2ConvertLowI32x4U => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
Operator::F32x4DemoteF64x2Zero => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F32x4DemoteF64x2Zero => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
Operator::F64x2PromoteLowF32x4 => Ok(Cow::Borrowed(&[Type::V128])),
|
Operator::F64x2PromoteLowF32x4 => Ok(Cow::Borrowed(&[Type::V128])),
|
||||||
|
|
||||||
|
Operator::CallRef { sig_index } => {
|
||||||
|
Ok(Vec::from(module.signatures[*sig_index].returns.clone()).into())
|
||||||
|
}
|
||||||
|
Operator::RefFunc { func_index } => {
|
||||||
|
let ty = module.funcs[*func_index].sig();
|
||||||
|
Ok(vec![Type::TypedFuncRef(true, ty.index() as u32)].into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1397,6 +1413,9 @@ impl Operator {
|
||||||
Operator::F64x2ConvertLowI32x4U => &[],
|
Operator::F64x2ConvertLowI32x4U => &[],
|
||||||
Operator::F32x4DemoteF64x2Zero => &[],
|
Operator::F32x4DemoteF64x2Zero => &[],
|
||||||
Operator::F64x2PromoteLowF32x4 => &[],
|
Operator::F64x2PromoteLowF32x4 => &[],
|
||||||
|
|
||||||
|
Operator::CallRef { .. } => &[All],
|
||||||
|
Operator::RefFunc { .. } => &[],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1885,6 +1904,9 @@ impl std::fmt::Display for Operator {
|
||||||
Operator::F64x2ConvertLowI32x4U => write!(f, "f64x2convertlowi32x4u")?,
|
Operator::F64x2ConvertLowI32x4U => write!(f, "f64x2convertlowi32x4u")?,
|
||||||
Operator::F32x4DemoteF64x2Zero => write!(f, "f32x4demotef64x2zero")?,
|
Operator::F32x4DemoteF64x2Zero => write!(f, "f32x4demotef64x2zero")?,
|
||||||
Operator::F64x2PromoteLowF32x4 => write!(f, "f64x2promotelowf32x4")?,
|
Operator::F64x2PromoteLowF32x4 => write!(f, "f64x2promotelowf32x4")?,
|
||||||
|
|
||||||
|
Operator::CallRef { sig_index } => write!(f, "call_ref<{}>", sig_index)?,
|
||||||
|
Operator::RefFunc { func_index } => write!(f, "ref_func<{}>", func_index)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
14
src/ops.rs
14
src/ops.rs
|
@ -630,6 +630,13 @@ pub enum Operator {
|
||||||
F64x2ConvertLowI32x4U,
|
F64x2ConvertLowI32x4U,
|
||||||
F32x4DemoteF64x2Zero,
|
F32x4DemoteF64x2Zero,
|
||||||
F64x2PromoteLowF32x4,
|
F64x2PromoteLowF32x4,
|
||||||
|
|
||||||
|
CallRef {
|
||||||
|
sig_index: Signature,
|
||||||
|
},
|
||||||
|
RefFunc {
|
||||||
|
func_index: Func,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1259,6 +1266,13 @@ impl<'a, 'b> std::convert::TryFrom<&'b wasmparser::Operator<'a>> for Operator {
|
||||||
&wasmparser::Operator::F32x4DemoteF64x2Zero => Ok(Operator::F32x4DemoteF64x2Zero),
|
&wasmparser::Operator::F32x4DemoteF64x2Zero => Ok(Operator::F32x4DemoteF64x2Zero),
|
||||||
&wasmparser::Operator::F64x2PromoteLowF32x4 => Ok(Operator::F64x2PromoteLowF32x4),
|
&wasmparser::Operator::F64x2PromoteLowF32x4 => Ok(Operator::F64x2PromoteLowF32x4),
|
||||||
|
|
||||||
|
&wasmparser::Operator::CallRef { type_index } => Ok(Operator::CallRef {
|
||||||
|
sig_index: Signature::from(type_index),
|
||||||
|
}),
|
||||||
|
&wasmparser::Operator::RefFunc { function_index } => Ok(Operator::RefFunc {
|
||||||
|
func_index: Func::from(function_index),
|
||||||
|
}),
|
||||||
|
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
wasm_tests/typed-funcref.wat
Normal file
21
wasm_tests/typed-funcref.wat
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
(module
|
||||||
|
(type $t (func (param i32 i32) (result i32)))
|
||||||
|
|
||||||
|
(table $tab 10 10 (ref null $t))
|
||||||
|
(table $tab2 10 10 (ref null $t))
|
||||||
|
|
||||||
|
(elem (table $tab2) (i32.const 0) (ref null $t) (ref.func $f))
|
||||||
|
|
||||||
|
(func $callit (param i32 i32 i32) (result i32)
|
||||||
|
(call_ref $t (local.get 1)
|
||||||
|
(local.get 2)
|
||||||
|
(table.get $tab (local.get 0))))
|
||||||
|
|
||||||
|
(func $setit (param i32 (ref null $t))
|
||||||
|
(table.set $tab (local.get 0) (local.get 1)))
|
||||||
|
|
||||||
|
(func $getf (result (ref null $t))
|
||||||
|
(ref.func $f))
|
||||||
|
|
||||||
|
(func $f (param i32 i32) (result i32)
|
||||||
|
local.get 0))
|
Loading…
Reference in a new issue