gp_wasm_interface/
util.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use super::*;
19use wasmtime::{AsContext, AsContextMut};
20pub use sp_wasm_interface_common::util::checked_range;
21
22pub fn write_memory_from(
23    mut ctx: impl AsContextMut<Data = StoreData>,
24    address: Pointer<u8>,
25    data: &[u8],
26) -> Result<()> {
27    let memory = ctx.as_context().data().memory();
28    let memory = memory.data_mut(&mut ctx);
29
30    let range = checked_range(address.into(), data.len(), memory.len())
31        .ok_or_else(|| String::from("memory write is out of bounds"))?;
32    memory[range].copy_from_slice(data);
33    Ok(())
34}
35
36pub fn read_memory_into(
37    ctx: impl AsContext<Data = StoreData>,
38    address: Pointer<u8>,
39    dest: &mut [u8],
40) -> Result<()> {
41    let memory = ctx.as_context().data().memory().data(&ctx);
42
43    let range = checked_range(address.into(), dest.len(), memory.len())
44        .ok_or_else(|| String::from("memory read is out of bounds"))?;
45    dest.copy_from_slice(&memory[range]);
46    Ok(())
47}
48
49pub fn read_memory(
50    ctx: impl AsContext<Data = StoreData>,
51    address: Pointer<u8>,
52    size: WordSize,
53) -> Result<Vec<u8>> {
54    let mut vec = vec![0; size as usize];
55    read_memory_into(ctx, address, &mut vec)?;
56    Ok(vec)
57}
58
59#[track_caller]
60fn host_state_mut<'a>(caller: &'a mut Caller<'_, StoreData>) -> &'a mut HostState {
61    caller
62        .data_mut()
63        .host_state_mut()
64        .expect("host state is not empty when calling a function in wasm; qed")
65}
66
67pub fn allocate_memory(caller: &mut Caller<'_, StoreData>, size: WordSize) -> Result<Pointer<u8>> {
68    let mut allocator = host_state_mut(caller)
69        .allocator
70        .take()
71        .expect("allocator is not empty when calling a function in wasm; qed");
72
73    let memory = caller.data().memory();
74    // We can not return on error early, as we need to store back allocator.
75    let res = allocator
76        .allocate(&mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), size)
77        .map_err(|e| e.to_string());
78
79    host_state_mut(caller).allocator = Some(allocator);
80
81    res
82}
83
84pub fn deallocate_memory(caller: &mut Caller<'_, StoreData>, ptr: Pointer<u8>) -> Result<()> {
85    let mut allocator = host_state_mut(caller)
86        .allocator
87        .take()
88        .expect("allocator is not empty when calling a function in wasm; qed");
89
90    let memory = caller.data().memory();
91
92    // We can not return on error early, as we need to store back allocator.
93    let res = allocator
94        .deallocate(&mut MemoryWrapper::from((&memory, &mut caller.as_context_mut())), ptr)
95        .map_err(|e| e.to_string());
96
97    host_state_mut(caller).allocator = Some(allocator);
98
99    res
100}