Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Caching Frank functions #863

Merged
merged 17 commits into from
Oct 7, 2019
Merged
3 changes: 2 additions & 1 deletion vm/frank/src/jni/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
* limitations under the License.
*/

use crate::jni::jni_results::*;
/// Defines export functions that will be accessible from the Scala part.

use crate::jni::jni_results::*;
use crate::vm::config::Config;
use crate::vm::errors::FrankError;
use crate::vm::frank::{Frank, FRANK};
Expand Down
1 change: 0 additions & 1 deletion vm/frank/src/jni/jni_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

/// Defines functions used to construct result of the VM invocation for the Scala part.
/// Corresponding case classes could be found in vm/src/main/scala/fluence/vm/frank/result.

use crate::jni::option::*;
use crate::vm::frank_result::FrankResult;
use jni::objects::{JObject, JValue};
Expand Down
1 change: 0 additions & 1 deletion vm/frank/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,4 @@
)]

mod jni;
mod modules;
mod vm;
10 changes: 6 additions & 4 deletions vm/frank/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@

/// Command-line tool intended to test Frank VM.
mod jni;
mod modules;
mod vm;

use crate::vm::config::Config;
use crate::vm::prepare::prepare_module;
use crate::vm::frank::Frank;

use clap::{App, AppSettings, Arg, SubCommand};
use exitfailure::ExitFailure;
use failure::err_msg;
use std::fs;
use vm::frank::Frank;
use crate::vm::prepare::prepare_module;

