Skip to content

Commit c01f506

Browse files
mrcnskinathanwhit
authored andcommitted
Executor: Add create_runtime_from_artifact_bytes (paritytech#14184)
1 parent 2a73694 commit c01f506

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

client/executor/benches/bench.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,19 @@ fn bench_call_instance(c: &mut Criterion) {
188188
},
189189
),
190190
(
191-
"pooling_vanilla",
191+
"pooling_vanilla_fresh",
192192
Method::Compiled {
193193
instantiation_strategy: InstantiationStrategy::Pooling,
194194
precompile: false,
195195
},
196196
),
197+
(
198+
"pooling_vanilla_precompiled",
199+
Method::Compiled {
200+
instantiation_strategy: InstantiationStrategy::Pooling,
201+
precompile: true,
202+
},
203+
),
197204
(
198205
"pooling_cow_fresh",
199206
Method::Compiled {

client/executor/wasmtime/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ mod util;
3737
mod tests;
3838

3939
pub use runtime::{
40-
create_runtime, create_runtime_from_artifact, prepare_runtime_artifact, Config,
41-
DeterministicStackLimit, InstantiationStrategy, Semantics,
40+
create_runtime, create_runtime_from_artifact, create_runtime_from_artifact_bytes,
41+
prepare_runtime_artifact, Config, DeterministicStackLimit, InstantiationStrategy, Semantics,
42+
WasmtimeRuntime,
4243
};

client/executor/wasmtime/src/runtime.rs

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ pub struct DeterministicStackLimit {
435435
/// All of the CoW strategies (with `CopyOnWrite` suffix) are only supported when either:
436436
/// a) we're running on Linux,
437437
/// b) we're running on an Unix-like system and we're precompiling
438-
/// our module beforehand.
438+
/// our module beforehand and instantiating from a file.
439439
///
440440
/// If the CoW variant of a strategy is unsupported the executor will
441441
/// fall back to the non-CoW equivalent.
@@ -537,14 +537,20 @@ enum CodeSupplyMode<'a> {
537537
/// The runtime is instantiated using the given runtime blob.
538538
Fresh(RuntimeBlob),
539539

540-
/// The runtime is instantiated using a precompiled module.
540+
/// The runtime is instantiated using a precompiled module at the given path.
541541
///
542542
/// This assumes that the code is already prepared for execution and the same `Config` was
543543
/// used.
544544
///
545545
/// We use a `Path` here instead of simply passing a byte slice to allow `wasmtime` to
546546
/// map the runtime's linear memory on supported platforms in a copy-on-write fashion.
547547
Precompiled(&'a Path),
548+
549+
/// The runtime is instantiated using a precompiled module with the given bytes.
550+
///
551+
/// This assumes that the code is already prepared for execution and the same `Config` was
552+
/// used.
553+
PrecompiledBytes(&'a [u8]),
548554
}
549555

550556
/// Create a new `WasmtimeRuntime` given the code. This function performs translation from Wasm to
@@ -589,6 +595,31 @@ where
589595
do_create_runtime::<H>(CodeSupplyMode::Precompiled(compiled_artifact_path), config)
590596
}
591597

598+
/// The same as [`create_runtime`] but takes the bytes of a precompiled artifact,
599+
/// which makes this function considerably faster than [`create_runtime`],
600+
/// but slower than the more optimized [`create_runtime_from_artifact`].
601+
/// This is especially slow on non-Linux Unix systems. Useful in very niche cases.
602+
///
603+
/// # Safety
604+
///
605+
/// The caller must ensure that the compiled artifact passed here was:
606+
/// 1) produced by [`prepare_runtime_artifact`],
607+
/// 2) was not modified,
608+
///
609+
/// Failure to adhere to these requirements might lead to crashes and arbitrary code execution.
610+
///
611+
/// It is ok though if the compiled artifact was created by code of another version or with
612+
/// different configuration flags. In such case the caller will receive an `Err` deterministically.
613+
pub unsafe fn create_runtime_from_artifact_bytes<H>(
614+
compiled_artifact_bytes: &[u8],
615+
config: Config,
616+
) -> std::result::Result<WasmtimeRuntime, WasmError>
617+
where
618+
H: HostFunctions,
619+
{
620+
do_create_runtime::<H>(CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes), config)
621+
}
622+
592623
/// # Safety
593624
///
594625
/// This is only unsafe if called with [`CodeSupplyMode::Artifact`]. See
@@ -663,6 +694,22 @@ where
663694

664695
(module, InternalInstantiationStrategy::Builtin)
665696
},
697+
CodeSupplyMode::PrecompiledBytes(compiled_artifact_bytes) => {
698+
if let InstantiationStrategy::LegacyInstanceReuse =
699+
config.semantics.instantiation_strategy
700+
{
701+
return Err(WasmError::Other("the legacy instance reuse instantiation strategy is incompatible with precompiled modules".into()));
702+
}
703+
704+
// SAFETY: The unsafety of `deserialize` is covered by this function. The
705+
// responsibilities to maintain the invariants are passed to the caller.
706+
//
707+
// See [`create_runtime_from_artifact_bytes`] for more details.
708+
let module = wasmtime::Module::deserialize(&engine, compiled_artifact_bytes)
709+
.map_err(|e| WasmError::Other(format!("cannot deserialize module: {:#}", e)))?;
710+
711+
(module, InternalInstantiationStrategy::Builtin)
712+
},
666713
};
667714

668715
let mut linker = wasmtime::Linker::new(&engine);

0 commit comments

Comments
 (0)