Skip to main content

ostd/mm/frame/
unique.rs

1// SPDX-License-Identifier: MPL-2.0
2//! The unique frame pointer that is not shared with others.
3use vstd::atomic::PermissionU64;
4use vstd::prelude::*;
5use vstd::simple_pptr::{self, PPtr};
6
7use crate::specs::mm::frame::meta_region_owners::MetaRegionOwners;
8
9use vstd_extra::cast_ptr::*;
10use vstd_extra::drop_tracking::*;
11use vstd_extra::ownership::*;
12
13use super::meta::{has_safe_slot, AnyFrameMeta, GetFrameError, MetaSlot};
14use super::Frame;
15
16use core::{marker::PhantomData, sync::atomic::Ordering};
17
18use super::meta::mapping::{
19    frame_to_index, frame_to_meta, max_meta_slots, meta_addr, meta_to_frame, META_SLOT_SIZE,
20};
21use super::meta::{REF_COUNT_UNIQUE, REF_COUNT_UNUSED};
22use crate::mm::frame::MetaPerm;
23use crate::mm::{Paddr, PagingLevel, MAX_NR_PAGES, MAX_PADDR, PAGE_SIZE};
24use crate::specs::arch::kspace::FRAME_METADATA_RANGE;
25use crate::specs::arch::paging_consts::PagingConsts;
26use crate::specs::mm::frame::meta_owners::MetaSlotStorage;
27use crate::specs::mm::frame::meta_owners::Metadata;
28use crate::specs::mm::frame::unique::UniqueFrameOwner;
29
30verus! {
31
32pub struct UniqueFrame<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> {
33    pub ptr: PPtr<MetaSlot>,
34    pub _marker: PhantomData<M>,
35}
36
37#[verus_verify]
38impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
39    /// Gets a [`UniqueFrame`] with a specific usage from a raw, unused page.
40    ///
41    /// The caller should provide the initial metadata of the page.
42    /// # Verified Properties
43    /// ## Preconditions
44    /// The page must be unused and the metadata region must be well-formed.
45    /// ## Postconditions
46    /// If the page is valid, the function returns a unique frame.
47    /// ## Safety
48    /// If `paddr` is misaligned or out of bounds, the function will return an error. If it returns a frame,
49    /// it also returns an owner for that frame, indicating that the caller now has exclusive ownership of it.
50    /// See [Safe Encapsulation] for more details.
51    #[verus_spec(res =>
52        with Tracked(regions): Tracked<&mut MetaRegionOwners>
53        -> owner: Tracked<Option<UniqueFrameOwner<M>>>
54        requires
55            old(regions).slots.contains_key(frame_to_index(paddr)),
56            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
57            old(regions).slot_owners[frame_to_index(paddr)].usage is Unused,
58            old(regions).inv(),
59        ensures
60            !has_safe_slot(paddr) ==> res is Err,
61            res is Ok ==> res.unwrap().wf(owner@.unwrap()),
62    )]
63    pub fn from_unused(paddr: Paddr, metadata: M) -> Result<Self, GetFrameError> {
64        #[verus_spec(with Tracked(regions))]
65        let from_unused = MetaSlot::get_from_unused(paddr, metadata, true);
66
67        if let Err(err) = from_unused {
68            proof_with!(|= Tracked(None));
69            Err(err)
70        } else {
71            let (ptr, Tracked(perm)) = from_unused.unwrap();
72            proof_decl! {
73                let tracked owner = UniqueFrameOwner::<M>::from_unused_owner(regions, paddr, perm);
74            }
75            proof_with!(|= Tracked(Some(owner)));
76            Ok(Self { ptr, _marker: PhantomData })
77        }
78    }
79
80    pub open spec fn transmute_spec<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
81        self,
82        transmuted: UniqueFrame<M1>,
83    ) -> bool {
84        &&& transmuted.ptr.addr() == self.ptr.addr()
85        &&& transmuted._marker == PhantomData::<M1>
86    }
87
88    #[verifier::external_body]
89    pub fn transmute<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(self) -> (res: UniqueFrame<
90        M1,
91    >)
92        ensures
93            Self::transmute_spec(self, res),
94    {
95        unimplemented!()
96    }
97
98    /// Repurposes the frame with a new metadata.
99    /// # Verified Properties
100    /// ## Preconditions
101    /// - The caller must provide a valid owner for the frame, and the metadata region invariants must hold.
102    /// - The meta slot's reference count must be `REF_COUNT_UNIQUE`.
103    /// ## Postconditions
104    /// The function returns a new owner for the frame with the new metadata,
105    /// and the metadata region invariants are preserved.
106    /// ## Safety
107    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
108    /// and represents that the caller has exclusive ownership of the frame.
109    #[verus_spec(res =>
110        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
111            Tracked(regions): Tracked<&mut MetaRegionOwners>
112        -> new_owner: Tracked<UniqueFrameOwner<M1>>
113        requires
114            self.wf(owner),
115            owner.inv(),
116            owner.global_inv(*old(regions)),
117            old(regions).slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr()))),
118            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
119            old(regions).inv(),
120        ensures
121            res.wf(new_owner@),
122            new_owner@.meta_perm.value().metadata == metadata,
123            final(regions).inv(),
124    )]
125    pub fn repurpose<M1: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf>(
126        self,
127        metadata: M1,
128    ) -> UniqueFrame<M1> {
129        let tracked mut slot_own = regions.slot_owners.tracked_remove(
130            frame_to_index(meta_to_frame(self.ptr.addr())),
131        );
132        let tracked mut slot_perm = owner.meta_perm.points_to;
133
134        #[verus_spec(with Tracked(&slot_perm))]
135        let slot = self.slot();
136
137        assert(slot_own.inv()) by {
138            let idx = frame_to_index(meta_to_frame(self.ptr.addr()));
139            assert(old(regions).slot_owners.contains_key(idx));
140            assert(old(regions).slot_owners[idx].inv());
141        }
142
143        // SAFETY: We are the sole owner and the metadata is initialized.
144        #[verus_spec(with Tracked(&mut slot_own))]
145        slot.drop_meta_in_place();
146
147        // After drop_meta_in_place, slot_own.inner_perms has uninit storage+vtable.
148        // Extract them for write_meta, which requires uninit vtable_ptr.
149        let tracked mut inner_perms = slot_own.take_inner_perms();
150
151        // write_meta preconditions: connect inner_perms ids to slot cell ids.
152        // global_inv gives: old(regions).slot_owners[idx].inner_perms == owner.meta_perm.inner_perms
153        // owner.inv gives: owner.meta_perm.inner_perms.storage.id() == slot_perm.value().storage.id()
154        // drop_meta_in_place preserves storage.id(), take_inner_perms returns the inner_perms.
155        proof {
156            let idx = frame_to_index(meta_to_frame(self.ptr.addr()));
157            assert(inner_perms.storage.id() == slot_perm.value().storage.id());
158        }
159
160        // Write the new metadata into the slot.
161        let slot = self.ptr.borrow(Tracked(&slot_perm));
162
163        #[verus_spec(with
164            Tracked(&mut inner_perms.storage),
165            Tracked(&mut inner_perms.vtable_ptr)
166        )]
167        slot.write_meta(metadata);
168
169        // Re-sync slot_own with the updated inner_perms (now storage+vtable are init).
170        proof { slot_own.sync_inner(&inner_perms); }
171        let tracked meta_perm = MetaSlot::cast_perm::<M1>(slot_perm, inner_perms);
172
173        let tracked mut new_owner = UniqueFrameOwner::<M1>::from_unused_owner(
174            regions,
175            meta_to_frame(self.ptr.addr()),
176            meta_perm,
177        );
178
179        // SAFETY: The metadata is initialized with type `M1`.
180        proof_with!(|= Tracked(new_owner));
181        self.transmute()
182    }
183
184    /// Gets the metadata of this page.
185    /// Note that this function body differs from the original, because `as_meta_ptr` returns
186    /// a `ReprPtr<MetaSlot, Metadata<M>>` instead of a `*M`. So in order to keep the immutable borrow, we
187    /// borrow the metadata value from that pointer.
188    /// # Verified Properties
189    /// ## Preconditions
190    /// The caller must provide a valid owner for the frame.
191    /// ## Postconditions
192    /// The function returns the metadata of the frame.
193    /// ## Safety
194    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
195    /// and represents that the caller has exclusive ownership of the frame.
196    #[verus_spec(
197        with Tracked(owner): Tracked<&'a UniqueFrameOwner<M>>
198    )]
199    pub fn meta<'a>(&self) -> (l: &'a M)
200        requires
201            owner.inv(),
202            self.wf(*owner),
203        ensures
204            owner.meta_perm.mem_contents().value().metadata == l,
205    {
206        // SAFETY: The type is tracked by the type system.
207        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
208        let slot = self.slot();
209
210        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
211        let ptr = slot.as_meta_ptr();
212
213        &ptr.borrow(Tracked(&owner.meta_perm)).metadata
214    }
215
216    /// Gets the mutable metadata of this page.
217    /// Verified Properties
218    /// ## Preconditions
219    /// The caller must provide a valid owner for the frame.
220    /// ## Postconditions
221    /// The function returns the mutable metadata of the frame.
222    /// ## Safety
223    /// The existence of a valid owner guarantees that the memory is initialized with metadata of type `M`,
224    /// and represents that the caller has exclusive ownership of the frame. (See [Safe Encapsulation])
225    #[verus_spec(
226        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>
227    )]
228    pub fn meta_mut(&mut self) -> (res: ReprPtr<MetaSlot, Metadata<M>>)
229        requires
230            owner.inv(),
231            old(self).wf(*owner),
232        ensures
233            res.addr() == final(self).ptr.addr(),
234            res.ptr.addr() == final(self).ptr.addr(),
235            *final(self) == *old(self),
236    {
237        // SAFETY: The type is tracked by the type system.
238        // And we have the exclusive access to the metadata.
239        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
240        let slot = self.slot();
241
242        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
243        slot.as_meta_ptr()
244    }
245}
246
247impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
248    /// Gets the physical address of the start of the frame.
249    #[verus_spec(
250        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
251        requires
252            owner.inv(),
253            self.wf(*owner),
254        returns
255            meta_to_frame(self.ptr.addr()),
256    )]
257    pub fn start_paddr(&self) -> Paddr {
258        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
259        let slot = self.slot();
260
261        #[verus_spec(with Tracked(&owner.meta_perm.points_to))]
262        slot.frame_paddr()
263    }
264
265    /// Gets the paging level of this page.
266    ///
267    /// This is the level of the page table entry that maps the frame,
268    /// which determines the size of the frame.
269    ///
270    /// Currently, the level is always 1, which means the frame is a regular
271    /// page frame.
272    pub const fn level(&self) -> PagingLevel {
273        1
274    }
275
276    /// Gets the size of this page in bytes.
277    pub const fn size(&self) -> usize {
278        PAGE_SIZE
279    }
280
281    /*    /// Gets the dynamically-typed metadata of this frame.
282    ///
283    /// If the type is known at compile time, use [`Frame::meta`] instead.
284
285    #[verifier::external_body]
286    pub fn dyn_meta(&self) -> &M {
287        // SAFETY: The metadata is initialized and valid.
288        unsafe { &*self.slot().dyn_meta_ptr::<M>() }
289    }
290
291    /// Gets the dynamically-typed metadata of this frame.
292    ///
293    /// If the type is known at compile time, use [`Frame::meta`] instead.
294
295    #[verifier::external_body]
296    pub fn dyn_meta_mut(&mut self) -> &mut FrameMeta {
297        // SAFETY: The metadata is initialized and valid. We have the exclusive
298        // access to the frame.
299        unsafe { &mut *self.slot().dyn_meta_ptr() }
300    }*/
301    pub open spec fn into_raw_requires(self, regions: MetaRegionOwners) -> bool {
302        &&& regions.slot_owners.contains_key(frame_to_index(meta_to_frame(self.ptr.addr())))
303        &&& regions.slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == 0
304        &&& regions.inv()
305    }
306
307    pub open spec fn into_raw_ensures(
308        self,
309        old_regions: MetaRegionOwners,
310        regions: MetaRegionOwners,
311        r: Paddr,
312    ) -> bool {
313        &&& r == meta_to_frame(self.ptr.addr())
314        &&& regions.inv()
315        &&& regions.slots =~= old_regions.slots
316        &&& regions.slot_owners[frame_to_index(r)].raw_count == 1
317        &&& forall|i: usize|
318            #![trigger regions.slot_owners[i]]
319            i != frame_to_index(r) ==> regions.slot_owners[i] == old_regions.slot_owners[i]
320    }
321
322    /// Resets the frame to unused without up-calling the allocator.
323    ///
324    /// This is solely useful for the allocator implementation/testing and
325    /// is highly experimental. Usage of this function is discouraged.
326    ///
327    /// Usage of this function other than the allocator would actually leak
328    /// the frame since the allocator would not be aware of the frame.
329    //
330    // FIXME: We may have a better `Segment` and `UniqueSegment` design to
331    // allow the allocator hold the ownership of all the frames in a chunk
332    // instead of the head. Then this weird public API can be `#[cfg(ktest)]`.
333    #[verus_spec(
334        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
335            Tracked(regions): Tracked<&mut MetaRegionOwners>
336        requires
337            self.wf(owner),
338            owner.inv(),
339            old(regions).inv(),
340            old(regions).slot_owners.contains_key(owner.slot_index),
341            old(regions).slot_owners[owner.slot_index].raw_count == 0,
342            old(regions).slot_owners[owner.slot_index].self_addr == meta_addr(owner.slot_index),
343            !old(regions).slots.contains_key(owner.slot_index),
344            owner.meta_perm.inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
345            owner.meta_perm.inner_perms.in_list.value() == 0,
346            owner.meta_perm.inner_perms.storage.is_init(),
347            owner.meta_perm.inner_perms.vtable_ptr.is_init(),
348        ensures
349            final(regions).slot_owners[owner.slot_index].raw_count == 0,
350            final(regions).inv(),
351    )]
352    pub fn reset_as_unused(self) {
353        let ghost idx = owner.slot_index;
354        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
355        let tracked perm = owner.meta_perm.points_to;
356
357        proof {
358            slot_own.inner_perms = owner.meta_perm.inner_perms;
359        }
360
361        #[verus_spec(with Tracked(&perm))]
362        let slot = self.slot();
363        slot.ref_count.store(Tracked(&mut slot_own.inner_perms.ref_count), 0);
364
365        // SAFETY: We are the sole owner and the reference count is 0.
366        // The slot is initialized.
367        #[verus_spec(with Tracked(&mut slot_own))]
368        slot.drop_last_in_place();
369
370        proof {
371            regions.slot_owners.tracked_insert(idx, slot_own);
372            regions.slots.tracked_insert(idx, perm);
373        }
374    }
375    /// Converts this frame into a raw physical address.
376    #[verus_spec(r =>
377        with Tracked(owner): Tracked<&UniqueFrameOwner<M>>,
378            Tracked(regions): Tracked<&mut MetaRegionOwners>
379        requires
380            Self::into_raw_requires(self, *old(regions)),
381            self.wf(*owner),
382            owner.inv(),
383            old(regions).inv(),
384            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].raw_count == 0,
385            old(regions).slot_owners[frame_to_index(meta_to_frame(self.ptr.addr()))].inner_perms.ref_count.value() != REF_COUNT_UNUSED,
386        ensures
387            Self::into_raw_ensures(self, *old(regions), *final(regions), r),
388            final(regions).inv(),
389    )]
390    pub(crate) fn into_raw(self) -> Paddr {
391        #[verus_spec(with Tracked(owner))]
392        let paddr = self.start_paddr();
393
394        assert(self.constructor_requires(*old(regions)));
395        let _ = ManuallyDrop::new(self, Tracked(regions));
396
397        paddr
398    }
399
400    /// Restores a raw physical address back into a unique frame.
401    ///
402    /// # Safety
403    ///
404    /// The caller must ensure that the physical address is valid and points to
405    /// a forgotten frame that was previously casted by [`Self::into_raw`].
406    #[verus_spec(res =>
407        with Tracked(regions): Tracked<&mut MetaRegionOwners>,
408            Tracked(meta_perm): Tracked<PointsTo<MetaSlot, Metadata<M>>>,
409            Tracked(meta_own): Tracked<M::Owner>
410    )]
411    pub(crate) fn from_raw(paddr: Paddr) -> (res: (Self, Tracked<UniqueFrameOwner<M>>))
412        requires
413            paddr < MAX_PADDR,
414            paddr % PAGE_SIZE == 0,
415            old(regions).inv(),
416            old(regions).slot_owners.contains_key(frame_to_index(paddr)),
417            old(regions).slot_owners[frame_to_index(paddr)].raw_count > 0,
418            !old(regions).slots.contains_key(frame_to_index(paddr)),
419            meta_perm.inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
420            meta_perm.addr() == frame_to_meta(paddr),
421        ensures
422            res.0.ptr.addr() == frame_to_meta(paddr),
423            res.0.wf(res.1@),
424            res.1@.meta_own == meta_own,
425            res.1@.meta_perm == meta_perm,
426            final(regions).inv(),
427            final(regions).slot_owners[frame_to_index(paddr)].raw_count == old(
428                regions,
429            ).slot_owners[frame_to_index(paddr)].raw_count - 1,
430    {
431        let vaddr = frame_to_meta(paddr);
432        let ptr = vstd::simple_pptr::PPtr::<MetaSlot>::from_addr(vaddr);
433
434        proof {
435            let tracked mut slot_own = regions.slot_owners.tracked_remove(frame_to_index(paddr));
436            slot_own.raw_count = (slot_own.raw_count - 1) as usize;
437            regions.slot_owners.tracked_insert(frame_to_index(paddr), slot_own);
438        }
439
440        let tracked owner = UniqueFrameOwner {
441            meta_own,
442            meta_perm,
443            slot_index: frame_to_index(paddr),
444        };
445
446        (Self { ptr, _marker: PhantomData }, Tracked(owner))
447    }
448
449    #[verifier::external_body]
450    #[verus_spec(
451        with Tracked(slot_perm): Tracked<&'a vstd::simple_pptr::PointsTo<MetaSlot>>
452    )]
453    pub fn slot<'a>(&self) -> &'a MetaSlot
454        requires
455            slot_perm.pptr() == self.ptr,
456            slot_perm.is_init(),
457        returns
458            slot_perm.value(),
459    {
460        unimplemented!()
461        // SAFETY: `ptr` points to a valid `MetaSlot` that will never be
462        // mutably borrowed, so taking an immutable reference to it is safe.
463        //        unsafe { &*self.ptr }
464
465    }
466
467}
468
469impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf + ?Sized> UniqueFrame<M> {
470    #[verus_spec(
471        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
472            Tracked(regions): Tracked<&mut MetaRegionOwners>,
473        requires
474            old(self).wf(owner),
475            owner.inv(),
476            old(regions).slot_owners.contains_key(owner.slot_index),
477            old(regions).slot_owners[owner.slot_index].raw_count == 0,
478            old(regions).slot_owners[owner.slot_index].self_addr == meta_addr(owner.slot_index),
479            !old(regions).slots.contains_key(owner.slot_index),
480            owner.meta_perm.inner_perms.ref_count.value() == REF_COUNT_UNIQUE,
481            owner.meta_perm.inner_perms.in_list.value() == 0,
482            owner.meta_perm.inner_perms.storage.is_init(),
483            owner.meta_perm.inner_perms.vtable_ptr.is_init(),
484            old(regions).inv(),
485        ensures
486            final(regions).slot_owners[owner.slot_index].raw_count == 0,
487            final(regions).inv(),
488    )]
489    pub(crate) fn drop(&mut self) {
490        let ghost idx = owner.slot_index;
491        let ghost inner_storage_id = owner.meta_perm.inner_perms.storage.id();
492        let ghost inner_ref_count_id = owner.meta_perm.inner_perms.ref_count.id();
493        let ghost inner_vtable_pptr = owner.meta_perm.inner_perms.vtable_ptr.pptr();
494        let ghost inner_in_list_id = owner.meta_perm.inner_perms.in_list.id();
495
496        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
497        let tracked perm = owner.meta_perm.points_to;
498
499        proof {
500            assert(perm.value().storage.id() == inner_storage_id);
501            assert(perm.value().ref_count.id() == inner_ref_count_id);
502            slot_own.inner_perms = owner.meta_perm.inner_perms;
503        }
504        ;
505
506        // SAFETY: We are the sole owner and the reference count is 0.
507        // The slot is initialized.
508        #[verus_spec(with Tracked(&perm))]
509        let slot = self.slot();
510
511        #[verus_spec(with Tracked(&mut slot_own))]
512        slot.drop_last_in_place();
513
514        proof {
515            regions.slot_owners.tracked_insert(idx, slot_own);
516            regions.slots.tracked_insert(idx, perm);
517        }
518
519        //        super::allocator::get_global_frame_allocator().dealloc(self.start_paddr(), PAGE_SIZE);
520    }
521}
522
523impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> Frame<M> {
524    /// Converts a unique frame into a shared one by setting ref_count = 1.
525    /// Inherent sibling of `From<UniqueFrame<M>> for Frame<M>`: freed from
526    /// the trait-signature straitjacket, this version can thread the tracked
527    /// `MetaRegionOwners` via `verus_spec`.
528    #[verus_spec(
529        with Tracked(owner): Tracked<UniqueFrameOwner<M>>,
530            Tracked(regions): Tracked<&mut MetaRegionOwners>
531    )]
532    pub fn from_unique(unique: UniqueFrame<M>) -> (res: Self)
533        requires
534            unique.wf(owner),
535            owner.inv(),
536            old(regions).inv(),
537            old(regions).slots.contains_key(owner.slot_index),
538            old(regions).slot_owners.contains_key(owner.slot_index),
539            old(regions).slots[owner.slot_index].pptr() == unique.ptr,
540            old(regions).slot_owners[owner.slot_index].inner_perms.ref_count.id()
541                == old(regions).slots[owner.slot_index].value().ref_count.id(),
542        ensures
543            final(regions).slots == old(regions).slots,
544            final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
545    {
546        let ghost idx_g = owner.slot_index;
547        let idx = frame_to_index(meta_to_frame(unique.ptr.addr()));
548        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
549        let tracked slot_perm = regions.slots.tracked_borrow(idx);
550        let tracked mut inner_perms = slot_own.take_inner_perms();
551
552        #[verus_spec(with Tracked(&slot_perm))]
553        let slot = unique.slot();
554        slot.ref_count.store(Tracked(&mut inner_perms.ref_count), 1);
555
556        proof {
557            slot_own.sync_inner(&inner_perms);
558            regions.slot_owners.tracked_insert(idx, slot_own);
559        }
560
561        // UniqueFrame and Frame have identical layout (ptr + PhantomData),
562        // so reconstructing Frame from unique's ptr preserves the handle.
563        Frame { ptr: unique.ptr, _marker: PhantomData }
564    }
565}
566
567impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> UniqueFrame<M> {
568    /// Tries to convert a shared frame into a unique one by CAS'ing ref_count
569    /// from 1 to `REF_COUNT_UNIQUE`. Inherent sibling of
570    /// `TryFrom<Frame<M>> for UniqueFrame<M>`.
571    #[verus_spec(
572        with Tracked(regions): Tracked<&mut MetaRegionOwners>
573    )]
574    pub fn try_from_shared(frame: Frame<M>) -> (res: Result<Self, Frame<M>>)
575        requires
576            frame.inv(),
577            old(regions).inv(),
578            old(regions).slots.contains_key(
579                frame_to_index(meta_to_frame(frame.ptr.addr()))),
580            old(regions).slot_owners.contains_key(
581                frame_to_index(meta_to_frame(frame.ptr.addr()))),
582            old(regions).slots[frame_to_index(meta_to_frame(frame.ptr.addr()))].pptr()
583                == frame.ptr,
584            old(regions).slot_owners[frame_to_index(meta_to_frame(frame.ptr.addr()))]
585                .inner_perms.ref_count.id()
586                == old(regions).slots[frame_to_index(meta_to_frame(frame.ptr.addr()))]
587                    .value().ref_count.id(),
588        ensures
589            final(regions).slots == old(regions).slots,
590            final(regions).slot_owners.dom() == old(regions).slot_owners.dom(),
591    {
592        let idx = frame_to_index(meta_to_frame(frame.ptr.addr()));
593        let tracked mut slot_own = regions.slot_owners.tracked_remove(idx);
594        let tracked slot_perm = regions.slots.tracked_borrow(idx);
595        let tracked mut inner_perms = slot_own.take_inner_perms();
596
597        #[verus_spec(with Tracked(&slot_perm))]
598        let slot = frame.slot();
599        let res = slot.ref_count.compare_exchange(
600            Tracked(&mut inner_perms.ref_count),
601            1,
602            REF_COUNT_UNIQUE,
603        );
604
605        proof {
606            slot_own.sync_inner(&inner_perms);
607            regions.slot_owners.tracked_insert(idx, slot_own);
608        }
609
610        match res {
611            // Frame and UniqueFrame share layout; construct directly.
612            Ok(_) => Ok(UniqueFrame { ptr: frame.ptr, _marker: PhantomData }),
613            Err(_) => Err(frame),
614        }
615    }
616}
617
618impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> From<UniqueFrame<M>> for Frame<M> {
619    #[verifier::external_body]
620    fn from(unique: UniqueFrame<M>) -> Self {
621        Frame::from_unique(unique)
622    }
623}
624
625impl<M: AnyFrameMeta + Repr<MetaSlotStorage> + OwnerOf> TryFrom<Frame<M>> for UniqueFrame<M> {
626    type Error = Frame<M>;
627
628    /// Tries to get a unique frame from a shared frame.
629    ///
630    /// If the reference count is not 1, the frame is returned back.
631    #[verifier::external_body]
632    fn try_from(frame: Frame<M>) -> Result<Self, Self::Error> {
633        UniqueFrame::try_from_shared(frame)
634    }
635}
636} // verus!