const VERSION: &str = env!("CARGO_PKG_VERSION");
const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
Expand Down Expand Up @@ -79,7 +79,9 @@ fn main() -> Result<(), ExitFailure> {
let in_module_path = arg.value_of(IN_MODULE_PATH).unwrap();
let wasm_code =
fs::read(in_module_path).unwrap_or_else(|err| panic!(format!("{}", err)));
let wasm_code = prepare_module(&wasm_code, &config).map_err(|e| panic!(format!("{}", e))).unwrap();
let wasm_code = prepare_module(&wasm_code, &config)
.map_err(|e| panic!(format!("{}", e)))
.unwrap();
let invoke_arg = arg.value_of(INVOKE_ARG).unwrap();

let _ = Frank::new(&wasm_code, config)
Expand Down
113 changes: 53 additions & 60 deletions vm/frank/src/vm/frank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,39 @@
*/

use crate::{
modules::env_module::EnvModule,
vm::modules::env_module::EnvModule,
vm::config::Config,
vm::errors::FrankError,
vm::frank_result::FrankResult,
};

use sha2::{
digest::generic_array::GenericArray,
digest::FixedOutput,
Digest,
Sha256,
};

use sha2::{digest::generic_array::GenericArray, digest::FixedOutput, Digest, Sha256};
use std::ffi::c_void;
use wasmer_runtime::{func, imports, instantiate, Ctx, Func, Instance};
use failure::_core::marker::PhantomData;
use wasmer_runtime_core::memory::ptr::{Array, WasmPtr};

use wasmer_runtime::{
func,
imports,
instantiate,
Ctx,
Func,
Instance
};
pub struct Frank {
instance: &'static Instance,

use wasmer_runtime_core::{
memory::{
ptr::{Array, WasmPtr},
},
};
// it is safe to use unwrap() while calling these functions because Option is used here
// just to allow partially initialization of the struct. And all Option fields will
// really contain Some after invoking Frank::new.
allocate: Option<Func<'static, i32, i32>>,
deallocate: Option<Func<'static, (i32, i32), ()>>,
invoke: Option<Func<'static, (i32, i32), i32>>,

pub struct Frank {
instance: Box<Instance>,
config: Box<Config>,
_tag: PhantomData<&'static Instance>,
}

impl Drop for Frank {
// In normal situation this method should be called only while shutting down
fn drop(&mut self) {
drop(self.allocate.as_ref());
drop(self.deallocate.as_ref());
drop(self.invoke.as_ref());
drop(Box::from(self.instance));
}
}

// Waiting for new release of Wasmer with https://github.com/wasmerio/wasmer/issues/748.
Expand All @@ -63,7 +63,7 @@ const ETH_FUNC_NAME: &str = "expects_eth";
impl Frank {
/// Writes given value on the given address.
fn write_to_mem(&mut self, address: usize, value: &[u8]) -> Result<(), FrankError> {
let memory = self.instance.context_mut().memory(0);
let memory = self.instance.context().memory(0);

for (byte_id, cell) in memory.view::<u8>()[address as usize..(address + value.len())]
.iter()
Expand Down Expand Up @@ -93,52 +93,33 @@ impl Frank {
Ok(result)
}

/// Calls invoke function exported from the main module.
fn call_invoke_func(&self, addr: i32, len: i32) -> Result<i32, FrankError> {
let invoke_func: Func<(i32, i32), (i32)> =
self.instance.func(&self.config.invoke_function_name)?;
let result = invoke_func.call(addr, len)?;
Ok(result)
}

/// Calls allocate function exported from the main module.
fn call_allocate_func(&self, size: i32) -> Result<i32, FrankError> {
let allocate_func: Func<(i32), (i32)> =
self.instance.func(&self.config.allocate_function_name)?;
let result = allocate_func.call(size)?;
Ok(result)
}

/// Calls deallocate function exported from the main module.
fn call_deallocate_func(&self, addr: i32, size: i32) -> Result<(), FrankError> {
let deallocate_func: Func<(i32, i32), ()> =
self.instance.func(&self.config.deallocate_function_name)?;
deallocate_func.call(addr, size)?;

Ok(())
}

/// Invokes a main module supplying byte array and expecting byte array with some outcome back.
pub fn invoke(&mut self, fn_argument: &[u8]) -> Result<FrankResult, FrankError> {
// renew the state of the registered environment module to track spent gas and eic
let env: &mut EnvModule =
unsafe { &mut *(self.instance.context_mut().data as *mut EnvModule) };
let env: &mut EnvModule = unsafe { &mut *(self.instance.context().data as *mut EnvModule) };
env.renew_state();

// allocate memory for the given argument and write it to memory
let argument_len = fn_argument.len() as i32;
let argument_address = if argument_len != 0 {
let address = self.call_allocate_func(argument_len)?;
let address = self.allocate.as_ref().unwrap().call(argument_len)?;
self.write_to_mem(address as usize, fn_argument)?;
address
} else {
0
};

// invoke a main module, read a result and deallocate it
let result_address = self.call_invoke_func(argument_address, argument_len)?;
let result_address = self
.invoke
.as_ref()
.unwrap()
.call(argument_address, argument_len)?;
let result = self.read_result_from_mem(result_address as _)?;
self.call_deallocate_func(result_address, result.len() as i32)?;
self.deallocate
.as_ref()
.unwrap()
.call(result_address, result.len() as i32)?;

let state = env.get_state();
Ok(FrankResult::new(result, state.0, state.1))
Expand All @@ -149,7 +130,7 @@ impl Frank {
&mut self,
) -> GenericArray<u8, <Sha256 as FixedOutput>::OutputSize> {
let mut hasher = Sha256::new();
let memory = self.instance.context_mut().memory(0);
let memory = self.instance.context().memory(0);

let wasm_ptr = WasmPtr::<u8, Array>::new(0 as _);
let raw_mem = wasm_ptr
Expand Down Expand Up @@ -186,10 +167,22 @@ impl Frank {
},
};

let instance = Box::new(instantiate(module, &import_objects)?);
let expects_eth = instance.func::<(i32, i32), ()>(ETH_FUNC_NAME).is_ok();

Ok((Self { instance, config }, expects_eth))
let instance: &'static mut Instance =
Box::leak(Box::new(instantiate(module, &import_objects)?));
let expects_eth = instance.func::<(), ()>(ETH_FUNC_NAME).is_ok();

Ok((
Self {
instance,
allocate: Some(instance.func::<(i32), i32>(&config.allocate_function_name)?),
deallocate: Some(
instance.func::<(i32, i32), ()>(&config.deallocate_function_name)?,
),
invoke: Some(instance.func::<(i32, i32), i32>(&config.invoke_function_name)?),
_tag: PhantomData,
},
expects_eth,
))
}
}

Expand Down
1 change: 1 addition & 0 deletions vm/frank/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ pub mod errors;
pub mod frank;
pub mod frank_result;
pub mod prepare;
mod modules;
File renamed without changes.
10 changes: 4 additions & 6 deletions vm/frank/src/vm/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,11 @@ impl<'a> ModulePreparator {
// At now, there is could be only one memory section, so
// it needs just to extract previous initial page count, delete existing memory section
let limits = match module.memory_section_mut() {
Some(section) => {
match section.entries_mut().pop() {
Some(entry) => *entry.limits(),
None => ResizableLimits::new(0 as _, Some(mem_pages_count))
}
Some(section) => match section.entries_mut().pop() {
Some(entry) => *entry.limits(),
None => ResizableLimits::new(0 as _, Some(mem_pages_count)),
},
None => ResizableLimits::new(0 as _, Some(mem_pages_count))
None => ResizableLimits::new(0 as _, Some(mem_pages_count)),
};

let memory_entry = MemoryType::new(limits.initial(), Some(mem_pages_count));
Expand Down