use super::header_metadata::HeaderMetadataSpec;
use crate::util::metadata::metadata_val_traits::*;
use crate::util::metadata::side_metadata::SideMetadataSpec;
use crate::util::ObjectReference;
use crate::vm::ObjectModel;
use crate::vm::VMBinding;
use atomic::Ordering;
#[derive(Clone, Copy, Debug)]
pub enum MetadataSpec {
InHeader(HeaderMetadataSpec),
OnSide(SideMetadataSpec),
}
impl MetadataSpec {
pub const fn is_on_side(&self) -> bool {
matches!(self, &MetadataSpec::OnSide(_))
}
pub const fn extract_side_spec(&self) -> &SideMetadataSpec {
match self {
MetadataSpec::OnSide(spec) => spec,
MetadataSpec::InHeader(_) => panic!("Expect a side spec"),
}
}
#[inline(always)]
pub unsafe fn load<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
mask: Option<T>,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => metadata_spec.load(object.to_address::<VM>()),
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::load_metadata::<T>(metadata_spec, object, mask)
}
}
}
#[inline(always)]
pub fn load_atomic<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
mask: Option<T>,
ordering: Ordering,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.load_atomic(object.to_address::<VM>(), ordering)
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::load_metadata_atomic::<T>(metadata_spec, object, mask, ordering)
}
}
}
#[inline(always)]
pub unsafe fn store<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
mask: Option<T>,
) {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.store(object.to_address::<VM>(), val);
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::store_metadata::<T>(metadata_spec, object, val, mask)
}
}
}
#[inline(always)]
pub fn store_atomic<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
mask: Option<T>,
ordering: Ordering,
) {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.store_atomic(object.to_address::<VM>(), val, ordering);
}
MetadataSpec::InHeader(metadata_spec) => VM::VMObjectModel::store_metadata_atomic::<T>(
metadata_spec,
object,
val,
mask,
ordering,
),
}
}
#[inline(always)]
pub fn compare_exchange_metadata<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
old_val: T,
new_val: T,
mask: Option<T>,
success_order: Ordering,
failure_order: Ordering,
) -> std::result::Result<T, T> {
match self {
MetadataSpec::OnSide(metadata_spec) => metadata_spec.compare_exchange_atomic(
object.to_address::<VM>(),
old_val,
new_val,
success_order,
failure_order,
),
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::compare_exchange_metadata::<T>(
metadata_spec,
object,
old_val,
new_val,
mask,
success_order,
failure_order,
)
}
}
}
#[inline(always)]
pub fn fetch_add_metadata<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
order: Ordering,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.fetch_add_atomic(object.to_address::<VM>(), val, order)
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::fetch_add_metadata::<T>(metadata_spec, object, val, order)
}
}
}
#[inline(always)]
pub fn fetch_sub_metadata<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
order: Ordering,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.fetch_sub_atomic(object.to_address::<VM>(), val, order)
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::fetch_sub_metadata::<T>(metadata_spec, object, val, order)
}
}
}
#[inline(always)]
pub fn fetch_and_metadata<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
order: Ordering,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.fetch_and_atomic(object.to_address::<VM>(), val, order)
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::fetch_and_metadata::<T>(metadata_spec, object, val, order)
}
}
}
#[inline(always)]
pub fn fetch_or_metadata<VM: VMBinding, T: MetadataValue>(
&self,
object: ObjectReference,
val: T,
order: Ordering,
) -> T {
match self {
MetadataSpec::OnSide(metadata_spec) => {
metadata_spec.fetch_or_atomic(object.to_address::<VM>(), val, order)
}
MetadataSpec::InHeader(metadata_spec) => {
VM::VMObjectModel::fetch_or_metadata::<T>(metadata_spec, object, val, order)
}
}
}
#[inline(always)]
pub fn fetch_update_metadata<
VM: VMBinding,
T: MetadataValue,
F: FnMut(T) -> Option<T> + Copy,
>(
&self,
object: ObjectReference,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> std::result::Result<T, T> {
match self {
MetadataSpec::OnSide(metadata_spec) => metadata_spec.fetch_update_atomic(
object.to_address::<VM>(),
set_order,
fetch_order,
f,
),
MetadataSpec::InHeader(metadata_spec) => VM::VMObjectModel::fetch_update_metadata(
metadata_spec,
object,
set_order,
fetch_order,
f,
),
}
}
}
pub(crate) fn extract_side_metadata(specs: &[MetadataSpec]) -> Vec<SideMetadataSpec> {
let mut side_specs = vec![];
for spec in specs {
if let MetadataSpec::OnSide(ss) = *spec {
side_specs.push(ss);
}
}
side_specs
}