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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
/* * garbage-collected memory manager in Rust * Copyright (C) 2020 Xie Ruifeng * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ //! Common memory-related utilities. use core::ptr; use core::mem; use core::marker; use core::fmt; /// Memory address with a valid lifetime. /// /// We need this because raw pointers does not have a lifetime attached. Note that an `Address` /// can be constructed from a raw pointer, and the lifetime attached is ARBITRARY, so it is on the /// caller to guarantee the correct lifetime is specified. /// /// # Construct from raw pointer /// /// ``` /// use memory_manager::common::Address; /// let raw_p = 0xDEAD_BEEF as *mut (); /// let addr = Address::from(raw_p); /// ``` /// /// # Debug format /// /// ``` /// # use memory_manager::common::Address; /// # let raw_p = 0xDEAD_BEEF as *mut (); /// # let addr = Address::from(raw_p); /// assert_eq!(format!("{:?}", addr), "Address(0xdeadbeef)"); /// ``` #[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone)] pub struct Address<'a> { address: *mut u8, phantom: marker::PhantomData<&'a ()>, } impl<'a> fmt::Debug for Address<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Address").field(&self.address).finish() } } impl<'a, T> From<*mut T> for Address<'a> { fn from(address: *mut T) -> Self { Address { address: address as *mut u8, phantom: marker::PhantomData } } } impl<'a> Address<'a> { /// Convert an `Address` to a raw pointer of some type `T`. /// /// Note that raw pointers do not have lifetime attached, so the lifetime is dropped after /// converting to a raw pointer. This should not give rise to any unsafety, as long as the /// `Address` was constructed correctly. /// /// # Panics /// /// This function `assert!` that the memory address is properly aligned for `T`. /// See also [`assert_aligned`](fn.assert_aligned.html). /// /// The following use would panic: /// /// ```should_panic /// use memory_manager::common::Address; /// let addr = Address::from(0xDEAD_BEEF as *mut ()); /// let raw_p = addr.as_ptr::<usize>(); /// ``` pub fn as_ptr<T>(&self) -> *mut T { assert_aligned(self.address) } /// Add an offset to an `Address`. /// /// This method is analogous to `*mut T::offset`. /// /// ``` /// use memory_manager::common::Address; /// let addr = Address::from(0x1000 as *mut ()); /// assert_eq!(unsafe { addr.offset(4isize) }, Address::from(0x1004 as *mut ())); /// ``` pub unsafe fn offset(&self, count: isize) -> Self { Address::from(self.address.offset(count)) } } /// Assert that some memory is properly aligned. /// /// Given an [`Address`](struct.Address.html), check the alignment, coerce the pointer to `*mut T`. /// /// # Panics /// /// Panics if input is NOT properly aligned for `T`. /// /// The following use would panic: /// /// ```should_panic /// use memory_manager::common::assert_aligned; /// let raw_p = assert_aligned::<usize>(0xDEAD_BEEF as *mut u8); /// ``` pub fn assert_aligned<T>(mem: *mut u8) -> *mut T { assert_eq!(mem as usize % mem::align_of::<T>(), 0); mem as *mut T } /// Consumes a memory chunk as a slice. /// /// Construct a slice with a given length from the current [`Address`](struct.Address.html), /// then advance it. /// /// ``` /// use memory_manager::common::{consume_as_slice, Address}; /// let mut addr = Address::from(0x1000 as *mut u8); /// let _ = unsafe { consume_as_slice::<usize>(&mut addr, 20) }; /// assert_eq!( /// addr, /// unsafe { /// Address::from(0x1000 as *mut u8).offset( /// core::mem::size_of::<usize>() as isize * 20) /// } /// ); /// ``` pub unsafe fn consume_as_slice<'a, T>(mem: &mut Address<'a>, n: usize) -> &'a mut [T] { let res = ptr::slice_from_raw_parts_mut(mem.as_ptr::<T>(), n); let bytes = mem::size_of::<T>() * n; *mem = mem.offset(bytes as isize); res.as_mut().unwrap() } /// Consumes a memory chunk as a reference. /// /// Construct a reference from the current [`Address`](struct.Address.html), then advance it. /// /// ``` /// use memory_manager::common::{consume_as_ref, Address}; /// let mut addr = Address::from(0x1000 as *mut u8); /// let _ = unsafe { consume_as_ref::<usize>(&mut addr) }; /// assert_eq!( /// addr, /// unsafe { /// Address::from(0x1000 as *mut u8).offset( /// core::mem::size_of::<usize>() as isize) /// } /// ); /// ``` pub unsafe fn consume_as_ref<'a, T>(mem: &mut Address<'a>) -> &'a mut T { let res = mem.as_ptr::<T>(); let bytes = mem::size_of::<T>(); *mem = mem.offset(bytes as isize); res.as_mut().unwrap() } /// size in Bytes pub const B: usize = 1; /// size in Kibibytes, as defined in IEC 60027-2 #[allow(non_upper_case_globals)] pub const KiB: usize = 1024 * B; /// size in Mebibytes, as defined in IEC 60027-2 #[allow(non_upper_case_globals)] pub const MiB: usize = 1024 * KiB; /// size in Gibibytes, as defined in IEC 60027-2 #[allow(non_upper_case_globals)] pub const GiB: usize = 1024 * MiB;