mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-01 15:31:04 +00:00
!temp
This commit is contained in:
parent
0e27f2fa72
commit
2a041f898e
@ -12,33 +12,46 @@ fn imported_functions_forms() {
|
|||||||
(import "env" "memory" (memory 1 1))
|
(import "env" "memory" (memory 1 1))
|
||||||
(import "env" "callback_fn" (func $callback_fn (type $type)))
|
(import "env" "callback_fn" (func $callback_fn (type $type)))
|
||||||
(import "env" "callback_closure" (func $callback_closure (type $type)))
|
(import "env" "callback_closure" (func $callback_closure (type $type)))
|
||||||
|
(import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type)))
|
||||||
(import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type)))
|
(import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type)))
|
||||||
(import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type)))
|
(import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type)))
|
||||||
(import "env" "callback_fn_trap" (func $callback_fn_trap (type $type)))
|
(import "env" "callback_fn_trap" (func $callback_fn_trap (type $type)))
|
||||||
(import "env" "callback_closure_trap" (func $callback_closure_trap (type $type)))
|
(import "env" "callback_closure_trap" (func $callback_closure_trap (type $type)))
|
||||||
(import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type)))
|
(import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type)))
|
||||||
(import "env" "callback_closure_trap_with_vmctx" (func $callback_closure_trap_with_vmctx (type $type)))
|
(import "env" "callback_closure_trap_with_vmctx" (func $callback_closure_trap_with_vmctx (type $type)))
|
||||||
|
|
||||||
(func (export "function_fn") (type $type)
|
(func (export "function_fn") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_fn)
|
call $callback_fn)
|
||||||
|
|
||||||
(func (export "function_closure") (type $type)
|
(func (export "function_closure") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure)
|
call $callback_closure)
|
||||||
|
|
||||||
|
(func (export "function_closure_with_env") (type $type)
|
||||||
|
get_local 0
|
||||||
|
call $callback_closure_with_env)
|
||||||
|
|
||||||
(func (export "function_fn_with_vmctx") (type $type)
|
(func (export "function_fn_with_vmctx") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_fn_with_vmctx)
|
call $callback_fn_with_vmctx)
|
||||||
|
|
||||||
(func (export "function_closure_with_vmctx") (type $type)
|
(func (export "function_closure_with_vmctx") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure_with_vmctx)
|
call $callback_closure_with_vmctx)
|
||||||
|
|
||||||
(func (export "function_fn_trap") (type $type)
|
(func (export "function_fn_trap") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_fn_trap)
|
call $callback_fn_trap)
|
||||||
|
|
||||||
(func (export "function_closure_trap") (type $type)
|
(func (export "function_closure_trap") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure_trap)
|
call $callback_closure_trap)
|
||||||
|
|
||||||
(func (export "function_fn_trap_with_vmctx") (type $type)
|
(func (export "function_fn_trap_with_vmctx") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_fn_trap_with_vmctx)
|
call $callback_fn_trap_with_vmctx)
|
||||||
|
|
||||||
(func (export "function_closure_trap_with_vmctx") (type $type)
|
(func (export "function_closure_trap_with_vmctx") (type $type)
|
||||||
get_local 0
|
get_local 0
|
||||||
call $callback_closure_trap_with_vmctx))
|
call $callback_closure_trap_with_vmctx))
|
||||||
@ -51,6 +64,7 @@ fn imported_functions_forms() {
|
|||||||
|
|
||||||
const SHIFT: i32 = 10;
|
const SHIFT: i32 = 10;
|
||||||
memory.view()[0].set(SHIFT);
|
memory.view()[0].set(SHIFT);
|
||||||
|
let shift = 100;
|
||||||
|
|
||||||
let import_object = imports! {
|
let import_object = imports! {
|
||||||
"env" => {
|
"env" => {
|
||||||
@ -59,6 +73,9 @@ fn imported_functions_forms() {
|
|||||||
"callback_closure" => Func::new(|n: i32| -> Result<i32, ()> {
|
"callback_closure" => Func::new(|n: i32| -> Result<i32, ()> {
|
||||||
Ok(n + 1)
|
Ok(n + 1)
|
||||||
}),
|
}),
|
||||||
|
"callback_closure_with_env" => Func::new(move |n: i32| -> Result<i32, ()> {
|
||||||
|
Ok(shift + n + 1)
|
||||||
|
}),
|
||||||
"callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx),
|
"callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx),
|
||||||
"callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
"callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result<i32, ()> {
|
||||||
let memory = vmctx.memory(0);
|
let memory = vmctx.memory(0);
|
||||||
@ -134,6 +151,7 @@ fn imported_functions_forms() {
|
|||||||
|
|
||||||
call_and_assert!(function_fn, Ok(2));
|
call_and_assert!(function_fn, Ok(2));
|
||||||
call_and_assert!(function_closure, Ok(2));
|
call_and_assert!(function_closure, Ok(2));
|
||||||
|
call_and_assert!(function_closure_with_env, Ok(2 + shift));
|
||||||
call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT));
|
call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT));
|
||||||
call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT));
|
call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT));
|
||||||
call_and_assert!(
|
call_and_assert!(
|
||||||
|
@ -586,18 +586,18 @@ fn import_functions(
|
|||||||
if *expected_sig == *signature {
|
if *expected_sig == *signature {
|
||||||
functions.push(vm::ImportedFunc {
|
functions.push(vm::ImportedFunc {
|
||||||
func: func.inner(),
|
func: func.inner(),
|
||||||
func_ctx: {
|
func_ctx: NonNull::new(Box::into_raw(Box::new(vm::FuncCtx {
|
||||||
let _ = match ctx {
|
|
||||||
Context::External(ctx) => ctx,
|
|
||||||
Context::Internal => vmctx,
|
|
||||||
};
|
|
||||||
|
|
||||||
NonNull::new(Box::into_raw(Box::new(vm::FuncCtx {
|
|
||||||
vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."),
|
vmctx: NonNull::new(vmctx).expect("`vmctx` must not be null."),
|
||||||
func_env: ptr::null_mut(),
|
func_env: match ctx {
|
||||||
})))
|
Context::External(ctx) => {
|
||||||
.unwrap()
|
NonNull::new(ctx).map(|pointer| {
|
||||||
|
pointer.cast() // `*mut vm::FuncEnv` was casted to `*mut vm::Ctx` to fit in `Context::External`. Cast it back.
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Context::Internal => None,
|
||||||
},
|
},
|
||||||
|
})))
|
||||||
|
.unwrap(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
link_errors.push(LinkError::IncorrectImportSignature {
|
link_errors.push(LinkError::IncorrectImportSignature {
|
||||||
|
@ -175,7 +175,7 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
fn to_raw(&self) -> NonNull<vm::Func>;
|
fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait TrapEarly<Rets>
|
pub trait TrapEarly<Rets>
|
||||||
@ -208,10 +208,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a function that can be used by WebAssembly.
|
/// Represents a function that can be used by WebAssembly.
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
|
pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> {
|
||||||
inner: Inner,
|
inner: Inner,
|
||||||
f: NonNull<vm::Func>,
|
func: NonNull<vm::Func>,
|
||||||
ctx: *mut vm::Ctx,
|
func_env: Option<NonNull<vm::FuncEnv>>,
|
||||||
|
vmctx: *mut vm::Ctx,
|
||||||
_phantom: PhantomData<(&'a (), Args, Rets)>,
|
_phantom: PhantomData<(&'a (), Args, Rets)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,19 +227,20 @@ where
|
|||||||
{
|
{
|
||||||
pub(crate) unsafe fn from_raw_parts(
|
pub(crate) unsafe fn from_raw_parts(
|
||||||
inner: Wasm,
|
inner: Wasm,
|
||||||
f: NonNull<vm::Func>,
|
func: NonNull<vm::Func>,
|
||||||
ctx: *mut vm::Ctx,
|
vmctx: *mut vm::Ctx,
|
||||||
) -> Func<'a, Args, Rets, Wasm> {
|
) -> Func<'a, Args, Rets, Wasm> {
|
||||||
Func {
|
Func {
|
||||||
inner,
|
inner,
|
||||||
f,
|
func,
|
||||||
ctx,
|
func_env: None,
|
||||||
|
vmctx,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_vm_func(&self) -> NonNull<vm::Func> {
|
pub fn get_vm_func(&self) -> NonNull<vm::Func> {
|
||||||
self.f
|
self.func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,15 +249,18 @@ where
|
|||||||
Args: WasmTypeList,
|
Args: WasmTypeList,
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
pub fn new<F, Kind>(f: F) -> Func<'a, Args, Rets, Host>
|
pub fn new<F, Kind>(func: F) -> Func<'a, Args, Rets, Host>
|
||||||
where
|
where
|
||||||
Kind: ExternalFunctionKind,
|
Kind: ExternalFunctionKind,
|
||||||
F: ExternalFunction<Kind, Args, Rets>,
|
F: ExternalFunction<Kind, Args, Rets>,
|
||||||
{
|
{
|
||||||
|
let (func, func_env) = func.to_raw();
|
||||||
|
|
||||||
Func {
|
Func {
|
||||||
inner: Host(()),
|
inner: Host(()),
|
||||||
f: f.to_raw(),
|
func,
|
||||||
ctx: ptr::null_mut(),
|
func_env,
|
||||||
|
vmctx: ptr::null_mut(),
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -391,7 +397,7 @@ where
|
|||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
{
|
{
|
||||||
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
||||||
unsafe { <A as WasmTypeList>::call(a, self.f, self.inner, self.ctx) }
|
unsafe { <A as WasmTypeList>::call(a, self.func, self.inner, self.vmctx) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,11 +488,10 @@ macro_rules! impl_traits {
|
|||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
Trap: TrapEarly<Rets>,
|
Trap: TrapEarly<Rets>,
|
||||||
FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap,
|
FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap + 'static,
|
||||||
{
|
{
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn to_raw(&self) -> NonNull<vm::Func> {
|
fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>) {
|
||||||
if mem::size_of::<Self>() == 0 {
|
|
||||||
/// This is required for the llvm backend to be able to unwind through this function.
|
/// This is required for the llvm backend to be able to unwind through this function.
|
||||||
#[cfg_attr(nightly, unwind(allowed))]
|
#[cfg_attr(nightly, unwind(allowed))]
|
||||||
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
||||||
@ -498,13 +503,26 @@ macro_rules! impl_traits {
|
|||||||
Trap: TrapEarly<Rets>,
|
Trap: TrapEarly<Rets>,
|
||||||
FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap,
|
FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap,
|
||||||
{
|
{
|
||||||
|
dbg!(func_ctx.vmctx.as_ptr());
|
||||||
|
|
||||||
let vmctx = unsafe { func_ctx.vmctx.as_mut() };
|
let vmctx = unsafe { func_ctx.vmctx.as_mut() };
|
||||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
let func_env = func_ctx.func_env;
|
||||||
|
|
||||||
|
dbg!(func_env);
|
||||||
|
|
||||||
|
let func: &FN = match func_env {
|
||||||
|
Some(func_env) => unsafe {
|
||||||
|
let func: NonNull<FN> = func_env.cast();
|
||||||
|
|
||||||
|
&*func.as_ptr()
|
||||||
|
},
|
||||||
|
None => unsafe { mem::transmute_copy(&()) }
|
||||||
|
};
|
||||||
|
|
||||||
let err = match panic::catch_unwind(
|
let err = match panic::catch_unwind(
|
||||||
panic::AssertUnwindSafe(
|
panic::AssertUnwindSafe(
|
||||||
|| {
|
|| {
|
||||||
f(vmctx $( , WasmExternType::from_native($x) )* ).report()
|
func(vmctx $( , WasmExternType::from_native($x) )* ).report()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -521,18 +539,24 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap()
|
let func_env: Option<NonNull<vm::FuncEnv>> =
|
||||||
} else {
|
// `FN` is a function pointer, or a closure
|
||||||
assert_eq!(
|
// _without_ a captured environment.
|
||||||
mem::size_of::<Self>(),
|
if mem::size_of::<Self>() == 0 {
|
||||||
mem::size_of::<usize>(),
|
None
|
||||||
"you cannot use a closure that captures state for `Func`."
|
|
||||||
);
|
|
||||||
|
|
||||||
NonNull::new(unsafe {
|
|
||||||
mem::transmute_copy::<_, *mut vm::Func>(self)
|
|
||||||
}).unwrap()
|
|
||||||
}
|
}
|
||||||
|
// `FN` is a closure _with_ a captured
|
||||||
|
// environment. Grab it.
|
||||||
|
else {
|
||||||
|
NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast)
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(func_env);
|
||||||
|
|
||||||
|
(
|
||||||
|
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(),
|
||||||
|
func_env
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,11 +565,10 @@ macro_rules! impl_traits {
|
|||||||
$( $x: WasmExternType, )*
|
$( $x: WasmExternType, )*
|
||||||
Rets: WasmTypeList,
|
Rets: WasmTypeList,
|
||||||
Trap: TrapEarly<Rets>,
|
Trap: TrapEarly<Rets>,
|
||||||
FN: Fn($( $x, )*) -> Trap,
|
FN: Fn($( $x, )*) -> Trap + 'static,
|
||||||
{
|
{
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn to_raw(&self) -> NonNull<vm::Func> {
|
fn to_raw(self) -> (NonNull<vm::Func>, Option<NonNull<vm::FuncEnv>>) {
|
||||||
if mem::size_of::<Self>() == 0 {
|
|
||||||
/// This is required for the llvm backend to be able to unwind through this function.
|
/// This is required for the llvm backend to be able to unwind through this function.
|
||||||
#[cfg_attr(nightly, unwind(allowed))]
|
#[cfg_attr(nightly, unwind(allowed))]
|
||||||
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
extern fn wrap<$( $x, )* Rets, Trap, FN>(
|
||||||
@ -557,13 +580,26 @@ macro_rules! impl_traits {
|
|||||||
Trap: TrapEarly<Rets>,
|
Trap: TrapEarly<Rets>,
|
||||||
FN: Fn($( $x, )*) -> Trap,
|
FN: Fn($( $x, )*) -> Trap,
|
||||||
{
|
{
|
||||||
|
dbg!(func_ctx.vmctx.as_ptr());
|
||||||
|
|
||||||
let vmctx = unsafe { func_ctx.vmctx.as_mut() };
|
let vmctx = unsafe { func_ctx.vmctx.as_mut() };
|
||||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
let func_env = func_ctx.func_env;
|
||||||
|
|
||||||
|
dbg!(func_env);
|
||||||
|
|
||||||
|
let func: &FN = match func_env {
|
||||||
|
Some(func_env) => unsafe {
|
||||||
|
let func: NonNull<FN> = func_env.cast();
|
||||||
|
|
||||||
|
&*func.as_ptr()
|
||||||
|
},
|
||||||
|
None => unsafe { mem::transmute_copy(&()) }
|
||||||
|
};
|
||||||
|
|
||||||
let err = match panic::catch_unwind(
|
let err = match panic::catch_unwind(
|
||||||
panic::AssertUnwindSafe(
|
panic::AssertUnwindSafe(
|
||||||
|| {
|
|| {
|
||||||
f($( WasmExternType::from_native($x), )* ).report()
|
func($( WasmExternType::from_native($x), )* ).report()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -580,18 +616,24 @@ macro_rules! impl_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap()
|
let func_env: Option<NonNull<vm::FuncEnv>> =
|
||||||
} else {
|
// `FN` is a function pointer, or a closure
|
||||||
assert_eq!(
|
// _without_ a captured environment.
|
||||||
mem::size_of::<Self>(),
|
if mem::size_of::<Self>() == 0 {
|
||||||
mem::size_of::<usize>(),
|
None
|
||||||
"you cannot use a closure that captures state for `Func`."
|
|
||||||
);
|
|
||||||
|
|
||||||
NonNull::new(unsafe {
|
|
||||||
mem::transmute_copy::<_, *mut vm::Func>(self)
|
|
||||||
}).unwrap()
|
|
||||||
}
|
}
|
||||||
|
// `FN` is a closure _with_ a captured
|
||||||
|
// environment. Grab it.
|
||||||
|
else {
|
||||||
|
NonNull::new(Box::into_raw(Box::new(self))).map(NonNull::cast)
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(func_env);
|
||||||
|
|
||||||
|
(
|
||||||
|
NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(),
|
||||||
|
func_env
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,9 +648,9 @@ macro_rules! impl_traits {
|
|||||||
unsafe {
|
unsafe {
|
||||||
<( $( $x ),* ) as WasmTypeList>::call(
|
<( $( $x ),* ) as WasmTypeList>::call(
|
||||||
( $( $x ),* ),
|
( $( $x ),* ),
|
||||||
self.f,
|
self.func,
|
||||||
self.inner,
|
self.inner,
|
||||||
self.ctx
|
self.vmctx
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,8 +688,11 @@ where
|
|||||||
Inner: Kind,
|
Inner: Kind,
|
||||||
{
|
{
|
||||||
fn to_export(&self) -> Export {
|
fn to_export(&self) -> Export {
|
||||||
let func = unsafe { FuncPointer::new(self.f.as_ptr()) };
|
let func = unsafe { FuncPointer::new(self.func.as_ptr()) };
|
||||||
let ctx = Context::Internal;
|
let ctx = match self.func_env {
|
||||||
|
Some(func_env) => Context::External(func_env.cast().as_ptr()),
|
||||||
|
None => Context::Internal,
|
||||||
|
};
|
||||||
let signature = Arc::new(FuncSig::new(Args::types(), Rets::types()));
|
let signature = Arc::new(FuncSig::new(Args::types(), Rets::types()));
|
||||||
|
|
||||||
Export::Function {
|
Export::Function {
|
||||||
|
@ -512,16 +512,16 @@ pub struct FuncEnv {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FuncCtx {
|
pub struct FuncCtx {
|
||||||
pub vmctx: NonNull<Ctx>,
|
pub(crate) vmctx: NonNull<Ctx>,
|
||||||
pub func_env: *mut FuncEnv,
|
pub(crate) func_env: Option<NonNull<FuncEnv>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An imported function, which contains the vmctx that owns this function.
|
/// An imported function, which contains the vmctx that owns this function.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ImportedFunc {
|
pub struct ImportedFunc {
|
||||||
pub func: *const Func,
|
pub(crate) func: *const Func,
|
||||||
pub func_ctx: NonNull<FuncCtx>,
|
pub(crate) func_ctx: NonNull<FuncCtx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// manually implemented because ImportedFunc contains raw pointers
|
// manually implemented because ImportedFunc contains raw pointers
|
||||||
|
Loading…
x
Reference in New Issue
Block a user