Skip to content

Commit

Permalink
Caching Frank functions (#863)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikevoronov authored Oct 7, 2019
1 parent a311545 commit ea61c12
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 73 deletions.
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
// to allow partially initialization of the struct. And all Option fields will contain
// Some if invoking Frank::new is succeed.
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 VM 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.
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

0 comments on commit ea61c12

Please sign in to comment.