Section ALLOC.
Variable m1: mem.
Variables lo hi: Z.
Variable m2: mem.
Variable b: block.
Hypothesis ALLOC: alloc m1 lo hi = (m2, b).
Local Hint Resolve valid_block_alloc fresh_block_alloc valid_new_block: mem.
Local Hint Resolve perm_alloc_1 perm_alloc_2 perm_alloc_3 perm_alloc_4: mem.
Local Hint Resolve valid_access_alloc_other valid_access_alloc_same: mem.
End ALLOC.
Local Hint Resolve valid_block_alloc fresh_block_alloc valid_new_block: mem.
Local Hint Resolve valid_access_alloc_other valid_access_alloc_same: mem.
(** ** Properties related to [free]. *)
Local Hint Resolve valid_block_free_1 valid_block_free_2: mem.
End FREE.
Local Hint Resolve valid_block_free_1 valid_block_free_2
perm_free_1 perm_free_2 perm_free_3
valid_access_free_1 valid_access_free_inv_1: mem.
(** ** Properties related to [drop_perm] *)
End DROP.
(** * Generic injections *)
(** A memory state [m1] generically injects into another memory state [m2] via the memory injection [f] if the following conditions hold: - each access in [m2] that corresponds to a valid access in [m1] is itself valid; - the memory value associated in [m1] to an accessible address must inject into [m2]'s memory value at the corersponding address. *)
Record mem_inj (f: meminj) (m1 m2: mem) : Prop :=
mk_mem_inj {
mi_perm:
forall b1 b2 delta ofs k p,
f b1 = Some(b2, delta) ->
perm m1 b1 ofs k p ->
perm m2 b2 (ofs + delta) k p;
mi_align:
forall b1 b2 delta chunk ofs p,
f b1 = Some(b2, delta) ->
range_perm m1 b1 ofs (ofs + size_chunk chunk) Max p ->
(align_chunk chunk | delta);
mi_memval:
forall b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
perm m1 b1 ofs Cur Readable ->
memval_inject f (ZMap.get ofs m1.(mem_contents)#b1) (ZMap.get (ofs+delta) m2.(mem_contents)#b2)
}.
(** Preservation of permissions *)
(** Preservation of loads. *)
(** Preservation of stores. *)
Definition meminj_no_overlap (f: meminj) (m: mem) : Prop :=
forall b1 b1' delta1 b2 b2' delta2 ofs1 ofs2,
b1 <> b2 ->
f b1 = Some (b1', delta1) ->
f b2 = Some (b2', delta2) ->
perm m b1 ofs1 Max Nonempty ->
perm m b2 ofs2 Max Nonempty ->
b1' <> b2' \/ ofs1 + delta1 <> ofs2 + delta2.
(** Preservation of allocations *)
Definition inj_offset_aligned (delta: Z) (size: Z) : Prop :=
forall chunk, size_chunk chunk <= size -> (align_chunk chunk | delta).
(** Preservation of [drop_perm] operations. *)
(** * Memory extensions *)
(**  A store [m2] extends a store [m1] if [m2] can be obtained from [m1] by increasing the sizes of the memory blocks of [m1] (decreasing the low bounds, increasing the high bounds), and replacing some of the [Vundef] values stored in [m1] by more defined values stored in [m2] at the same locations. *)
Record extends' (m1 m2: mem) : Prop :=
mk_extends {
mext_next: nextblock m1 = nextblock m2;
mext_inj:  mem_inj inject_id m1 m2;
mext_perm_inv: forall b ofs k p,
perm m2 b ofs k p ->
perm m1 b ofs k p \/ ~perm m1 b ofs Max Nonempty
}.
Definition extends := extends'.
(** * Memory injections *)
(** A memory state [m1] injects into another memory state [m2] via the memory injection [f] if the following conditions hold: - each access in [m2] that corresponds to a valid access in [m1] is itself valid; - the memory value associated in [m1] to an accessible address must inject into [m2]'s memory value at the corersponding address; - unallocated blocks in [m1] must be mapped to [None] by [f]; - if [f b = Some(b', delta)], [b'] must be valid in [m2]; - distinct blocks in [m1] are mapped to non-overlapping sub-blocks in [m2]; - the sizes of [m2]'s blocks are representable with unsigned machine integers; - pointers that could be represented using unsigned machine integers remain representable after the injection. *)
Record inject' (f: meminj) (m1 m2: mem) : Prop :=
mk_inject {
mi_inj:
mem_inj f m1 m2;
mi_freeblocks:
forall b, ~(valid_block m1 b) -> f b = None;
mi_mappedblocks:
forall b b' delta, f b = Some(b', delta) -> valid_block m2 b';
mi_no_overlap:
meminj_no_overlap f m1;
mi_representable:
forall b b' delta ofs,
f b = Some(b', delta) ->
perm m1 b (Ptrofs.unsigned ofs) Max Nonempty \/ perm m1 b (Ptrofs.unsigned ofs - 1) Max Nonempty ->
delta >= 0 /\ 0 <= Ptrofs.unsigned ofs + delta <= Ptrofs.max_unsigned;
mi_perm_inv:
forall b1 ofs b2 delta k p,
f b1 = Some(b2, delta) ->
perm m2 b2 (ofs + delta) k p ->
perm m1 b1 ofs k p \/ ~perm m1 b1 ofs Max Nonempty
}.
Definition inject := inject'.
Local Hint Resolve mi_mappedblocks: mem.
(** Preservation of access validity and pointer validity *)
Local Hint Resolve valid_block_inject_1 valid_block_inject_2: mem.
(** The following lemmas establish the absence of machine integer overflow during address computations. *)
(** Preservation of loads *)
(** Preservation of stores *)
(* Preservation of allocations *)
(** Preservation of [free] operations *)

Theorem free_parallel_inject:
forall f m1 m2 b lo hi m1' b' delta,
inject f m1 m2 ->
free m1 b lo hi = Some m1' ->
f b = Some(b', delta) ->
exists m2',
free m2 b' (lo + delta) (hi + delta) = Some m2'
/\ inject f m1' m2'.