This repository was archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Opt-out from fast instance reuse and foundation for other refactorings #8394
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
123b710
Establish the runtime_blob module
pepyakin e0e9b11
Port wasmtime mutable globals instrumentation into runtime blob APIs
pepyakin 3d8a804
Opt-out from fast instance reuse
pepyakin 92a96f7
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin 395992c
Minor clean up
pepyakin ca8d2aa
Spaces
pepyakin b361477
Docs clean up
pepyakin 0dff243
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin ca82b7a
Apply suggestions from code review
pepyakin 853c035
Factor out the expects
pepyakin 4a813c9
Fix the suggestion
pepyakin f5a082a
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin 302449f
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin aad4b26
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin ae8091a
Merge remote-tracking branch 'origin/master' into ser-instrument
pepyakin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 hidden or 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 hidden or 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 hidden or 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 hidden or 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. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That file is technically moved, not created, so I left this. |
||
| // 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 hidden or 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 hidden or 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`]. | ||
bkchr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| 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 hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.