Handle typed funcrefs.

This commit is contained in:
Chris Fallin 2024-03-28 16:36:07 -07:00
parent fcbd32e6b4
commit 86be4c06e1
7 changed files with 143 additions and 41 deletions

View file

@ -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!(),
}
}
} }
} }
} }

View file

@ -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)?
} }

View file

@ -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();

View file

@ -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,
}) })
} }

View file

@ -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(())

View file

@ -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(()),
} }
} }

View 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))