forked from paritytech/substrate
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Opt-out from fast instance reuse and foundation for other refactorings (
paritytech#8394) * Establish the runtime_blob module Seed it with the existing contents of the `util` module. * Port wasmtime mutable globals instrumentation into runtime blob APIs * Opt-out from fast instance reuse * Minor clean up * Spaces * Docs clean up * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Factor out the expects * Fix the suggestion Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
- Loading branch information
1 parent
51aafa7
commit 3304e6b
Showing
15 changed files
with
596 additions
and
289 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,5 +23,5 @@ | |
|
||
pub mod error; | ||
pub mod sandbox; | ||
pub mod util; | ||
pub mod wasm_runtime; | ||
pub mod runtime_blob; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
client/executor/common/src/runtime_blob/globals_snapshot.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// This file is part of Substrate. | ||
|
||
// Copyright (C) 2020-2021 Parity Technologies (UK) Ltd. | ||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
|
||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
|
||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
use super::RuntimeBlob; | ||
|
||
/// Saved value of particular exported global. | ||
struct SavedValue<Global> { | ||
/// The handle of this global which can be used to refer to this global. | ||
handle: Global, | ||
/// The global value that was observed during the snapshot creation. | ||
value: sp_wasm_interface::Value, | ||
} | ||
|
||
/// An adapter for a wasm module instance that is focused on getting and setting globals. | ||
pub trait InstanceGlobals { | ||
/// A handle to a global which can be used to get or set a global variable. This is supposed to | ||
/// be a lightweight handle, like an index or an Rc-like smart-pointer, which is cheap to clone. | ||
type Global: Clone; | ||
/// Get a handle to a global by it's export name. | ||
/// | ||
/// The requested export is must exist in the exported list, and it should be a mutable global. | ||
fn get_global(&self, export_name: &str) -> Self::Global; | ||
/// Get the current value of the global. | ||
fn get_global_value(&self, global: &Self::Global) -> sp_wasm_interface::Value; | ||
/// Update the current value of the global. | ||
/// | ||
/// The global behind the handle is guaranteed to be mutable and the value to be the same type | ||
/// as the global. | ||
fn set_global_value(&self, global: &Self::Global, value: sp_wasm_interface::Value); | ||
} | ||
|
||
/// A set of exposed mutable globals. | ||
/// | ||
/// This is set of globals required to create a [`GlobalsSnapshot`] and that are collected from | ||
/// a runtime blob that was instrumented by [`InstrumentModule::expose_mutable_globals`]. | ||
/// | ||
/// If the code wasn't instrumented then it would be empty and snapshot would do nothing. | ||
pub struct ExposedMutableGlobalsSet(Vec<String>); | ||
|
||
impl ExposedMutableGlobalsSet { | ||
/// Collect the set from the given runtime blob. See the struct documentation for details. | ||
pub fn collect(runtime_blob: &RuntimeBlob) -> Self { | ||
let global_names = runtime_blob | ||
.exported_internal_global_names() | ||
.map(ToOwned::to_owned) | ||
.collect(); | ||
Self(global_names) | ||
} | ||
} | ||
|
||
/// A snapshot of a global variables values. This snapshot can be later used for restoring the | ||
/// values to the preserved state. | ||
/// | ||
/// Technically, a snapshot stores only values of mutable global variables. This is because | ||
/// immutable global variables always have the same values. | ||
/// | ||
/// We take it from an instance rather from a module because the start function could potentially | ||
/// change any of the mutable global values. | ||
pub struct GlobalsSnapshot<Global>(Vec<SavedValue<Global>>); | ||
|
||
impl<Global> GlobalsSnapshot<Global> { | ||
/// Take a snapshot of global variables for a given instance. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This function panics if the instance doesn't correspond to the module from which the | ||
/// [`ExposedMutableGlobalsSet`] was collected. | ||
pub fn take<Instance>(mutable_globals: &ExposedMutableGlobalsSet, instance: &Instance) -> Self | ||
where | ||
Instance: InstanceGlobals<Global = Global>, | ||
{ | ||
let global_names = &mutable_globals.0; | ||
let mut saved_values = Vec::with_capacity(global_names.len()); | ||
|
||
for global_name in global_names { | ||
let handle = instance.get_global(global_name); | ||
let value = instance.get_global_value(&handle); | ||
saved_values.push(SavedValue { handle, value }); | ||
} | ||
|
||
Self(saved_values) | ||
} | ||
|
||
/// Apply the snapshot to the given instance. | ||
/// | ||
/// This instance must be the same that was used for creation of this snapshot. | ||
pub fn apply<Instance>(&self, instance: &Instance) | ||
where | ||
Instance: InstanceGlobals<Global = Global>, | ||
{ | ||
for saved_value in &self.0 { | ||
instance.set_global_value(&saved_value.handle, saved_value.value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// This file is part of Substrate. | ||
|
||
// Copyright (C) 2021 Parity Technologies (UK) Ltd. | ||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
|
||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
|
||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
//! This module allows for inspection and instrumentation, i.e. modifying the module to alter it's | ||
//! structure or behavior, of a wasm module. | ||
//! | ||
//! ## Instrumentation | ||
//! | ||
//! In ideal world, there would be no instrumentation. However, in the real world the execution | ||
//! engines we use are somewhat limited in their APIs or abilities. | ||
//! | ||
//! To give you some examples: | ||
//! | ||
//! - wasmi allows reaching to non-exported mutable globals so that we could reset them. | ||
//! Wasmtime doesn’t support that. | ||
//! | ||
//! We need to reset the globals because when we | ||
//! execute the Substrate Runtime, we do not drop and create the instance anew, instead | ||
//! we restore some selected parts of the state. | ||
//! | ||
//! - stack depth metering can be performed via instrumentation or deferred to the engine and say | ||
//! be added directly in machine code. Implementing this in machine code is rather cumbersome so | ||
//! instrumentation looks like a good solution. | ||
//! | ||
//! Stack depth metering is needed to make a wasm blob | ||
//! execution deterministic, which in turn is needed by the Parachain Validation Function in Polkadot. | ||
//! | ||
//! ## Inspection | ||
//! | ||
//! Inspection of a wasm module may be needed to extract some useful information, such as to extract | ||
//! data segment snapshot, which is helpful for quickly restoring the initial state of instances. | ||
//! Inspection can be also useful to prove that a wasm module possesses some properties, such as, | ||
//! is free of any floating point operations, which is a useful step towards making instances produced | ||
//! from such a module deterministic. | ||
mod data_segments_snapshot; | ||
mod globals_snapshot; | ||
mod runtime_blob; | ||
|
||
pub use data_segments_snapshot::DataSegmentsSnapshot; | ||
pub use globals_snapshot::{GlobalsSnapshot, ExposedMutableGlobalsSet, InstanceGlobals}; | ||
pub use runtime_blob::RuntimeBlob; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// This file is part of Substrate. | ||
|
||
// Copyright (C) 2021 Parity Technologies (UK) Ltd. | ||
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 | ||
|
||
// This program is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
|
||
// This program is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
|
||
// You should have received a copy of the GNU General Public License | ||
// along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
use parity_wasm::elements::{DataSegment, Module as RawModule, deserialize_buffer, serialize}; | ||
|
||
use crate::error::WasmError; | ||
|
||
/// A bunch of information collected from a WebAssembly module. | ||
#[derive(Clone)] | ||
pub struct RuntimeBlob { | ||
raw_module: RawModule, | ||
} | ||
|
||
impl RuntimeBlob { | ||
/// Create `RuntimeBlob` from the given wasm code. | ||
/// | ||
/// Returns `Err` if the wasm code cannot be deserialized. | ||
pub fn new(wasm_code: &[u8]) -> Result<Self, WasmError> { | ||
let raw_module: RawModule = deserialize_buffer(wasm_code) | ||
.map_err(|e| WasmError::Other(format!("cannot deserialize module: {:?}", e)))?; | ||
Ok(Self { raw_module }) | ||
} | ||
|
||
/// Extract the data segments from the given wasm code. | ||
pub(super) fn data_segments(&self) -> Vec<DataSegment> { | ||
self.raw_module | ||
.data_section() | ||
.map(|ds| ds.entries()) | ||
.unwrap_or(&[]) | ||
.to_vec() | ||
} | ||
|
||
/// The number of globals defined in locally in this module. | ||
pub fn declared_globals_count(&self) -> u32 { | ||
self.raw_module | ||
.global_section() | ||
.map(|gs| gs.entries().len() as u32) | ||
.unwrap_or(0) | ||
} | ||
|
||
/// The number of imports of globals. | ||
pub fn imported_globals_count(&self) -> u32 { | ||
self.raw_module | ||
.import_section() | ||
.map(|is| is.globals() as u32) | ||
.unwrap_or(0) | ||
} | ||
|
||
/// Perform an instrumentation that makes sure that the mutable globals are exported. | ||
pub fn expose_mutable_globals(&mut self) { | ||
pwasm_utils::export_mutable_globals(&mut self.raw_module, "exported_internal_global"); | ||
} | ||
|
||
/// Returns an iterator of all globals which were exported by [`expose_mutable_globals`]. | ||
pub(super) fn exported_internal_global_names<'module>( | ||
&'module self, | ||
) -> impl Iterator<Item = &'module str> { | ||
let exports = self | ||
.raw_module | ||
.export_section() | ||
.map(|es| es.entries()) | ||
.unwrap_or(&[]); | ||
exports.iter().filter_map(|export| match export.internal() { | ||
parity_wasm::elements::Internal::Global(_) | ||
if export.field().starts_with("exported_internal_global") => | ||
{ | ||
Some(export.field()) | ||
} | ||
_ => None, | ||
}) | ||
} | ||
|
||
/// Consumes this runtime blob and serializes it. | ||
pub fn serialize(self) -> Vec<u8> { | ||
serialize(self.raw_module) | ||
.expect("serializing into a vec should succeed; qed") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.