Executor: Add create_runtime_from_artifact_bytes (#14184)

This commit is contained in:
Marcin S
2023-05-22 11:43:51 -04:00
committed by GitHub
parent 09a7e69012
commit 2decceef76
3 changed files with 60 additions and 5 deletions
+8 -1
View File
@@ -188,12 +188,19 @@ fn bench_call_instance(c: &mut Criterion) {
},
),
(
"pooling_vanilla",
"pooling_vanilla_fresh",
Method::Compiled {
instantiation_strategy: InstantiationStrategy::Pooling,
precompile: false,
},
),
(
"pooling_vanilla_precompiled",
Method::Compiled {
instantiation_strategy: InstantiationStrategy::Pooling,
precompile: true,
},
),
(
"pooling_cow_fresh",
Method::Compiled {
@@ -37,6 +37,7 @@ mod util;
mod tests;
pub use runtime::{
create_runtime, create_runtime_from_artifact, prepare_runtime_artifact, Config,
DeterministicStackLimit, InstantiationStrategy, Semantics,
create_runtime, create_runtime_from_artifact, create_runtime_from_artifact_bytes,
prepare_runtime_artifact, Config, DeterministicStackLimit, InstantiationStrategy, Semantics,
WasmtimeRuntime,
};
@@ -435,7 +435,7 @@ pub struct DeterministicStackLimit {
/// All of the CoW strategies (with `CopyOnWrite` suffix) are only supported when either:
/// a) we're running on Linux,
/// b) we're running on an Unix-like system and we're precompiling
/// our module beforehand.
/// our module beforehand and instantiating from a file.
///
/// If the CoW variant of a strategy is unsupported the executor will
/// fall back to the non-CoW equivalent.
@@ -537,7 +537,7 @@ enum CodeSupplyMode<'a> {
/// The runtime is instantiated using the given runtime blob.
Fresh(RuntimeBlob),
/// The runtime is instantiated using a precompiled module.
/// The runtime is instantiated using a precompiled module at the given path.
///
/// This assumes that the code is already prepared for execution and the same `Config` was
/// used.
@@ -545,6 +545,12 @@ enum CodeSupplyMode<'a> {
/// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to
/// map the runtime's linear memory on supported platforms in a copy-on-write fashion.
Precompiled(&'a Path),
/// The runtime is instantiated using a precompiled module with the given bytes.
///
/// This assumes that the code is already prepared for execution and the same `Config` was
/// used.
PrecompiledBytes(&'a [u8]),
}
/// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to
@@ -589,6 +595,31 @@ where
do_create_runtime::<H>(CodeSupplyMode::Precompiled(compiled_artifact_path), config)
}
/// The same as [`create_runtime`] but takes the bytes of a precompiled artifact,
/// which makes this function considerably faster than [`create_runtime`],
/// but slower than the more optimized [`create_runtime_from_artifact`].
/// This is especially slow on non-Linux Unix systems. Useful in very niche cases.
///
/// # Safety
///
/// The caller must ensure that the compiled artifact passed here was:
/// 1) produced by [`prepare_runtime_artifact`],
/// 2) was not modified,
///
/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
///
/// It is ok though if the compiled artifact was created by code of another version or with
/// different configuration flags. In such case the caller will receive an `Err` deterministically.
pub unsafe fn create_runtime_from_artifact_bytes<H>(
compiled_artifact_bytes: &[u8],
config: Config,
) -> std::result::Result<WasmtimeRuntime, WasmError>
where
H: HostFunctions,
{
do_create_runtime::<H>(CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes), config)
}
/// # Safety
///
/// This is only unsafe if called with [`CodeSupplyMode::Artifact`]. See
@@ -663,6 +694,22 @@ where
(module, InternalInstantiationStrategy::Builtin)
},
CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes) => {
if let InstantiationStrategy::LegacyInstanceReuse =
config.semantics.instantiation_strategy
{
return Err(WasmError::Other("the legacy instance reuse instantiation strategy is incompatible with precompiled modules".into()));
}
// SAFETY: The unsafety of `deserialize` is covered by this function. The
// responsibilities to maintain the invariants are passed to the caller.
//
// See [`create_runtime_from_artifact_bytes`] for more details.
let module = wasmtime::Module::deserialize(&engine, compiled_artifact_bytes)
.map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?;
(module, InternalInstantiationStrategy::Builtin)
},
};
let mut linker = wasmtime::Linker::new(&engine);