rocq/theories/Pieces.v
The resource model of the program logic (Logic.v, docs/logic.md), shared with the logic spikes: the pieces of memory an assertion may own, keyed by identity, and the facts about the whole memory that make owning them mean something.
A piece is an object's life (PLive), or one byte (PByte) or aux slot (PAux) at an offset in it. Pieces are keyed by identity, not address, because the model's fresh lets a new object take the addresses of a freed one: an address may belong to two identities in turn, an identity never to two objects. One more kind of piece is no memory: the ghost name of a string the world lends (PName), such as a locale's name, which the world interpretation ties to the world so that a proof can remember, across steps, which string a library call returned.
Two facts about the whole memory are the logics' state interpretation. Live objects do not overlap (live_disjoint), which a run keeps, so a store into one object leaves every other live object's bytes alone. And a safepoint changes no region and no byte, and changes an aux slot only where the capability stored there names a freed object (safepoint_shape, from Runtime.v's collector_live, non_moving and aux_round_trip), so no safepoint frees a live object (keeps_live, once a premise, now a lemma).
Pieces
A piece of memory an assertion may own: the life of the object of identity b, or the byte or aux slot at offset o in it; or the ghost name of the string the world lends under the key k, such as the name of locale category k, which is no memory at all.
| | | PLive | b : Z | |
| | | PByte | b o : Z | |
| | | PAux | b o : Z | |
| | | PName | k : Z |
The identity a piece belongs to; a name, which belongs to no object, says 0, and facts about objects skip it (mem_piece).
The piece p is a piece of memory, not a name.
The null pointer, a constant 0 at class p.
The whole memory
The object of identity b is live in m, with the region reg.
The live objects of m do not overlap.
m and m' have the same objects, each with the same region.
From m to m', every aux slot is kept, or held a capability of an object freed in m' and now holds one that traps as a freed one does: what the collector may do at a safepoint (aux_round_trip).
The aux slot at a holds the capability c, or c names a freed object and the slot holds one that traps as a freed one does: a stored capability is known up to the collector's rewriting of dead ones (aux_moves). For a capability whose object is live, or no object's, this is equality (aux_holds_live).
A freed object's capability stays freed while objects keep their regions.
Explore proof 4 tactics
Initial goal
intros m m′ c Hr b & reg & Hc & E & L
exists b, reg
rewrite Hr
auto
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A capability that traps as a freed one keeps doing so while objects keep their regions.
Explore proof 4 tactics
Initial goal
intros m m′ c Hr H a size r align Hs
rewrite <- Ha size r align Hs
unfold cap_access_res
destruct c ; try reflexivity ; rewrite Hr ; reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
What an aux slot is known to hold survives what a safepoint may do to it (aux_moves) while objects keep their regions.
Explore proof 12 tactics
Initial goal
intros m m′ a c Hr Hm E | Hf & Ht ; destruct Hma as E′ | Hf′ & Ht′
4 openfocused goal
focused goal
–left
4 opendeferred goal
deferred goal
rewrite E′
4 opendeferred goal
deferred goal
exact E
3 opendeferred goal
deferred goal
–right
3 opendeferred goal
subst c
3 opendeferred goal
split ; exact Hf′ | exact Ht′
2 opendeferred goal
–right
2 openrewrite E′
2 opensplit ; exact freed_in_same_ _ _ Hr Hf | exact traps_as_freed_same_ _ _ Hr Ht
–right
split ; exact freed_in_same_ _ _ Hr Hf | exact Ht′
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
For no object's capability, or a live object's, aux_holds is equality.
Explore proof 5 tactics
Initial goal
intros m a c E | b & reg & Hc & E & L & _ Hc′ ; exact E |
destruct Hc′ as [ ->| ( b′ & reg′ & -> & E′ & L′ ) ] ; destruct Hc as [ ?|? ] ; discriminate |
destruct Hc as Hc | Hc ; | discriminate
injection Hc as ←
congruence
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A capability whose object is not freed is exactly what the slot holds: the collector rewrites only freed objects' capabilities.
Explore proof 1 tactics
Bytes
A store of size bytes at a leaves every other byte.
Explore proof 7 tactics
Initial goal
intros m a size x a′ H
unfold store_bytes ; cbn [ m_bytes ]
destruct a ≤? a′ && a′ <? a + size eqn: E ; | reflexivity
apply andb_true_iff in E as E1 E2
apply Z.leb_le in E1
apply Z.ltb_lt in E2
lia
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
An 8-byte store of an unsigned 64-bit v reads back as v (ExternalCalls.v's stored_bytes_value).
Explore proof 5 tactics
Initial goal
intros m a v Hv
rewrite stored_bytes_value by lia
change 256 ^ 8 with 2 ^ 64
apply Z.mod_small
exact Hv
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Neither a byte store nor an aux store changes an object.
Explore proof 1 tactics
Allocation
After allocating q at base, the object of identity base is the new one, and every other identity finds what it found before.
Explore proof 2 tactics
Initial goal
intros m q base b
reflexivity
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Allocating at a fresh base keeps live objects apart.
Explore proof 22 tactics
Initial goal
intros m q base Hd Hf Hq b1 r1 b2 r2 E1 L1 E2 L2 Hne
destruct Hf as _ & _ & _ & _ & Hover & _
rewrite object_region_allocated in E1 , E2
destruct Z.eqb_specbase b1 as [ <-| N1 ] ; destruct Z.eqb_specbase b2 as [ <-| N2 ]
4 openfocused goal
focused goal
focused goal
–congruence
3 opendeferred goal
deferred goal
deferred goal
–injection E1 as ←
3 opendeferred goal
deferred goal
cbn [ r_end ]
3 opendeferred goal
deferred goal
specialize Hoverb2 r2 E2
3 opendeferred goal
deferred goal
destruct Z_le_gt_decbase + req_extentq b2 ; left ; lia |
3 opendeferred goal
deferred goal
destruct Z_le_gt_decr_endr2 base ; right ; lia |
3 opendeferred goal
deferred goal
exfalso
3 opendeferred goal
deferred goal
apply Hover
3 opendeferred goal
deferred goal
lia
2 opendeferred goal
deferred goal
–injection E2 as ←
2 opendeferred goal
cbn [ r_end ]
2 opendeferred goal
specialize Hoverb1 r1 E1
2 opendeferred goal
destruct Z_le_gt_decr_endr1 base ; left ; lia |
2 opendeferred goal
destruct Z_le_gt_decbase + req_extentq b1 ; right ; lia |
2 opendeferred goal
exfalso
2 opendeferred goal
apply Hover
2 opendeferred goal
lia
deferred goal
–exact Hdb1 r1 b2 r2 conjE1 L1 conjE2 L2 Hne
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
Safepoints
What any runtime R does at a safepoint: by Runtime.v's collector_live it frees no object.
No safepoint of R frees a live object, the premise Buffer.v once took: a safepoint changes no region (collector_live).
Explore proof 3 tactics
Initial goal
intros s m s′ m′ b reg Hsp E _
rewrite R.collector_live_ _ _ _ Hsp
exact E
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A safepoint keeps every object's region (collector_live) and every byte, and changes an aux slot only as aux_moves allows.
Explore proof 7 tactics
Initial goal
intros s m s′ m′ Hsp
split ; | split
3 open–intros b
3 openrewrite R.collector_live_ _ _ _ Hsp
3 openreflexivity
2 open–exact R.non_moving_ _ _ _ Hsp
–exact R.aux_round_trip_ _ _ _ Hsp
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.
Source script
A safepoint of R keeps live objects apart: it changes no region.
Explore proof 4 tactics
Initial goal
intros s m s′ m′ Hsp Hd b1 r1 b2 r2 E1 L1 E2 L2
destruct safepoint_shape_ _ _ _ Hsp as Hr & _
rewrite Hr in E1 , E2
exact Hdb1 r1 b2 r2 conjE1 L1 conjE2 L2
No remaining goals.
Qed
✓ Proof checked and closed by Rocq.