mirror of
https://github.com/fluencelabs/marine.git
synced 2025-03-15 22:10:49 +00:00
refactor using of ABI
This commit is contained in:
parent
893f01d22f
commit
44ac703e65
19
src/main.rs
19
src/main.rs
@ -35,7 +35,7 @@ use exitfailure::ExitFailure;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() -> Result<(), ExitFailure> {
|
fn main() -> Result<(), ExitFailure> {
|
||||||
println!("Welcome to the Frank CLI:");
|
println!("Welcome to the FCE CLI:");
|
||||||
let mut rl = rustyline::Editor::<()>::new();
|
let mut rl = rustyline::Editor::<()>::new();
|
||||||
let mut frank = Frank::new();
|
let mut frank = Frank::new();
|
||||||
|
|
||||||
@ -49,17 +49,20 @@ fn main() -> Result<(), ExitFailure> {
|
|||||||
"add" => {
|
"add" => {
|
||||||
let module_name = cmd[1].to_string();
|
let module_name = cmd[1].to_string();
|
||||||
let wasm_bytes = fs::read(cmd[2]);
|
let wasm_bytes = fs::read(cmd[2]);
|
||||||
if let None = wasm_bytes {
|
if let Err(e) = wasm_bytes {
|
||||||
println!("incorrect path provided");
|
println!("failed to read wasm module: {}", e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = Config::default();
|
let config = Config::default();
|
||||||
let result_msg =
|
let result_msg = match frank.register_module(
|
||||||
match frank.register_module(module_name, &wasm_bytes.unwrap(), config) {
|
module_name,
|
||||||
Ok(_) => "module successfully registered in Frank".to_string(),
|
&wasm_bytes.unwrap(),
|
||||||
Err(e) => format!("module registration failed with: {:?}", e),
|
config,
|
||||||
};
|
) {
|
||||||
|
Ok(_) => "module successfully registered in Frank".to_string(),
|
||||||
|
Err(e) => format!("module registration failed with: {:?}", e),
|
||||||
|
};
|
||||||
println!("{}", result_msg);
|
println!("{}", result_msg);
|
||||||
}
|
}
|
||||||
"del" => {
|
"del" => {
|
||||||
|
175
src/vm/frank.rs
175
src/vm/frank.rs
@ -15,41 +15,94 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::vm::module::frank_result::FrankResult;
|
use crate::vm::module::frank_result::FrankResult;
|
||||||
use crate::vm::module::{FrankModule, ModuleABI, ModuleAPI};
|
use crate::vm::module::{FrankModule, ModuleAPI};
|
||||||
use crate::vm::{config::Config, errors::FrankError, service::FrankService};
|
use crate::vm::{config::Config, errors::FrankError, service::FrankService};
|
||||||
|
|
||||||
use sha2::{digest::generic_array::GenericArray, digest::FixedOutput};
|
use sha2::{digest::generic_array::GenericArray, digest::FixedOutput};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use wasmer_runtime::{func, Ctx};
|
use wasmer_runtime::{func, Ctx};
|
||||||
use wasmer_runtime_core::import::ImportObject;
|
use wasmer_runtime_core::import::{ImportObject, Namespace};
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Dispatcher {
|
|
||||||
api: HashMap<String, ModuleABI>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Dispatcher {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
api: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Frank {
|
pub struct Frank {
|
||||||
|
// set of modules registered inside Frank
|
||||||
modules: HashMap<String, FrankModule>,
|
modules: HashMap<String, FrankModule>,
|
||||||
dispatcher: Dispatcher,
|
|
||||||
|
// contains ABI of each registered module in specific format for Wasmer
|
||||||
|
abi_import_object: ImportObject,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Frank {
|
impl Frank {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
dispatcher: Dispatcher::new(),
|
abi_import_object: ImportObject::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds ABI of a module with provided module name to the abi_import_object.
|
||||||
|
fn create_import_object(module: &FrankModule, config: &Config) -> Namespace {
|
||||||
|
let mut namespace = Namespace::new();
|
||||||
|
|
||||||
|
// TODO: introduce a macro for such things
|
||||||
|
let allocate = module.abi.allocate.clone();
|
||||||
|
namespace.insert(
|
||||||
|
config.allocate_fn_name.clone(),
|
||||||
|
func!(move |_ctx: &mut Ctx, size: i32| -> i32 {
|
||||||
|
allocate
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.call(size)
|
||||||
|
.expect("allocate failed")
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let invoke = module.abi.invoke.clone();
|
||||||
|
namespace.insert(
|
||||||
|
config.invoke_fn_name.clone(),
|
||||||
|
func!(move |_ctx: &mut Ctx, offset: i32, size: i32| -> i32 {
|
||||||
|
invoke
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.call(offset, size)
|
||||||
|
.expect("invoke failed")
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let deallocate = module.abi.deallocate.clone();
|
||||||
|
namespace.insert(
|
||||||
|
config.deallocate_fn_name.clone(),
|
||||||
|
func!(move |_ctx: &mut Ctx, ptr: i32, size: i32| {
|
||||||
|
deallocate
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.call(ptr, size)
|
||||||
|
.expect("deallocate failed");
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let store = module.abi.store.clone();
|
||||||
|
namespace.insert(
|
||||||
|
config.store_fn_name.clone(),
|
||||||
|
func!(move |_ctx: &mut Ctx, offset: i32, value: i32| {
|
||||||
|
store
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.call(offset, value)
|
||||||
|
.expect("store failed")
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let load = module.abi.load.clone();
|
||||||
|
namespace.insert(
|
||||||
|
config.load_fn_name.clone(),
|
||||||
|
func!(move |_ctx: &mut Ctx, offset: i32| -> i32 {
|
||||||
|
load.as_ref().unwrap().call(offset).expect("load failed")
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
namespace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrankService for Frank {
|
impl FrankService for Frank {
|
||||||
@ -69,81 +122,23 @@ impl FrankService for Frank {
|
|||||||
let prepared_wasm_bytes =
|
let prepared_wasm_bytes =
|
||||||
crate::vm::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
|
crate::vm::prepare::prepare_module(wasm_bytes, config.mem_pages_count)?;
|
||||||
|
|
||||||
let mut import_object = ImportObject::new();
|
let module = FrankModule::new(
|
||||||
for (module, abi) in self.dispatcher.api.iter() {
|
&prepared_wasm_bytes,
|
||||||
use wasmer_runtime_core::import::Namespace;
|
config.clone(),
|
||||||
|
self.abi_import_object.clone_ref(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// TODO: introduce a macro for such things
|
// registers ABI of newly registered module in abi_import_object
|
||||||
let mut namespace = Namespace::new();
|
let namespace = Frank::create_import_object(&module, &config);
|
||||||
let allocate = abi.allocate.clone();
|
self.abi_import_object.register(module_name.clone(), namespace);
|
||||||
namespace.insert(
|
|
||||||
config.allocate_fn_name.clone(),
|
|
||||||
func!(move |_ctx: &mut Ctx, size: i32| -> i32 {
|
|
||||||
allocate
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.call(size)
|
|
||||||
.expect("allocate failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let invoke = abi.invoke.clone();
|
match self.modules.entry(module_name) {
|
||||||
namespace.insert(
|
Entry::Vacant(entry) => {
|
||||||
config.invoke_fn_name.clone(),
|
entry.insert(module);
|
||||||
func!(move |_ctx: &mut Ctx, offset: i32, size: i32| -> i32 {
|
Ok(())
|
||||||
invoke
|
},
|
||||||
.as_ref()
|
Entry::Occupied(_) => Err(FrankError::NonUniqueModuleName)
|
||||||
.unwrap()
|
|
||||||
.call(offset, size)
|
|
||||||
.expect("invoke failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let deallocate = abi.deallocate.clone();
|
|
||||||
namespace.insert(
|
|
||||||
config.deallocate_fn_name.clone(),
|
|
||||||
func!(move |_ctx: &mut Ctx, ptr: i32, size: i32| {
|
|
||||||
deallocate
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.call(ptr, size)
|
|
||||||
.expect("deallocate failed");
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let store = abi.store.clone();
|
|
||||||
namespace.insert(
|
|
||||||
config.store_fn_name.clone(),
|
|
||||||
func!(move |_ctx: &mut Ctx, offset: i32, value: i32| {
|
|
||||||
store
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.call(offset, value)
|
|
||||||
.expect("store failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let load = abi.load.clone();
|
|
||||||
namespace.insert(
|
|
||||||
config.load_fn_name.clone(),
|
|
||||||
func!(move |_ctx: &mut Ctx, offset: i32| -> i32 {
|
|
||||||
load.as_ref().unwrap().call(offset).expect("load failed")
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
import_object.register(module, namespace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (module, module_abi) = FrankModule::new(&prepared_wasm_bytes, config, import_object)?;
|
|
||||||
match self.modules.entry(module_name.clone()) {
|
|
||||||
Entry::Vacant(entry) => entry.insert(module),
|
|
||||||
Entry::Occupied(_) => return Err(FrankError::NonUniqueModuleName),
|
|
||||||
};
|
|
||||||
|
|
||||||
// registers new abi in a dispatcher
|
|
||||||
self.dispatcher.api.insert(module_name, module_abi);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unregister_module(&mut self, module_name: &str) -> Result<(), FrankError> {
|
fn unregister_module(&mut self, module_name: &str) -> Result<(), FrankError> {
|
||||||
|
@ -48,24 +48,3 @@ pub struct ModuleABI {
|
|||||||
/// Loads one bytes from provided address.
|
/// Loads one bytes from provided address.
|
||||||
pub(crate) load: Option<Func<'static, i32, i32>>,
|
pub(crate) load: Option<Func<'static, i32, i32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ModuleABI {
|
|
||||||
// The manually drop is needed because at first we need to delete functions
|
|
||||||
// and only then instance.
|
|
||||||
fn drop(&mut self) {
|
|
||||||
#[allow(clippy::drop_copy)]
|
|
||||||
drop(self.allocate.as_ref());
|
|
||||||
|
|
||||||
#[allow(clippy::drop_copy)]
|
|
||||||
drop(self.deallocate.as_ref());
|
|
||||||
|
|
||||||
#[allow(clippy::drop_copy)]
|
|
||||||
drop(self.invoke.as_ref());
|
|
||||||
|
|
||||||
#[allow(clippy::drop_copy)]
|
|
||||||
drop(self.store.as_ref());
|
|
||||||
|
|
||||||
#[allow(clippy::drop_copy)]
|
|
||||||
drop(self.load.as_ref());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -21,25 +21,14 @@ use crate::vm::module::{ModuleABI, ModuleAPI};
|
|||||||
|
|
||||||
use sha2::digest::generic_array::GenericArray;
|
use sha2::digest::generic_array::GenericArray;
|
||||||
use sha2::digest::FixedOutput;
|
use sha2::digest::FixedOutput;
|
||||||
use wasmer_runtime::{compile, func, imports, Ctx, Func, Instance};
|
use wasmer_runtime::{compile, func, imports, Ctx, Instance};
|
||||||
use wasmer_runtime_core::import::ImportObject;
|
use wasmer_runtime_core::import::ImportObject;
|
||||||
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};
|
||||||
use wasmer_wasi::generate_import_object_for_version;
|
use wasmer_wasi::generate_import_object_for_version;
|
||||||
|
|
||||||
pub struct FrankModule {
|
pub(crate) struct FrankModule {
|
||||||
instance: &'static Instance,
|
instance: &'static Instance,
|
||||||
|
pub(crate) abi: ModuleABI,
|
||||||
// It is safe to use unwrap() while calling these functions because Option is used here
|
|
||||||
// just to allow partially initialization. And all Option fields will contain Some if
|
|
||||||
// invoking Frank::new has been succeed.
|
|
||||||
/// Allocates a region of memory inside a module. Used for passing argument inside the module.
|
|
||||||
allocate: Option<Func<'static, i32, i32>>,
|
|
||||||
|
|
||||||
/// Deallocates previously allocated memory region.
|
|
||||||
deallocate: Option<Func<'static, (i32, i32), ()>>,
|
|
||||||
|
|
||||||
/// Calls the main entry point of a module called invoke.
|
|
||||||
invoke: Option<Func<'static, (i32, i32), i32>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrankModule {
|
impl FrankModule {
|
||||||
@ -48,7 +37,7 @@ impl FrankModule {
|
|||||||
wasm_bytes: &[u8],
|
wasm_bytes: &[u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
imports: ImportObject,
|
imports: ImportObject,
|
||||||
) -> Result<(Self, ModuleABI), FrankError> {
|
) -> Result<Self, FrankError> {
|
||||||
let logger_imports = imports! {
|
let logger_imports = imports! {
|
||||||
"logger" => {
|
"logger" => {
|
||||||
"log_utf8_string" => func!(FrankModule::logger_log_utf8_string),
|
"log_utf8_string" => func!(FrankModule::logger_log_utf8_string),
|
||||||
@ -68,22 +57,15 @@ impl FrankModule {
|
|||||||
|
|
||||||
let instance = compile(&wasm_bytes)?.instantiate(&import_object)?;
|
let instance = compile(&wasm_bytes)?.instantiate(&import_object)?;
|
||||||
let instance: &'static mut Instance = Box::leak(Box::new(instance));
|
let instance: &'static mut Instance = Box::leak(Box::new(instance));
|
||||||
|
let abi = ModuleABI {
|
||||||
|
allocate: Some(instance.exports.get(&config.allocate_fn_name)?),
|
||||||
|
deallocate: Some(instance.exports.get(&config.deallocate_fn_name)?),
|
||||||
|
invoke: Some(instance.exports.get(&config.invoke_fn_name)?),
|
||||||
|
store: Some(instance.exports.get(&config.store_fn_name)?),
|
||||||
|
load: Some(instance.exports.get(&config.load_fn_name)?),
|
||||||
|
};
|
||||||
|
|
||||||
Ok((
|
Ok(Self { instance, abi })
|
||||||
Self {
|
|
||||||
instance,
|
|
||||||
allocate: Some(instance.exports.get(&config.allocate_fn_name)?),
|
|
||||||
deallocate: Some(instance.exports.get(&config.deallocate_fn_name)?),
|
|
||||||
invoke: Some(instance.exports.get(&config.invoke_fn_name)?),
|
|
||||||
},
|
|
||||||
ModuleABI {
|
|
||||||
allocate: Some(instance.exports.get(&config.allocate_fn_name)?),
|
|
||||||
deallocate: Some(instance.exports.get(&config.deallocate_fn_name)?),
|
|
||||||
invoke: Some(instance.exports.get(&config.invoke_fn_name)?),
|
|
||||||
store: Some(instance.exports.get(&config.store_fn_name)?),
|
|
||||||
load: Some(instance.exports.get(&config.load_fn_name)?),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints utf8 string of the given size from the given offset. Called from the wasm.
|
/// Prints utf8 string of the given size from the given offset. Called from the wasm.
|
||||||
@ -133,7 +115,7 @@ impl ModuleAPI for FrankModule {
|
|||||||
// allocate memory for the given argument and write it to memory
|
// allocate memory for the given argument and write it to memory
|
||||||
let argument_len = argument.len() as i32;
|
let argument_len = argument.len() as i32;
|
||||||
let argument_address = if argument_len != 0 {
|
let argument_address = if argument_len != 0 {
|
||||||
let address = self.allocate.as_ref().unwrap().call(argument_len)?;
|
let address = self.abi.allocate.as_ref().unwrap().call(argument_len)?;
|
||||||
self.write_to_mem(address as usize, argument)?;
|
self.write_to_mem(address as usize, argument)?;
|
||||||
address
|
address
|
||||||
} else {
|
} else {
|
||||||
@ -142,13 +124,15 @@ impl ModuleAPI for FrankModule {
|
|||||||
|
|
||||||
// invoke a main module, read a result and deallocate it
|
// invoke a main module, read a result and deallocate it
|
||||||
let result_address = self
|
let result_address = self
|
||||||
|
.abi
|
||||||
.invoke
|
.invoke
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.call(argument_address, argument_len)?;
|
.call(argument_address, argument_len)?;
|
||||||
let result = self.read_result_from_mem(result_address as _)?;
|
let result = self.read_result_from_mem(result_address as _)?;
|
||||||
|
|
||||||
self.deallocate
|
self.abi
|
||||||
|
.deallocate
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.call(result_address, result.len() as i32)?;
|
.call(result_address, result.len() as i32)?;
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub mod abi;
|
pub(crate) mod abi;
|
||||||
pub mod api;
|
pub(crate) mod api;
|
||||||
pub mod frank_module;
|
pub(crate) mod frank_module;
|
||||||
pub mod frank_result;
|
pub mod frank_result;
|
||||||
|
|
||||||
pub use abi::ModuleABI;
|
pub(crate) use abi::ModuleABI;
|
||||||
pub use api::ModuleAPI;
|
pub(crate) use api::ModuleAPI;
|
||||||
pub use frank_module::FrankModule;
|
pub(crate) use frank_module::FrankModule;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user