diff --git a/lib/emscripten/src/env.rs b/lib/emscripten/src/env.rs index 8889906a7..6e3390cdf 100644 --- a/lib/emscripten/src/env.rs +++ b/lib/emscripten/src/env.rs @@ -8,25 +8,15 @@ use std::mem; use std::os::raw::c_char; use super::utils::{allocate_on_stack, copy_cstr_into_wasm, copy_terminated_array_of_cstrs}; +use super::EmscriptenData; use wasmer_runtime_core::{types::Value, vm::Ctx}; -//use super::EmscriptenData; - -//impl Instance { -// pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const usize { -// unimplemented!("TODO replace this stub") -// } -// -// pub fn emscripten_data(&self) -> &'static mut Option { -// unimplemented!("TODO replace this stub") -// } -//} // #[no_mangle] /// emscripten: _getenv // (name: *const char) -> *const c_char; -pub extern "C" fn _getenv(name: c_int, vmctx: &mut Ctx) -> u32 { +pub extern "C" fn _getenv(name: c_int, ctx: &mut Ctx) -> u32 { debug!("emscripten::_getenv"); - let name_addr = vmctx.memory(0)[name as usize] as *const c_char; + let name_addr = ctx.memory(0)[name as usize] as *const c_char; debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); @@ -35,15 +25,15 @@ pub extern "C" fn _getenv(name: c_int, vmctx: &mut Ctx) -> u32 { return 0; } - unsafe { copy_cstr_into_wasm(vmctx, c_str) } + unsafe { copy_cstr_into_wasm(ctx, c_str) } } /// emscripten: _setenv // (name: *const char, name: *const value, overwrite: int); -pub extern "C" fn _setenv(name: c_int, value: c_int, overwrite: c_int, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn _setenv(name: c_int, value: c_int, overwrite: c_int, ctx: &mut Ctx) -> c_int { debug!("emscripten::_setenv"); - let name_addr = vmctx.memory(0)[name as usize] as *const c_char; - let value_addr = vmctx.memory(0)[value as usize] as *const c_char; + let name_addr = ctx.memory(0)[name as usize] as *const c_char; + let value_addr = ctx.memory(0)[value as usize] as *const c_char; debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); debug!("=> value({:?})", unsafe { CStr::from_ptr(value_addr) }); @@ -52,10 +42,10 @@ pub extern "C" fn _setenv(name: c_int, value: c_int, overwrite: c_int, vmctx: &m } /// emscripten: _putenv // (name: *const char); -pub extern "C" fn _putenv(name: c_int, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn _putenv(name: c_int, ctx: &mut Ctx) -> c_int { debug!("emscripten::_putenv"); - let name_addr = vmctx.memory(0)[name as usize] as *const c_char; + let name_addr = ctx.memory(0)[name as usize] as *const c_char; debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); @@ -63,10 +53,10 @@ pub extern "C" fn _putenv(name: c_int, vmctx: &mut Ctx) -> c_int { } /// emscripten: _unsetenv // (name: *const char); -pub extern "C" fn _unsetenv(name: c_int, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn _unsetenv(name: c_int, ctx: &mut Ctx) -> c_int { debug!("emscripten::_unsetenv"); - let name_addr = vmctx.memory(0)[name as usize] as *const c_char; + let name_addr = ctx.memory(0)[name as usize] as *const c_char; debug!("=> name({:?})", unsafe { CStr::from_ptr(name_addr) }); @@ -74,7 +64,7 @@ pub extern "C" fn _unsetenv(name: c_int, vmctx: &mut Ctx) -> c_int { } #[allow(clippy::cast_ptr_alignment)] -pub extern "C" fn _getpwnam(name_ptr: c_int, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn _getpwnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { debug!("emscripten::_getpwnam {}", name_ptr); #[repr(C)] @@ -89,20 +79,20 @@ pub extern "C" fn _getpwnam(name_ptr: c_int, vmctx: &mut Ctx) -> c_int { } let name = unsafe { - let memory_name_ptr = vmctx.memory(0)[name_ptr as usize] as *const c_char; + let memory_name_ptr = ctx.memory(0)[name_ptr as usize] as *const c_char; CStr::from_ptr(memory_name_ptr) }; unsafe { let passwd = &*libc_getpwnam(name.as_ptr()); - let passwd_struct_offset = call_malloc(mem::size_of::() as _, vmctx); + let passwd_struct_offset = call_malloc(mem::size_of::() as _, ctx); - let passwd_struct_ptr = vmctx.memory(0)[passwd_struct_offset as usize] as *mut GuestPasswd; - (*passwd_struct_ptr).pw_name = copy_cstr_into_wasm(vmctx, passwd.pw_name); - (*passwd_struct_ptr).pw_passwd = copy_cstr_into_wasm(vmctx, passwd.pw_passwd); - (*passwd_struct_ptr).pw_gecos = copy_cstr_into_wasm(vmctx, passwd.pw_gecos); - (*passwd_struct_ptr).pw_dir = copy_cstr_into_wasm(vmctx, passwd.pw_dir); - (*passwd_struct_ptr).pw_shell = copy_cstr_into_wasm(vmctx, passwd.pw_shell); + let passwd_struct_ptr = ctx.memory(0)[passwd_struct_offset as usize] as *mut GuestPasswd; + (*passwd_struct_ptr).pw_name = copy_cstr_into_wasm(ctx, passwd.pw_name); + (*passwd_struct_ptr).pw_passwd = copy_cstr_into_wasm(ctx, passwd.pw_passwd); + (*passwd_struct_ptr).pw_gecos = copy_cstr_into_wasm(ctx, passwd.pw_gecos); + (*passwd_struct_ptr).pw_dir = copy_cstr_into_wasm(ctx, passwd.pw_dir); + (*passwd_struct_ptr).pw_shell = copy_cstr_into_wasm(ctx, passwd.pw_shell); (*passwd_struct_ptr).pw_uid = passwd.pw_uid; (*passwd_struct_ptr).pw_gid = passwd.pw_gid; @@ -111,7 +101,7 @@ pub extern "C" fn _getpwnam(name_ptr: c_int, vmctx: &mut Ctx) -> c_int { } #[allow(clippy::cast_ptr_alignment)] -pub extern "C" fn _getgrnam(name_ptr: c_int, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn _getgrnam(name_ptr: c_int, ctx: &mut Ctx) -> c_int { debug!("emscripten::_getgrnam {}", name_ptr); #[repr(C)] @@ -123,69 +113,38 @@ pub extern "C" fn _getgrnam(name_ptr: c_int, vmctx: &mut Ctx) -> c_int { } let name = unsafe { - let memory_name_ptr = vmctx.memory(0)[name_ptr as usize] as *const c_char; + let memory_name_ptr = ctx.memory(0)[name_ptr as usize] as *const c_char; CStr::from_ptr(memory_name_ptr) }; unsafe { let group = &*libc_getgrnam(name.as_ptr()); - let group_struct_offset = call_malloc(mem::size_of::() as _, vmctx); + let group_struct_offset = call_malloc(mem::size_of::() as _, ctx); - let group_struct_ptr = vmctx.memory(0)[group_struct_offset as usize] as *mut GuestGroup; - (*group_struct_ptr).gr_name = copy_cstr_into_wasm(vmctx, group.gr_name); - (*group_struct_ptr).gr_passwd = copy_cstr_into_wasm(vmctx, group.gr_passwd); + let group_struct_ptr = ctx.memory(0)[group_struct_offset as usize] as *mut GuestGroup; + (*group_struct_ptr).gr_name = copy_cstr_into_wasm(ctx, group.gr_name); + (*group_struct_ptr).gr_passwd = copy_cstr_into_wasm(ctx, group.gr_passwd); (*group_struct_ptr).gr_gid = group.gr_gid; - (*group_struct_ptr).gr_mem = copy_terminated_array_of_cstrs(vmctx, group.gr_mem); + (*group_struct_ptr).gr_mem = copy_terminated_array_of_cstrs(ctx, group.gr_mem); group_struct_offset as c_int } } -pub fn call_malloc(size: i32, vmctx: &mut Ctx) -> u32 { - unimplemented!() - // let ret = instance - // .call("_malloc", &[Value::I32(size)]) - // .expect("_malloc call failed"); - // if let [Value::I32(x)] = ret.as_slice() { - // *x as u32 - // } else { - // panic!("unexpected value from _malloc: {:?}", ret); - // } +pub fn call_malloc(size: i32, ctx: &mut Ctx) -> u32 { + (get_emscripten_data(ctx).malloc)(size, ctx) } -pub fn call_memalign(alignment: u32, size: u32, vmctx: &mut Ctx) -> u32 { - unimplemented!() - // let ret = - // call( - // vmctx, - // "_memalign", - // &[Value::I32(alignment as i32), Value::I32(size as i32)], - // ) - // .expect("_memalign call failed"); - // if let [Value::I32(x)] = ret.as_slice() { - // *x as u32 - // } else { - // panic!("unexpected value from _memalign {:?}", ret); - // } +pub fn call_memalign(alignment: u32, size: u32, ctx: &mut Ctx) -> u32 { + (get_emscripten_data(ctx).memalign)(alignment, size, ctx) } -pub fn call_memset(pointer: u32, value: i32, size: u32, vmctx: &mut Ctx) -> u32 { - unimplemented!() - // let ret = instance - // .call( - // "_memset", - // &[ - // Value::I32(pointer as i32), - // Value::I32(value), - // Value::I32(size as i32), - // ], - // ) - // .expect("_memset call failed"); - // if let [Value::I32(x)] = ret.as_slice() { - // *x as u32 - // } else { - // panic!("unexpected value from _memset {:?}", ret); - // } +pub fn call_memset(pointer: u32, value: i32, size: u32, ctx: &mut Ctx) -> u32 { + (get_emscripten_data(ctx).memset)(pointer, value, size, ctx) +} + +pub(crate) fn get_emscripten_data(ctx: &mut Ctx) -> &mut EmscriptenData { + unsafe { &mut *(ctx.data as *mut EmscriptenData) } } pub extern "C" fn _getpagesize() -> u32 { @@ -194,18 +153,18 @@ pub extern "C" fn _getpagesize() -> u32 { } #[allow(clippy::cast_ptr_alignment)] -pub extern "C" fn ___build_environment(environ: c_int, vmctx: &mut Ctx) { +pub extern "C" fn ___build_environment(environ: c_int, ctx: &mut Ctx) { debug!("emscripten::___build_environment {}", environ); const MAX_ENV_VALUES: u32 = 64; const TOTAL_ENV_SIZE: u32 = 1024; - let mut environment = vmctx.memory(0)[environ as usize] as *mut c_int; + let mut environment = ctx.memory(0)[environ as usize] as *mut c_int; unsafe { let (pool_offset, _pool_slice): (u32, &mut [u8]) = - allocate_on_stack(TOTAL_ENV_SIZE as u32, vmctx); + allocate_on_stack(TOTAL_ENV_SIZE as u32, ctx); let (env_offset, _env_slice): (u32, &mut [u8]) = - allocate_on_stack((MAX_ENV_VALUES * 4) as u32, vmctx); - let mut env_ptr = vmctx.memory(0)[env_offset as usize] as *mut c_int; - let mut _pool_ptr = vmctx.memory(0)[pool_offset as usize] as *mut c_int; + allocate_on_stack((MAX_ENV_VALUES * 4) as u32, ctx); + let mut env_ptr = ctx.memory(0)[env_offset as usize] as *mut c_int; + let mut _pool_ptr = ctx.memory(0)[pool_offset as usize] as *mut c_int; *env_ptr = pool_offset as i32; *environment = env_offset as i32; @@ -216,13 +175,13 @@ pub extern "C" fn ___build_environment(environ: c_int, vmctx: &mut Ctx) { // }; } -pub extern "C" fn _sysconf(name: c_int, _vmctx: &mut Ctx) -> c_long { +pub extern "C" fn _sysconf(name: c_int, _ctx: &mut Ctx) -> c_long { debug!("emscripten::_sysconf {}", name); // TODO: Implement like emscripten expects regarding memory/page size unsafe { sysconf(name) } } -pub extern "C" fn ___assert_fail(a: c_int, b: c_int, c: c_int, d: c_int, _vmctx: &mut Ctx) { +pub extern "C" fn ___assert_fail(a: c_int, b: c_int, c: c_int, d: c_int, _ctx: &mut Ctx) { debug!("emscripten::___assert_fail {} {} {} {}", a, b, c, d); // TODO: Implement like emscripten expects regarding memory/page size unimplemented!() diff --git a/lib/emscripten/src/jmp.rs b/lib/emscripten/src/jmp.rs index 87d105546..25bdd9059 100644 --- a/lib/emscripten/src/jmp.rs +++ b/lib/emscripten/src/jmp.rs @@ -1,39 +1,39 @@ +use super::env::get_emscripten_data; use libc::{c_int, c_void}; +use std::cell::UnsafeCell; use wasmer_runtime_core::vm::Ctx; /// setjmp -pub extern "C" fn __setjmp(env_addr: u32, vmctx: &mut Ctx) -> c_int { +pub extern "C" fn __setjmp(env_addr: u32, ctx: &mut Ctx) -> c_int { debug!("emscripten::__setjmp (setjmp)"); - unimplemented!() - // unsafe { - // // Rather than using the env as the holder of the jump buffer pointer, - // // we use the environment address to store the index relative to jumps - // // so the address of the jump it's outside the wasm memory itself. - // let jump_index = vmctx.memory(0)[env_addr as usize] as *mut i8; - // // We create the jump buffer outside of the wasm memory - // let jump_buf: UnsafeCell<[c_int; 27]> = UnsafeCell::new([0; 27]); - // let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; - // let result = setjmp(jump_buf.get() as _); - // // We set the jump index to be the last value of jumps - // *jump_index = jumps.len() as _; - // // We hold the reference of the jump buffer - // jumps.push(jump_buf); - // result - // } + unsafe { + // Rather than using the env as the holder of the jump buffer pointer, + // we use the environment address to store the index relative to jumps + // so the address of the jump it's outside the wasm memory itself. + let jump_index = ctx.memory(0)[env_addr as usize] as *mut i8; + // We create the jump buffer outside of the wasm memory + let jump_buf: UnsafeCell<[c_int; 27]> = UnsafeCell::new([0; 27]); + let mut jumps = &mut get_emscripten_data(ctx).jumps; + let result = setjmp(jump_buf.get() as _); + // We set the jump index to be the last value of jumps + *jump_index = jumps.len() as _; + // We hold the reference of the jump buffer + jumps.push(jump_buf); + result + } } /// longjmp -pub extern "C" fn __longjmp(env_addr: u32, val: c_int, vmctx: &mut Ctx) -> ! { - debug!("emscripten::__longjmp (longjmp) {}", val); - unimplemented!() - // unsafe { - // // We retrieve the jump index from the env address - // let jump_index = vmctx.memory(0)[env_addr as usize] as *mut i8; - // let mut jumps = &mut instance.emscripten_data().as_mut().unwrap().jumps; - // // We get the real jump buffer from the jumps vector, using the retrieved index - // let mut jump_buf = &jumps[*jump_index as usize]; - // longjmp(jump_buf.get() as _, val) - // }; +pub extern "C" fn __longjmp(env_addr: u32, val: c_int, ctx: &mut Ctx) -> ! { + debug!("emscripten::__longjmp (longmp)"); + unsafe { + // We retrieve the jump index from the env address + let jump_index = ctx.memory(0)[env_addr as usize] as *mut i8; + let mut jumps = &mut get_emscripten_data(ctx).jumps; + // We get the real jump buffer from the jumps vector, using the retrieved index + let mut jump_buf = &jumps[*jump_index as usize]; + longjmp(jump_buf.get() as _, val) + }; } extern "C" { diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 0d777e79d..0f3a0f54c 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -3,8 +3,9 @@ extern crate wasmer_runtime_core; use byteorder::{ByteOrder, LittleEndian}; use hashbrown::HashMap; -use std::mem; -use std::ptr; +use libc::c_int; +use std::cell::UnsafeCell; +use std::{ffi::c_void, mem, ptr}; use std::{mem::size_of, panic, slice}; use wasmer_runtime_core::{ error::{CallError, CallResult, ResolveError}, @@ -20,6 +21,7 @@ use wasmer_runtime_core::{ Type::{self, *}, Value, }, + vm::Ctx, vm::LocalGlobal, vm::LocalMemory, vm::LocalTable, @@ -82,14 +84,40 @@ fn dynamictop_ptr(static_bump: u32) -> u32 { static_bump + DYNAMICTOP_PTR_DIFF } -//pub struct EmscriptenData { -// pub malloc: extern "C" fn(i32, &Instance) -> u32, -// pub free: extern "C" fn(i32, &mut Instance), -// pub memalign: extern "C" fn(u32, u32, &mut Instance) -> u32, -// pub memset: extern "C" fn(u32, i32, u32, &mut Instance) -> u32, -// pub stack_alloc: extern "C" fn(u32, &Instance) -> u32, -// pub jumps: Vec>, -//} +pub struct EmscriptenData { + pub malloc: extern "C" fn(i32, &mut Ctx) -> u32, + pub free: extern "C" fn(i32, &mut Ctx), + pub memalign: extern "C" fn(u32, u32, &mut Ctx) -> u32, + pub memset: extern "C" fn(u32, i32, u32, &mut Ctx) -> u32, + pub stack_alloc: extern "C" fn(u32, &mut Ctx) -> u32, + pub jumps: Vec>, +} + +impl EmscriptenData { + pub fn new(instance: &mut Instance) -> Self { + unsafe { + let malloc_func = instance.func("_malloc").unwrap(); + let malloc_addr = malloc_func.raw() as *const u8; + let free_func = instance.func("_free").unwrap(); + let free_addr = free_func.raw() as *const u8; + let memalign_func = instance.func("_memalign").unwrap(); + let memalign_addr = memalign_func.raw() as *const u8; + let memset_func = instance.func("_memset").unwrap(); + let memset_addr = memset_func.raw() as *const u8; + let stack_alloc_func = instance.func("stackAlloc").unwrap(); + let stack_alloc_addr = stack_alloc_func.raw() as *const u8; + + EmscriptenData { + malloc: mem::transmute(malloc_addr), + free: mem::transmute(free_addr), + memalign: mem::transmute(memalign_addr), + memset: mem::transmute(memset_addr), + stack_alloc: mem::transmute(stack_alloc_addr), + jumps: Vec::new(), + } + } + } +} pub fn run_emscripten_instance( module: &Module, @@ -97,7 +125,9 @@ pub fn run_emscripten_instance( _path: &str, args: Vec<&str>, ) -> CallResult<()> { - // TODO atinit and atexit for emscripten + let mut data = EmscriptenData::new(instance); + let data_ptr = &mut data as *mut _ as *mut c_void; + instance.ctx().data = data_ptr; // Get main arguments. let main_args = get_main_args("_main", args, instance).unwrap(); diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index f98bfca1f..e61b16fae 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -1,8 +1,10 @@ use wasmer_runtime_core::{module::Module, vm::Ctx}; //use wasmer_runtime_core::Instance; use super::env; +use super::env::get_emscripten_data; use libc::stat; use std::ffi::CStr; +use std::mem::size_of; use std::os::raw::c_char; use std::slice; /// We check if a provided module is an Emscripten generated one @@ -15,8 +17,8 @@ pub fn is_emscripten_module(module: &Module) -> bool { false } -pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, vmctx: &mut Ctx) -> u32 { - let buf_addr = vmctx.memory(0)[buf as usize] as *mut c_char; +pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, ctx: &mut Ctx) -> u32 { + let buf_addr = ctx.memory(0)[buf as usize] as *mut c_char; for i in 0..max { *buf_addr.add(i as _) = *string.add(i as _); @@ -26,11 +28,11 @@ pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, vmctx: &mu } /// This function expects nullbyte to be appended. -pub unsafe fn copy_cstr_into_wasm(vmctx: &mut Ctx, cstr: *const c_char) -> u32 { +pub unsafe fn copy_cstr_into_wasm(ctx: &mut Ctx, cstr: *const c_char) -> u32 { let s = CStr::from_ptr(cstr).to_str().unwrap(); let cstr_len = s.len(); - let space_offset = env::call_malloc((cstr_len as i32) + 1, vmctx); - let raw_memory = vmctx.memory(0)[space_offset as usize] as *mut u8; + let space_offset = env::call_malloc((cstr_len as i32) + 1, ctx); + let raw_memory = ctx.memory(0)[space_offset as usize] as *mut u8; let slice = slice::from_raw_parts_mut(raw_memory, cstr_len); for (byte, loc) in s.bytes().zip(slice.iter_mut()) { @@ -44,20 +46,16 @@ pub unsafe fn copy_cstr_into_wasm(vmctx: &mut Ctx, cstr: *const c_char) -> u32 { space_offset } -pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, vmctx: &'a Ctx) -> (u32, &'a mut [T]) { - unimplemented!("allocate_on_stack not implemented") - // let offset = (instance.emscripten_data().as_ref().unwrap().stack_alloc)( - // count * (size_of::() as u32), - // vmctx, - // ); - // let addr = vmctx.memory(0)[offset as usize] as *mut T; - // let slice = slice::from_raw_parts_mut(addr, count as usize); - // - // (offset, slice) +pub unsafe fn allocate_on_stack<'a, T: Copy>(count: u32, ctx: &'a mut Ctx) -> (u32, &'a mut [T]) { + let offset = (get_emscripten_data(ctx).stack_alloc)(count * (size_of::() as u32), ctx); + let addr = ctx.memory(0)[offset as usize] as *mut T; + let slice = slice::from_raw_parts_mut(addr, count as usize); + + (offset, slice) } -pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, vmctx: &'a Ctx) -> (u32, &'a [u8]) { - let (offset, slice) = allocate_on_stack((s.len() + 1) as u32, vmctx); +pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, ctx: &'a mut Ctx) -> (u32, &'a [u8]) { + let (offset, slice) = allocate_on_stack((s.len() + 1) as u32, ctx); use std::iter; for (byte, loc) in s.bytes().chain(iter::once(0)).zip(slice.iter_mut()) { @@ -67,7 +65,7 @@ pub unsafe fn allocate_cstr_on_stack<'a>(s: &str, vmctx: &'a Ctx) -> (u32, &'a [ (offset, slice) } -pub unsafe fn copy_terminated_array_of_cstrs(_vmctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 { +pub unsafe fn copy_terminated_array_of_cstrs(_ctx: &mut Ctx, cstrs: *mut *mut c_char) -> u32 { let total_num = { let mut ptr = cstrs; let mut counter = 0; @@ -105,8 +103,8 @@ pub struct GuestStat { } #[allow(clippy::cast_ptr_alignment)] -pub unsafe fn copy_stat_into_wasm(vmctx: &mut Ctx, buf: u32, stat: &stat) { - let stat_ptr = vmctx.memory(0)[buf as usize] as *mut GuestStat; +pub unsafe fn copy_stat_into_wasm(ctx: &mut Ctx, buf: u32, stat: &stat) { + let stat_ptr = ctx.memory(0)[buf as usize] as *mut GuestStat; (*stat_ptr).st_dev = stat.st_dev as _; (*stat_ptr).__st_dev_padding = 0; (*stat_ptr).__st_ino_truncated = stat.st_ino as _; diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index ed88bbe8c..20d352f4c 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -227,7 +227,6 @@ impl Instance { Ok(returns) } - } impl InstanceInner {