1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// This file is part of Substrate.

// Copyright (C) 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/>.

//! Definitions for a wasm runtime.

use crate::error::Error;
use sp_wasm_interface::Value;

pub use sc_allocator::AllocationStats;

/// Default heap allocation strategy.
pub const DEFAULT_HEAP_ALLOC_STRATEGY: HeapAllocStrategy =
	HeapAllocStrategy::Static { extra_pages: DEFAULT_HEAP_ALLOC_PAGES };

/// Default heap allocation pages.
pub const DEFAULT_HEAP_ALLOC_PAGES: u32 = 2048;

/// A method to be used to find the entrypoint when calling into the runtime
///
/// Contains variants on how to resolve wasm function that will be invoked.
pub enum InvokeMethod<'a> {
	/// Call function exported with this name.
	///
	/// Located function should have (u32, u32) -> u64 signature.
	Export(&'a str),
	/// Call a function found in the exported table found under the given index.
	///
	/// Located function should have (u32, u32) -> u64 signature.
	Table(u32),
	/// Call function by reference from table through a wrapper.
	///
	/// Invoked function (`dispatcher_ref`) function
	/// should have (u32, u32, u32) -> u64 signature.
	///
	/// `func` will be passed to the invoked function as a first argument.
	TableWithWrapper {
		/// Wrapper for the call.
		///
		/// Function pointer, index into runtime exported table.
		dispatcher_ref: u32,
		/// Extra argument for dispatch.
		///
		/// Common usage would be to use it as an actual wasm function pointer
		/// that should be invoked, but can be used as any extra argument on the
		/// callee side.
		///
		/// This is typically generated and invoked by the runtime itself.
		func: u32,
	},
}

impl<'a> From<&'a str> for InvokeMethod<'a> {
	fn from(val: &'a str) -> InvokeMethod<'a> {
		InvokeMethod::Export(val)
	}
}

/// A trait that defines an abstract WASM runtime module.
///
/// This can be implemented by an execution engine.
pub trait WasmModule: Sync + Send {
	/// Create a new instance.
	fn new_instance(&self) -> Result<Box<dyn WasmInstance>, Error>;
}

/// A trait that defines an abstract wasm module instance.
///
/// This can be implemented by an execution engine.
pub trait WasmInstance: Send {
	/// Call a method on this WASM instance.
	///
	/// Before execution, instance is reset.
	///
	/// Returns the encoded result on success.
	fn call(&mut self, method: InvokeMethod, data: &[u8]) -> Result<Vec<u8>, Error> {
		self.call_with_allocation_stats(method, data).0
	}

	/// Call a method on this WASM instance.
	///
	/// Before execution, instance is reset.
	///
	/// Returns the encoded result on success.
	fn call_with_allocation_stats(
		&mut self,
		method: InvokeMethod,
		data: &[u8],
	) -> (Result<Vec<u8>, Error>, Option<AllocationStats>);

	/// Call an exported method on this WASM instance.
	///
	/// Before execution, instance is reset.
	///
	/// Returns the encoded result on success.
	fn call_export(&mut self, method: &str, data: &[u8]) -> Result<Vec<u8>, Error> {
		self.call(method.into(), data)
	}

	/// Get the value from a global with the given `name`.
	///
	/// This method is only suitable for getting immutable globals.
	fn get_global_const(&mut self, name: &str) -> Result<Option<Value>, Error>;
}

/// Defines the heap pages allocation strategy the wasm runtime should use.
///
/// A heap page is defined as 64KiB of memory.
#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
pub enum HeapAllocStrategy {
	/// Allocate a static number of heap pages.
	///
	/// The total number of allocated heap pages is the initial number of heap pages requested by
	/// the wasm file plus the `extra_pages`.
	Static {
		/// The number of pages that will be added on top of the initial heap pages requested by
		/// the wasm file.
		extra_pages: u32,
	},
	/// Allocate the initial heap pages as requested by the wasm file and then allow it to grow
	/// dynamically.
	Dynamic {
		/// The absolute maximum size of the linear memory (in pages).
		///
		/// When `Some(_)` the linear memory will be allowed to grow up to this limit.
		/// When `None` the linear memory will be allowed to grow up to the maximum limit supported
		/// by WASM (4GB).
		maximum_pages: Option<u32>,
	},
}