polkavm_derive/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3
4pub use polkavm_derive_impl_macro::__PRIVATE_DO_NOT_USE_polkavm_define_abi as polkavm_define_abi;
5pub use polkavm_derive_impl_macro::__PRIVATE_DO_NOT_USE_polkavm_export as polkavm_export;
6pub use polkavm_derive_impl_macro::__PRIVATE_DO_NOT_USE_polkavm_import as polkavm_import;
7
8pub mod default_abi {
9    polkavm_derive_impl_macro::__PRIVATE_DO_NOT_USE_polkavm_impl_abi_support!();
10}
11
12/// Increases the size of the program's heap by a given number of bytes, allocating memory if necessary.
13/// If successful returns a pointer to the *end* of the heap. If unsuccessful returns a null pointer.
14///
15/// When called with a `size` of 0 this can be used to find the current end of the heap. This will always succeed.
16///
17/// Memory allocated through this function can only be freed once the program finishes execution and its whole memory is cleared.
18#[cfg(any(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"), doc))]
19#[inline]
20pub fn sbrk(size: usize) -> *mut u8 {
21    // SAFETY: Allocating memory is always safe.
22    unsafe {
23        let address;
24        core::arch::asm!(
25            ".insn r 0xb, 1, 0, {dst}, {size}, zero",
26            size = in(reg) size,
27            dst = lateout(reg) address,
28        );
29        address
30    }
31}
32
33/// A hardware accelerated memset.
34#[inline]
35#[allow(unused_assignments)]
36#[allow(unused_mut)]
37#[allow(clippy::missing_safety_doc)]
38#[allow(clippy::undocumented_unsafe_blocks)]
39pub unsafe fn memset(mut dst: *mut u8, value: usize, mut count: usize) {
40    #[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"))]
41    unsafe {
42        core::arch::asm!(
43            ".insn r 0xb, 2, 0, zero, zero, zero",
44            inout("a0") dst,
45            in("a1") value,
46            inout("a2") count,
47        );
48    }
49
50    #[cfg(not(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e")))]
51    unsafe {
52        core::ptr::write_bytes(dst, value as u8, count);
53    }
54}
55
56#[inline]
57pub fn heap_base() -> *mut core::ffi::c_void {
58    #[cfg(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"))]
59    unsafe {
60        let mut output;
61        core::arch::asm!(
62            ".insn r 0xb, 3, 0, {dst}, zero, zero",
63            dst = out(reg) output,
64        );
65        output
66    }
67
68    #[cfg(not(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e")))]
69    {
70        core::ptr::null_mut()
71    }
72}
73
74/// A basic memory allocator which doesn't support deallocation.
75pub struct LeakingAllocator;
76
77#[cfg(any(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"), doc))]
78unsafe impl core::alloc::GlobalAlloc for LeakingAllocator {
79    #[inline]
80    unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
81        let pointer = crate::sbrk(0);
82        let padding = (-(pointer as isize)) as usize & (layout.align() - 1);
83        let size = layout.size().wrapping_add(padding);
84        if crate::sbrk(size).is_null() {
85            return core::ptr::null_mut();
86        }
87
88        pointer.add(padding)
89    }
90
91    #[inline]
92    unsafe fn dealloc(&self, _ptr: *mut u8, _layout: core::alloc::Layout) {}
93}
94
95/// Sets the minimum stack size.
96#[cfg(any(all(any(target_arch = "riscv32", target_arch = "riscv64"), target_feature = "e"), doc))]
97#[macro_export]
98macro_rules! min_stack_size {
99    ($size:expr) => {
100        ::core::arch::global_asm!(
101            ".pushsection .polkavm_min_stack_size,\"R\",@note\n",
102            ".4byte {size}",
103            ".popsection\n",
104            size = const $size,
105        );
106    }
107}
108
109#[cfg(target_pointer_width = "32")]
110#[cfg(any(all(target_arch = "riscv32", target_feature = "e"), doc))]
111#[no_mangle]
112pub unsafe extern "C" fn __atomic_fetch_add_8(address: *mut u64, value: u64) -> u64 {
113    unsafe {
114        let old_value = *address;
115        *address += value;
116        old_value
117    }
118}