use shape_value::heap_value::{
AtomicData, ChannelData, DequeData, HashSetData, LazyData,
MutexData, PriorityQueueData,
};
use shape_value::kinded_slot::KindedSlot;
use shape_value::ValueSlot;
use std::sync::Arc;
use super::super::stack_kind_code;
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_hashset() -> u64 {
let data = HashSetData::default();
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_hashmap() -> u64 {
use shape_value::heap_value::{HashMapData, HashMapKindedRef};
let inner: Arc<HashMapData<*const shape_value::v2::string_obj::StringObj>> =
Arc::new(HashMapData::new());
let kref = HashMapKindedRef::String(inner);
Arc::into_raw(Arc::new(kref)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_deque() -> u64 {
let data = DequeData::default();
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_priorityqueue() -> u64 {
let data = PriorityQueueData::default();
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_channel() -> u64 {
let data = ChannelData::default();
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_atomic(i: i64) -> u64 {
let data = AtomicData::new(i);
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_lazy(closure_bits: u64) -> u64 {
let closure_slot = ValueSlot::from_raw(closure_bits);
let initializer = KindedSlot::new(
closure_slot,
shape_value::NativeKind::Ptr(shape_value::HeapKind::Closure),
);
let data = LazyData::new(initializer);
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_v2_make_mutex(bits: u64, kind: u8) -> u64 {
let Some(value_kind) = stack_kind_code::decode(kind) else {
tracing::debug!(
target: "shape_jit",
kind,
bits,
"jit_v2_make_mutex SURFACE: kind code is sentinel/unknown. \
ADR-006 \u{a7}2.7.7 #9 \u{2014} producer-site MIR kind \
classification gap. Returning null bits; the inner share is \
leaked rather than dropped with a fabricated Bool kind.",
);
return 0;
};
let value_slot = ValueSlot::from_raw(bits);
let value = KindedSlot::new(value_slot, value_kind);
let data = MutexData::new(value);
Arc::into_raw(Arc::new(data)) as u64
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_hashset_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const HashSetData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_hashset_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const HashSetData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_hashmap_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(
bits as *const shape_value::heap_value::HashMapKindedRef,
);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_hashmap_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(
bits as *const shape_value::heap_value::HashMapKindedRef,
);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_deque_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const DequeData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_deque_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const DequeData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_priorityqueue_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const PriorityQueueData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_priorityqueue_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const PriorityQueueData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_channel_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const ChannelData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_channel_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const ChannelData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_mutex_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const MutexData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_mutex_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const MutexData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_atomic_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const AtomicData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_atomic_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const AtomicData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_lazy_retain(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::increment_strong_count(bits as *const LazyData);
}
}
#[unsafe(no_mangle)]
pub extern "C" fn jit_arc_lazy_release(bits: u64) {
if bits == 0 {
return;
}
unsafe {
Arc::decrement_strong_count(bits as *const LazyData);
}
}
#[cfg(test)]
mod tests {
use super::*;
unsafe fn observe_strong_count<T>(bits: u64) -> usize {
let arc = unsafe { Arc::<T>::from_raw(bits as *const T) };
let count = Arc::strong_count(&arc);
let _ = Arc::into_raw(arc);
count
}
unsafe fn drop_arc<T>(bits: u64) {
if bits != 0 {
let _ = unsafe { Arc::<T>::from_raw(bits as *const T) };
}
}
#[test]
fn hashset_ctor_roundtrip() {
let bits = jit_v2_make_hashset();
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<HashSetData>(bits), 1);
drop_arc::<HashSetData>(bits);
}
}
#[test]
fn hashmap_ctor_roundtrip() {
let bits = jit_v2_make_hashmap();
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<shape_value::heap_value::HashMapKindedRef>(bits), 1);
drop_arc::<shape_value::heap_value::HashMapKindedRef>(bits);
}
}
#[test]
fn deque_ctor_roundtrip() {
let bits = jit_v2_make_deque();
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<DequeData>(bits), 1);
drop_arc::<DequeData>(bits);
}
}
#[test]
fn priorityqueue_ctor_roundtrip() {
let bits = jit_v2_make_priorityqueue();
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<PriorityQueueData>(bits), 1);
drop_arc::<PriorityQueueData>(bits);
}
}
#[test]
fn channel_ctor_roundtrip() {
let bits = jit_v2_make_channel();
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<ChannelData>(bits), 1);
drop_arc::<ChannelData>(bits);
}
}
#[test]
fn atomic_ctor_roundtrip() {
let bits = jit_v2_make_atomic(42);
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<AtomicData>(bits), 1);
let arc = Arc::<AtomicData>::from_raw(bits as *const AtomicData);
assert_eq!(arc.load(), 42);
let _ = Arc::into_raw(arc);
drop_arc::<AtomicData>(bits);
}
}
#[test]
fn lazy_ctor_roundtrip() {
let bits = jit_v2_make_lazy(0);
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<LazyData>(bits), 1);
drop_arc::<LazyData>(bits);
}
}
#[test]
fn mutex_ctor_roundtrip_with_int64_inner() {
let inner_bits = ValueSlot::from_int(42).raw();
let bits = jit_v2_make_mutex(inner_bits, stack_kind_code::C_INT64);
assert_ne!(bits, 0);
unsafe {
assert_eq!(observe_strong_count::<MutexData>(bits), 1);
drop_arc::<MutexData>(bits);
}
}
#[test]
fn mutex_ctor_surfaces_on_sentinel_kind() {
let bits = jit_v2_make_mutex(0, stack_kind_code::SENTINEL);
assert_eq!(bits, 0, "SENTINEL kind ord must surface as null");
}
#[test]
fn hashset_retain_bumps_refcount() {
let bits = jit_v2_make_hashset();
unsafe {
assert_eq!(observe_strong_count::<HashSetData>(bits), 1);
jit_arc_hashset_retain(bits);
assert_eq!(observe_strong_count::<HashSetData>(bits), 2);
drop_arc::<HashSetData>(bits);
drop_arc::<HashSetData>(bits);
}
}
#[test]
fn hashmap_retain_bumps_refcount() {
let bits = jit_v2_make_hashmap();
type HM = shape_value::heap_value::HashMapKindedRef;
unsafe {
assert_eq!(observe_strong_count::<HM>(bits), 1);
jit_arc_hashmap_retain(bits);
assert_eq!(observe_strong_count::<HM>(bits), 2);
drop_arc::<HM>(bits);
drop_arc::<HM>(bits);
}
}
#[test]
fn deque_retain_bumps_refcount() {
let bits = jit_v2_make_deque();
unsafe {
assert_eq!(observe_strong_count::<DequeData>(bits), 1);
jit_arc_deque_retain(bits);
assert_eq!(observe_strong_count::<DequeData>(bits), 2);
drop_arc::<DequeData>(bits);
drop_arc::<DequeData>(bits);
}
}
#[test]
fn priorityqueue_retain_bumps_refcount() {
let bits = jit_v2_make_priorityqueue();
unsafe {
assert_eq!(observe_strong_count::<PriorityQueueData>(bits), 1);
jit_arc_priorityqueue_retain(bits);
assert_eq!(observe_strong_count::<PriorityQueueData>(bits), 2);
drop_arc::<PriorityQueueData>(bits);
drop_arc::<PriorityQueueData>(bits);
}
}
#[test]
fn channel_retain_bumps_refcount() {
let bits = jit_v2_make_channel();
unsafe {
assert_eq!(observe_strong_count::<ChannelData>(bits), 1);
jit_arc_channel_retain(bits);
assert_eq!(observe_strong_count::<ChannelData>(bits), 2);
drop_arc::<ChannelData>(bits);
drop_arc::<ChannelData>(bits);
}
}
#[test]
fn mutex_retain_bumps_refcount() {
let inner_bits = ValueSlot::from_int(7).raw();
let bits = jit_v2_make_mutex(inner_bits, stack_kind_code::C_INT64);
unsafe {
assert_eq!(observe_strong_count::<MutexData>(bits), 1);
jit_arc_mutex_retain(bits);
assert_eq!(observe_strong_count::<MutexData>(bits), 2);
drop_arc::<MutexData>(bits);
drop_arc::<MutexData>(bits);
}
}
#[test]
fn atomic_retain_bumps_refcount() {
let bits = jit_v2_make_atomic(0);
unsafe {
assert_eq!(observe_strong_count::<AtomicData>(bits), 1);
jit_arc_atomic_retain(bits);
assert_eq!(observe_strong_count::<AtomicData>(bits), 2);
drop_arc::<AtomicData>(bits);
drop_arc::<AtomicData>(bits);
}
}
#[test]
fn lazy_retain_bumps_refcount() {
let bits = jit_v2_make_lazy(0);
unsafe {
assert_eq!(observe_strong_count::<LazyData>(bits), 1);
jit_arc_lazy_retain(bits);
assert_eq!(observe_strong_count::<LazyData>(bits), 2);
drop_arc::<LazyData>(bits);
drop_arc::<LazyData>(bits);
}
}
#[test]
fn hashset_release_decrements_without_dealloc() {
let bits = jit_v2_make_hashset();
unsafe {
jit_arc_hashset_retain(bits);
assert_eq!(observe_strong_count::<HashSetData>(bits), 2);
jit_arc_hashset_release(bits);
assert_eq!(observe_strong_count::<HashSetData>(bits), 1);
drop_arc::<HashSetData>(bits);
}
}
#[test]
fn hashmap_release_decrements_without_dealloc() {
let bits = jit_v2_make_hashmap();
type HM = shape_value::heap_value::HashMapKindedRef;
unsafe {
jit_arc_hashmap_retain(bits);
assert_eq!(observe_strong_count::<HM>(bits), 2);
jit_arc_hashmap_release(bits);
assert_eq!(observe_strong_count::<HM>(bits), 1);
drop_arc::<HM>(bits);
}
}
#[test]
fn deque_release_decrements_without_dealloc() {
let bits = jit_v2_make_deque();
unsafe {
jit_arc_deque_retain(bits);
assert_eq!(observe_strong_count::<DequeData>(bits), 2);
jit_arc_deque_release(bits);
assert_eq!(observe_strong_count::<DequeData>(bits), 1);
drop_arc::<DequeData>(bits);
}
}
#[test]
fn priorityqueue_release_decrements_without_dealloc() {
let bits = jit_v2_make_priorityqueue();
unsafe {
jit_arc_priorityqueue_retain(bits);
assert_eq!(observe_strong_count::<PriorityQueueData>(bits), 2);
jit_arc_priorityqueue_release(bits);
assert_eq!(observe_strong_count::<PriorityQueueData>(bits), 1);
drop_arc::<PriorityQueueData>(bits);
}
}
#[test]
fn channel_release_decrements_without_dealloc() {
let bits = jit_v2_make_channel();
unsafe {
jit_arc_channel_retain(bits);
assert_eq!(observe_strong_count::<ChannelData>(bits), 2);
jit_arc_channel_release(bits);
assert_eq!(observe_strong_count::<ChannelData>(bits), 1);
drop_arc::<ChannelData>(bits);
}
}
#[test]
fn mutex_release_decrements_without_dealloc() {
let inner_bits = ValueSlot::from_int(99).raw();
let bits = jit_v2_make_mutex(inner_bits, stack_kind_code::C_INT64);
unsafe {
jit_arc_mutex_retain(bits);
assert_eq!(observe_strong_count::<MutexData>(bits), 2);
jit_arc_mutex_release(bits);
assert_eq!(observe_strong_count::<MutexData>(bits), 1);
drop_arc::<MutexData>(bits);
}
}
#[test]
fn atomic_release_decrements_without_dealloc() {
let bits = jit_v2_make_atomic(-1);
unsafe {
jit_arc_atomic_retain(bits);
assert_eq!(observe_strong_count::<AtomicData>(bits), 2);
jit_arc_atomic_release(bits);
assert_eq!(observe_strong_count::<AtomicData>(bits), 1);
drop_arc::<AtomicData>(bits);
}
}
#[test]
fn lazy_release_decrements_without_dealloc() {
let bits = jit_v2_make_lazy(0);
unsafe {
jit_arc_lazy_retain(bits);
assert_eq!(observe_strong_count::<LazyData>(bits), 2);
jit_arc_lazy_release(bits);
assert_eq!(observe_strong_count::<LazyData>(bits), 1);
drop_arc::<LazyData>(bits);
}
}
#[test]
fn collection_retain_release_null_bits_safe() {
jit_arc_hashset_retain(0);
jit_arc_hashset_release(0);
jit_arc_hashmap_retain(0);
jit_arc_hashmap_release(0);
jit_arc_deque_retain(0);
jit_arc_deque_release(0);
jit_arc_priorityqueue_retain(0);
jit_arc_priorityqueue_release(0);
jit_arc_channel_retain(0);
jit_arc_channel_release(0);
jit_arc_mutex_retain(0);
jit_arc_mutex_release(0);
jit_arc_atomic_retain(0);
jit_arc_atomic_release(0);
jit_arc_lazy_retain(0);
jit_arc_lazy_release(0);
}
}