gear_lazy_pages_native_interface/
lib.rs

1// This file is part of Gear.
2
3// Copyright (C) 2024-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Lazy pages support for native.
20
21use gear_core::{
22    costs::LazyPagesCosts,
23    ids::ProgramId,
24    memory::{HostPointer, Memory, MemoryInterval},
25    pages::{GearPage, WasmPage, WasmPagesAmount},
26    program::MemoryInfix,
27};
28use gear_lazy_pages_common::{GlobalsAccessConfig, LazyPagesInterface, ProcessAccessError, Status};
29
30pub struct LazyPagesNative;
31
32impl LazyPagesInterface for LazyPagesNative {
33    fn try_to_enable_lazy_pages(_prefix: [u8; 32]) -> bool {
34        let err_msg = "LazyPagesNative::try_to_enable_lazy_pages: this function should not be called in native";
35
36        log::error!("{err_msg}");
37        unreachable!("{err_msg}")
38    }
39
40    fn init_for_program<Context>(
41        ctx: &mut Context,
42        mem: &mut impl Memory<Context>,
43        program_id: ProgramId,
44        memory_infix: MemoryInfix,
45        stack_end: Option<WasmPage>,
46        globals_config: GlobalsAccessConfig,
47        costs: LazyPagesCosts,
48    ) {
49        let wasm_mem_addr = mem.get_buffer_host_addr(ctx).map(|addr| {
50            usize::try_from(addr).unwrap_or_else(|err| {
51                let err_msg = format!(
52                    "LazyPagesNative::init_for_program: can't convert native address to usize. \
53                    Got error - {err:?}"
54                );
55
56                log::error!("{err_msg}");
57                unreachable!("{err_msg}")
58            })
59        });
60        let wasm_mem_size = mem.size(ctx).into();
61        let program_key = {
62            let memory_infix = memory_infix.inner().to_le_bytes();
63            [program_id.as_ref(), memory_infix.as_ref()].concat()
64        };
65        let stack_end = stack_end.map(|page| page.into());
66        let costs = [
67            costs.signal_read,
68            costs.signal_write,
69            costs.signal_write_after_read,
70            costs.host_func_read,
71            costs.host_func_write,
72            costs.host_func_write_after_read,
73            costs.load_page_storage_data,
74        ]
75        .map(|w| w.cost_for_one())
76        .to_vec();
77
78        gear_lazy_pages::initialize_for_program(
79            wasm_mem_addr,
80            wasm_mem_size,
81            stack_end,
82            program_key,
83            Some(globals_config),
84            costs,
85        )
86        .unwrap_or_else(|err| {
87            let err_msg = format!(
88                "LazyPagesNative::init_for_program: can't initialize lazy pages for program. \
89                Program id - {program_id:?}, memory infix - {memory_infix:?}. Got error - {err:?}"
90            );
91
92            log::error!("{err_msg}");
93            unreachable!("{err_msg}")
94        });
95    }
96
97    fn remove_lazy_pages_prot<Context>(_ctx: &mut Context, _mem: &mut impl Memory<Context>) {
98        gear_lazy_pages::unset_lazy_pages_protection().unwrap_or_else(|err| {
99            let err_msg = format!(
100                "LazyPagesNative::remove_lazy_pages_prot: can't unset lazy pages protection. \
101                    Got error - {err:?}"
102            );
103
104            log::error!("{err_msg}");
105            unreachable!("{err_msg}")
106        });
107    }
108
109    fn update_lazy_pages_and_protect_again<Context>(
110        ctx: &mut Context,
111        mem: &mut impl Memory<Context>,
112        _old_mem_addr: Option<HostPointer>,
113        _old_mem_size: WasmPagesAmount,
114        _new_mem_addr: HostPointer,
115    ) {
116        let addr = mem.get_buffer_host_addr(ctx).map(|addr| {
117            usize::try_from(addr).unwrap_or_else(|err| {
118                let err_msg = format!(
119                    "LazyPagesNative::update_lazy_pages_and_protect_again: can't convert native address to usize. \
120                        Got error - {err:?}"
121                );
122
123                log::error!("{err_msg}");
124                unreachable!("{err_msg}")
125            })
126        });
127        let size: u32 = mem.size(ctx).into();
128        gear_lazy_pages::change_wasm_mem_addr_and_size(addr, Some(size))
129            .unwrap_or_else(|err| {
130                let err_msg = format!(
131                    "LazyPagesNative::update_lazy_pages_and_protect_again: can't change wasm memory address and size. \
132                        Got error - {err:?}"
133                );
134
135                log::error!("{err_msg}");
136                unreachable!("{err_msg}")
137            });
138        gear_lazy_pages::set_lazy_pages_protection()
139            .unwrap_or_else(|err| {
140                let err_msg = format!(
141                    "LazyPagesNative::update_lazy_pages_and_protect_again: can't set lazy pages protection. \
142                        Got error - {err:?}"
143                );
144
145                log::error!("{err_msg}");
146                unreachable!("{err_msg}")
147        });
148    }
149
150    fn get_write_accessed_pages() -> Vec<GearPage> {
151        gear_lazy_pages::write_accessed_pages()
152            .unwrap_or_else(|err| {
153                let err_msg = format!(
154                    "LazyPagesNative::get_write_accessed_pages: can't get write accessed pages. \
155                        Got error - {err:?}"
156                );
157
158                log::error!("{err_msg}");
159                unreachable!("{err_msg}")
160            })
161            .into_iter()
162            .map(|p| {
163                GearPage::try_from(p)
164                    .unwrap_or_else(|err| {
165                        let err_msg = format!(
166                            "LazyPagesNative::get_write_accessed_pages: incorrect accessed page number. \
167                                Got error - {err:?}"
168                        );
169
170                        log::error!("{err_msg}");
171                        unreachable!("{err_msg}")
172                    })
173            })
174            .collect()
175    }
176
177    fn get_status() -> Status {
178        gear_lazy_pages::status().unwrap_or_else(|err| {
179            let err_msg = format!(
180                "LazyPagesNative::get_status: can't get lazy pages status. \
181                        Got error - {err:?}"
182            );
183
184            log::error!("{err_msg}");
185            unreachable!("{err_msg}")
186        })
187    }
188
189    fn pre_process_memory_accesses(
190        reads: &[MemoryInterval],
191        writes: &[MemoryInterval],
192        gas_counter: &mut u64,
193    ) -> Result<(), ProcessAccessError> {
194        gear_lazy_pages::pre_process_memory_accesses(reads, writes, gas_counter)
195    }
196}