#[cfg(any(
all(test, feature = "check_contracts_in_tests"),
feature = "check_contracts"
))]
use contracts::*;
#[cfg(not(any(
all(test, feature = "check_contracts_in_tests"),
feature = "check_contracts"
)))]
use disabled_contracts::*;
use std::ffi::c_void;
use std::ptr::NonNull;
#[cfg(any(
all(test, feature = "check_contracts_in_tests"),
feature = "check_contracts"
))]
use crate::debug_allocation_map;
#[cfg(any(
all(test, feature = "check_contracts_in_tests"),
feature = "check_contracts"
))]
use crate::debug_type_map;
#[cfg(any(
all(test, feature = "check_contracts_in_tests"),
feature = "check_contracts"
))]
use crate::press;
use crate::cache;
use crate::class::Class;
use crate::class::ClassInfo;
use crate::linear_ref::LinearRef;
use crate::magazine::LocalMagazineCache;
impl Class {
#[ensures(ret.is_some() ->
debug_allocation_map::mark_allocated(self, ret.as_ref().unwrap()).is_ok(),
"Successful allocations match the class and avoid double-allocation.")]
#[ensures(ret.is_some() -> debug_type_map::ptr_is_class(self, ret.as_ref().unwrap()).is_ok(),
"Successful allocations come from an address of the correct class.")]
#[ensures(ret.is_some() -> press::check_allocation(self, ret.as_ref().unwrap().as_ptr() as usize).is_ok(),
"Sucessful allocations must have the allocation metadata set correctly.")]
#[inline(always)]
pub fn allocate(self) -> Option<NonNull<c_void>> {
cache::allocate(self).map(|x| x.convert_to_non_null())
}
#[requires(debug_allocation_map::mark_released(self, &block).is_ok(),
"Released blocks must match the class and not double-free.")]
#[requires(debug_type_map::ptr_is_class(self, &block).is_ok(),
"Released blocks come from an address of the correct class.")]
#[inline(always)]
pub fn release(self, block: NonNull<c_void>) {
cache::release(self, LinearRef::new(block));
}
}
impl ClassInfo {
#[ensures(ret.is_some() ->
debug_allocation_map::can_be_allocated(self.id, ret.as_ref().unwrap().get()).is_ok(),
"Successful allocations are fresh, or match the class and avoid double-allocation.")]
#[ensures(ret.is_some() ->
debug_type_map::is_class(self.id, ret.as_ref().unwrap()).is_ok(),
"Successful allocations come from an address of the correct class.")]
#[ensures(ret.is_some() ->
press::check_allocation(self.id, ret.as_ref().unwrap().get().as_ptr() as usize).is_ok(),
"Sucessful allocations must have the allocation metadata set correctly.")]
#[inline(never)]
pub(crate) fn allocate_slow(&self) -> Option<LinearRef> {
let mut empty_cache = LocalMagazineCache::Nothing;
if let Some(mut mag) = self.get_cached_magazine(&mut empty_cache) {
let allocated = mag.get();
assert!(allocated.is_some());
self.release_magazine(mag, None);
allocated
} else {
self.press.allocate_one_object()
}
}
#[requires(debug_allocation_map::has_been_released(self.id, block.get()).is_ok(),
"Slow-released blocks went through `Class::release`.")]
#[requires(debug_type_map::is_class(self.id, &block).is_ok(),
"Released blocks come from an address of the correct class.")]
#[requires(press::check_allocation(self.id, block.get().as_ptr() as usize).is_ok(),
"Deallocated block must have the allocation metadata set correctly.")]
#[inline(never)]
pub(crate) fn release_slow(&self, block: LinearRef) {
let mut empty_cache = LocalMagazineCache::Nothing;
let mut mag = self.allocate_non_full_magazine(&mut empty_cache);
assert_eq!(mag.put(block), None);
self.release_magazine(mag, None);
}
}