mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-06 12:48:20 +00:00
Make FuncRef nullable at the API level
This commit is contained in:
@@ -118,7 +118,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
);
|
);
|
||||||
// Now demonstarte that the function we grew the table with is actually in the table.
|
// Now demonstarte that the function we grew the table with is actually in the table.
|
||||||
for table_index in 3..6 {
|
for table_index in 3..6 {
|
||||||
if let Value::FuncRef(f) = guest_table.get(table_index as _).unwrap() {
|
if let Value::FuncRef(Some(f)) = guest_table.get(table_index as _).unwrap() {
|
||||||
let result = f.call(&[Value::I32(1), Value::I32(9)])?;
|
let result = f.call(&[Value::I32(1), Value::I32(9)])?;
|
||||||
assert_eq!(result[0], Value::I32(10));
|
assert_eq!(result[0], Value::I32(10));
|
||||||
} else {
|
} else {
|
||||||
@@ -140,7 +140,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
// Now demonstrate that the host and guest see the same table and that both
|
// Now demonstrate that the host and guest see the same table and that both
|
||||||
// get the same result.
|
// get the same result.
|
||||||
for table_index in 3..6 {
|
for table_index in 3..6 {
|
||||||
if let Value::FuncRef(f) = guest_table.get(table_index as _).unwrap() {
|
if let Value::FuncRef(Some(f)) = guest_table.get(table_index as _).unwrap() {
|
||||||
let result = f.call(&[Value::I32(1), Value::I32(9)])?;
|
let result = f.call(&[Value::I32(1), Value::I32(9)])?;
|
||||||
assert_eq!(result[0], Value::I32(10));
|
assert_eq!(result[0], Value::I32(10));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ pub type Val = Value<Function>;
|
|||||||
impl StoreObject for Val {
|
impl StoreObject for Val {
|
||||||
fn comes_from_same_store(&self, store: &Store) -> bool {
|
fn comes_from_same_store(&self, store: &Store) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::FuncRef(f) => Store::same(store, f.store()),
|
Self::FuncRef(None) => true,
|
||||||
|
Self::FuncRef(Some(f)) => Store::same(store, f.store()),
|
||||||
Self::ExternRef(ExternRef::Ref(_)) | Self::ExternRef(ExternRef::Other(_)) => false,
|
Self::ExternRef(ExternRef::Ref(_)) | Self::ExternRef(ExternRef::Other(_)) => false,
|
||||||
Self::ExternRef(ExternRef::Null) => true,
|
Self::ExternRef(ExternRef::Null) => todo!("update this code"),
|
||||||
Self::I32(_) | Self::I64(_) | Self::F32(_) | Self::F64(_) | Self::V128(_) => true,
|
Self::I32(_) | Self::I64(_) | Self::F32(_) | Self::F64(_) | Self::V128(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +30,7 @@ impl StoreObject for Val {
|
|||||||
|
|
||||||
impl From<Function> for Val {
|
impl From<Function> for Val {
|
||||||
fn from(val: Function) -> Self {
|
fn from(val: Function) -> Self {
|
||||||
Self::FuncRef(val)
|
Self::FuncRef(Some(val))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,21 +61,29 @@ impl ValFuncRef for Val {
|
|||||||
return Err(RuntimeError::new("cross-`Store` values are not supported"));
|
return Err(RuntimeError::new("cross-`Store` values are not supported"));
|
||||||
}
|
}
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
|
Self::ExternRef(ExternRef::Null) => todo!("Extern ref not yet implemented"), /*wasmer_vm::VMCallerCheckedAnyfunc {
|
||||||
|
func_ptr: ptr::null(),
|
||||||
|
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
||||||
|
vmctx: wasmer_vm::VMFunctionEnvironment {
|
||||||
|
host_env: ptr::null_mut(),
|
||||||
|
},
|
||||||
|
},*/
|
||||||
|
Self::FuncRef(None) => wasmer_vm::VMCallerCheckedAnyfunc {
|
||||||
func_ptr: ptr::null(),
|
func_ptr: ptr::null(),
|
||||||
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
||||||
vmctx: wasmer_vm::VMFunctionEnvironment {
|
vmctx: wasmer_vm::VMFunctionEnvironment {
|
||||||
host_env: ptr::null_mut(),
|
host_env: ptr::null_mut(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Self::FuncRef(f) => f.checked_anyfunc(),
|
Self::FuncRef(Some(f)) => f.checked_anyfunc(),
|
||||||
_ => return Err(RuntimeError::new("val is not funcref")),
|
_ => return Err(RuntimeError::new("val is not reference")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self {
|
fn from_checked_anyfunc(item: wasmer_vm::VMCallerCheckedAnyfunc, store: &Store) -> Self {
|
||||||
|
// TODO: use `is_null()`?
|
||||||
if item.type_index == wasmer_vm::VMSharedSignatureIndex::default() {
|
if item.type_index == wasmer_vm::VMSharedSignatureIndex::default() {
|
||||||
return Self::ExternRef(ExternRef::Null);
|
return Self::FuncRef(None);
|
||||||
}
|
}
|
||||||
let signature = store
|
let signature = store
|
||||||
.engine()
|
.engine()
|
||||||
@@ -96,7 +105,7 @@ impl ValFuncRef for Val {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let f = Function::from_vm_export(store, export);
|
let f = Function::from_vm_export(store, export);
|
||||||
Self::FuncRef(f)
|
Self::FuncRef(Some(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_table_reference(
|
fn into_table_reference(
|
||||||
@@ -107,16 +116,28 @@ impl ValFuncRef for Val {
|
|||||||
return Err(RuntimeError::new("cross-`Store` values are not supported"));
|
return Err(RuntimeError::new("cross-`Store` values are not supported"));
|
||||||
}
|
}
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
Self::ExternRef(ExternRef::Null) => wasmer_vm::TableReference::FuncRef(wasmer_vm::VMCallerCheckedAnyfunc {
|
Self::ExternRef(ExternRef::Null) =>
|
||||||
|
/*wasmer_vm::TableReference::FuncRef(wasmer_vm::VMCallerCheckedAnyfunc {
|
||||||
func_ptr: ptr::null(),
|
func_ptr: ptr::null(),
|
||||||
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
||||||
vmctx: wasmer_vm::VMFunctionEnvironment {
|
vmctx: wasmer_vm::VMFunctionEnvironment {
|
||||||
host_env: ptr::null_mut(),
|
host_env: ptr::null_mut(),
|
||||||
},
|
},
|
||||||
}),
|
}),*/
|
||||||
// existing code uses `ExtenRef` for null pointers
|
// existing code uses `ExtenRef` for null pointers
|
||||||
//todo!("extern ref not yet supported"),
|
{
|
||||||
Self::FuncRef(f) => wasmer_vm::TableReference::FuncRef(f.checked_anyfunc()),
|
todo!("extern ref not yet supported")
|
||||||
|
}
|
||||||
|
Self::FuncRef(None) => {
|
||||||
|
wasmer_vm::TableReference::FuncRef(wasmer_vm::VMCallerCheckedAnyfunc {
|
||||||
|
func_ptr: ptr::null(),
|
||||||
|
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
|
||||||
|
vmctx: wasmer_vm::VMFunctionEnvironment {
|
||||||
|
host_env: ptr::null_mut(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Self::FuncRef(Some(f)) => wasmer_vm::TableReference::FuncRef(f.checked_anyfunc()),
|
||||||
_ => return Err(RuntimeError::new("val is not reference")),
|
_ => return Err(RuntimeError::new("val is not reference")),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ fn table_new() -> Result<()> {
|
|||||||
maximum: None,
|
maximum: None,
|
||||||
};
|
};
|
||||||
let f = Function::new_native(&store, || {});
|
let f = Function::new_native(&store, || {});
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(f))?;
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f)))?;
|
||||||
assert_eq!(*table.ty(), table_type);
|
assert_eq!(*table.ty(), table_type);
|
||||||
|
|
||||||
// Anyrefs not yet supported
|
// Anyrefs not yet supported
|
||||||
@@ -92,7 +92,7 @@ fn table_get() -> Result<()> {
|
|||||||
maximum: Some(1),
|
maximum: Some(1),
|
||||||
};
|
};
|
||||||
let f = Function::new_native(&store, |num: i32| num + 1);
|
let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(f.clone()))?;
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
assert_eq!(*table.ty(), table_type);
|
assert_eq!(*table.ty(), table_type);
|
||||||
let _elem = table.get(0).unwrap();
|
let _elem = table.get(0).unwrap();
|
||||||
// assert_eq!(elem.funcref().unwrap(), f);
|
// assert_eq!(elem.funcref().unwrap(), f);
|
||||||
@@ -115,13 +115,13 @@ fn table_grow() -> Result<()> {
|
|||||||
maximum: Some(10),
|
maximum: Some(10),
|
||||||
};
|
};
|
||||||
let f = Function::new_native(&store, |num: i32| num + 1);
|
let f = Function::new_native(&store, |num: i32| num + 1);
|
||||||
let table = Table::new(&store, table_type, Value::FuncRef(f.clone()))?;
|
let table = Table::new(&store, table_type, Value::FuncRef(Some(f.clone())))?;
|
||||||
// Growing to a bigger maximum should return None
|
// Growing to a bigger maximum should return None
|
||||||
let old_len = table.grow(12, Value::FuncRef(f.clone()));
|
let old_len = table.grow(12, Value::FuncRef(Some(f.clone())));
|
||||||
assert!(old_len.is_err());
|
assert!(old_len.is_err());
|
||||||
|
|
||||||
// Growing to a bigger maximum should return None
|
// Growing to a bigger maximum should return None
|
||||||
let old_len = table.grow(5, Value::FuncRef(f.clone()))?;
|
let old_len = table.grow(5, Value::FuncRef(Some(f.clone())))?;
|
||||||
assert_eq!(old_len, 0);
|
assert_eq!(old_len, 0);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -762,6 +762,17 @@ pub struct VMCallerCheckedAnyfunc {
|
|||||||
// If more elements are added here, remember to add offset_of tests below!
|
// If more elements are added here, remember to add offset_of tests below!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VMCallerCheckedAnyfunc {
|
||||||
|
/// Check if this anyfunc is a null funcref.
|
||||||
|
// TODO: we probably want to clean this up before shipping, maybe actually add
|
||||||
|
// an extra layer of indirection
|
||||||
|
pub fn is_null(&self) -> bool {
|
||||||
|
self.func_ptr == std::ptr::null()
|
||||||
|
&& self.type_index == VMSharedSignatureIndex::default()
|
||||||
|
&& self.vmctx.is_null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_vmcaller_checked_anyfunc {
|
mod test_vmcaller_checked_anyfunc {
|
||||||
use super::VMCallerCheckedAnyfunc;
|
use super::VMCallerCheckedAnyfunc;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub enum Value<T> {
|
|||||||
ExternRef(ExternRef),
|
ExternRef(ExternRef),
|
||||||
|
|
||||||
/// A first-class reference to a WebAssembly function.
|
/// A first-class reference to a WebAssembly function.
|
||||||
FuncRef(T),
|
FuncRef(Option<T>),
|
||||||
|
|
||||||
/// A 128-bit number
|
/// A 128-bit number
|
||||||
V128(u128),
|
V128(u128),
|
||||||
@@ -120,7 +120,7 @@ impl<T> Value<T> {
|
|||||||
(I64(i64) i64 unwrap_i64 *e)
|
(I64(i64) i64 unwrap_i64 *e)
|
||||||
(F32(f32) f32 unwrap_f32 *e)
|
(F32(f32) f32 unwrap_f32 *e)
|
||||||
(F64(f64) f64 unwrap_f64 *e)
|
(F64(f64) f64 unwrap_f64 *e)
|
||||||
(FuncRef(&T) funcref unwrap_funcref e)
|
(FuncRef(&Option<T>) funcref unwrap_funcref e)
|
||||||
(V128(u128) v128 unwrap_v128 *e)
|
(V128(u128) v128 unwrap_v128 *e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub fn spectest_importobject(store: &Store) -> ImportObject {
|
|||||||
let global_f64 = Global::new(store, Val::F64(f64::from_bits(0x4084_d000_0000_0000)));
|
let global_f64 = Global::new(store, Val::F64(f64::from_bits(0x4084_d000_0000_0000)));
|
||||||
|
|
||||||
let ty = TableType::new(ValType::FuncRef, 10, Some(20));
|
let ty = TableType::new(ValType::FuncRef, 10, Some(20));
|
||||||
let table = Table::new(store, ty, Val::ExternRef(ExternRef::Null)).unwrap();
|
let table = Table::new(store, ty, Val::FuncRef(None)).unwrap();
|
||||||
|
|
||||||
let ty = MemoryType::new(1, Some(2), false);
|
let ty = MemoryType::new(1, Some(2), false);
|
||||||
let memory = Memory::new(store, ty).unwrap();
|
let memory = Memory::new(store, ty).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user