mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 16:57:58 +00:00
WASM runtime switch to import memory (#4737)
* WASM runtime switch to import memory Up to now runtimes have exported their memory. To unify it with sandboxing, this pr switches runtimes to import memory as well. From a functional perspective, exporting/importing memory makes no difference to the runtime. To provide backwards compatibility, WASM exported memory is still supported. * Revert debug stuff * Revert some stuff
This commit is contained in:
@@ -255,8 +255,6 @@ cfg_if! {
|
||||
fn use_trie() -> u64;
|
||||
fn benchmark_indirect_call() -> u64;
|
||||
fn benchmark_direct_call() -> u64;
|
||||
fn returns_mutable_static() -> u64;
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8>;
|
||||
fn vec_with_capacity(size: u32) -> Vec<u8>;
|
||||
/// Returns the initialized block number.
|
||||
fn get_block_number() -> u64;
|
||||
@@ -299,8 +297,6 @@ cfg_if! {
|
||||
fn use_trie() -> u64;
|
||||
fn benchmark_indirect_call() -> u64;
|
||||
fn benchmark_direct_call() -> u64;
|
||||
fn returns_mutable_static() -> u64;
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8>;
|
||||
fn vec_with_capacity(size: u32) -> Vec<u8>;
|
||||
/// Returns the initialized block number.
|
||||
fn get_block_number() -> u64;
|
||||
@@ -448,11 +444,6 @@ impl_opaque_keys! {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
/// Mutable static variables should be always observed to have
|
||||
/// the initialized value at the start of a runtime call.
|
||||
static mut MUTABLE_STATIC: u64 = 32;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "std")] {
|
||||
impl_runtime_apis! {
|
||||
@@ -558,14 +549,6 @@ cfg_if! {
|
||||
(0..1000).fold(0, |p, i| p + benchmark_add_one(i))
|
||||
}
|
||||
|
||||
fn returns_mutable_static() -> u64 {
|
||||
unimplemented!("is not expected to be invoked from non-wasm builds");
|
||||
}
|
||||
|
||||
fn allocates_huge_stack_array(_trap: bool) -> Vec<u8> {
|
||||
unimplemented!("is not expected to be invoked from non-wasm builds");
|
||||
}
|
||||
|
||||
fn vec_with_capacity(_size: u32) -> Vec<u8> {
|
||||
unimplemented!("is not expected to be invoked from non-wasm builds");
|
||||
}
|
||||
@@ -753,41 +736,6 @@ cfg_if! {
|
||||
(0..10000).fold(0, |p, i| p + benchmark_add_one(i))
|
||||
}
|
||||
|
||||
fn returns_mutable_static() -> u64 {
|
||||
unsafe {
|
||||
MUTABLE_STATIC += 1;
|
||||
MUTABLE_STATIC
|
||||
}
|
||||
}
|
||||
|
||||
fn allocates_huge_stack_array(trap: bool) -> Vec<u8> {
|
||||
// Allocate a stack frame that is approx. 75% of the stack (assuming it is 1MB).
|
||||
// This will just decrease (stacks in wasm32-u-u grow downwards) the stack
|
||||
// pointer. This won't trap on the current compilers.
|
||||
let mut data = [0u8; 1024 * 768];
|
||||
|
||||
// Then make sure we actually write something to it.
|
||||
//
|
||||
// If:
|
||||
// 1. the stack area is placed at the beginning of the linear memory space, and
|
||||
// 2. the stack pointer points to out-of-bounds area, and
|
||||
// 3. a write is performed around the current stack pointer.
|
||||
//
|
||||
// then a trap should happen.
|
||||
//
|
||||
for (i, v) in data.iter_mut().enumerate() {
|
||||
*v = i as u8; // deliberate truncation
|
||||
}
|
||||
|
||||
if trap {
|
||||
// There is a small chance of this to be pulled up in theory. In practice
|
||||
// the probability of that is rather low.
|
||||
panic!()
|
||||
}
|
||||
|
||||
data.to_vec()
|
||||
}
|
||||
|
||||
fn vec_with_capacity(size: u32) -> Vec<u8> {
|
||||
Vec::with_capacity(size as usize)
|
||||
}
|
||||
@@ -970,54 +918,6 @@ mod tests {
|
||||
use sp_state_machine::ExecutionStrategy;
|
||||
use codec::Encode;
|
||||
|
||||
#[test]
|
||||
fn returns_mutable_static() {
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||
|
||||
let ret = runtime_api.returns_mutable_static(&block_id).unwrap();
|
||||
assert_eq!(ret, 33);
|
||||
|
||||
// We expect that every invocation will need to return the initial
|
||||
// value plus one. If the value increases more than that then it is
|
||||
// a sign that the wasm runtime preserves the memory content.
|
||||
let ret = runtime_api.returns_mutable_static(&block_id).unwrap();
|
||||
assert_eq!(ret, 33);
|
||||
}
|
||||
|
||||
// If we didn't restore the wasm instance properly, on a trap the stack pointer would not be
|
||||
// returned to its initial value and thus the stack space is going to be leaked.
|
||||
//
|
||||
// See https://github.com/paritytech/substrate/issues/2967 for details
|
||||
#[test]
|
||||
fn restoration_of_globals() {
|
||||
// Allocate 32 pages (of 65536 bytes) which gives the runtime 2048KB of heap to operate on
|
||||
// (plus some additional space unused from the initial pages requested by the wasm runtime
|
||||
// module).
|
||||
//
|
||||
// The fixture performs 2 allocations of 768KB and this theoretically gives 1536KB, however, due
|
||||
// to our allocator algorithm there are inefficiencies.
|
||||
const REQUIRED_MEMORY_PAGES: u64 = 32;
|
||||
|
||||
let client = TestClientBuilder::new()
|
||||
.set_execution_strategy(ExecutionStrategy::AlwaysWasm)
|
||||
.set_heap_pages(REQUIRED_MEMORY_PAGES)
|
||||
.build();
|
||||
let runtime_api = client.runtime_api();
|
||||
let block_id = BlockId::Number(client.chain_info().best_number);
|
||||
|
||||
// On the first invocation we allocate approx. 768KB (75%) of stack and then trap.
|
||||
let ret = runtime_api.allocates_huge_stack_array(&block_id, true);
|
||||
assert!(ret.is_err());
|
||||
|
||||
// On the second invocation we allocate yet another 768KB (75%) of stack
|
||||
let ret = runtime_api.allocates_huge_stack_array(&block_id, false);
|
||||
assert!(ret.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn heap_pages_is_respected() {
|
||||
// This tests that the on-chain HEAP_PAGES parameter is respected.
|
||||
|
||||
Reference in New Issue
Block a user