Better wasm instance cache (#5109)

* Wasm instance cache

* Reduce slot locking

* Fixed test

* Dispose of instance in case of error

* Fixed benches

* Style, comments, some renames

* Replaced upgradable lock with mutex

* Bump dependencies

* Re-export CallInWasm

* Update client/executor/src/wasm_runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/native_executor.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/native_executor.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/wasm_runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/wasmtime/src/runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/wasm_runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/wasm_runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Update client/executor/src/wasm_runtime.rs

Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com>

* Indents

* Whitespace

* Formatting

* Added issue link

Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
Co-authored-by: Gavin Wood <github@gavwood.com>
Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Benjamin Kampmann
2020-03-05 14:02:04 +01:00
committed by GitHub
parent 40b243f1c8
commit d3208aa7bc
19 changed files with 730 additions and 609 deletions
@@ -21,7 +21,7 @@ use hex_literal::hex;
use sp_core::{
blake2_128, blake2_256, ed25519, sr25519, map, Pair,
offchain::{OffchainExt, testing},
traits::Externalities,
traits::{Externalities, CallInWasm},
};
use sc_runtime_test::WASM_BINARY;
use sp_state_machine::TestExternalities as CoreTestExternalities;
@@ -40,15 +40,18 @@ fn call_in_wasm<E: Externalities>(
call_data: &[u8],
execution_method: WasmExecutionMethod,
ext: &mut E,
) -> crate::error::Result<Vec<u8>> {
crate::call_in_wasm::<HostFunctions>(
) -> Result<Vec<u8>, String> {
let executor = crate::WasmExecutor::new(
execution_method,
Some(1024),
HostFunctions::host_functions(),
true,
);
executor.call_in_wasm(
&WASM_BINARY[..],
function,
call_data,
execution_method,
ext,
&WASM_BINARY[..],
1024,
true,
)
}
@@ -84,12 +87,12 @@ fn call_not_existing_function(wasm_method: WasmExecutionMethod) {
match wasm_method {
WasmExecutionMethod::Interpreted => assert_eq!(
&format!("{:?}", e),
"Wasmi(Trap(Trap { kind: Host(Other(\"Function `missing_external` is only a stub. Calling a stub is not allowed.\")) }))"
"\"Trap: Trap { kind: Host(Other(\\\"Function `missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\""
),
#[cfg(feature = "wasmtime")]
WasmExecutionMethod::Compiled => assert_eq!(
&format!("{:?}", e),
"Other(\"Wasm execution trapped: call to a missing function env:missing_external\")"
"\"Wasm execution trapped: call to a missing function env:missing_external\""
),
}
}
@@ -113,12 +116,12 @@ fn call_yet_another_not_existing_function(wasm_method: WasmExecutionMethod) {
match wasm_method {
WasmExecutionMethod::Interpreted => assert_eq!(
&format!("{:?}", e),
"Wasmi(Trap(Trap { kind: Host(Other(\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\")) }))"
"\"Trap: Trap { kind: Host(Other(\\\"Function `yet_another_missing_external` is only a stub. Calling a stub is not allowed.\\\")) }\""
),
#[cfg(feature = "wasmtime")]
WasmExecutionMethod::Compiled => assert_eq!(
&format!("{:?}", e),
"Other(\"Wasm execution trapped: call to a missing function env:yet_another_missing_external\")"
"\"Wasm execution trapped: call to a missing function env:yet_another_missing_external\""
),
}
}
@@ -502,29 +505,32 @@ fn offchain_http_should_work(wasm_method: WasmExecutionMethod) {
fn should_trap_when_heap_exhausted(wasm_method: WasmExecutionMethod) {
let mut ext = TestExternalities::default();
crate::call_in_wasm::<HostFunctions>(
let executor = crate::WasmExecutor::new(
wasm_method,
Some(17), // `17` is the initial number of pages compiled into the binary.
HostFunctions::host_functions(),
true,
);
executor.call_in_wasm(
&WASM_BINARY[..],
"test_exhaust_heap",
&[0],
wasm_method,
&mut ext.ext(),
&WASM_BINARY[..],
// `17` is the initial number of pages compiled into the binary.
17,
true,
).unwrap();
}
#[test_case(WasmExecutionMethod::Interpreted)]
#[cfg_attr(feature = "wasmtime", test_case(WasmExecutionMethod::Compiled))]
fn returns_mutable_static(wasm_method: WasmExecutionMethod) {
let mut instance = crate::wasm_runtime::create_wasm_runtime_with_code(
let runtime = crate::wasm_runtime::create_wasm_runtime_with_code(
wasm_method,
1024,
&WASM_BINARY[..],
HostFunctions::host_functions(),
true,
).expect("Creates instance");
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
let res = instance.call("returns_mutable_static", &[0]).unwrap();
assert_eq!(33, u64::decode(&mut &res[..]).unwrap());
@@ -550,13 +556,14 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) {
// to our allocator algorithm there are inefficiencies.
const REQUIRED_MEMORY_PAGES: u64 = 32;
let mut instance = crate::wasm_runtime::create_wasm_runtime_with_code(
let runtime = crate::wasm_runtime::create_wasm_runtime_with_code(
wasm_method,
REQUIRED_MEMORY_PAGES,
&WASM_BINARY[..],
HostFunctions::host_functions(),
true,
).expect("Creates instance");
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
// On the first invocation we allocate approx. 768KB (75%) of stack and then trap.
let res = instance.call("allocates_huge_stack_array", &true.encode());
@@ -569,15 +576,16 @@ fn restoration_of_globals(wasm_method: WasmExecutionMethod) {
#[test_case(WasmExecutionMethod::Interpreted)]
fn heap_is_reset_between_calls(wasm_method: WasmExecutionMethod) {
let mut instance = crate::wasm_runtime::create_wasm_runtime_with_code(
let runtime = crate::wasm_runtime::create_wasm_runtime_with_code(
wasm_method,
1024,
&WASM_BINARY[..],
HostFunctions::host_functions(),
true,
).expect("Creates instance");
).expect("Creates runtime");
let instance = runtime.new_instance().unwrap();
let heap_base = instance.get_global_val("__heap_base")
let heap_base = instance.get_global_const("__heap_base")
.expect("`__heap_base` is valid")
.expect("`__heap_base` exists")
.as_i32()