Skip to content

Commit

Permalink
save image with CompiledModule; refactor Module::serialize
Browse files Browse the repository at this point in the history
  • Loading branch information
yurydelendik committed Jul 16, 2020
1 parent 8801c29 commit ed254d4
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 52 deletions.
13 changes: 5 additions & 8 deletions crates/c-api/include/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -920,24 +920,21 @@ WASM_API_EXTERN void wasmtime_externref_new_with_finalizer(
WASM_API_EXTERN bool wasmtime_externref_data(wasm_val_t* val, void** datap);

/**
* \brief This function will compile a WebAssembly binary and saves artifacts
* \brief This function serializes compiled module artifacts
* as blob data.
*
* \param engine this is engine that will provide the compiler.
* \param binary this it the input buffer with the WebAssembly Binary Format inside of
* it. This will be parsed and converted to the binary format.
* \param module the module
* \param ret if the conversion is successful, this byte vector is filled in with
* the serialized compiled module.
*
* \return a non-null error if parsing fails, or returns `NULL`. If parsing
* fails then `ret` isn't touched.
*
* This function does not take ownership of `binary` or `engine`, and the caller is
* This function does not take ownership of `module`, and the caller is
* expected to deallocate the returned #wasmtime_error_t and #wasm_byte_vec_t.
*/
WASM_API_EXTERN own wasmtime_error_t* wasmtime_compile_and_serialize(
wasm_engine_t* engine,
const wasm_byte_vec_t* binary,
WASM_API_EXTERN own wasmtime_error_t* wasmtime_module_serialize(
wasm_module_t* module,
own wasm_byte_vec_t *ret
);

Expand Down
20 changes: 8 additions & 12 deletions crates/c-api/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
handle_result, wasm_byte_vec_t, wasm_engine_t, wasm_exporttype_t, wasm_exporttype_vec_t,
wasm_importtype_t, wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t,
handle_result, wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t,
};
use std::ptr;
use wasmtime::{compile_and_serialize, Engine, Module};
use wasmtime::{Engine, Module};

#[repr(C)]
#[derive(Clone)]
Expand Down Expand Up @@ -132,18 +132,14 @@ pub extern "C" fn wasm_module_obtain(
}

#[no_mangle]
pub extern "C" fn wasmtime_compile_and_serialize(
engine: &wasm_engine_t,
binary: &wasm_byte_vec_t,
pub extern "C" fn wasmtime_module_serialize(
module: &wasm_module_t,
ret: &mut wasm_byte_vec_t,
) -> Option<Box<wasmtime_error_t>> {
let mut result = Vec::new();
handle_result(
compile_and_serialize(&engine.engine, binary.as_slice(), &mut result),
|()| {
ret.set_buffer(result);
},
)
handle_result(module.module.serialize(&mut result), |()| {
ret.set_buffer(result);
})
}

#[no_mangle]
Expand Down
4 changes: 2 additions & 2 deletions crates/environ/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ impl TablePlan {

/// A translated WebAssembly module, excluding the function bodies and
/// memory initializers.
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Module {
/// A unique identifier (within this process) for this module.
#[serde(skip_serializing, skip_deserializing, default = "Module::next_id")]
Expand Down Expand Up @@ -181,7 +181,7 @@ pub struct Module {
/// This is stored within a `Module` and it implements `Hash`, unlike `Module`,
/// and is used as part of the cache key when we load compiled modules from the
/// global cache.
#[derive(Debug, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, Hash, Serialize, Deserialize)]
pub struct ModuleLocal {
/// Unprocessed signatures exactly as provided by `declare_signature()`.
pub signatures: PrimaryMap<SignatureIndex, (WasmFuncType, ir::Signature)>,
Expand Down
26 changes: 22 additions & 4 deletions crates/jit/src/instantiate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ pub struct CompiledModule {
traps: Traps,
stack_maps: StackMaps,
address_transform: ModuleAddressMap,
obj: Box<[u8]>,
unwind_info: Box<[ObjectUnwindInfo]>,
}

impl CompiledModule {
Expand Down Expand Up @@ -191,7 +193,7 @@ impl CompiledModule {
// Allocate all of the compiled functions into executable memory,
// copying over their contents.
let (code_memory, code_range, finished_functions, trampolines) =
build_code_memory(isa, &obj, &module, unwind_info).map_err(|message| {
build_code_memory(isa, &obj, &module, &unwind_info).map_err(|message| {
SetupError::Instantiate(InstantiationError::Resource(format!(
"failed to build code memory for functions: {}",
message
Expand Down Expand Up @@ -225,9 +227,25 @@ impl CompiledModule {
traps,
stack_maps,
address_transform,
obj,
unwind_info,
})
}

/// Extracts `CompilationArtifacts` from the compiled module.
pub fn to_compilation_artifacts(&self) -> CompilationArtifacts {
CompilationArtifacts {
module: (*self.module).clone(),
obj: self.obj.clone(),
unwind_info: self.unwind_info.clone(),
data_initializers: self.data_initializers.clone(),
traps: self.traps.clone(),
stack_maps: self.stack_maps.clone(),
address_transform: self.address_transform.clone(),
debug_info: self.code.dbg_jit_registration.is_some(),
}
}

/// Crate an `Instance` from this `CompiledModule`.
///
/// Note that if only one instance of this module is needed, it may be more
Expand Down Expand Up @@ -336,7 +354,7 @@ impl CompiledModule {

/// Similar to `DataInitializer`, but owns its own copy of the data rather
/// than holding a slice of the original module.
#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
pub struct OwnedDataInitializer {
/// The location where the initialization is to be performed.
location: DataInitializerLocation,
Expand Down Expand Up @@ -372,7 +390,7 @@ fn build_code_memory(
isa: &dyn TargetIsa,
obj: &[u8],
module: &Module,
unwind_info: Box<[ObjectUnwindInfo]>,
unwind_info: &Box<[ObjectUnwindInfo]>,
) -> Result<
(
CodeMemory,
Expand All @@ -386,7 +404,7 @@ fn build_code_memory(

let mut code_memory = CodeMemory::new();

let allocation = code_memory.allocate_for_object(&obj, &unwind_info)?;
let allocation = code_memory.allocate_for_object(&obj, unwind_info)?;

// Second, create a PrimaryMap from result vector of pointers.
let mut finished_functions = PrimaryMap::new();
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ pub use crate::frame_info::FrameInfo;
pub use crate::func::*;
pub use crate::instance::Instance;
pub use crate::linker::*;
pub use crate::module::{compile_and_serialize, Module};
pub use crate::module::Module;
pub use crate::r#ref::ExternRef;
pub use crate::runtime::*;
pub use crate::trap::Trap;
Expand Down
32 changes: 12 additions & 20 deletions crates/wasmtime/src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,18 @@ impl Module {
})
}

/// Serialize artifacts in I/O.
pub fn serialize(&self, w: impl std::io::Write) -> Result<()> {
let artifacts = (
compiler_fingerprint(self.engine.config()),
self.compiled.to_compilation_artifacts(),
);

bincode::serialize_into(w, &artifacts)?;

Ok(())
}

/// Read compiled module from I/O.
pub unsafe fn deserialize(engine: &Engine, r: impl std::io::Read) -> Result<Module> {
let expected_fingerprint = compiler_fingerprint(engine.config());
Expand Down Expand Up @@ -566,26 +578,6 @@ fn compiler_fingerprint(config: &Config) -> u64 {
hasher.finish()
}

/// Compile and write artifacts in I/O.
pub fn compile_and_serialize(
engine: &Engine,
bytes: impl AsRef<[u8]>,
w: impl std::io::Write,
) -> Result<()> {
#[cfg(feature = "wat")]
let bytes = wat::parse_bytes(bytes.as_ref())?;

Module::validate(engine, bytes.as_ref())?;
let artifacts = (
compiler_fingerprint(engine.config()),
CompilationArtifacts::build(engine.compiler(), bytes.as_ref())?,
);

bincode::serialize_into(w, &artifacts)?;

Ok(())
}

fn _assert_send_sync() {
fn _assert<T: Send + Sync>() {}
_assert::<Module>();
Expand Down
11 changes: 10 additions & 1 deletion examples/serialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ int serialize(wasm_byte_vec_t* buffer) {
wasm_engine_t *engine = wasm_engine_new();
assert(engine != NULL);

// With an engine we can create a *store* which is a long-lived group of wasm
// modules.
wasm_store_t *store = wasm_store_new(engine);
assert(store != NULL);

// Read our input file, which in this case is a wasm text file.
FILE* file = fopen("examples/hello.wat", "r");
assert(file != NULL);
Expand All @@ -62,10 +67,14 @@ int serialize(wasm_byte_vec_t* buffer) {
// and serialize into buffer.
printf("Compiling and serializing module...\n");
wasm_module_t *module = NULL;
error = wasmtime_compile_and_serialize(engine, &wasm, buffer);
error = wasmtime_module_new(store, &wasm, &module);
wasm_byte_vec_delete(&wasm);
if (error != NULL)
exit_with_error("failed to compile module", error, NULL);
error = wasmtime_module_serialize(module, buffer);
wasm_module_delete(module);
if (error != NULL)
exit_with_error("failed to serialize module", error, NULL);

printf("Serialized.\n");

Expand Down
8 changes: 4 additions & 4 deletions examples/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// You can execute this example with `cargo run --example serialize`

use anyhow::Result;
use std::fs::{self, File};
use std::fs::File;
use std::io::{Seek, SeekFrom};
use wasmtime::*;

Expand All @@ -17,9 +17,9 @@ fn serialize() -> Result<File> {

// Compile the wasm binary into an in-memory instance of a `Module`.
println!("Compiling module...");
let wasm = fs::read("examples/hello.wat")?;
let module = Module::from_file(&engine, "examples/hello.wat")?;
let mut file = tempfile::tempfile()?;
compile_and_serialize(&engine, wasm, file.try_clone()?)?;
module.serialize(file.try_clone()?)?;

file.seek(SeekFrom::Start(0))?;

Expand All @@ -35,7 +35,7 @@ fn deserialize(file: File) -> Result<()> {
let store = Store::default();

// Compile the wasm binary into an in-memory instance of a `Module`.
println!("Compiling module...");
println!("Deserialize module...");
let module = unsafe { Module::deserialize(store.engine(), file)? };

// Here we handle the imports of the module, which in this case is our
Expand Down

0 comments on commit ed254d4

Please sign in to comment.